From df6561ec06d26102dfbc61e20a09da75e521e8ce Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 16 Feb 2023 01:08:26 +0200 Subject: [PATCH] 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 --- src/ap/ap_drv_ops.c | 1 + src/drivers/driver.h | 4 +++ src/drivers/driver_nl80211.c | 58 +++++++++++++++++++++++++++++++----- wpa_supplicant/driver_i.h | 5 +++- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 1ffc37ff3..f77f738e4 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -459,6 +459,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.qosinfo = qosinfo; params.support_p2p_ps = supp_p2p_ps; params.set = set; + params.mld_link_id = -1; return hapd->driver->sta_add(hapd->drv_priv, ¶ms); } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 932972781..64b71a51c 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2403,6 +2403,10 @@ struct hostapd_sta_add_params { const u8 *supp_oper_classes; size_t supp_oper_classes_len; int support_p2p_ps; + + bool mld_link_sta; + s8 mld_link_id; + const u8 *mld_link_addr; }; struct mac_address { diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 34f06cd4e..c32822cc9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -5285,16 +5285,29 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct nl_msg *msg; struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; + u8 cmd; + const char *cmd_string; if ((params->flags & WPA_STA_TDLS_PEER) && !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) 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, - params->set ? "Set" : "Add", MAC2STR(params->addr)); - msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION : - NL80211_CMD_NEW_STATION); - if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr)) + cmd_string, MAC2STR(params->addr)); + msg = nl80211_bss_msg(bss, 0, cmd); + if (!msg) goto fail; /* @@ -5512,12 +5525,43 @@ static int wpa_driver_nl80211_sta_add(void *priv, 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); msg = NULL; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION " - "result: %d (%s)", params->set ? "SET" : "NEW", ret, - strerror(-ret)); + wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)", + cmd_string, ret, strerror(-ret)); if (ret == -EEXIST) ret = 0; fail: diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index cfce5fa6a..d707cf556 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -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, 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 -1; }