MBO: Send MBO WNM-Notification Request frames to notify changes
Send a WNM-Notification Request frame with Non-preferred Channel Report subelement if the non-preferred channels list changes during an association. Signed-off-by: David Spinadel <david.spinadel@intel.com>
This commit is contained in:
parent
92c6e2e3a9
commit
2d5b8614b7
2 changed files with 76 additions and 5 deletions
|
@ -68,15 +68,40 @@ static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
|
static void wpas_mbo_non_pref_chan_subelem_hdr(struct wpabuf *mbo, u8 len)
|
||||||
struct wpabuf *mbo)
|
{
|
||||||
|
wpabuf_put_u8(mbo, WLAN_EID_VENDOR_SPECIFIC);
|
||||||
|
wpabuf_put_u8(mbo, len); /* Length */
|
||||||
|
wpabuf_put_be24(mbo, OUI_WFA);
|
||||||
|
wpabuf_put_u8(mbo, MBO_ATTR_ID_NON_PREF_CHAN_REPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_mbo_non_pref_chan_subelement(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpabuf *mbo, u8 start,
|
||||||
|
u8 end)
|
||||||
|
{
|
||||||
|
size_t size = end - start + 8;
|
||||||
|
|
||||||
|
if (size + 2 > wpabuf_tailroom(mbo))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpas_mbo_non_pref_chan_subelem_hdr(mbo, size);
|
||||||
|
wpas_mbo_non_pref_chan_attr_body(wpa_s, mbo, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpabuf *mbo, int subelement)
|
||||||
{
|
{
|
||||||
u8 i, start = 0;
|
u8 i, start = 0;
|
||||||
struct wpa_mbo_non_pref_channel *start_pref;
|
struct wpa_mbo_non_pref_channel *start_pref;
|
||||||
|
|
||||||
if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num)
|
if (!wpa_s->non_pref_chan || !wpa_s->non_pref_chan_num) {
|
||||||
|
if (subelement)
|
||||||
|
wpas_mbo_non_pref_chan_subelem_hdr(mbo, 4);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
start_pref = &wpa_s->non_pref_chan[0];
|
start_pref = &wpa_s->non_pref_chan[0];
|
||||||
|
|
||||||
for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
|
for (i = 1; i <= wpa_s->non_pref_chan_num; i++) {
|
||||||
|
@ -89,7 +114,12 @@ static void wpas_mbo_non_pref_chan_attrs(struct wpa_supplicant *wpa_s,
|
||||||
non_pref->reason != start_pref->reason ||
|
non_pref->reason != start_pref->reason ||
|
||||||
non_pref->reason_detail != start_pref->reason_detail ||
|
non_pref->reason_detail != start_pref->reason_detail ||
|
||||||
non_pref->preference != start_pref->preference) {
|
non_pref->preference != start_pref->preference) {
|
||||||
wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start, i);
|
if (subelement)
|
||||||
|
wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
|
||||||
|
start, i);
|
||||||
|
else
|
||||||
|
wpas_mbo_non_pref_chan_attr(wpa_s, mbo, start,
|
||||||
|
i);
|
||||||
|
|
||||||
if (!non_pref)
|
if (!non_pref)
|
||||||
return;
|
return;
|
||||||
|
@ -116,7 +146,7 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Add non-preferred channels attribute */
|
/* Add non-preferred channels attribute */
|
||||||
wpas_mbo_non_pref_chan_attrs(wpa_s, mbo);
|
wpas_mbo_non_pref_chan_attrs(wpa_s, mbo, 0);
|
||||||
|
|
||||||
res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
|
res = mbo_add_ie(buf, len, wpabuf_head_u8(mbo), wpabuf_len(mbo));
|
||||||
if (!res)
|
if (!res)
|
||||||
|
@ -127,6 +157,45 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_mbo_send_wnm_notification(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpabuf *buf;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send WNM-Notification Request frame only in case of a change in
|
||||||
|
* non-preferred channels list during association, if the AP supports
|
||||||
|
* MBO.
|
||||||
|
*/
|
||||||
|
if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_bss ||
|
||||||
|
!wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(512);
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
|
||||||
|
wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
|
||||||
|
wpa_s->mbo_wnm_token++;
|
||||||
|
if (wpa_s->mbo_wnm_token == 0)
|
||||||
|
wpa_s->mbo_wnm_token++;
|
||||||
|
wpabuf_put_u8(buf, wpa_s->mbo_wnm_token);
|
||||||
|
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); /* Type */
|
||||||
|
|
||||||
|
wpas_mbo_non_pref_chan_attrs(wpa_s, buf, 1);
|
||||||
|
|
||||||
|
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
|
||||||
|
wpa_s->own_addr, wpa_s->bssid,
|
||||||
|
wpabuf_head(buf), wpabuf_len(buf), 0);
|
||||||
|
if (res < 0)
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Failed to send WNM-Notification Request frame with non-preferred channel list");
|
||||||
|
|
||||||
|
wpabuf_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
|
static int wpa_non_pref_chan_is_eq(struct wpa_mbo_non_pref_channel *a,
|
||||||
struct wpa_mbo_non_pref_channel *b)
|
struct wpa_mbo_non_pref_channel *b)
|
||||||
{
|
{
|
||||||
|
@ -252,6 +321,7 @@ update:
|
||||||
os_free(wpa_s->non_pref_chan);
|
os_free(wpa_s->non_pref_chan);
|
||||||
wpa_s->non_pref_chan = chans;
|
wpa_s->non_pref_chan = chans;
|
||||||
wpa_s->non_pref_chan_num = num;
|
wpa_s->non_pref_chan_num = num;
|
||||||
|
wpas_mbo_send_wnm_notification(wpa_s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -1027,6 +1027,7 @@ struct wpa_supplicant {
|
||||||
u8 preference;
|
u8 preference;
|
||||||
} *non_pref_chan;
|
} *non_pref_chan;
|
||||||
size_t non_pref_chan_num;
|
size_t non_pref_chan_num;
|
||||||
|
u8 mbo_wnm_token;
|
||||||
#endif /* CONFIG_MBO */
|
#endif /* CONFIG_MBO */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue