diff mbox series

[1/2] Basic support for Multi-AP Profile 2 - WPS changes

Message ID 20211022092646.10016-1-stf_xl@wp.pl
State New
Headers show
Series [1/2] Basic support for Multi-AP Profile 2 - WPS changes | expand

Commit Message

Stanislaw Gruszka Oct. 22, 2021, 9:26 a.m. UTC
Patch adds hostapd config option to allow to configure Multi-AP
profile and primary vlan_id.

It then use those values to send Multi-AP Profile and
Multi-AP Default 802.1Q subelements via WPS WFA Vendor Extensions.
This is can be used Multi-AP onbaording with Traffic Separation
feature.

Some important parts are missed i.e. passing values from supplicant
and needs to be added. We infernally use ubus event when get WPS
credentials and pass vlan_id value there. It's needed further
to allow authentication be done via vlan when Traffic Separation
feature is enababled.

Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
---
 hostapd/config_file.c    | 20 ++++++++++++++
 src/ap/ap_config.h       |  2 ++
 src/ap/wps_hostapd.c     |  8 +++++-
 src/wps/wps.h            | 16 ++++++++++-
 src/wps/wps_attr_build.c | 57 ++++++++++++++++++++++++++++++++++++++++
 src/wps/wps_attr_parse.c | 22 ++++++++++++++++
 src/wps/wps_attr_parse.h |  3 +++
 src/wps/wps_defs.h       |  4 ++-
 src/wps/wps_enrollee.c   |  4 ++-
 src/wps/wps_i.h          |  2 ++
 src/wps/wps_registrar.c  | 36 +++++++++++++++++++++++--
 11 files changed, 168 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7b03edf36..0554115d1 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4551,6 +4551,26 @@  static int hostapd_config_fill(struct hostapd_config *conf,
 		}
 
 		bss->multi_ap = val;
+	} else if (os_strcmp(buf, "multi_ap_profile") == 0) {
+		int val = atoi(pos);
+
+		if (val < 1 || val > 2) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap_profile '%s'",
+				   line, buf);
+			return -1;
+		}
+
+		bss->multi_ap_profile = val;
+	} else if (os_strcmp(buf, "multi_ap_primary_vlan_id") == 0) {
+		int val = atoi(pos);
+
+		if (val < 0 || val > MAX_VLAN_ID) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid multi_ap_primary_vlan_id %d (expected 0..%d)",
+				   line, val, MAX_VLAN_ID);
+			return 1;
+		}
+		bss->multi_ap_primary_vlan_id = val;
 	} else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
 		conf->rssi_reject_assoc_rssi = atoi(pos);
 	} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 3ba368987..ed800a9e3 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -774,6 +774,8 @@  struct hostapd_bss_config {
 #define BACKHAUL_BSS 1
 #define FRONTHAUL_BSS 2
 	int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
+	int multi_ap_profile;
+	int multi_ap_primary_vlan_id;
 
 #ifdef CONFIG_AIRTIME_POLICY
 	unsigned int airtime_weight;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 9f22e39a2..7a634352a 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1290,6 +1290,10 @@  int hostapd_init_wps(struct hostapd_data *hapd,
 			cfg.multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
 		}
 	}
+	if (conf->multi_ap) {
+		cfg.multi_ap_profile = conf->multi_ap_profile;
+		cfg.multi_ap_primary_vlan_id = conf->multi_ap_primary_vlan_id;
+	}
 
 	wps->ap_settings = conf->ap_settings;
 	wps->ap_settings_len = conf->ap_settings_len;
@@ -1418,7 +1422,9 @@  static int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
 		reg, conf->multi_ap_backhaul_ssid.ssid,
 		conf->multi_ap_backhaul_ssid.ssid_len,
 		multi_ap_backhaul_network_key,
-		multi_ap_backhaul_network_key_len);
+		multi_ap_backhaul_network_key_len,
+		conf->multi_ap_profile,
+		conf->multi_ap_primary_vlan_id);
 	os_free(multi_ap_backhaul_network_key);
 
 	return ret;
diff --git a/src/wps/wps.h b/src/wps/wps.h
index fed3e2848..5a99d3abd 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -437,6 +437,18 @@  struct wps_registrar_config {
 	 * multi_ap_backhaul_network_key in octets
 	 */
 	size_t multi_ap_backhaul_network_key_len;
+
+	/**
+	 * multi_ap_prorifle - This is parameter for
+	 * Multi-AP Profile subelement
+	 */
+	int multi_ap_profile;
+
+	/**
+	 * multi_ap_primary_vlan_id - This is parameter for
+	 * Default 8021Q Settings Subelement
+	 */
+	int multi_ap_primary_vlan_id;
 };
 
 
