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