]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: mld: implement NAN peer station management
authorJohannes Berg <johannes.berg@intel.com>
Sun, 10 May 2026 20:48:32 +0000 (23:48 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:09 +0000 (15:17 +0300)
Implement peer station management for NAN, i.e. support for adding,
removing, and updating NMI and NDI stations.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260510234534.cbf6bac4744f.I3bd01266e47f24fb7f1240db62ac3bd47c479127@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/nan.c
drivers/net/wireless/intel/iwlwifi/mld/sta.c
drivers/net/wireless/intel/iwlwifi/mld/sta.h

index 3c84c6b0faaafc91951f64cf1d88022ab61598a8..6b4b2683cd1ee718a4b1587bd605178b04cc94b3 100644 (file)
@@ -1841,7 +1841,7 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
                   new_state == IEEE80211_STA_AUTHORIZED) {
                ret = 0;
 
-               if (!sta->tdls) {
+               if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
                        mld_vif->authorized = true;
 
                        /* Ensure any block due to a non-BSS link is synced */
index eba79aca8c062e4e726f68ccfb571d06e6bea9f0..53d39717deabfd2eaef981ccacc53f018eb81004 100644 (file)
@@ -464,19 +464,17 @@ static int iwl_mld_nan_link_set_active(struct iwl_mld *mld,
 }
 
 static void iwl_mld_nan_link_remove(struct iwl_mld *mld,
-                                   struct iwl_mld_nan_link *nan_link)
+                                   struct iwl_mld_nan_link *nan_link,
+                                   u32 link_id)
 {
        struct iwl_link_config_cmd cmd = {
-               .link_id = cpu_to_le32(nan_link->fw_id),
+               .link_id = cpu_to_le32(link_id),
                .phy_id = cpu_to_le32(FW_CTXT_ID_INVALID),
        };
 
-       if (WARN_ON_ONCE(nan_link->fw_id == FW_CTXT_ID_INVALID))
-               return;
-
        iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE);
 
-       RCU_INIT_POINTER(mld->fw_id_to_bss_conf[nan_link->fw_id], NULL);
+       RCU_INIT_POINTER(mld->fw_id_to_bss_conf[link_id], NULL);
        nan_link->fw_id = FW_CTXT_ID_INVALID;
        nan_link->active = false;
        nan_link->chanctx = NULL;
@@ -518,6 +516,8 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
        struct ieee80211_nan_channel **slots = sched_cfg->schedule;
        bool link_used[ARRAY_SIZE(mld_vif->nan.links)] = {};
        struct iwl_mld_nan_link *nan_link;
+       unsigned long remove_link_ids = 0;
+       bool added_links = false;
        bool empty_schedule = true;
        int ret, i;
 
@@ -588,6 +588,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
 
                /* we have a link, activate it */
                if (links[i]) {
+                       added_links = true;
                        link_used[links[i]->fw_id] = true;
                        iwl_mld_nan_link_set_active(mld, links[i], true);
                }
@@ -626,14 +627,32 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
        if (ret)
                IWL_ERR(mld, "NAN: failed to update schedule (%d)\n", ret);
 
-       /* delete unused links */
+       /* prepare stations for links we'll remove */
        for_each_mld_nan_valid_link(mld_vif, nan_link) {
                if (!link_used[nan_link->fw_id]) {
                        iwl_mld_nan_link_set_active(mld, nan_link, false);
-                       iwl_mld_nan_link_remove(mld, nan_link);
+                       remove_link_ids |= BIT(nan_link->fw_id);
+                       /* mark unused for STA updates */
+                       nan_link->fw_id = FW_CTXT_ID_INVALID;
+               }
+       }
+
+       if (added_links || remove_link_ids) {
+               struct ieee80211_sta *sta;
+
+               for_each_station(sta, mld->hw) {
+                       struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+
+                       if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NMI ||
+                           mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI)
+                               iwl_mld_add_modify_sta_cmd(mld, &sta->deflink);
                }
        }
 
