]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: AP MLD support for adding multi link stations
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Wed, 15 Feb 2023 23:08:26 +0000 (01:08 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 7 Mar 2023 19:43:41 +0000 (21:43 +0200)
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>
src/ap/ap_drv_ops.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/driver_i.h

index 1ffc37ff33f5bf26913d0439b9d95e9f0c1ac062..f77f738e4c317f06f217e0ccca5ee70a13f69b66 100644 (file)
@@ -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, &params);
 }
 
index 9329727817086e0a55da902df19d863a2b7a14b4..64b71a51c47b6361a1f5af59386b8590f9e73235 100644 (file)
@@ -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 {
index 34f06cd4e33f6a8dfe42428868a39116f43067a4..c32822cc90bb8b4f6b644910cb950bcc535bf89d 100644 (file)
@@ -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:
index cfce5fa6a7ef947de915a16249763631731e2339..d707cf556dcb0875686529870e27bbfdf3412a9b 100644 (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,
                                  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;
 }