]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wpa_supplicant: Add Multi-AP backhaul STA support
authorVenkateswara Naralasetty <vnaralas@codeaurora.org>
Wed, 5 Dec 2018 10:23:53 +0000 (11:23 +0100)
committerJouni Malinen <j@w1.fi>
Thu, 20 Dec 2018 10:10:31 +0000 (12:10 +0200)
Advertise vendor specific Multi-AP IE in (Re)Association Request frames
and process Multi-AP IE from (Re)Association Response frames if the user
enables Multi-AP fuctionality. If the (Re)Association Response frame
does not contain the Multi-AP IE, disassociate.

This adds a new configuration parameter 'multi_ap_backhaul_sta' to
enable/disable Multi-AP functionality.

Enable 4-address mode after association (if the Association Response
frame contains the Multi-AP IE). Also enable the bridge in that case.
This is necessary because wpa_supplicant only enables the bridge in
wpa_drv_if_add(), which only gets called when an interface is added
through the control interface, not when it is configured from the
command line.

Signed-off-by: Venkateswara Naralasetty <vnaralas@codeaurora.org>
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/config.c
wpa_supplicant/config_ssid.h
wpa_supplicant/driver_i.h
wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpa_supplicant_i.h

index 4a011f6ba83865bf666acc09f4c42a4d9c833e8b..6b8334711c3a2ae2ab2de1a412011a0af659851b 100644 (file)
@@ -4120,6 +4120,15 @@ struct wpa_driver_ops {
         */
        int (*send_external_auth_status)(void *priv,
                                         struct external_auth *params);
+
+       /**
+        * set_4addr_mode - Set 4-address mode
+        * @priv: Private driver interface data
+        * @bridge_ifname: Bridge interface name
+        * @val: 0 - disable 4addr mode, 1 - enable 4addr mode
+        * Returns: 0 on success, < 0 on failure
+        */
+       int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
 };
 
 /**
index c9dd8621198ef9fa5792e10ebbd039f36ed494ab..929b852f6a508193ace34b4d0a6be3b68628fdc0 100644 (file)
@@ -10738,6 +10738,49 @@ fail:
 }
 
 
+static int nl80211_set_4addr_mode(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;
+
+       wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+                  val ? "Enable" : "Disable", bridge_ifname);
+
+       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 interface %s from 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 &&
+                   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 enable/disable 4addr");
+
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -10867,4 +10910,5 @@ 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,
+       .set_4addr_mode = nl80211_set_4addr_mode,
 };
index 78da98de342f1aef1f2fb5135a5e9eca0405ea9f..0f71e9fb610cb8925b199f17fd786a2e34b651b3 100644 (file)
@@ -2384,6 +2384,7 @@ static const struct parse_data ssid_fields[] = {
 #endif /* CONFIG_DPP */
        { INT_RANGE(owe_group, 0, 65535) },
        { INT_RANGE(owe_only, 0, 1) },
+       { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
 };
 
 #undef OFFSET
index 6427fbb01055a7a7ce6ce71781d0369e226af9b4..5205b074679b0c0fe352943affd298d5cdacdd73 100644 (file)
@@ -948,6 +948,13 @@ struct wpa_ssid {
         * the selection attempts for OWE BSS exceed the configured threshold.
         */
        int owe_transition_bss_select_count;
+
+       /**
+        * multi_ap_backhaul_sta - Multi-AP backhaul STA
+        * 0 = normal (non-Multi-AP) station
+        * 1 = Multi-AP backhaul station
+        */
+       int multi_ap_backhaul_sta;
 };
 
 #endif /* CONFIG_SSID_H */
index 5581bb064501930d61a2a126a4cb4966062790c2..86c891aa4bf29429d2f78081b2ce2b324f23bb5a 100644 (file)
@@ -1054,4 +1054,12 @@ wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
                                                        params);
 }
 
+static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
+{
+       if (!wpa_s->driver->set_4addr_mode)
+               return -1;
+       return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv,
+                                            wpa_s->bridge_ifname, val);
+}
+
 #endif /* DRIVER_I_H */
index 8eac4be0f57390932943744c92af623828610f81..7f2302900c1703f7f779fe8bf803eced661b6b91 100644 (file)
@@ -324,6 +324,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
        os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
 #endif /* CONFIG_TESTING_OPTIONS */
        wpa_s->ieee80211ac = 0;
+
+       if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+               wpa_s->enabled_4addr_mode = 0;
 }
 
 
