[PATCH 2/2] wpa_supplicant: Add Multi-AP protocol support to supplicant

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Venkateswara Naralasetty <vnaralas@xxxxxxxxxxxxxx>

Advertise vendor specific Multi-AP IE in (Re)Association request
and process Multi-AP IE from (Re)Association response frames if
user enable Multi-AP fuctionality.

This patch introducing new configuration parameter 'multi_ap_enabled'
to enable/disable Multi-AP funtionality from user.

Signed-off-by: Venkateswara Naralasetty <vnaralas@xxxxxxxxxxxxxx>
Signed-off-by: Jouni Malinen <jouni@xxxxxxxxxxxxxx>
---
 src/common/ieee802_11_defs.h       |  1 +
 src/drivers/driver.h               | 10 +++++++++
 src/drivers/driver_nl80211.c       | 44 ++++++++++++++++++++++++++++++++++++++
 wpa_supplicant/Makefile            |  4 ++++
 wpa_supplicant/config.c            |  3 +++
 wpa_supplicant/config_ssid.h       |  8 +++++++
 wpa_supplicant/ctrl_iface.c        |  9 ++++++++
 wpa_supplicant/defconfig           |  3 +++
 wpa_supplicant/driver_i.h          | 11 ++++++++++
 wpa_supplicant/events.c            | 34 +++++++++++++++++++++++++++++
 wpa_supplicant/sme.c               | 43 +++++++++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant.c    | 29 +++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant.conf |  4 ++++
 13 files changed, 203 insertions(+)

diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index c1a3a85..8033e58 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1216,6 +1216,7 @@ struct ieee80211_ampe_ie {
 #define MULTI_AP_SUB_ELEM_TYPE 0x06
 #define MULTI_AP_BACKHAUL_BSS 0x40
 #define MULTI_AP_FRONTHAUL_BSS 0x20
+#define MULTI_AP_BACKHAUL_STA 0x80
 #define BACKHAUL_BSS 1
 #define FRONTHAUL_BSS 2
 
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d34c679..df6ddaa 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4079,6 +4079,16 @@ struct wpa_driver_ops {
 	 */
 	int (*send_external_auth_status)(void *priv,
 					 struct external_auth *params);
+
+#ifdef CONFIG_MULTI_AP
+	/**
+	 * set_multi_ap - Enable/disable Multi-AP functionality
+	 * @priv: Private driver interface data
+	 * @bridge_ifname: Name of the bridge interface
+	 * @val: 0 for Multi-AP disable, 1 for Multi-AP enable
+	 */
+	int (*set_multi_ap)(void *priv, const char *bridge_ifname, int val);
+#endif /* CONFIG_MULTI_AP */
 };
 
 /**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 771e766..6ec0d0a 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10647,6 +10647,47 @@ fail:
 	return ret;
 }
 
+#ifdef CONFIG_MULTI_AP
+static int nl80211_set_multi_ap(void *priv, const char *bridge_ifname, int val)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+
+	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+	if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+		goto fail;
+
+	if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+		if (linux_br_del_if(drv->global->ioctl_sock,
+				    bridge_ifname, bss->ifname)) {
+			wpa_printf(MSG_ERROR, "nl80211: Failed to remove the "
+				   "interface %s to a bridge %s",
+				   bss->ifname, bridge_ifname);
+			return -1;
+		}
+		bss->added_if_into_bridge = 0;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (!ret) {
+		if (bridge_ifname[0] && val) {
+			if (i802_check_bridge(drv, bss,
+					      bridge_ifname, bss->ifname) < 0)
+				return -1;
+		}
+		return 0;
+	}
+
+fail:
+	nlmsg_free(msg);
+	wpa_printf(MSG_ERROR, "nl80211: Failed to set Multi-AP");
+
+	return ret;
+}
+#endif /* CONFIG_MULTI_AP */
 
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
@@ -10776,4 +10817,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.get_ext_capab = nl80211_get_ext_capab,
 	.update_connect_params = nl80211_update_connection_params,
 	.send_external_auth_status = nl80211_send_external_auth_status,
+#ifdef CONFIG_MULTI_AP
+	.set_multi_ap = nl80211_set_multi_ap,
+#endif /* CONFIG_MULTI_AP */
 };
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index c2e93e2..52892ea 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -96,6 +96,10 @@ CONFIG_NO_RANDOM_POOL=
 CONFIG_OPENSSL_CMAC=y
 endif
 
