wpa_supplicant: Add Multi-AP backhaul STA support
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>
This commit is contained in:
parent
9c06f0f6ae
commit
5abc7823bd
10 changed files with 161 additions and 0 deletions
|
@ -4120,6 +4120,15 @@ struct wpa_driver_ops {
|
||||||
*/
|
*/
|
||||||
int (*send_external_auth_status)(void *priv,
|
int (*send_external_auth_status)(void *priv,
|
||||||
struct external_auth *params);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 = {
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.name = "nl80211",
|
.name = "nl80211",
|
||||||
.desc = "Linux nl80211/cfg80211",
|
.desc = "Linux nl80211/cfg80211",
|
||||||
|
@ -10867,4 +10910,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.get_ext_capab = nl80211_get_ext_capab,
|
.get_ext_capab = nl80211_get_ext_capab,
|
||||||
.update_connect_params = nl80211_update_connection_params,
|
.update_connect_params = nl80211_update_connection_params,
|
||||||
.send_external_auth_status = nl80211_send_external_auth_status,
|
.send_external_auth_status = nl80211_send_external_auth_status,
|
||||||
|
.set_4addr_mode = nl80211_set_4addr_mode,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2384,6 +2384,7 @@ static const struct parse_data ssid_fields[] = {
|
||||||
#endif /* CONFIG_DPP */
|
#endif /* CONFIG_DPP */
|
||||||
{ INT_RANGE(owe_group, 0, 65535) },
|
{ INT_RANGE(owe_group, 0, 65535) },
|
||||||
{ INT_RANGE(owe_only, 0, 1) },
|
{ INT_RANGE(owe_only, 0, 1) },
|
||||||
|
{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef OFFSET
|
#undef OFFSET
|
||||||
|
|
|
@ -948,6 +948,13 @@ struct wpa_ssid {
|
||||||
* the selection attempts for OWE BSS exceed the configured threshold.
|
* the selection attempts for OWE BSS exceed the configured threshold.
|
||||||
*/
|
*/
|
||||||
int owe_transition_bss_select_count;
|
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 */
|
#endif /* CONFIG_SSID_H */
|
||||||
|
|
|
@ -1054,4 +1054,12 @@ wpa_drv_send_external_auth_status(struct wpa_supplicant *wpa_s,
|
||||||
params);
|
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 */
|
#endif /* DRIVER_I_H */
|
||||||
|
|
|
@ -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));
|
os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
|
||||||
#endif /* CONFIG_TESTING_OPTIONS */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
wpa_s->ieee80211ac = 0;
|
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 */
|
#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
|
#ifdef CONFIG_FST
|
||||||
static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
|
static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *ie, size_t ie_len)
|
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,
|
get_ie(data->assoc_info.resp_ies,
|
||||||
data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
|
data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
|
||||||
wpa_s->ieee80211ac = 1;
|
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)
|
if (data->assoc_info.beacon_ies)
|
||||||
wpa_hexdump(MSG_DEBUG, "beacon_ies",
|
wpa_hexdump(MSG_DEBUG, "beacon_ies",
|
||||||
|
|
|
@ -1554,6 +1554,22 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OWE */
|
#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.bssid = bssid;
|
||||||
params.ssid = wpa_s->sme.ssid;
|
params.ssid = wpa_s->sme.ssid;
|
||||||
params.ssid_len = wpa_s->sme.ssid_len;
|
params.ssid_len = wpa_s->sme.ssid_len;
|
||||||
|
|
|
@ -2816,6 +2816,21 @@ static u8 * wpas_populate_assoc_ies(
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#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 = wpa_ie;
|
||||||
params->wpa_ie_len = wpa_ie_len;
|
params->wpa_ie_len = wpa_ie_len;
|
||||||
params->auth_alg = algs;
|
params->auth_alg = algs;
|
||||||
|
@ -3294,6 +3309,9 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
|
||||||
zero_addr = 1;
|
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
|
#ifdef CONFIG_TDLS
|
||||||
wpa_tdls_teardown_peers(wpa_s->wpa);
|
wpa_tdls_teardown_peers(wpa_s->wpa);
|
||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
|
|
|
@ -1403,6 +1403,13 @@ fast_reauth=1
|
||||||
# 2: MCS 0-9
|
# 2: MCS 0-9
|
||||||
# 3: not supported
|
# 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 #####################################
|
##### Fast Session Transfer (FST) support #####################################
|
||||||
#
|
#
|
||||||
# The options in this section are only available when the build configuration
|
# The options in this section are only available when the build configuration
|
||||||
|
|
|
@ -1234,6 +1234,7 @@ struct wpa_supplicant {
|
||||||
unsigned int disable_fils:1;
|
unsigned int disable_fils:1;
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
unsigned int ieee80211ac:1;
|
unsigned int ieee80211ac:1;
|
||||||
|
unsigned int enabled_4addr_mode:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue