WPS: Cross band overlap detection with multiple interfaces

When WPS is running simultaneously on multiple per-band radios (e.g., a
separate 2.4 GHz and 5 GHz band radios in an AP device), handle
synchronization of scan results, detect PBC session overlap, and cancel
WPS for enrollees on both interface, if the UUID of the registrars on
different bands differ.

Signed-off-by: Sai Pratyusha Magam <quic_smagam@quicinc.com>
This commit is contained in:
Sai Pratyusha Magam 2022-11-28 18:32:52 +05:30 committed by Jouni Malinen
parent ed68ac9301
commit b43e19f3f3
5 changed files with 131 additions and 29 deletions

View file

@ -389,6 +389,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
wpa_s->enabled_4addr_mode = 0; wpa_s->enabled_4addr_mode = 0;
wpa_s->wps_scan_done = false;
wpas_reset_mlo_info(wpa_s); wpas_reset_mlo_info(wpa_s);
} }
@ -1807,10 +1808,12 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_bss *selected,
struct wpa_ssid *ssid) struct wpa_ssid *ssid)
{ {
if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { if (wpas_wps_partner_link_overlap_detect(wpa_s) ||
wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
"PBC session overlap"); "PBC session overlap");
wpas_notify_wps_event_pbc_overlap(wpa_s); wpas_notify_wps_event_pbc_overlap(wpa_s);
wpa_s->wps_overlap = true;
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT || if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
wpa_s->p2p_in_provisioning) { wpa_s->p2p_in_provisioning) {
@ -2314,6 +2317,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
} }
} }
if (wpa_s->supp_pbc_active && !wpas_wps_partner_link_scan_done(wpa_s))
return ret;
return wpas_select_network_from_last_scan(wpa_s, 1, own_request); return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done: scan_work_done:
@ -2380,6 +2386,8 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed"); wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1; return -1;
} }
wpa_s->supp_pbc_active = false;
if (new_scan) if (new_scan)
wpa_supplicant_rsn_preauth_scan_results(wpa_s); wpa_supplicant_rsn_preauth_scan_results(wpa_s);
/* /*
@ -2546,6 +2554,17 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_NO_SCAN_PROCESSING */ #endif /* CONFIG_NO_SCAN_PROCESSING */
} }
int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_NO_SCAN_PROCESSING
return -1;
#else /* CONFIG_NO_SCAN_PROCESSING */
return wpas_select_network_from_last_scan(wpa_s, 1, 1);
#endif /* CONFIG_NO_SCAN_PROCESSING */
}
#ifdef CONFIG_WNM #ifdef CONFIG_WNM
static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx) static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
@ -5302,6 +5321,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
wpa_s->scan_start_time.sec = 0; wpa_s->scan_start_time.sec = 0;
wpa_s->scan_start_time.usec = 0; wpa_s->scan_start_time.usec = 0;
wpa_s->wps_scan_done = true;
wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
diff.sec, diff.usec); diff.sec, diff.usec);
} }

View file

@ -299,6 +299,8 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
return -1; return -1;
} }
wpa_s->wps_scan_done = false;
return 0; return 0;
} }

View file

@ -1500,6 +1500,10 @@ struct wpa_supplicant {
struct robust_av_data robust_av; struct robust_av_data robust_av;
bool mscs_setup_done; bool mscs_setup_done;
bool wps_scan_done; /* Set upon receiving scan results event */
bool supp_pbc_active; /* Set for interface when PBC is triggered */
bool wps_overlap;
#ifdef CONFIG_PASN #ifdef CONFIG_PASN
struct pasn_data pasn; struct pasn_data pasn;
struct wpa_radio_work *pasn_auth_work; struct wpa_radio_work *pasn_auth_work;
@ -1752,6 +1756,7 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx); void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s); void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s); int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid); struct wpa_ssid **selected_ssid);
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);

View file

