WNM: Collocated Interference Reporting

Add support for negotiating WNM Collocated Interference Reporting. This
allows hostapd to request associated STAs to report their collocated
interference information and wpa_supplicant to process such request and
reporting. The actual values (Collocated Interference Report Elements)
are out of scope of hostapd and wpa_supplicant, i.e., external
components are expected to generated and process these.

For hostapd/AP, this mechanism is enabled by setting
coloc_intf_reporting=1 in configuration. STAs are requested to perform
reporting with "COLOC_INTF_REQ <addr> <Automatic Report Enabled> <Report
Timeout>" control interface command. The received reports are indicated
as control interface events "COLOC-INTF-REPORT <addr> <dialog token>
<hexdump of report elements>".

For wpa_supplicant/STA, this mechanism is enabled by setting
coloc_intf_reporting=1 in configuration and setting Collocated
Interference Report Elements as a hexdump with "SET coloc_intf_elems
<hexdump>" control interface command. The hexdump can contain one or
more Collocated Interference Report Elements (each including the
information element header). For additional testing purposes, received
requests are reported with "COLOC-INTF-REQ <dialog token> <automatic
report enabled> <report timeout>" control interface events and
unsolicited reports can be sent with "COLOC_INTF_REPORT <hexdump>".

This commit adds support for reporting changes in the collocated
interference (Automatic Report Enabled == 1 and partial 3), but not for
periodic reports (2 and other part of 3).

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2018-10-30 14:00:00 +02:00 committed by Jouni Malinen
parent 224eddb03b
commit d514b50265
18 changed files with 324 additions and 1 deletions

View file

@ -4108,6 +4108,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
bss->coloc_intf_reporting = atoi(pos);
#endif /* CONFIG_OWE */
} else {
wpa_printf(MSG_ERROR,

View file

@ -992,6 +992,42 @@ fail:
return ret;
}
static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
const char *cmd)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
unsigned int auto_report, timeout;
if (hwaddr_aton(cmd, addr)) {
wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
return -1;
}
sta = ap_get_sta(hapd, addr);
if (!sta) {
wpa_printf(MSG_DEBUG, "Station " MACSTR
" not found for Collocated Interference Request",
MAC2STR(addr));
return -1;
}
pos = cmd + 17;
if (*pos != ' ')
return -1;
pos++;
auto_report = atoi(pos);
pos = os_strchr(pos, ' ');
if (!pos)
return -1;
pos++;
timeout = atoi(pos);
return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
}
#endif /* CONFIG_WNM_AP */
@ -2961,6 +2997,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
reply_len = -1;
} else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
reply_len = -1;
#endif /* CONFIG_WNM_AP */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,

View file

@ -684,6 +684,8 @@ struct hostapd_bss_config {
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
};
/**

View file

@ -178,6 +178,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
case 1: /* Bits 8-15 */
if (hapd->conf->proxy_arp)
*pos |= 0x10; /* Bit 12 - Proxy ARP */
if (hapd->conf->coloc_intf_reporting) {
/* Bit 13 - Collocated Interference Reporting */
*pos |= 0x20;
}
break;
case 2: /* Bits 16-23 */
if (hapd->conf->wnm_sleep_mode)

View file

@ -453,6 +453,48 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
}
static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf,
size_t len)
{
u8 dialog_token;
char *hex;
size_t hex_len;
if (!hapd->conf->coloc_intf_reporting) {
wpa_printf(MSG_DEBUG,
"WNM: Ignore unexpected Collocated Interference Report from "
MACSTR, MAC2STR(addr));
return;
}
if (len < 1) {
wpa_printf(MSG_DEBUG,
"WNM: Ignore too short Collocated Interference Report from "
MACSTR, MAC2STR(addr));
return;
}
dialog_token = *buf++;
len--;
wpa_printf(MSG_DEBUG,
"WNM: Received Collocated Interference Report frame from "
MACSTR " (dialog_token=%u)",
MAC2STR(addr), dialog_token);
wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
buf, len);
hex_len = 2 * len + 1;
hex = os_malloc(hex_len);
if (!hex)
return;
wpa_snprintf_hex(hex, hex_len, buf, len);
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
MAC2STR(addr), dialog_token, hex);
os_free(hex);
}
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@ -483,6 +525,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
plen);
return 0;
case WNM_COLLOCATED_INTERFERENCE_REPORT:
ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
plen);
return 0;
}
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
@ -681,3 +727,40 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
unsigned int auto_report, unsigned int timeout)
{
u8 buf[100], *pos;
struct ieee80211_mgmt *mgmt;
u8 dialog_token = 1;
if (auto_report > 3 || timeout > 63)
return -1;
os_memset(buf, 0, sizeof(buf));
mgmt = (struct ieee80211_mgmt *) buf;
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.coloc_intf_req.action =
WNM_COLLOCATED_INTERFERENCE_REQ;
mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
pos = &mgmt->u.action.u.coloc_intf_req.req_info;
pos++;
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;
}
return 0;
}

