]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211/MBO: Set temporary disallowed BSSID list to driver
authorAshwini Patil <c_apati@qti.qualcomm.com>
Wed, 21 Jun 2017 14:46:07 +0000 (20:16 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 30 Jun 2017 14:27:44 +0000 (17:27 +0300)
Set temporary disallowed BSSID list to the driver so that the driver
doesn't try to connect to any of the blacklisted BSSIDs during
driver-based roaming operation. This commit includes support only for
the nl80211 driver interface using a QCA vendor command for this.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_capa.c
wpa_supplicant/driver_i.h
wpa_supplicant/mbo.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index aee0cf60d5fd8bde22318e560fb1bc2101ba77e2..455e7dffc7e5828288bff51c20781c51fdcc048b 100644 (file)
@@ -3966,6 +3966,15 @@ struct wpa_driver_ops {
         * Returns: 0 on success, -1 on failure
         */
        int (*ignore_assoc_disallow)(void *priv, int ignore_disallow);
+
+       /**
+        * set_bssid_blacklist - Set blacklist of BSSIDs to the driver
+        * @priv: Private driver interface data
+        * @num_bssid: Number of blacklist BSSIDs
+        * @bssids: List of blacklisted BSSIDs
+        */
+       int (*set_bssid_blacklist)(void *priv, unsigned int num_bssid,
+                                  const u8 *bssid);
 };
 
 /**
index d18cdeb890844d8ce06befdafc3695db0bd18e6d..40889ce1f38847f3e0f80b0f42070b34a7e6bbd0 100644 (file)
@@ -8814,6 +8814,67 @@ static int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
+
+
+/* Reserved QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID value for wpa_supplicant */
+#define WPA_SUPPLICANT_CLIENT_ID 1
+
+static int nl80211_set_bssid_blacklist(void *priv, unsigned int num_bssid,
+                                      const u8 *bssid)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *params, *nlbssids, *attr;
+       unsigned int i;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set blacklist BSSID (num=%u)",
+                  num_bssid);
+
+       if (!drv->roam_vendor_cmd_avail)
+               return -1;
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_ROAM) ||
+           !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
+                       QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
+                       WPA_SUPPLICANT_CLIENT_ID) ||
+           nla_put_u32(msg,
+                       QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
+                       num_bssid))
+               goto fail;
+
+       nlbssids = nla_nest_start(
+               msg, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
+       if (!nlbssids)
+               goto fail;
+
+       for (i = 0; i < num_bssid; i++) {
+               attr = nla_nest_start(msg, i);
+               if (!attr)
+                       goto fail;
+               if (nla_put(msg,
+                           QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
+                           ETH_ALEN, &bssid[i * ETH_ALEN]))
+                       goto fail;
+               wpa_printf(MSG_DEBUG, "nl80211:   BSSID[%u]: " MACSTR, i,
+                          MAC2STR(&bssid[i * ETH_ALEN]));
+               nla_nest_end(msg, attr);
+       }
+       nla_nest_end(msg, nlbssids);
+       nla_nest_end(msg, params);
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+fail:
+       nlmsg_free(msg);
+       return -1;
+}
+
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
@@ -10282,6 +10343,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .get_bss_transition_status = nl80211_get_bss_transition_status,
        .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
 #endif /* CONFIG_MBO */
+       .set_bssid_blacklist = nl80211_set_bssid_blacklist,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
        .configure_data_frame_filters = nl80211_configure_data_frame_filters,
        .get_ext_capab = nl80211_get_ext_capab,
index 3eaccaa9b947593e6757b2e3ab336ebf842af075..23cf9dbeb8b36c5387c44dc3c6ae4bd39817fe01 100644 (file)
@@ -163,6 +163,7 @@ struct wpa_driver_nl80211_data {
        unsigned int set_wifi_conf_vendor_cmd_avail:1;
        unsigned int he_capab_vendor_cmd_avail:1;
        unsigned int fetch_bss_trans_status:1;
+       unsigned int roam_vendor_cmd_avail:1;
 
        u64 vendor_scan_cookie;
        u64 remain_on_chan_cookie;
index 3d747ce0fc1030c1da8a36f49cf116ae9e1b5908..c1423bd588f8a9ba9d4c4c40ffcd582af4465eeb 100644 (file)
@@ -752,6 +752,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
                                case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS:
                                        drv->fetch_bss_trans_status = 1;
                                        break;
+                               case QCA_NL80211_VENDOR_SUBCMD_ROAM:
+                                       drv->roam_vendor_cmd_avail = 1;
+                                       break;
 #endif /* CONFIG_DRIVER_NL80211_QCA */
                                }
                        }