+ifdef CONFIG_MULTI_AP
+CFLAGS += -DCONFIG_MULTI_AP
+endif
+
 OBJS = config.o
 OBJS += notify.o
 OBJS += bss.o
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c439606..2171476 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2320,6 +2320,9 @@ static const struct parse_data ssid_fields[] = {
 #endif /* CONFIG_DPP */
 	{ INT_RANGE(owe_group, 0, 65535) },
 	{ INT_RANGE(owe_only, 0, 1) },
+#ifdef CONFIG_MULTI_AP
+	{ INT_RANGE(multi_ap_enabled, 0, 1) },
+#endif
 };
 
 #undef OFFSET
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index d2a52d7..8f51ab3 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -937,6 +937,14 @@ struct wpa_ssid {
 	 * the selection attempts for OWE BSS exceed the configured threshold.
 	 */
 	int owe_transition_bss_select_count;
+
+#ifdef CONFIG_MULTI_AP
+	/** multi_ap_enabled - Enable/disable Multi-AP functionality
+	 * 0 = disable Multi-AP
+	 * 1 = enable Multi-AP
+	 */
+	int multi_ap_enabled;
+#endif /* CONFIG_MULTI_AP */
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 77a3133..b158e9a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3328,6 +3328,15 @@ static int wpa_supplicant_ctrl_iface_update_network(
 	else if (os_strcmp(name, "priority") == 0)
 		wpa_config_update_prio_list(wpa_s->conf);
 
+#ifdef CONFIG_MULTI_AP
+	if (os_strcmp(name, "multi_ap_enabled") == 0) {
+		wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		if (wpa_drv_set_multi_ap(wpa_s, wpa_s->bridge_ifname,
+					 ssid->multi_ap_enabled))
+			wpa_printf(MSG_ERROR, "failed to set Multi-AP\n");
+	}
+#endif /* CONFIG_MULTI_AP */
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 08f5857..3c3081c 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -593,3 +593,6 @@ CONFIG_BACKEND=file
 # Opportunistic Wireless Encryption (OWE)
 # Experimental implementation of draft-harkins-owe-07.txt
 #CONFIG_OWE=y
+
+#Multi-AP protocol support
+#CONFIG_MULTI_AP=y
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 078de23..d5809c7 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -30,6 +30,17 @@ static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s)
 		wpa_s->driver->deinit(wpa_s->drv_priv);
 }
 
