nl80211: AP MLD support for adding multi link stations

Multi link stations are represented in the kernel using a single
station with multiple links and the first ADD_STA command also
creates the first link. Subsequent links should be added with
LINK_ADD commands.

Implement this logic and provide the required MLD information per
station/link.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
This commit is contained in:
Andrei Otcheretianski 2023-02-16 01:08:26 +02:00 committed by Jouni Malinen
parent b8b4ceb8d6
commit df6561ec06
4 changed files with 60 additions and 8 deletions

View file

@ -459,6 +459,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.qosinfo = qosinfo; params.qosinfo = qosinfo;
params.support_p2p_ps = supp_p2p_ps; params.support_p2p_ps = supp_p2p_ps;
params.set = set; params.set = set;
params.mld_link_id = -1;
return hapd->driver->sta_add(hapd->drv_priv, &params); return hapd->driver->sta_add(hapd->drv_priv, &params);
} }

View file

@ -2403,6 +2403,10 @@ struct hostapd_sta_add_params {
const u8 *supp_oper_classes; const u8 *supp_oper_classes;
size_t supp_oper_classes_len; size_t supp_oper_classes_len;
int support_p2p_ps; int support_p2p_ps;
bool mld_link_sta;
s8 mld_link_id;
const u8 *mld_link_addr;
}; };
struct mac_address { struct mac_address {

View file

@ -5285,16 +5285,29 @@ static int wpa_driver_nl80211_sta_add(void *priv,
struct nl_msg *msg; struct nl_msg *msg;
struct nl80211_sta_flag_update upd; struct nl80211_sta_flag_update upd;
int ret = -ENOBUFS; int ret = -ENOBUFS;
u8 cmd;
const char *cmd_string;
if ((params->flags & WPA_STA_TDLS_PEER) && if ((params->flags & WPA_STA_TDLS_PEER) &&
!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (params->mld_link_sta) {
cmd = params->set ? NL80211_CMD_MODIFY_LINK_STA :
NL80211_CMD_ADD_LINK_STA;
cmd_string = params->set ? "NL80211_CMD_MODIFY_LINK_STA" :
"NL80211_CMD_ADD_LINK_STA";
} else {
cmd = params->set ? NL80211_CMD_SET_STATION :
NL80211_CMD_NEW_STATION;
cmd_string = params->set ? "NL80211_CMD_SET_STATION" :
"NL80211_CMD_NEW_STATION";
}
wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR, wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
params->set ? "Set" : "Add", MAC2STR(params->addr)); cmd_string, MAC2STR(params->addr));
msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION : msg = nl80211_bss_msg(bss, 0, cmd);
NL80211_CMD_NEW_STATION); if (!msg)
if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
goto fail; goto fail;
/* /*
@ -5512,12 +5525,43 @@ static int wpa_driver_nl80211_sta_add(void *priv,
nla_nest_end(msg, wme); nla_nest_end(msg, wme);
} }
/* In case we are an AP MLD need to always specify the link ID */
if (params->mld_link_id >= 0) {
wpa_printf(MSG_DEBUG, " * mld_link_id=%d",
params->mld_link_id);
if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
params->mld_link_id))
goto fail;
/*
* If the link address is specified the station is a non-AP MLD
* and thus need to provide the MLD address as the station
* address, and the non-AP MLD link address as the link address.
*/
if (params->mld_link_addr) {
wpa_printf(MSG_DEBUG, " * mld_link_addr=" MACSTR,
MAC2STR(params->mld_link_addr));
if (nla_put(msg, NL80211_ATTR_MLD_ADDR,
ETH_ALEN, params->addr) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
params->mld_link_addr))
goto fail;
} else {
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
params->addr))
goto fail;
}
} else {
if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL; msg = NULL;
if (ret) if (ret)
wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION " wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)",
"result: %d (%s)", params->set ? "SET" : "NEW", ret, cmd_string, ret, strerror(-ret));
strerror(-ret));
if (ret == -EEXIST) if (ret == -EEXIST)
ret = 0; ret = 0;
fail: fail:

View file

@ -350,8 +350,11 @@ static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s, static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s,
struct hostapd_sta_add_params *params) struct hostapd_sta_add_params *params)
{ {
if (wpa_s->driver->sta_add) if (wpa_s->driver->sta_add) {
/* Set link_id to -1 as it's needed for AP only */
params->mld_link_id = -1;
return wpa_s->driver->sta_add(wpa_s->drv_priv, params); return wpa_s->driver->sta_add(wpa_s->drv_priv, params);
}
return -1; return -1;
} }