index fa2296b7336e93acad3e42716c87f41e14717c1f..60628dbf7b0827f7ba27f12d1b56fb5e85ff80e2 100644 (file)
@@ -1007,4 +1007,14 @@ static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
        return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
 }
 
+static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
+                                             unsigned int num_bssid,
+                                             const u8 *bssids)
+{
+       if (!wpa_s->driver->set_bssid_blacklist)
+               return -1;
+       return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
+                                                 bssids);
+}
+
 #endif /* DRIVER_I_H */
index 138b4055b759761f9e565ab0cf831378b6ed3e31..4bf227dca4e272f65af45644d0ba5f1fab52c482 100644 (file)
@@ -432,6 +432,9 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
                        } else if (wpa_s->wnm_mode &
                                   WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
                                disallowed_sec = WPA_GET_LE16(pos);
+                               wpa_printf(MSG_DEBUG,
+                                          "MBO: Association retry delay: %u",
+                                          disallowed_sec);
                        } else {
                                wpa_printf(MSG_DEBUG,
                                           "MBO: Association retry delay attribute not in disassoc imminent mode");
index f599c7e8bf29d715d6fce27323bf953a375ca211..08168d370fa6f208dc665e79df5e503a1b5c8851 100644 (file)
@@ -114,6 +114,10 @@ const char *const wpa_supplicant_full_license5 =
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
+
+static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
 /* Configure default/group WEP keys for static WEP */
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
@@ -416,6 +420,7 @@ static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
 
        dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
                              struct wpa_bss_tmp_disallowed, list) {
+               eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
                dl_list_del(&bss->list);
                os_free(bss);
        }
@@ -6706,18 +6711,56 @@ wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss_tmp_disallowed *tmp;
+       unsigned int num_bssid = 0;
+       u8 *bssids;
+       int ret;
+
+       bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
+       if (!bssids)
+               return -1;
+       dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
+                         ETH_ALEN);
+               num_bssid++;
+       }
+       ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+       os_free(bssids);
+       return ret;
+}
+
+
+static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
+
+       /* Make sure the bss is not already freed */
+       dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
+                        struct wpa_bss_tmp_disallowed, list) {
+               if (bss == tmp) {
+                       dl_list_del(&tmp->list);
+                       os_free(tmp);
+                       wpa_set_driver_tmp_disallow_list(wpa_s);
+                       break;
+               }
+       }
+}
+
+
 void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
                          unsigned int sec)
 {
        struct wpa_bss_tmp_disallowed *bss;
-       struct os_reltime until;
-
-       os_get_reltime(&until);
-       until.sec += sec;
 
        bss = wpas_get_disallowed_bss(wpa_s, bssid);
        if (bss) {
-               bss->disallowed_until = until;
+               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;
        }
 
@@ -6728,27 +6771,20 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
                return;
        }
 
-       bss->disallowed_until = until;
        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);
+       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)
 {
        struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
-       struct os_reltime now, age;
-
-       os_get_reltime(&now);
 
        dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
                         struct wpa_bss_tmp_disallowed, list) {
-               if (!os_reltime_before(&now, &tmp->disallowed_until)) {
-                       /* This BSS is not disallowed anymore */
-                       dl_list_del(&tmp->list);
-                       os_free(tmp);
-                       continue;
-               }
                if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
                        bss = tmp;
                        break;
@@ -6757,9 +6793,5 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        if (!bss)
                return 0;
 
-       os_reltime_sub(&bss->disallowed_until, &now, &age);
-       wpa_printf(MSG_DEBUG,
-                  "BSS " MACSTR " disabled for %ld.%0ld seconds",
-                  MAC2STR(bss->bssid), age.sec, age.usec);
        return 1;
 }
index 156f800c2ef0e6de28a0c7bc8297843072c791be..02acb56d06e2e9ebbbbe97c2a1584644901063d8 100644 (file)
@@ -447,7 +447,6 @@ struct icon_entry {
 struct wpa_bss_tmp_disallowed {
        struct dl_list list;
        u8 bssid[ETH_ALEN];
-       struct os_reltime disallowed_until;
 };
 
 struct beacon_rep_data {