@@ -881,7 +893,9 @@  int wps_registrar_update_multi_ap(struct wps_registrar *reg,
 				  const u8 *multi_ap_backhaul_ssid,
 				  size_t multi_ap_backhaul_ssid_len,
 				  const u8 *multi_ap_backhaul_network_key,
-				  size_t multi_ap_backhaul_network_key_len);
+				  size_t multi_ap_backhaul_network_key_len,
+				  u8 multi_ap_profile,
+				  u16 multi_ap_primary_vlan_id);
 
 int wps_build_credential_wrap(struct wpabuf *msg,
 			      const struct wps_credential *cred);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index f37225676..e231cb88e 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -248,6 +248,48 @@  int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
 				   MAC2STR(&auth_macs[i * ETH_ALEN]));
 	}
 
+	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
+
+#ifdef CONFIG_WPS_TESTING
+	if (WPS_VERSION > 0x20) {
+		if (wpabuf_tailroom(msg) < 5)
+			return -1;
+		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
+			   "attribute");
+		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, 42);
+	}
+#endif /* CONFIG_WPS_TESTING */
+	return 0;
+}
+
+
+int wps_build_wfa_ext_multi_ap(struct wpabuf *msg, u8 multi_ap_subelem,
+			       u8 profile, u16 vlan_id)
+{
+	u8 *len;
+
+#ifdef CONFIG_WPS_TESTING
+	if (WPS_VERSION == 0x10)
+		return 0;
+#endif /* CONFIG_WPS_TESTING */
+
+	if (wpabuf_tailroom(msg) <
+	    7 + 3 +
+	    (multi_ap_subelem ? 3 : 0) +
+	    (profile ? 7 : 0))
+		return -1;
+
+	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
+	len = wpabuf_put(msg, 2); /* to be filled */
+	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
+
+	wpa_printf(MSG_INFO, "WPS:  * Version2 (0x%x)", WPS_VERSION);
+	wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
+	wpabuf_put_u8(msg, 1);
+	wpabuf_put_u8(msg, WPS_VERSION);
+
 	if (multi_ap_subelem) {
 		wpa_printf(MSG_DEBUG, "WPS:  * Multi-AP (0x%x)",
 			   multi_ap_subelem);
@@ -256,6 +298,21 @@  int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
 		wpabuf_put_u8(msg, multi_ap_subelem);
 	}
 
+	if (profile) {
+		wpa_printf(MSG_DEBUG, "WPS:  * Multi-AP profile (%d)", profile);
+		wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP_PROFILE);
+		wpabuf_put_u8(msg, 1); /* length */
+		wpabuf_put_u8(msg, profile);
+
+		if (vlan_id) {
+			wpa_printf(MSG_DEBUG, "WPS:  * Multi-AP vlan_id (%d)",
+				   vlan_id);
+			wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP_8021Q);
+			wpabuf_put_u8(msg, 2); /* length */
+			wpabuf_put_le16(msg, vlan_id);
+		}
+	}
+
 	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
 
 #ifdef CONFIG_WPS_TESTING
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index fd5163515..0cc41f026 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -78,6 +78,28 @@  static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
 		wpa_printf(MSG_DEBUG, "WPS: Multi-AP Extension 0x%02x",
 			   attr->multi_ap_ext);
 		break;
+	case WFA_ELEM_MULTI_AP_PROFILE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: Invalid Multi-AP Profile length %u",
+				   len);
+			return -1;
+		}
+		attr->multi_ap_profile = *pos;
+		wpa_printf(MSG_DEBUG, "WPS: Multi-AP Profile %u",
+			   attr->multi_ap_profile);
+		break;
+	case WFA_ELEM_MULTI_AP_8021Q:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG,
+				   "WPS: Invalid Multi-AP Default 8021Q Settings length %u",
+				   len);
+			return -1;
+		}
+		attr->multi_ap_primary_vlan_id = WPA_GET_LE16(pos);
+		wpa_printf(MSG_DEBUG, "WPS: Multi-AP vlan_id %u",
+			   attr->multi_ap_primary_vlan_id);
+		break;
 	default:
 		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
 			   "Extension subelement %u", id);
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
index 4de27b26d..4fc91aa59 100644
--- a/src/wps/wps_attr_parse.h
+++ b/src/wps/wps_attr_parse.h
@@ -97,7 +97,10 @@  struct wps_parse_attr {
 	const u8 *cred[MAX_CRED_COUNT];
 	const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
 	const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
+
 	u8 multi_ap_ext;
+	u8 multi_ap_profile;
+	u16 multi_ap_primary_vlan_id;
 };
 
 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index ddaeda56d..d19f66e23 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -153,7 +153,9 @@  enum {
 	WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
 	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04,
 	WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05,
-	WFA_ELEM_MULTI_AP = 0x06
+	WFA_ELEM_MULTI_AP = 0x06,
+	WFA_ELEM_MULTI_AP_PROFILE = 0x07,
+	WFA_ELEM_MULTI_AP_8021Q = 0x08
 };
 
 /* Device Password ID */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 819cd43f6..d0106e6d9 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -156,7 +156,9 @@  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, multi_ap_backhaul_sta) ||
+	    (multi_ap_backhaul_sta ?
+	     wps_build_wfa_ext_multi_ap(msg, multi_ap_backhaul_sta, 0, 0) :
+	     wps_build_wfa_ext(msg, 0, NULL, 0, 0)) ||
 	    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 2cf22d4b7..527cfe06a 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -167,6 +167,8 @@  int wps_build_version(struct wpabuf *msg);
 int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
 		      const u8 *auth_macs, size_t auth_macs_count,
 		      u8 multi_ap_subelem);
+int wps_build_wfa_ext_multi_ap(struct wpabuf *msg, u8 multi_ap_subelem,
+			       u8 profile, u16 vlan_id);
 int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
 int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 9587293d0..43285cba0 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -220,6 +220,18 @@  struct wps_registrar {
 	 * multi_ap_backhaul_network_key in octets
 	 */
 	size_t multi_ap_backhaul_network_key_len;
+
+	/**
+	 * multi_ap_primary - This is parameter for
+	 * Multi-AP Profile subelement
+	 */
+	int multi_ap_profile;
+
+	/**
+	 * multi_ap_primary_vlan_id - This is parameter for
+	 * Default 8021Q Settings Subelement
+	 */
+	int multi_ap_primary_vlan_id;
 };
 
 
@@ -714,6 +726,8 @@  wps_registrar_init(struct wps_context *wps,
 			reg->multi_ap_backhaul_network_key_len =
 				cfg->multi_ap_backhaul_network_key_len;
 	}
+	reg->multi_ap_profile = cfg->multi_ap_profile;
+	reg->multi_ap_primary_vlan_id = cfg->multi_ap_primary_vlan_id;
 
 	if (wps_set_ie(reg)) {
 		wps_registrar_deinit(reg);
@@ -2064,7 +2078,11 @@  static struct wpabuf * wps_build_m6(struct wps_data *wps)
 
 static struct wpabuf * wps_build_m8(struct wps_data *wps)
 {
+	struct wps_registrar *reg = wps->wps->registrar;
 	struct wpabuf *msg, *plain;
+	u8 multi_ap_ext = 0;
+	u8 profile = 0;
+	u16 vlan_id = 0;
 
 	wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
 
@@ -2078,6 +2096,14 @@  static struct wpabuf * wps_build_m8(struct wps_data *wps)
 		return NULL;
 	}
 
+
+	if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA) {
+		multi_ap_ext = MULTI_AP_BACKHAUL_BSS |
+			       MULTI_AP_FRONTHAUL_BSS;
+		profile = reg->multi_ap_profile;
+		vlan_id = reg->multi_ap_primary_vlan_id;
+	}
+
 	if (wps_build_version(msg) ||
 	    wps_build_msg_type(msg, WPS_M8) ||
 	    wps_build_enrollee_nonce(wps, msg) ||
@@ -2085,7 +2111,9 @@  static struct wpabuf * wps_build_m8(struct wps_data *wps)
 	    (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
 	    wps_build_key_wrap_auth(wps, plain) ||
 	    wps_build_encr_settings(wps, msg, plain) ||
-	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
+	    (multi_ap_ext ?
+	     wps_build_wfa_ext_multi_ap(msg, multi_ap_ext, profile, vlan_id) :
+	     wps_build_wfa_ext(msg, 0, NULL, 0, 0)) ||
 	    wps_build_authenticator(wps, msg)) {
 		wpabuf_clear_free(plain);
 		wpabuf_clear_free(msg);
@@ -3663,7 +3691,9 @@  int wps_registrar_update_multi_ap(struct wps_registrar *reg,
 				  const u8 *multi_ap_backhaul_ssid,
 				  size_t multi_ap_backhaul_ssid_len,
 				  const u8 *multi_ap_backhaul_network_key,
-				  size_t multi_ap_backhaul_network_key_len)
+				  size_t multi_ap_backhaul_network_key_len,
+				  u8 multi_ap_profile,
+				  u16 multi_ap_primary_vlan_id)
 {
 	if (multi_ap_backhaul_ssid) {
 		os_memcpy(reg->multi_ap_backhaul_ssid,
@@ -3683,6 +3713,8 @@  int wps_registrar_update_multi_ap(struct wps_registrar *reg,
 		reg->multi_ap_backhaul_network_key_len =
 			multi_ap_backhaul_network_key_len;
 	}
+	reg->multi_ap_profile = multi_ap_profile;
+	reg->multi_ap_primary_vlan_id = multi_ap_primary_vlan_id;
 
 	return 0;
 }