From: Johannes Berg Date: Sun, 10 May 2026 20:48:29 +0000 (+0300) Subject: wifi: iwlwifi: mld: support NAN and NAN_DATA interfaces X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e373b916a60848508dbbc1af79ba7ca5b893373;p=thirdparty%2Flinux.git wifi: iwlwifi: mld: support NAN and NAN_DATA interfaces 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 Co-developed-by: Miri Korenblit Link: https://patch.msgid.link/20260510234534.dd12944c140b.I3578198660a533faf9f6a94432ef2114f4a9dfae@changeid Signed-off-by: Miri Korenblit --- diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index 1e85a9168d2b0..150ad095e0ae2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -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 @@ -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); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index 8dfc79fed2534..1ac14996985c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index e66b304f345a7..3c84c6b0faaaf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -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); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 4d8e85f2bd7c2..96e79ba5234a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -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); + } +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h index c04d77208971e..9487155cf6b38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -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__ */