View file

@ -24,5 +24,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *nei_rep, size_t nei_rep_len,
const u8 *mbo_attrs, size_t mbo_len);
void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
unsigned int auto_report, unsigned int timeout);
#endif /* WNM_AP_H */

View file

@ -921,6 +921,16 @@ struct ieee80211_mgmt {
* Entries (optional) */
u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
u8 action; /* 11 */
u8 dialog_token;
u8 req_info;
} STRUCT_PACKED coloc_intf_req;
struct {
u8 action; /* 12 */
u8 dialog_token;
u8 variable[];
} STRUCT_PACKED coloc_intf_report;
struct {
u8 action; /* 15 */
u8 variable[];

View file

@ -332,6 +332,13 @@ extern "C" {
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
/* Collocated Interference Request frame received;
* parameters: <dialog token> <automatic report enabled> <report timeout> */
#define COLOC_INTF_REQ "COLOC-INTF-REQ "
/* Collocated Interference Report frame received;
* parameters: <STA address> <dialog token> <hexdump of report elements> */
#define COLOC_INTF_REPORT "COLOC-INTF-REPORT "
/* MBO IE with cellular data connection preference received */
#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "

View file

@ -2200,6 +2200,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
/* WNM-Sleep Mode Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
ret = -1;
#ifdef CONFIG_WNM
/* WNM - Collocated Interference Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x0b", 2) < 0)
ret = -1;
#endif /* CONFIG_WNM */
#ifdef CONFIG_HS20
/* WNM-Notification */

View file

@ -4755,6 +4755,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
};
#undef FUNC

View file

@ -1469,6 +1469,15 @@ struct wpa_config {
* profile automatically
*/
int dpp_config_processing;
/**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
* 0 = disabled (false)
* 1 = enabled (true)
*/
int coloc_intf_reporting;
};

View file

@ -1511,7 +1511,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->dpp_config_processing)
fprintf(f, "dpp_config_processing=%d\n",
config->dpp_config_processing);
if (config->coloc_intf_reporting)
fprintf(f, "coloc_intf_reporting=%d\n",
config->coloc_intf_reporting);
}
#endif /* CONFIG_NO_CONFIG_WRITE */

View file

@ -750,6 +750,15 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
} else if (os_strcasecmp(cmd, "roaming") == 0) {
ret = wpa_drv_roaming(wpa_s, atoi(value), NULL);
#ifdef CONFIG_WNM
} else if (os_strcasecmp(cmd, "coloc_intf_elems") == 0) {
struct wpabuf *elems;
elems = wpabuf_parse_bin(value);
if (!elems)
return -1;
wnm_set_coloc_intf_elems(wpa_s, elems);
#endif /* CONFIG_WNM */
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@ -7437,6 +7446,22 @@ static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd
list);
}
static int wpas_ctrl_iface_coloc_intf_report(struct wpa_supplicant *wpa_s,
char *cmd)
{
struct wpabuf *elems;
int ret;
elems = wpabuf_parse_bin(cmd);
if (!elems)
return -1;
ret = wnm_send_coloc_intf_report(wpa_s, 0, elems);
wpabuf_free(elems);
return ret;
}
#endif /* CONFIG_WNM */
@ -10423,6 +10448,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
reply_len = -1;
} else if (os_strncmp(buf, "COLOC_INTF_REPORT ", 18) == 0) {
if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);

View file

@ -317,6 +317,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
wnm_clear_coloc_intf_reporting(wpa_s);
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->last_tk_alg = WPA_ALG_NONE;
@ -4339,6 +4340,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_AP */
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
#ifdef CONFIG_AP
#ifdef NEED_AP_MLME