+#ifdef CONFIG_MULTI_AP
+static inline int wpa_drv_set_multi_ap(struct wpa_supplicant *wpa_s,
+				       const char *bridge_ifname, int val)
+{
+	if (wpa_s->driver->set_multi_ap)
+		return wpa_s->driver->set_multi_ap(wpa_s->drv_priv,
+						   bridge_ifname, val);
+	return -1;
+}
+#endif /* CONFIG_MULTI_AP */
+
 static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s,
 				    const char *param)
 {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index dd6dd52..837f036 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2266,6 +2266,26 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
 
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_MULTI_AP
+static int wpa_validate_multi_ap_ie(struct wpa_supplicant *wpa_s,
+			       const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return -1;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return -1;
+
+	if (wpa_s->current_ssid->multi_ap_enabled && !elems.multi_ap) {
+		wpa_printf(MSG_INFO, " AP doesn't support Multi-AP");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_MULTI_AP */
 
 #ifdef CONFIG_FST
 static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
@@ -2343,6 +2363,20 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
 		    get_ie(data->assoc_info.resp_ies,
 			   data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
 			wpa_s->ieee80211ac = 1;
+#ifdef CONFIG_MULTI_AP
+		if (wpa_validate_multi_ap_ie(wpa_s, data->assoc_info.resp_ies,
+					     data->assoc_info.resp_ies_len)) {
+			wpa_supplicant_deauthenticate(wpa_s,
+						      WLAN_REASON_INVALID_IE);
+			return -1;
+		} else if (wpa_drv_set_multi_ap(wpa_s, wpa_s->bridge_ifname,
+						wpa_s->current_ssid->multi_ap_enabled)) {
+			wpa_printf(MSG_ERROR, "failed to set Multi-AP\n");
+			wpa_supplicant_deauthenticate(wpa_s,
+						      WLAN_REASON_DEAUTH_LEAVING);
+			return -1;
+		}
+#endif /* CONFIG_MULTI_AP */
 	}
 	if (data->assoc_info.beacon_ies)
 		wpa_hexdump(MSG_DEBUG, "beacon_ies",
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d569aca..5d1ec35 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -39,6 +39,26 @@ static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 static void sme_stop_sa_query(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_MULTI_AP
+static struct wpabuf *multi_ap_build_assoc_req_ie(void)
+{
+	struct wpabuf *ie = NULL;
+
+	ie = wpabuf_alloc(10);
+	if (!ie)
+		return NULL;
+
+	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+	wpabuf_put_u8(ie, 7); /* len */
+	wpabuf_put_be24(ie, OUI_WFA);
+	wpabuf_put_u8(ie, MULTI_AP_OUI_TYPE);
+	wpabuf_put_u8(ie, MULTI_AP_SUB_ELEM_TYPE);
+	wpabuf_put_u8(ie, 1); /* sub elem len */
+	wpabuf_put_u8(ie, MULTI_AP_BACKHAUL_STA);
+
+	return ie;
+}
+#endif /* CONFIG_MULTI_AP */
 
 #ifdef CONFIG_SAE
 
@@ -1548,6 +1568,29 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
 	}
 #endif /* CONFIG_OWE */
 
+#ifdef CONFIG_MULTI_AP
+	if (wpa_s->conf->ssid->multi_ap_enabled) {
+		struct wpabuf *multi_ap_ie;
+
+		multi_ap_ie = multi_ap_build_assoc_req_ie();
+		if (!multi_ap_ie) {
+			wpa_printf(MSG_ERROR, "Multi-AP: Failed to build Multi-AP IE");
+			return;
+		}
+		if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(multi_ap_ie) >
+				sizeof(wpa_s->sme.assoc_req_ie)) {
+			wpa_printf(MSG_ERROR,
+					"Multi-AP: Not enough buffer for Association Request frame element");
+			wpabuf_free(multi_ap_ie);
+			return;
+		}
+		os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+			  wpabuf_head(multi_ap_ie), wpabuf_len(multi_ap_ie));
+		wpa_s->sme.assoc_req_ie_len += wpabuf_len(multi_ap_ie);
+		wpabuf_free(multi_ap_ie);
+	}
+#endif /* CONFIG_MULTI_AP */
+
 	params.bssid = bssid;
 	params.ssid = wpa_s->sme.ssid;
 	params.ssid_len = wpa_s->sme.ssid_len;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 0fe2adb..b061810 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -285,6 +285,25 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
 	wpa_s->last_con_fail_realm_len = 0;
 }
 
+#ifdef CONFIG_MULTI_AP
+u8 *wpa_add_multi_ap_info_ie(u8 *pos, size_t *len)
+{
+	struct multi_ap_ie *map = (struct multi_ap_ie *) (pos + 2);
+
+	pos[1] = WLAN_EID_VENDOR_SPECIFIC;
+	pos[2] = 7; /* len */
+	WPA_PUT_BE24((u8 *)map, OUI_WFA);
+	map->oui_type = MULTI_AP_OUI_TYPE;
+	map->sub_elem_id = MULTI_AP_SUB_ELEM_TYPE;
+	map->sub_elem_len = 0x01;/* sub element len */
+	map->sub_elem_val = MULTI_AP_BACKHAUL_STA;
+
+	pos = (u8 *) (map + 1);
+	*len += (2 + sizeof(*map));
+
+	return pos;
+}
+#endif /* CONFIG_MULTI_AP */
 
 /**
  * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
@@ -2808,6 +2827,11 @@ static u8 * wpas_populate_assoc_ies(
 	}
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_MULTI_AP
+	if (ssid->multi_ap_enabled && ((max_wpa_ie_len - wpa_ie_len) > 9))
+		wpa_add_multi_ap_info_ie(wpa_ie, &wpa_ie_len);
+#endif /* CONFIG_MULTI_AP */
+
 	params->wpa_ie = wpa_ie;
 	params->wpa_ie_len = wpa_ie_len;
 	params->auth_alg = algs;
@@ -3303,6 +3327,11 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 	}
 #endif /* CONFIG_MESH */
 
+#ifdef CONFIG_MULTI_AP
+	if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_enabled)
+		wpa_drv_set_multi_ap(wpa_s, wpa_s->bridge_ifname, 0);
+#endif /* CONFIG_MULTI_AP */
+
 	if (addr) {
 		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
 		os_memset(&event, 0, sizeof(event));
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 4f59160..ba9dc03 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1422,6 +1422,10 @@ fast_reauth=1
 # Transitioning between states).
 #fst_llt=100
 
+# Enable Multi-AP funtionality.
+# default = 0 (disable Multi-AP).
+# multi_ap_enabled = 1 (enable Multi-AP).
+
 # Example blocks:
 
 # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
-- 
2.7.4


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux