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) {