diff mbox series

[v4,4/7] wpa_supplicant: support Multi-AP backhaul STA onboarding

Message ID 20190212143528.5513-5-arnout@mind.be
State Accepted
Headers show
Series Multi-AP WPS support | expand

Commit Message

Arnout Vandecappelle Feb. 12, 2019, 2:35 p.m. UTC
From: Davina Lu <ylu@quantenna.com>

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.

The multi_ap argument is only added to the socket interface, not to the
dbus interface.

Since WPS associates with the fronthaul BSS instead of the backhaul BSS,
we should not drop association if the AP announces fronthaul-only.
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>
---
v4:
- use argument to wps_pbc instead of a global configuration option
 (requested by Jouni).
- allow association with fronthaul-only BSS during WPS.
---
 src/eap_peer/eap_wsc.c                      | 3 +++
 src/wps/wps.h                               | 6 ++++++
 src/wps/wps_enrollee.c                      | 6 +++++-
 wpa_supplicant/ctrl_iface.c                 | 6 +++++-
 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 +-
 10 files changed, 39 insertions(+), 10 deletions(-)

Comments

Jouni Malinen Feb. 18, 2019, 10:14 p.m. UTC | #1
On Tue, Feb 12, 2019 at 03:35:25PM +0100, Arnout Vandecappelle (Essensium/Mind) wrote:
> v4:
> - use argument to wps_pbc instead of a global configuration option
>  (requested by Jouni).

The main reason for that was to make this specific to the single WPS
protocol exchange and not use any of the global structs for this, so
this part here is not exactly ideal:

> diff --git a/src/wps/wps.h b/src/wps/wps.h
> @@ -612,6 +612,12 @@ struct wps_context {

> +	/**
> +	 * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA
> +	 * enrollee
> +	 */
> +	int multi_ap_backhaul_sta;

That should not be in struct wps_context and it would have been trivial
to fill this from core wpa_supplicant code without the EAP-WSC change.
Anyway, this belongs in struct wps_config and struct wps_data which is
where I moved it. In other words, this parameter needs to be in
per-WPS-exchange data structures, not long term data structures like
struct wps_context (or that previously used configuration parameter).

> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> @@ -1168,6 +1168,7 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
> @@ -1181,6 +1182,9 @@ 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);

This would mean that the BSSID argument could not be used with the
optional multi_ap parameter. That does not sound ideal, so I changes
this to allow multi_ap option to be specified with the BSSID parameter
as well as this wildcard case.
diff mbox series

Patch

diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index d140c88b8..e1f4092fb 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -274,6 +274,9 @@  static void * eap_wsc_init(struct eap_sm *sm)
 				      cfg.pin, cfg.pin_len, 0);
 	}
 
+	if (os_strstr(phase1, "multi_ap=1"))
+		wps->multi_ap_backhaul_sta = 1;
+
 	/* Use reduced client timeout for WPS to avoid long wait */
 	if (sm->ClientTimeout > 30)
 		sm->ClientTimeout = 30;
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 2505d2d9f..129f27ab4 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -612,6 +612,12 @@  struct wps_context {
 	 */
 	int ap_setup_locked;
 
+	/**
+	 * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA
+	 * enrollee
+	 */
+	int multi_ap_backhaul_sta;
+
 	/**
 	 * uuid - Own UUID
 	 */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 4786582af..e175770f1 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->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/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a0db9e42f..0b7fb6473 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1168,6 +1168,7 @@  static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_AP
 	u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
+	int multi_ap = 0;
 
 	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
 		_bssid = NULL;
@@ -1181,6 +1182,9 @@  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);
@@ -1192,7 +1196,7 @@  static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
 		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 638a9ab03..31d684773 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;
 	}
@@ -4809,7 +4816,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 e265128b7..37be1acf8 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1649,7 +1649,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..c57e4e5fd 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);