@@ -2267,6 +2270,50 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_INTERWORKING */
 
 
+static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
+                                       const u8 *ies, size_t ies_len)
+{
+       struct ieee802_11_elems elems;
+       const u8 *map_sub_elem, *pos;
+       size_t len;
+
+       if (!wpa_s->current_ssid ||
+           !wpa_s->current_ssid->multi_ap_backhaul_sta ||
+           !ies ||
+           ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+               return;
+
+       if (!elems.multi_ap || elems.multi_ap_len < 7) {
+               wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
+               goto fail;
+       }
+
+       pos = elems.multi_ap + 4;
+       len = elems.multi_ap_len - 4;
+
+       map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
+       if (!map_sub_elem || map_sub_elem[1] < 1) {
+               wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+               goto fail;
+       }
+
+       if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+               wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
+               goto fail;
+       }
+
+       if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
+               wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
+               goto fail;
+       }
+       wpa_s->enabled_4addr_mode = 1;
+       return;
+
+fail:
+       wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
 #ifdef CONFIG_FST
 static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
                                const u8 *ie, size_t ie_len)
@@ -2343,6 +2390,9 @@ 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;
+
+               multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+                                           data->assoc_info.resp_ies_len);
        }
        if (data->assoc_info.beacon_ies)
                wpa_hexdump(MSG_DEBUG, "beacon_ies",
index 779c79b4397619655952f9377b8091814c005c9c..b61e0c33c285f38a8458ade09f23f460cf1a6af3 100644 (file)
@@ -1554,6 +1554,22 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
        }
 #endif /* CONFIG_OWE */
 
+       if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+               size_t multi_ap_ie_len;
+
+               multi_ap_ie_len = add_multi_ap_ie(
+                       wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+                       sizeof(wpa_s->sme.assoc_req_ie) -
+                       wpa_s->sme.assoc_req_ie_len,
+                       MULTI_AP_BACKHAUL_STA);
+               if (multi_ap_ie_len == 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "Multi-AP: Failed to build Multi-AP IE");
+                       return;
+               }
+               wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
+       }
+
        params.bssid = bssid;
        params.ssid = wpa_s->sme.ssid;
        params.ssid_len = wpa_s->sme.ssid_len;
index bd66d9b599337cc93f0af487d55c04e9246b9c69..1ade6253f73bec4a46b025ce107b6963a8315c37 100644 (file)
@@ -2816,6 +2816,21 @@ static u8 * wpas_populate_assoc_ies(
        }
 #endif /* CONFIG_IEEE80211R */
 
+       if (ssid->multi_ap_backhaul_sta) {
+               size_t multi_ap_ie_len;
+
+               multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
+                                                 max_wpa_ie_len - wpa_ie_len,
+                                                 MULTI_AP_BACKHAUL_STA);
+               if (multi_ap_ie_len == 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "Multi-AP: Failed to build Multi-AP IE");
+                       os_free(wpa_ie);
+                       return NULL;
+               }
+               wpa_ie_len += multi_ap_ie_len;
+       }
+
        params->wpa_ie = wpa_ie;
        params->wpa_ie_len = wpa_ie_len;
        params->auth_alg = algs;
@@ -3294,6 +3309,9 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                zero_addr = 1;
        }
 
+       if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+               wpa_s->enabled_4addr_mode = 0;
+
 #ifdef CONFIG_TDLS
        wpa_tdls_teardown_peers(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
index b93990004ef837fbab039f172f978c157829b7d1..ffe5d2e0c3d13e97ef303c85470c532ef39aec5d 100644 (file)
@@ -1403,6 +1403,13 @@ fast_reauth=1
 #  2: MCS 0-9
 #  3: not supported
 
+# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
+# 0 = normal STA (default)
+# 1 = backhaul STA
+# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not
+# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
+# added to a bridge to allow forwarding frames over this backhaul link.
+
 ##### Fast Session Transfer (FST) support #####################################
 #
 # The options in this section are only available when the build configuration
index 8b749f44e235cf5e5aeefd3ee9003cb891cb6da4..b3a7db674e8b8bb9c1e117503bf2eef73c5d9b5e 100644 (file)
@@ -1234,6 +1234,7 @@ struct wpa_supplicant {
        unsigned int disable_fils:1;
 #endif /* CONFIG_FILS */
        unsigned int ieee80211ac:1;
+       unsigned int enabled_4addr_mode:1;
 };