From: Beni Lev <beni.lev@xxxxxxxxx> An AP might refuse to connect a STA if it has a low RSSI. In such case, the AP informs the STA with the desired RSSI delta and a retry timeout. Any association attempt should be avoided, unless the RSSI level improved by the desired delta or the timeout has expired Defined in WFA_OCE_TechSpec_v0.0.11, section 3.14 Signed-off-by: Beni Lev <beni.lev@xxxxxxxxx> --- src/common/ieee802_11_common.c | 16 ++++++++++++++++ src/common/ieee802_11_common.h | 2 ++ wpa_supplicant/ctrl_iface.c | 2 ++ wpa_supplicant/events.c | 24 +++++++++++++++++++++--- wpa_supplicant/mbo.c | 21 ++++++++++++++++++++- wpa_supplicant/wnm_sta.c | 2 +- wpa_supplicant/wpa_supplicant.c | 26 ++++++++++++++++---------- wpa_supplicant/wpa_supplicant_i.h | 9 +++++++-- 8 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 4da10d2..074cac1 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1432,6 +1432,22 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid) return NULL; } +const u8 *get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type) +{ + const u8 *pos = ies, *end = ies + len; + + while (end - pos > 1) { + if (2 + pos[1] > end - pos) + break; + + if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + vendor_type == WPA_GET_BE32(&pos[2])) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) { diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index ff2f8e7..e3c0325 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -176,6 +176,8 @@ extern const struct oper_class_map global_op_class[]; extern size_t global_op_class_size; const u8 * get_ie(const u8 *ies, size_t len, u8 eid); +const u8 *get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); + size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 6f91b83..138a35d 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7797,6 +7797,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpabuf_free(wpa_s->ric_ies); wpa_s->ric_ies = NULL; + + free_bss_tmp_disallowed(wpa_s); } diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index db7de89..b5f1737 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1201,10 +1201,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } - if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) { + if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, - " skip - MBO retry delay has not passed yet"); + " skip - AP disallowed"); continue; } #ifdef CONFIG_TESTING_OPTIONS @@ -2856,7 +2856,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, !disallowed_ssid(wpa_s, fast_reconnect->ssid, fast_reconnect->ssid_len) && !wpas_temp_disabled(wpa_s, fast_reconnect_ssid) && - !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) { + !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) { #ifndef CONFIG_NO_SCAN_PROCESSING wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS"); if (wpa_supplicant_connect(wpa_s, fast_reconnect, @@ -3903,6 +3903,24 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->assoc_reject.timeout_reason : ""); wpa_s->assoc_status_code = data->assoc_reject.status_code; wpas_notify_assoc_status_code(wpa_s); + +#ifdef CONFIG_MBO + if (data->assoc_reject.status_code == + WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) { + const u8 *rssi_rej = + mbo_get_attr_from_ies(data->assoc_reject.resp_ies, + data->assoc_reject.resp_ies_len, + OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT); + + if (rssi_rej && rssi_rej[1] == 2 && + wpa_s->current_bss) + wpa_bss_tmp_disallow(wpa_s, + data->assoc_reject.bssid, + rssi_rej[3], + rssi_rej[2] + + wpa_s->current_bss->level); + } +#endif /* CONFIG_MBO */ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_reject(wpa_s, data); else { diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c index 129d205..0535b88 100644 --- a/wpa_supplicant/mbo.c +++ b/wpa_supplicant/mbo.c @@ -37,6 +37,25 @@ static int wpas_mbo_validate_non_pref_chan(u8 oper_class, u8 chan, u8 reason) return 0; } +static const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, + enum mbo_attr_id attr) +{ + const u8 *mbo = mbo_ie + MBO_IE_HEADER, *end = mbo_ie + 2 + mbo_ie[1]; + + return get_ie(mbo, end - mbo, attr); +} + +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr) +{ + const u8 *mbo_ie; + + mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE); + if (!mbo_ie) + return NULL; + + return mbo_attr_from_mbo_ie(mbo_ie, attr); +} const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) { @@ -487,7 +506,7 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie, if (disallowed_sec && wpa_s->current_bss) wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid, - disallowed_sec); + disallowed_sec, 0); return; fail: diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 7339ed2..d3a2b24 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -691,7 +691,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, continue; } - if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { + if (wpa_is_bss_tmp_disallowed(wpa_s, target)) { wpa_printf(MSG_DEBUG, "MBO: Candidate BSS " MACSTR " retry delay is not over yet", diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index be44787..4932fa8 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -414,7 +414,7 @@ void free_hw_features(struct wpa_supplicant *wpa_s) } -static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) +void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s) { struct wpa_bss_tmp_disallowed *bss, *prev; @@ -6760,16 +6760,14 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx) void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, - unsigned int sec) + unsigned int sec, int rssi_threshold) { struct wpa_bss_tmp_disallowed *bss; bss = wpas_get_disallowed_bss(wpa_s, bssid); if (bss) { eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss); - eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout, - wpa_s, bss); - return; + goto finish; } bss = os_malloc(sizeof(*bss)); @@ -6782,23 +6780,31 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, os_memcpy(bss->bssid, bssid, ETH_ALEN); dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); wpa_set_driver_tmp_disallow_list(wpa_s); + +finish: + bss->rssi_threshold = rssi_threshold; eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout, wpa_s, bss); } -int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) { - struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev; + struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev; dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed, struct wpa_bss_tmp_disallowed, list) { - if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) { - bss = tmp; + if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) { + disallowed = tmp; break; } } - if (!bss) + if (!disallowed) + return 0; + + if (disallowed->rssi_threshold != 0 && + bss->level > disallowed->rssi_threshold) return 0; return 1; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8b7d2f5..2be4998 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -450,6 +450,7 @@ struct icon_entry { struct wpa_bss_tmp_disallowed { struct dl_list list; u8 bssid[ETH_ALEN]; + int rssi_threshold; }; struct beacon_rep_data { @@ -1328,6 +1329,8 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s); /* MBO functions */ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len); const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr); +const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, + enum mbo_attr_id attr); int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s, const char *non_pref_chan); void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie); @@ -1436,8 +1439,10 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, u16 num_modes, enum hostapd_hw_mode mode); void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, - unsigned int sec); -int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid); + unsigned int sec, int rssi_threshold); +int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); +void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s); struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_bss *bss, -- 2.7.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap