From 83ebf558654615e02beb3be7011e63307bf328b7 Mon Sep 17 00:00:00 2001 From: Davina Lu Date: Tue, 12 Feb 2019 15:35:25 +0100 Subject: [PATCH] wpa_supplicant: Support Multi-AP backhaul STA onboarding with WPS 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 Signed-off-by: Igor Mitsyanko Signed-off-by: Arnout Vandecappelle (Essensium/Mind) Signed-off-by: Daniel Golle Cc: Marianna Carrera --- src/eap_peer/eap_wsc.c | 3 +++ src/wps/wps.c | 2 ++ src/wps/wps.h | 6 ++++++ src/wps/wps_enrollee.c | 6 +++++- src/wps/wps_i.h | 2 ++ wpa_supplicant/ctrl_iface.c | 18 ++++++++++++++++-- wpa_supplicant/dbus/dbus_new_handlers_wps.c | 2 +- wpa_supplicant/dbus/dbus_old_handlers_wps.c | 4 ++-- wpa_supplicant/events.c | 9 ++++++++- wpa_supplicant/p2p_supplicant.c | 2 +- wpa_supplicant/wps_supplicant.c | 9 +++++++-- wpa_supplicant/wps_supplicant.h | 2 +- 12 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c index d140c88b8..92d5a0235 100644 --- a/src/eap_peer/eap_wsc.c +++ b/src/eap_peer/eap_wsc.c @@ -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); diff --git a/src/wps/wps.c b/src/wps/wps.c index c162e793d..484df262c 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -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; } diff --git a/src/wps/wps.h b/src/wps/wps.h index 2505d2d9f..8752647ee 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -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); diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 4786582af..80ed603fc 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -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; diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 7972fc225..2cf22d4b7 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -125,6 +125,8 @@ struct wps_data { int pbc_in_m1; struct wps_nfc_pw_token *nfc_pw_token; + + int multi_ap_backhaul_sta; }; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 89c5d45e7..80f2d080e 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c index 19c1a6157..1594dafc7 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c @@ -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) { diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c index 987e12d9c..6c8405b85 100644 --- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c +++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c @@ -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"); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 0e483ec1c..b254d4ee2 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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: diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 18fd02c3e..937b70f4e 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -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, diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 1a2677b8e..c11d4fbd0 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -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); diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h index c8fe47e37..0fbc85174 100644 --- a/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant/wps_supplicant.h @@ -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);