nl80211/MBO: Set temporary disallowed BSSID list to driver

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>
This commit is contained in:
Ashwini Patil 2017-06-21 20:16:07 +05:30 committed by Jouni Malinen
parent 2a71673e27
commit b04854ceff
8 changed files with 139 additions and 20 deletions

View File

@ -3966,6 +3966,15 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
*/ */
int (*ignore_assoc_disallow)(void *priv, int ignore_disallow); 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);
}; };
/** /**

View 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); 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 */ #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, .get_bss_transition_status = nl80211_get_bss_transition_status,
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow, .ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */ #endif /* CONFIG_MBO */
.set_bssid_blacklist = nl80211_set_bssid_blacklist,
#endif /* CONFIG_DRIVER_NL80211_QCA */ #endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters, .configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab, .get_ext_capab = nl80211_get_ext_capab,

View File

@ -163,6 +163,7 @@ struct wpa_driver_nl80211_data {
unsigned int set_wifi_conf_vendor_cmd_avail:1; unsigned int set_wifi_conf_vendor_cmd_avail:1;
unsigned int he_capab_vendor_cmd_avail:1; unsigned int he_capab_vendor_cmd_avail:1;
unsigned int fetch_bss_trans_status:1; unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
u64 vendor_scan_cookie; u64 vendor_scan_cookie;
u64 remain_on_chan_cookie; u64 remain_on_chan_cookie;

View 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: case QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS:
drv->fetch_bss_trans_status = 1; drv->fetch_bss_trans_status = 1;
break; break;
case QCA_NL80211_VENDOR_SUBCMD_ROAM:
drv->roam_vendor_cmd_avail = 1;
break;
#endif /* CONFIG_DRIVER_NL80211_QCA */ #endif /* CONFIG_DRIVER_NL80211_QCA */
} }
} }

View 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); 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 */ #endif /* DRIVER_I_H */

View 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 & } else if (wpa_s->wnm_mode &
WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
disallowed_sec = WPA_GET_LE16(pos); disallowed_sec = WPA_GET_LE16(pos);
wpa_printf(MSG_DEBUG,
"MBO: Association retry delay: %u",
disallowed_sec);
} else { } else {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"MBO: Association retry delay attribute not in disassoc imminent mode"); "MBO: Association retry delay attribute not in disassoc imminent mode");

View File

@ -114,6 +114,10 @@ const char *const wpa_supplicant_full_license5 =
"\n"; "\n";
#endif /* CONFIG_NO_STDOUT_DEBUG */ #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 */ /* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) 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, dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) { struct wpa_bss_tmp_disallowed, list) {
eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
dl_list_del(&bss->list); dl_list_del(&bss->list);
os_free(bss); 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, void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
unsigned int sec) unsigned int sec)
{ {
struct wpa_bss_tmp_disallowed *bss; 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); bss = wpas_get_disallowed_bss(wpa_s, bssid);
if (bss) { 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; return;
} }
@ -6728,27 +6771,20 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
return; return;
} }
bss->disallowed_until = until;
os_memcpy(bss->bssid, bssid, ETH_ALEN); os_memcpy(bss->bssid, bssid, ETH_ALEN);
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list); 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) int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
{ {
struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev; 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, dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) { 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) { if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
bss = tmp; bss = tmp;
break; break;
@ -6757,9 +6793,5 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
if (!bss) if (!bss)
return 0; 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; return 1;
} }

View File

@ -447,7 +447,6 @@ struct icon_entry {
struct wpa_bss_tmp_disallowed { struct wpa_bss_tmp_disallowed {
struct dl_list list; struct dl_list list;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct os_reltime disallowed_until;
}; };
struct beacon_rep_data { struct beacon_rep_data {