]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OCE: Add RSSI based association rejection support (STA)
authorBeni Lev <beni.lev@intel.com>
Mon, 21 Aug 2017 16:43:52 +0000 (19:43 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 1 Jan 2019 15:56:25 +0000 (17:56 +0200)
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 subsequent association attempt with that AP (BSS) should be avoided,
unless the RSSI level improved by the desired delta or the timeout has
expired.

Defined in Wi-Fi Alliance Optimized Connectivity Experience technical
specification v1.0, section 3.14 (RSSI-based association rejection
information).

Signed-off-by: Beni Lev <beni.lev@intel.com>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/events.c
wpa_supplicant/mbo.c
wpa_supplicant/wnm_sta.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 733a4f39d617a0f6d87dedfbbadcc164e5dbfa57..46d2a3546eff84b66fb4c38348a3b7f09444cd80 100644 (file)
@@ -1538,6 +1538,24 @@ const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
 }
 
 
+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)
 {
        /*
index 99c4d023a6c6643a4d2984fa0aba2e15a2eb21cf..5f22fcd318decb90ecdeb8b90035d85ff242e4fa 100644 (file)
@@ -193,6 +193,7 @@ extern size_t global_op_class_size;
 
 const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
 const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
+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);
 
index 42a5e886dd2e39782a15ee60bf47ea2e7a44689f..936cf3144fe2dc0ec23313ca331bc755f2ad8caf 100644 (file)
@@ -7959,6 +7959,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->ric_ies = NULL;
 
        wpa_supplicant_update_channel_list(wpa_s, NULL);
+
+       free_bss_tmp_disallowed(wpa_s);
 }
 
 
index e4ee7e20bc44179a0071a0982b1a8a559ac69f10..aacaed154a233d50d743e11f358d94138fbb09b7 100644 (file)
@@ -1338,10 +1338,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 temporarily disallowed");
                        continue;
                }
 #ifdef CONFIG_TESTING_OPTIONS
@@ -3060,7 +3060,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,
@@ -4037,6 +4037,32 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_MBO
+       if (data->assoc_reject.status_code ==
+           WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+           wpa_s->current_bss && data->assoc_reject.bssid &&
+           data->assoc_reject.resp_ies) {
+               const u8 *rssi_rej;
+
+               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_printf(MSG_DEBUG,
+                                  "OCE: RSSI-based association rejection from "
+                                  MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
+                                  MAC2STR(data->assoc_reject.bssid),
+                                  rssi_rej[2], rssi_rej[3]);
+                       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);
                return;
index 5adf61e58bd0b4e1e32f505f45d99cd7267f06a3..bd5020a80d5c17ce80a180e472534de403d8ecea 100644 (file)
@@ -51,6 +51,19 @@ const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id 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)
 {
        const u8 *mbo, *end;
@@ -501,7 +514,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:
index a6ccd842b90bc2a82041e8667a2db96a6d70dfbf..560b0712826e178b0325ba2222e72aff7f016765 100644 (file)
@@ -770,7 +770,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",
index 5d511043cd62dbb081a3da30028463c4384bc796..e8481e5a04b1a2ba1eed4018ce57bfb50b7edcf2 100644 (file)
@@ -444,7 +444,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;
 
@@ -7264,16 +7264,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));
@@ -7286,23 +7284,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;
index c8079c7132a2c862022c2098ebcb0464b546eba0..a2f78e685afac9dd5816a2d0c2f1a9539acb160f 100644 (file)
@@ -451,6 +451,7 @@ struct icon_entry {
 struct wpa_bss_tmp_disallowed {
        struct dl_list list;
        u8 bssid[ETH_ALEN];
+       int rssi_threshold;
 };
 
 struct beacon_rep_data {
@@ -1371,6 +1372,8 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
                int add_oce_capa);
 const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
 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);
@@ -1481,8 +1484,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,