]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wpa_supplicant: Support Multi-AP backhaul STA onboarding with WPS
authorDavina Lu <ylu@quantenna.com>
Tue, 12 Feb 2019 14:35:25 +0000 (15:35 +0100)
committerJouni Malinen <j@w1.fi>
Mon, 18 Feb 2019 20:35:41 +0000 (22:35 +0200)
The Wi-Fi Alliance Multi-AP Specification v1.0 allows onboarding of a
backhaul STA through WPS. To enable this, the backhaul STA needs to add
a Multi-AP IE to the WFA vendor extension element in the WSC M1 message
that indicates it supports the Multi-AP backhaul STA role. The Registrar
(if it support Multi-AP onboarding) will respond to that with a WSC M8
message that also contains the Multi-AP IE, and that contains the
credentials for the backhaul SSID (which may be different from the SSID
on which WPS is performed).

Introduce a new parameter to wpas_wps_start_pbc() and allow it to be
set via control interface's new multi_ap=1 parameter of WPS_PBC call.
multi_ap_backhaul_sta is set to 1 in the automatically created SSID.
Thus, if the AP does not support Multi-AP, association will fail and
WPS will be terminated.

Only wps_pbc is supported.

This commit adds the multi_ap argument only to the control socket
interface, not to the D-Bus interface.

Since WPS associates with the fronthaul BSS instead of the backhaul BSS,
we should not drop association if the AP announces fronthaul-only BSS.
Still, we should only do that in the specific case of WPS. Therefore,
add a check to multi_ap_process_assoc_resp() to allow association with a
fronthaul-only BSS if and only if key_mgmt contains WPS.

Signed-off-by: Davina Lu <ylu@quantenna.com>
Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Cc: Marianna Carrera <marianna.carrera.so@quantenna.com>
12 files changed:
src/eap_peer/eap_wsc.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_enrollee.c
src/wps/wps_i.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new_handlers_wps.c
wpa_supplicant/dbus/dbus_old_handlers_wps.c
wpa_supplicant/events.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index d140c88b8cdd8ad6892ade9aced1d08b64d23306..92d5a02351304dd0317acfd530fb583dcaaf536a 100644 (file)
@@ -255,6 +255,9 @@ static void * eap_wsc_init(struct eap_sm *sm)
                cfg.new_ap_settings = &new_ap_settings;
        }
 
+       if (os_strstr(phase1, "multi_ap=1"))
+               cfg.multi_ap_backhaul_sta = 1;
+
        data->wps = wps_init(&cfg);
        if (data->wps == NULL) {
                os_free(data);
index c162e793d567b56a75738602d89dba0df16156cf..484df262c3ca2f8c79ec5a8f4f4cb56a9d5c0f81 100644 (file)
@@ -145,6 +145,8 @@ struct wps_data * wps_init(const struct wps_config *cfg)
                data->peer_pubkey_hash_set = 1;
        }
 
+       data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta;
+
        return data;
 }
 
index 2505d2d9f246d093154e2c7305a6a73226ec8c4a..8752647eef9e40c5fdec965b5683386668840d6d 100644 (file)
@@ -187,6 +187,12 @@ struct wps_config {
         * peer_pubkey_hash - Peer public key hash or %NULL if not known
         */
        const u8 *peer_pubkey_hash;
+
+       /**
+        * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA
+        * enrollee
+        */
+       int multi_ap_backhaul_sta;
 };
 
 struct wps_data * wps_init(const struct wps_config *cfg);
index 4786582af4d57e39b53b7a466c933932f13bc857..80ed603fc3847a5541a0fec2e60a30889d66bf6f 100644 (file)
@@ -105,6 +105,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
 {
        struct wpabuf *msg;
        u16 config_methods;
+       u8 multi_ap_backhaul_sta = 0;
 
        if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
                return NULL;
@@ -134,6 +135,9 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
                                    WPS_CONFIG_PHY_PUSHBUTTON);
        }
 
+       if (wps->multi_ap_backhaul_sta)
+               multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA;
+
        if (wps_build_version(msg) ||
            wps_build_msg_type(msg, WPS_M1) ||
            wps_build_uuid_e(msg, wps->uuid_e) ||
@@ -152,7 +156,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps)
            wps_build_dev_password_id(msg, wps->dev_pw_id) ||
            wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
            wps_build_os_version(&wps->wps->dev, msg) ||
-           wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
+           wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) ||
            wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
                wpabuf_free(msg);
                return NULL;
index 7972fc2258e6540802bcbcebf1047ce7e4ff5fe8..2cf22d4b7a636890e8a262de9531cef70d8e73fe 100644 (file)
@@ -125,6 +125,8 @@ struct wps_data {
        int pbc_in_m1;
 
        struct wps_nfc_pw_token *nfc_pw_token;
+
+       int multi_ap_backhaul_sta;
 };
 
 
index 89c5d45e79670d2d34324ec4d30582b59ee13fe2..80f2d080eef5c05954d09ee8b8db5b8da0eaed0d 100644 (file)
@@ -1168,8 +1168,11 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_AP
        u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
