From b43e19f3f3695463472530c44c1fe0c317c5dd0c Mon Sep 17 00:00:00 2001 From: Sai Pratyusha Magam Date: Mon, 28 Nov 2022 18:32:52 +0530 Subject: [PATCH] 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 --- wpa_supplicant/events.c | 22 +++++- wpa_supplicant/scan.c | 2 + wpa_supplicant/wpa_supplicant_i.h | 5 ++ wpa_supplicant/wps_supplicant.c | 118 +++++++++++++++++++++++------- wpa_supplicant/wps_supplicant.h | 13 ++++ 5 files changed, 131 insertions(+), 29 deletions(-) diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 788ef5bdf..85add06d7 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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) wpa_s->enabled_4addr_mode = 0; + wpa_s->wps_scan_done = false; 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_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 "PBC session overlap"); wpas_notify_wps_event_pbc_overlap(wpa_s); + wpa_s->wps_overlap = true; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT || 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); 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"); return -1; } + wpa_s->supp_pbc_active = false; + if (new_scan) 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 */ } + +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 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); wpa_s->scan_start_time.sec = 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", diff.sec, diff.usec); } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index cfa3edcfa..5b866ec91 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -299,6 +299,8 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, return -1; } + wpa_s->wps_scan_done = false; + return 0; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index c1ed21dcc..0cc8633ee 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1500,6 +1500,10 @@ struct wpa_supplicant { struct robust_av_data robust_av; 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 struct pasn_data pasn; 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 wnm_bss_keep_alive_deinit(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_ssid **selected_ssid); int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 02111ea91..fdc1ec72f 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -1013,6 +1013,7 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) * during an EAP-WSC exchange). */ wpas_notify_wps_event_fail(wpa_s, &data.fail); + wpa_s->supp_pbc_active = false; 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; if (multi_ap_backhaul_sta) 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); eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); @@ -1382,6 +1385,7 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) wpas_clear_wps(wpa_s); } + wpa_s->supp_pbc_active = false; wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL); 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, struct wpa_bss *selected, struct wpa_ssid *ssid) { + struct wpa_supplicant *iface; const u8 *sel_uuid; struct wpabuf *wps_ie; int ret = 0; @@ -1870,36 +1905,21 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, sel_uuid = NULL; } - for (i = 0; i < wpa_s->num_wps_ap; i++) { - struct wps_ap_info *ap = &wpa_s->wps_ap[i]; + for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { + for (i = 0; i < iface->num_wps_ap; i++) { + struct wps_ap_info *ap = &iface->wps_ap[i]; - if (!ap->pbc_active || - os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0) - 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; + if (wpas_wps_is_pbc_overlap(ap, selected, ssid, + sel_uuid)) { + ret = 1; /* PBC overlap */ + wpa_msg(iface, MSG_INFO, + "WPS: PBC overlap detected: " + MACSTR " and " MACSTR, + MAC2STR(selected->bssid), + MAC2STR(ap->bssid)); + break; + } } - - 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 */ - wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " - MACSTR " and " MACSTR, - MAC2STR(selected->bssid), - MAC2STR(ap->bssid)); - break; - } - - /* TODO: verify that this is reasonable dual-band situation */ } 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) { struct wps_ap_info *ap; diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index c55936cee..aae3f7cb5 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -85,6 +85,8 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *sel); void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, 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); 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, const u8 *bssid) {