]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Cross band overlap detection with multiple interfaces
authorSai Pratyusha Magam <quic_smagam@quicinc.com>
Mon, 28 Nov 2022 13:02:52 +0000 (18:32 +0530)
committerJouni Malinen <j@w1.fi>
Tue, 29 Nov 2022 15:05:21 +0000 (17:05 +0200)
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>
wpa_supplicant/events.c
wpa_supplicant/scan.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 788ef5bdfefbc6369122a93ce7d6441616700984..85add06d74c8dd0844b26648980d65ecb8c5acda 100644 (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)
                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);
                }
index cfa3edcfaee53f66a6c5a806f2846e7a857f66a0..5b866ec91480ce964600ab21efb8b84237091bd5 100644 (file)
@@ -299,6 +299,8 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+       wpa_s->wps_scan_done = false;
+
        return 0;
 }
 
index c1ed21dccc7e4d1f326c5e07bf06dd79b1a3ef66..0cc8633eeaa7778111173564b9993c36aa6bbf0f 100644 (file)
@@ -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);
index 02111ea91100bf9dc46b7966418c22649b6759d1..fdc1ec72ffd9b889a050fa95682d176b4e976137 100644 (file)
@@ -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];
-
-               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;
-               }
+       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];
 
-               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;
+                       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;
+                       }
                }
-
-               /* 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;
index c55936ceeaafe471b0686ce5fc98bc617e528cac..aae3f7cb594a7e50e800d622eceeed0d43149c07 100644 (file)
@@ -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)
 {