]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: mld: support NAN and NAN_DATA interfaces
authorJohannes Berg <johannes.berg@intel.com>
Sun, 10 May 2026 20:48:29 +0000 (23:48 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:09 +0000 (15:17 +0300)
Until now we maintained the NAN vif in the driver only. The fw used the
AUX MAC for sync and discovery operations.
But when we want to configure a local schedule, we need to add the MAC
first.

NAN_DATA interfaces are not added to the FW. Instead, the local
address of these interfaces are configured to the FW via the NAN MAC.

Add the add/remove/update operations for the NAN interface, and fill the
NAN special parameters in it.

Note that this doesn't fully implement the schedule change, but only the
addition/removal of the NAN MAC. The full schedule management
implementation will come in a later patch.

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.dd12944c140b.I3578198660a533faf9f6a94432ef2114f4a9dfae@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/mld/iface.c
drivers/net/wireless/intel/iwlwifi/mld/iface.h
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
drivers/net/wireless/intel/iwlwifi/mld/nan.c
drivers/net/wireless/intel/iwlwifi/mld/nan.h

index 1e85a9168d2b01ef5794f0dfbab694df3846beec..150ad095e0ae2dda40f427cc353d20227f5f3fc0 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 <net/cfg80211.h>
 
@@ -55,6 +55,9 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
 
        ieee80211_iter_keys(mld->hw, vif, iwl_mld_cleanup_keys_iter, NULL);
 
+       if (vif->type == NL80211_IFTYPE_NAN)
+               mld_vif->nan.mac_added = false;
+
        CLEANUP_STRUCT(mld_vif);
 }
 
@@ -94,6 +97,8 @@ static int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif)
                return FW_MAC_TYPE_P2P_DEVICE;
        case NL80211_IFTYPE_ADHOC:
                return FW_MAC_TYPE_IBSS;
+       case NL80211_IFTYPE_NAN:
+               return FW_MAC_TYPE_NAN;
        default:
                WARN_ON_ONCE(1);
        }
@@ -362,6 +367,42 @@ static void iwl_mld_fill_mac_cmd_ibss(struct iwl_mld *mld,
                                         MAC_CFG_FILTER_ACCEPT_GRP);
 }
 
+static int iwl_mld_fill_mac_cmd_nan(struct iwl_mld *mld,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_vif *ndi_being_added,
+                                   struct iwl_mac_config_cmd *cmd)
+{
+       struct ieee80211_vif *iter;
+       u32 idx = 0;
+
+       cmd->filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);
+
+       /*
+        * A NAN_DATA vif might be in the process of being added - it won't
+        * be found by the iteration below since it's not yet active/in-driver.
+        * In hw restart, the iteration below will find the ndi_being_added.
+        */
+       if (ndi_being_added && !mld->fw_status.in_hw_restart) {
+               memcpy(cmd->nan.ndi_addrs[idx].addr, ndi_being_added->addr, ETH_ALEN);
+               idx++;
+       }
+
+       for_each_active_interface(iter, mld->hw) {
+               if (iter->type != NL80211_IFTYPE_NAN_DATA)
+                       continue;
+
+               if (WARN_ON_ONCE(idx >= ARRAY_SIZE(cmd->nan.ndi_addrs)))
+                       return -EINVAL;
+
+               memcpy(cmd->nan.ndi_addrs[idx].addr, iter->addr, ETH_ALEN);
+               idx++;
+       }
+
+       cmd->nan.ndi_addrs_count = cpu_to_le32(idx);
+
+       return 0;
+}
+
 static int
 iwl_mld_rm_mac_from_fw(struct iwl_mld *mld, struct ieee80211_vif *vif)
 {
@@ -374,16 +415,23 @@ iwl_mld_rm_mac_from_fw(struct iwl_mld *mld, struct ieee80211_vif *vif)
        return iwl_mld_send_mac_cmd(mld, &cmd);
 }
 
-int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
-                         u32 action)
+static int
+__iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
+                       u32 action, struct ieee80211_vif *ndi_being_added)
 {
        struct iwl_mac_config_cmd cmd = {};
+       int ret;
 
        lockdep_assert_wiphy(mld->wiphy);
 
-       /* NAN interface type is not known to FW */
-       if (vif->type == NL80211_IFTYPE_NAN)
-               return 0;
+       /* NAN_DATA interface type is not known to FW */
+       if (WARN_ON(vif->type == NL80211_IFTYPE_NAN_DATA))
+               return -EINVAL;
+
+       /* ndi_being_added is only relevant for NAN and when adding a NAN_DATA interface */
+       if (WARN_ON(ndi_being_added &&
+                   (vif->type != NL80211_IFTYPE_NAN || action != FW_CTXT_ACTION_MODIFY)))
+               return -EINVAL;
 
        if (action == FW_CTXT_ACTION_REMOVE)
                return iwl_mld_rm_mac_from_fw(mld, vif);
@@ -411,6 +459,11 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
        case NL80211_IFTYPE_ADHOC:
                iwl_mld_fill_mac_cmd_ibss(mld, vif, &cmd);
                break;
+       case NL80211_IFTYPE_NAN:
+               ret = iwl_mld_fill_mac_cmd_nan(mld, vif, ndi_being_added, &cmd);
+               if (ret)
+                       return ret;
+               break;
        default:
                WARN(1, "not supported yet\n");
                return -EOPNOTSUPP;
@@ -419,6 +472,12 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
        return iwl_mld_send_mac_cmd(mld, &cmd);
 }
 
+int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
+                         u32 action)
+{
+       return __iwl_mld_mac_fw_action(mld, vif, action, NULL);
+}
+
 static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy,
                                      struct wiphy_work *wk)
 {
@@ -459,6 +518,24 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
        iwl_mld_init_internal_sta(&mld_vif->aux_sta);
 }
 
+static int iwl_mld_update_nan_mac(struct iwl_mld *mld,
+                                 struct ieee80211_vif *ndi_being_added)
+{
+       struct ieee80211_vif *vif = mld->nan_device_vif;
+       struct iwl_mld_vif *mld_vif;
+
+       if (WARN_ON_ONCE(!vif))
+               return -ENODEV;
+
+       mld_vif = iwl_mld_vif_from_mac80211(vif);
+
+       if (!iwl_mld_vif_fw_id_valid(mld_vif))
+               return 0;
+
+       return __iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY,
+                                      ndi_being_added);
+}
+
 int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
 {
        struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
@@ -468,10 +545,14 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
 
        iwl_mld_init_vif(mld, vif);
 
-       /* NAN interface type is not known to FW */
+       /* NAN MACs are added to FW only when a schedule is set */
        if (vif->type == NL80211_IFTYPE_NAN)
                return 0;
 
+       /* NAN_DATA interface type is not known to FW, but we need to update NAN MAC */
+       if (vif->type == NL80211_IFTYPE_NAN_DATA)
+               return iwl_mld_update_nan_mac(mld, vif);
+
        ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif);
        if (ret)
                return ret;
@@ -483,23 +564,52 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
        return ret;
 }
 
+int iwl_mld_add_nan_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
+{
+       struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       int ret;
+
+       lockdep_assert_wiphy(mld->wiphy);
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
+               return -EINVAL;
+
+       ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif);
+       if (ret)
+               return ret;
+
+       ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_ADD);
+       if (ret) {
+               RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL);
+               return ret;
+       }
+
+       mld_vif->nan.mac_added = true;
+
+       return 0;
+}
+
 void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
 {
        struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
 
        lockdep_assert_wiphy(mld->wiphy);
 
-       /* NAN interface type is not known to FW */
-       if (vif->type == NL80211_IFTYPE_NAN)
+       if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+               iwl_mld_update_nan_mac(mld, NULL);
                return;
+       }
 
-       iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE);
-
-       if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif)))
+       if (!iwl_mld_vif_fw_id_valid(mld_vif))
                return;
 
+       iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE);
+
        RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL);
 
+       if (vif->type == NL80211_IFTYPE_NAN)
+               mld_vif->nan.mac_added = false;
+
        iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_VIF,
                                               mld_vif->fw_id);
 }
index 8dfc79fed253443536766d354c8d6ac43adeb681..1ac14996985c00828c264667122822e9c855c504 100644 (file)
@@ -152,6 +152,8 @@ struct iwl_mld_emlsr {
  *     p2p device only. Set to %ROC_NUM_ACTIVITIES when not in use.
  * @aux_sta: station used for remain on channel. Used in P2P device.
  * @mlo_scan_start_wk: worker to start a deferred MLO scan
+ * @nan: NAN parameters
+ * @nan.mac_added: track whether or not the MAC was added to FW
  */
 struct iwl_mld_vif {
        /* Add here fields that need clean up on restart */
@@ -175,6 +177,11 @@ struct iwl_mld_vif {
        struct iwl_mld_link deflink;
        struct iwl_mld_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
 
+       struct {
+               /* use only with wiphy protection */
+               bool mac_added;
+       } nan;
+
        struct iwl_mld_emlsr emlsr;
 
 #ifdef CONFIG_PM_SLEEP
@@ -206,6 +213,20 @@ iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif)
 /* Call only for interfaces that were added to the driver! */
 static inline bool iwl_mld_vif_fw_id_valid(struct iwl_mld_vif *mld_vif)
 {
+       struct ieee80211_vif *vif = iwl_mld_vif_to_mac80211(mld_vif);
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_NAN_DATA:
+               return false;
+       case NL80211_IFTYPE_NAN:
+               if (!mld_vif->nan.mac_added)
+                       return false;
+               break;
+       default:
+               break;
+       }
+
+       /* Should be added to FW */
        if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld_vif->mld->fw_id_to_vif)))
                return false;
 