+       /* delete unused links */
+       for_each_set_bit(i, &remove_link_ids, ARRAY_SIZE(mld_vif->nan.links))
+               iwl_mld_nan_link_remove(mld, &mld_vif->nan.links[i], i);
+
        /* remove MAC if needed */
        if (!previously_empty_schedule && empty_schedule) {
                /* must have been added */
index 4c97d12ce2d01722be0897779b4dbc018ed3dc2d..f794f80b0fddf45e6991c207e416d9aa48ad2fa2 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -13,6 +13,7 @@
 #include "key.h"
 #include "agg.h"
 #include "tlc.h"
+#include "nan.h"
 #include "fw/api/sta.h"
 #include "fw/api/mac.h"
 #include "fw/api/rx.h"
@@ -43,13 +44,13 @@ int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld,
 
 static void
 iwl_mld_fill_ampdu_size_and_dens(struct ieee80211_link_sta *link_sta,
-                                struct ieee80211_bss_conf *link,
+                                bool is_6ghz,
                                 __le32 *tx_ampdu_max_size,
                                 __le32 *tx_ampdu_spacing)
 {
        u32 agg_size = 0, mpdu_dens = 0;
 
-       if (WARN_ON(!link_sta || !link))
+       if (WARN_ON(!link_sta))
                return;
 
        /* Note that we always use only legacy & highest supported PPDUs, so
@@ -63,7 +64,7 @@ iwl_mld_fill_ampdu_size_and_dens(struct ieee80211_link_sta *link_sta,
                mpdu_dens = link_sta->ht_cap.ampdu_density;
        }
 
-       if (link->chanreq.oper.chan->band == NL80211_BAND_6GHZ) {
+       if (is_6ghz) {
                /* overwrite HT values on 6 GHz */
                mpdu_dens =
                        le16_get_bits(link_sta->he_6ghz_capa.capa,
@@ -439,29 +440,56 @@ static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
        return ret;
 }
 
-static int
-iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
-                          struct ieee80211_link_sta *link_sta)
+int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
+                             struct ieee80211_link_sta *link_sta)
 {
        struct ieee80211_sta *sta = link_sta->sta;
        struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
-       struct ieee80211_bss_conf *link;
-       struct iwl_mld_link *mld_link;
        struct iwl_sta_cfg_cmd cmd = {};
        int fw_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
+       bool is_6ghz, uora_exists;
+       u32 link_mask;
 
        lockdep_assert_wiphy(mld->wiphy);
 
-       link = link_conf_dereference_protected(mld_sta->vif,
-                                              link_sta->link_id);
+       if (WARN_ON(fw_id < 0))
+               return -EINVAL;
+
+       if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NMI ||
+           mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) {
+               struct iwl_mld_nan_link *nan_link;
+               struct iwl_mld_vif *nan_dev;
 
-       mld_link = iwl_mld_link_from_mac80211(link);
+               is_6ghz = false;
+               uora_exists = false;
 
-       if (WARN_ON(!link || !mld_link) || fw_id < 0)
-               return -EINVAL;
+               if (WARN_ON(!mld->nan_device_vif))
+                       return -EINVAL;
+
+               nan_dev = iwl_mld_vif_from_mac80211(mld->nan_device_vif);
+
+               link_mask = 0;
+
+               for_each_mld_nan_valid_link(nan_dev, nan_link)
+                       link_mask |= BIT(nan_link->fw_id);
+       } else {
+               struct ieee80211_bss_conf *link;
+               struct iwl_mld_link *mld_link;
+
+               link = link_conf_dereference_protected(mld_sta->vif,
+                                                      link_sta->link_id);
+               mld_link = iwl_mld_link_from_mac80211(link);
+
+               if (WARN_ON(!link || !mld_link))
+                       return -EINVAL;
+
+               link_mask = BIT(mld_link->fw_id);
+               is_6ghz = link->chanreq.oper.chan->band == NL80211_BAND_6GHZ;
+               uora_exists = link->uora_exists;
+       }
 
        cmd.sta_id = cpu_to_le32(fw_id);
-       cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id));
+       cmd.link_mask = cpu_to_le32(link_mask);
        cmd.station_type = cpu_to_le32(mld_sta->sta_type);
 
        memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
@@ -499,7 +527,7 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
                break;
        }
 
-       iwl_mld_fill_ampdu_size_and_dens(link_sta, link,
+       iwl_mld_fill_ampdu_size_and_dens(link_sta, is_6ghz,
                                         &cmd.tx_ampdu_max_size,
                                         &cmd.tx_ampdu_spacing);
 
@@ -511,7 +539,7 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
 
        if (link_sta->he_cap.has_he) {
                cmd.trig_rnd_alloc =
-                       cpu_to_le32(link->uora_exists ? 1 : 0);
+                       cpu_to_le32(uora_exists ? 1 : 0);
 
                /* PPE Thresholds */
                iwl_mld_fill_pkt_ext(mld, link_sta, &cmd.pkt_ext);
@@ -525,6 +553,25 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
                        cmd.ack_enabled = cpu_to_le32(1);
        }
 
+       if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) {
+               struct ieee80211_sta *nmi_sta =
+                       wiphy_dereference(mld->wiphy, sta->nmi);
+               int nmi_fw_id;
+
+               /* copy the local NDI address */
+               ether_addr_copy(cmd.ndi_local_addr, mld_sta->vif->addr);
+
+               if (WARN_ON(!nmi_sta))
+                       return -EINVAL;
+
+               nmi_fw_id = iwl_mld_fw_sta_id_from_link_sta(mld,
+                                       &nmi_sta->deflink);
+               if (nmi_fw_id < 0)
+                       return -EINVAL;
+
+               cmd.nmi_sta_id = (u8) nmi_fw_id;
+       }
+
        return iwl_mld_send_sta_cmd(mld, &cmd);
 }
 
@@ -759,10 +806,23 @@ int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta,
 {
        struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
        struct ieee80211_link_sta *link_sta;
+       enum iwl_fw_sta_type type;
        int link_id;
        int ret;
 
-       ret = iwl_mld_init_sta(mld, sta, vif, STATION_TYPE_PEER);
+       switch (vif->type) {
+       case NL80211_IFTYPE_NAN:
+               type = STATION_TYPE_NAN_PEER_NMI;
+               break;
+       case NL80211_IFTYPE_NAN_DATA:
+               type = STATION_TYPE_NAN_PEER_NDI;
+               break;
+       default:
+               type = STATION_TYPE_PEER;
+               break;
+       }
+
+       ret = iwl_mld_init_sta(mld, sta, vif, type);
        if (ret)
                return ret;
 
index 36288c2fb38c5e43a1b4faa7f2a24e2c2d751a04..13644ffd185d9eb5ebfb300b46f8a6e0171806a9 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 
 #ifndef __iwl_mld_sta_h__
@@ -195,6 +195,8 @@ void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta);
 int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld,
                                    struct ieee80211_link_sta *link_sta);
 u32 iwl_mld_fw_sta_id_mask(struct iwl_mld *mld, struct ieee80211_sta *sta);
+int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
+                              struct ieee80211_link_sta *link_sta);
 int iwl_mld_update_all_link_stations(struct iwl_mld *mld,
                                     struct ieee80211_sta *sta);
 void iwl_mld_flush_sta_txqs(struct iwl_mld *mld, struct ieee80211_sta *sta);