diff --git a/src/drivers/driver.h b/src/drivers/driver.h index aee0cf60d..455e7dffc 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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); }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d18cdeb89..40889ce1f 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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, diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 3eaccaa9b..23cf9dbeb 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -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; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 3d747ce0f..c1423bd58 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -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 */ } } diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index fa2296b73..60628dbf7 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -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 */ diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c index 138b4055b..4bf227dca 100644 --- a/wpa_supplicant/mbo.c +++ b/wpa_supplicant/mbo.c @@ -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"); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index f599c7e8b..08168d370 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 156f800c2..02acb56d0 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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 {