+       char *pos;
+       int multi_ap = 0;
 
-       if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+       if (!cmd || os_strcmp(cmd, "any") == 0 ||
+           os_strncmp(cmd, "any ", 4) == 0) {
                _bssid = NULL;
 #ifdef CONFIG_P2P
        } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -1181,18 +1184,29 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
                }
                _p2p_dev_addr = p2p_dev_addr;
 #endif /* CONFIG_P2P */
+       } else if (os_strncmp(cmd, "multi_ap=", 9) == 0) {
+               _bssid = NULL;
+               multi_ap = atoi(cmd + 9);
        } else if (hwaddr_aton(cmd, bssid)) {
                wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
                           cmd);
                return -1;
        }
 
+       if (cmd) {
+               pos = os_strstr(cmd, " multi_ap=");
+               if (pos) {
+                       pos += 10;
+                       multi_ap = atoi(pos);
+               }
+       }
+
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface)
                return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
 #endif /* CONFIG_AP */
 
-       return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+       return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap);
 }
 
 
index 19c1a6157f6d47ffc07386e39ae1ba62a9c865f0..1594dafc7bb52b965c73be4f642ab693e446498e 100644 (file)
@@ -293,7 +293,7 @@ DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
                                        message, "invalid PIN");
                }
        } else {
-               ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
+               ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0, 0);
        }
 
        if (ret < 0) {
index 987e12d9cf9a03d6d9a7a3408131fd3e03628a0d..6c8405b85d2275ab3242b9c15249ae5d29ea4e37 100644 (file)
@@ -37,9 +37,9 @@ DBusMessage * wpas_dbus_iface_wps_pbc(DBusMessage *message,
                return wpas_dbus_new_invalid_opts_error(message, NULL);
 
        if (os_strcmp(arg_bssid, "any") == 0)
-               ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
+               ret = wpas_wps_start_pbc(wpa_s, NULL, 0, 0);
        else if (!hwaddr_aton(arg_bssid, bssid))
-               ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
+               ret = wpas_wps_start_pbc(wpa_s, bssid, 0, 0);
        else {
                return wpas_dbus_new_invalid_opts_error(message,
                                                        "Invalid BSSID");
index 0e483ec1c0e56c13f9a6b7fc933789191df9a20b..b254d4ee2e2554a092e80a515168809e356eb912 100644 (file)
@@ -2305,6 +2305,13 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
        }
 
        if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+               if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) &&
+                   wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+                       wpa_printf(MSG_INFO,
+                                  "WPS active, accepting fronthaul-only BSS");
+                       /* Don't set 4addr mode in this case, so just return */
+                       return;
+               }
                wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
                goto fail;
        }
@@ -4829,7 +4836,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
                break;
        case EVENT_WPS_BUTTON_PUSHED:
 #ifdef CONFIG_WPS
-               wpas_wps_start_pbc(wpa_s, NULL, 0);
+               wpas_wps_start_pbc(wpa_s, NULL, 0, 0);
 #endif /* CONFIG_WPS */
                break;
        case EVENT_AVOID_FREQUENCIES:
index 18fd02c3e88d87d37725d1da4a85af7f3ff12213..937b70f4ed90446b8c33d86b2094ded7169e3439 100644 (file)
@@ -1656,7 +1656,7 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
        wpa_supplicant_ap_deinit(wpa_s);
        wpas_copy_go_neg_results(wpa_s, res);
        if (res->wps_method == WPS_PBC) {
-               wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
+               wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0);
 #ifdef CONFIG_WPS_NFC
        } else if (res->wps_method == WPS_NFC) {
                wpas_wps_start_nfc(wpa_s, res->peer_device_addr,
index 1a2677b8eea4237448212d424ed7d1d6a48cf5c5..c11d4fbd0b351075970da3bfafaa8410274784e7 100644 (file)
@@ -1137,9 +1137,10 @@ static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
 
 
 int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      int p2p_group)
+                      int p2p_group, int multi_ap_backhaul_sta)
 {
        struct wpa_ssid *ssid;
+       char phase1[32];
 
 #ifdef CONFIG_AP
        if (wpa_s->ap_iface) {
@@ -1177,10 +1178,14 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                }
        }
 #endif /* CONFIG_P2P */
-       if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+       os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
+                   multi_ap_backhaul_sta ? " multi_ap=1" : "");
+       if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
                return -1;
        if (wpa_s->wps_fragment_size)
                ssid->eap.fragment_size = wpa_s->wps_fragment_size;
+       if (multi_ap_backhaul_sta)
+               ssid->multi_ap_backhaul_sta = 1;
        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);
index c8fe47e372791854c4e0e9ef425347c1df7af297..0fbc85174f9426d713066d7504d91e8b6b30e60d 100644 (file)
@@ -30,7 +30,7 @@ void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
 enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
 int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
-                      int p2p_group);
+                      int p2p_group, int multi_ap_backhaul_sta);
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       const char *pin, int p2p_group, u16 dev_pw_id);
 void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s);