@ -1013,6 +1013,7 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
* during an EAP-WSC exchange). * during an EAP-WSC exchange).
*/ */
wpas_notify_wps_event_fail(wpa_s, &data.fail); wpas_notify_wps_event_fail(wpa_s, &data.fail);
wpa_s->supp_pbc_active = false;
wpas_clear_wps(wpa_s); wpas_clear_wps(wpa_s);
} }
@ -1215,6 +1216,8 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
ssid->eap.fragment_size = wpa_s->wps_fragment_size; ssid->eap.fragment_size = wpa_s->wps_fragment_size;
if (multi_ap_backhaul_sta) if (multi_ap_backhaul_sta)
ssid->multi_ap_backhaul_sta = 1; ssid->multi_ap_backhaul_sta = 1;
wpa_s->supp_pbc_active = true;
wpa_s->wps_overlap = false;
wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL); wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL); wpa_s, NULL);
@ -1382,6 +1385,7 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
wpas_clear_wps(wpa_s); wpas_clear_wps(wpa_s);
} }
wpa_s->supp_pbc_active = false;
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL); wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
wpa_s->after_wps = 0; wpa_s->after_wps = 0;
@ -1839,9 +1843,40 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
} }
static bool wpas_wps_is_pbc_overlap(struct wps_ap_info *ap,
struct wpa_bss *selected,
struct wpa_ssid *ssid,
const u8 *sel_uuid)
{
if (!ap->pbc_active ||
os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
return false;
if (!is_zero_ether_addr(ssid->bssid) &&
os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
" in active PBC mode due to local BSSID limitation",
MAC2STR(ap->bssid));
return 0;
}
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR,
MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
ap->uuid, UUID_LEN);
if (!sel_uuid || os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0)
return true;
/* TODO: verify that this is reasonable dual-band situation */
return false;
}
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_ssid *ssid) struct wpa_bss *selected, struct wpa_ssid *ssid)
{ {
struct wpa_supplicant *iface;
const u8 *sel_uuid; const u8 *sel_uuid;
struct wpabuf *wps_ie; struct wpabuf *wps_ie;
int ret = 0; int ret = 0;
@ -1870,36 +1905,21 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
sel_uuid = NULL; sel_uuid = NULL;
} }
for (i = 0; i < wpa_s->num_wps_ap; i++) { for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
struct wps_ap_info *ap = &wpa_s->wps_ap[i]; for (i = 0; i < iface->num_wps_ap; i++) {
struct wps_ap_info *ap = &iface->wps_ap[i];
if (!ap->pbc_active || if (wpas_wps_is_pbc_overlap(ap, selected, ssid,
os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0) sel_uuid)) {
continue;
if (!is_zero_ether_addr(ssid->bssid) &&
os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
" in active PBC mode due to local BSSID limitation",
MAC2STR(ap->bssid));
continue;
}
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
ap->uuid, UUID_LEN);
if (sel_uuid == NULL ||
os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
ret = 1; /* PBC overlap */ ret = 1; /* PBC overlap */
wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " wpa_msg(iface, MSG_INFO,
"WPS: PBC overlap detected: "
MACSTR " and " MACSTR, MACSTR " and " MACSTR,
MAC2STR(selected->bssid), MAC2STR(selected->bssid),
MAC2STR(ap->bssid)); MAC2STR(ap->bssid));
break; break;
} }
}
/* TODO: verify that this is reasonable dual-band situation */
} }
wpabuf_free(wps_ie); wpabuf_free(wps_ie);
@ -3007,6 +3027,48 @@ void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
} }
bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
{
struct wpa_global *global = wpa_s->global;
struct wpa_supplicant *iface;
for (iface = global->ifaces; iface; iface = iface->next) {
if (iface == wpa_s)
continue;
if (!iface->supp_pbc_active)
continue;
/* Scan results are available for both links. While the current
* link will proceed for network selection, ensure the partner
* link also gets an attempt at network selection and connect
* with the selected BSS. */
if (iface->wps_scan_done)
wpa_wps_supplicant_fast_associate(iface);
else
return false;
}
return true;
}
bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
{
struct wpa_global *global = wpa_s->global;
struct wpa_supplicant *iface;
for (iface = global->ifaces; iface; iface = iface->next) {
if (iface == wpa_s)
continue;
if (iface->wps_overlap)
return true;
}
return false;
}
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
{ {
struct wps_ap_info *ap; struct wps_ap_info *ap;

View file

@ -85,6 +85,8 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
const struct wpabuf *sel); const struct wpabuf *sel);
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res); struct wpa_scan_results *scan_res);
bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s);
bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid); void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s); int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s);
@ -144,6 +146,17 @@ static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
{ {
} }
static inline bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
{
return true;
}
static inline bool
wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
{
return false;
}
static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
const u8 *bssid) const u8 *bssid)
{ {