View file

@ -338,6 +338,9 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
wpa_s->wnm_num_neighbor_report = 0;
os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->wnm_neighbor_report_elements = NULL;
wpabuf_free(wpa_s->coloc_intf_elems);
wpa_s->coloc_intf_elems = NULL;
}
@ -1717,6 +1720,46 @@ static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
}
static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *frm,
int len)
{
u8 dialog_token, req_info, auto_report, timeout;
if (!wpa_s->conf->coloc_intf_reporting)
return;
/* Dialog Token [1] | Request Info [1] */
if (len < 2)
return;
dialog_token = frm[0];
req_info = frm[1];
auto_report = req_info & 0x03;
timeout = req_info >> 2;
wpa_dbg(wpa_s, MSG_DEBUG,
"WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")",
dialog_token, auto_report, timeout, MAC2STR(sa));
if (dialog_token == 0)
return; /* only nonzero values are used for request */
if (wpa_s->wpa_state != WPA_COMPLETED ||
os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"WNM: Collocated Interference Request frame not from current AP - ignore it");
return;
}
wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u",
dialog_token, auto_report, timeout);
wpa_s->coloc_intf_dialog_token = dialog_token;
wpa_s->coloc_intf_auto_report = auto_report;
wpa_s->coloc_intf_timeout = timeout;
}
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@ -1750,8 +1793,75 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
case WNM_NOTIFICATION_REQ:
ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
break;
case WNM_COLLOCATED_INTERFERENCE_REQ:
ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos,
end - pos);
break;
default:
wpa_printf(MSG_ERROR, "WNM: Unknown request");
break;
}
}
int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
const struct wpabuf *elems)
{
struct wpabuf *buf;
int ret;
if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems)
return -1;
wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to "
MACSTR " (dialog token %u)",
MAC2STR(wpa_s->bssid), dialog_token);
buf = wpabuf_alloc(3 + wpabuf_len(elems));
if (!buf)
return -1;
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT);
wpabuf_put_u8(buf, dialog_token);
wpabuf_put_buf(buf, elems);
ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
wpabuf_head_u8(buf), wpabuf_len(buf), 0);
wpabuf_free(buf);
return ret;
}
void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
struct wpabuf *elems)
{
wpabuf_free(wpa_s->coloc_intf_elems);
if (elems && wpabuf_len(elems) == 0) {
wpabuf_free(elems);
elems = NULL;
}
wpa_s->coloc_intf_elems = elems;
if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems &&
wpa_s->coloc_intf_dialog_token &&
(wpa_s->coloc_intf_auto_report == 1 ||
wpa_s->coloc_intf_auto_report == 3)) {
/* TODO: Check that there has not been less than
* wpa_s->coloc_intf_timeout * 200 TU from the last report.
*/
wnm_send_coloc_intf_report(wpa_s,
wpa_s->coloc_intf_dialog_token,
wpa_s->coloc_intf_elems);
}
}
void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_WNM
wpa_s->coloc_intf_dialog_token = 0;
wpa_s->coloc_intf_auto_report = 0;
#endif /* CONFIG_WNM */
}

View file

@ -65,11 +65,16 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
int cand_list);
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
const struct wpabuf *elems);
void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
struct wpabuf *elems);
#ifdef CONFIG_WNM
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
#else /* CONFIG_WNM */
@ -79,6 +84,10 @@ static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
return 0;
}
static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
{
}
#endif /* CONFIG_WNM */
#endif /* WNM_STA_H */

View file

@ -1645,6 +1645,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
case 0: /* Bits 0-7 */
break;
case 1: /* Bits 8-15 */
if (wpa_s->conf->coloc_intf_reporting) {
/* Bit 13 - Collocated Interference Reporting */
*pos |= 0x20;
}
break;
case 2: /* Bits 16-23 */
#ifdef CONFIG_WNM

View file

@ -1059,6 +1059,10 @@ struct wpa_supplicant {
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
u8 wnm_cand_from_bss[ETH_ALEN];
struct wpabuf *coloc_intf_elems;
u8 coloc_intf_dialog_token;
u8 coloc_intf_auto_report;
u8 coloc_intf_timeout;
#ifdef CONFIG_MBO
unsigned int wnm_mbo_trans_reason_present:1;
u8 wnm_mbo_transition_reason;