@@ -235,6 +256,7 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
 int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
                          u32 action);
 int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif);
+int iwl_mld_add_nan_vif(struct iwl_mld *mld, struct ieee80211_vif *vif);
 void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif);
 void iwl_mld_set_vif_associated(struct iwl_mld *mld,
                                struct ieee80211_vif *vif);
index e66b304f345a71f07a6611357c1ca80a7a5b5f88..3c84c6b0faaafc91951f64cf1d88022ab61598a8 100644 (file)
@@ -677,6 +677,9 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,
        if (ret)
                return ret;
 
+       if (vif->type == NL80211_IFTYPE_NAN_DATA)
+               return 0;
+
        /*
         * Add the default link, but not if this is an MLD vif as that implies
         * the HW is restarting and it will be configured by change_vif_links.
@@ -745,7 +748,7 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw,
 
        if (vif->type == NL80211_IFTYPE_NAN)
                mld->nan_device_vif = NULL;
-       else
+       else if (vif->type != NL80211_IFTYPE_NAN_DATA)
                iwl_mld_remove_link(mld, &vif->bss_conf);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1371,6 +1374,10 @@ iwl_mld_mac80211_link_info_changed(struct ieee80211_hw *hw,
                if (changes & BSS_CHANGED_MU_GROUPS)
                        iwl_mld_update_mu_groups(mld, link_conf);
                break;
+       case NL80211_IFTYPE_NAN:
+       case NL80211_IFTYPE_NAN_DATA:
+               /* NAN has no links */
+               break;
        default:
                /* shouldn't happen */
                WARN_ON_ONCE(1);
@@ -1418,6 +1425,11 @@ void iwl_mld_mac80211_vif_cfg_changed(struct ieee80211_hw *hw,
 
        lockdep_assert_wiphy(mld->wiphy);
 
+       if (vif->type == NL80211_IFTYPE_NAN) {
+               iwl_mld_nan_vif_cfg_changed(mld, vif, changes);
+               return;
+       }
+
        if (vif->type != NL80211_IFTYPE_STATION)
                return;
 
@@ -1613,7 +1625,7 @@ iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw,
 
        lockdep_assert_wiphy(mld->wiphy);
 
-       if (vif->type == NL80211_IFTYPE_NAN)
+       if (vif->type == NL80211_IFTYPE_NAN || vif->type == NL80211_IFTYPE_NAN_DATA)
                return 0;
 
        link = iwl_mld_link_dereference_check(mld_vif, link_id);
index 4d8e85f2bd7c23d9c08522157d29660b85333427..96e79ba5234a4dc8dd4517d4e999a057442cacdb 100644 (file)
@@ -296,3 +296,25 @@ void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,
        wdev = ieee80211_vif_to_wdev(mld->nan_device_vif);
        cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL);
 }
+
+void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
+                                struct ieee80211_vif *vif,
+                                u64 changes)
+{
+       struct ieee80211_nan_sched_cfg *sched_cfg = &vif->cfg.nan_sched;
+       struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       bool has_sched = memchr_inv(sched_cfg->schedule, 0,
+                                   sizeof(sched_cfg->schedule));
+
+       lockdep_assert_wiphy(mld->wiphy);
+
+       if (!(changes & BSS_CHANGED_NAN_LOCAL_SCHED))
+               return;
+
+       if (has_sched && !mld_vif->nan.mac_added) {
+               if (iwl_mld_add_nan_vif(mld, vif))
+                       IWL_ERR(mld, "Failed to add NAN vif\n");
+       } else if (!has_sched && mld_vif->nan.mac_added) {
+               iwl_mld_rm_vif(mld, vif);
+       }
+}
index c04d77208971e30afe4db5a73d0b36048c7a38b4..9487155cf6b38706e723906ef950bb6dc444746a 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2025 Intel Corporation
+ * Copyright (C) 2025-2026 Intel Corporation
  */
 #ifndef __iwl_mld_nan_h__
 #define __iwl_mld_nan_h__
@@ -27,5 +27,8 @@ bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld,
 bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,
                                     struct iwl_rx_packet *pkt,
                                     u32 obj_id);
+void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
+                                struct ieee80211_vif *vif,
+                                u64 changes);
 
 #endif /* __iwl_mld_nan_h__ */