From: Daniel Gabay Implement mac80211 schedule callbacks for NAN Data Path support: - Track local schedule via BSS_CHANGED_NAN_LOCAL_SCHED, caching the channel for each 16TU time slot. - Copy peer schedule to driver-private storage in nan_peer_sched_changed callback for use in TX availability decisions. Signed-off-by: Daniel Gabay Signed-off-by: Miri Korenblit --- .../net/wireless/virtual/mac80211_hwsim_i.h | 21 +++++ .../wireless/virtual/mac80211_hwsim_main.c | 14 ++-- .../net/wireless/virtual/mac80211_hwsim_nan.c | 80 +++++++++++++++++++ .../net/wireless/virtual/mac80211_hwsim_nan.h | 15 +++- 4 files changed, 121 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_i.h b/drivers/net/wireless/virtual/mac80211_hwsim_i.h index d182b5117bfb..0f0f2ac6d80e 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_i.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim_i.h @@ -14,6 +14,27 @@ #include "mac80211_hwsim.h" #include "mac80211_hwsim_nan.h" +struct hwsim_sta_nan_sched { + /* Later members are protected by this lock */ + spinlock_t lock; + u16 committed_dw; + struct { + u8 map_id; + struct cfg80211_chan_def chans[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; + } maps[CFG80211_NAN_MAX_PEER_MAPS]; +}; + +struct hwsim_sta_priv { + u32 magic; + unsigned int last_link; + u16 active_links_rx; + + /* NAN peer schedule - must be accessed under nan_sched.lock */ + struct hwsim_sta_nan_sched nan_sched; +}; + +#define HWSIM_STA_MAGIC 0x6d537749 + struct mac80211_hwsim_link_data { u32 link_id; u64 beacon_int /* beacon interval in us */; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c index fc940b38c52c..1ea33ec577dd 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c @@ -252,14 +252,6 @@ static inline void hwsim_clear_magic(struct ieee80211_vif *vif) vp->magic = 0; } -struct hwsim_sta_priv { - u32 magic; - unsigned int last_link; - u16 active_links_rx; -}; - -#define HWSIM_STA_MAGIC 0x6d537749 - static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; @@ -2652,6 +2644,9 @@ static void mac80211_hwsim_vif_info_changed(struct ieee80211_hw *hw, vp->aid = vif->cfg.aid; } + if (changed & BSS_CHANGED_NAN_LOCAL_SCHED) + mac80211_hwsim_nan_local_sched_changed(hw, vif); + if (vif->type == NL80211_IFTYPE_STATION && changed & (BSS_CHANGED_MLD_VALID_LINKS | BSS_CHANGED_MLD_TTLM)) { u16 usable_links = ieee80211_vif_usable_links(vif); @@ -2818,6 +2813,8 @@ static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, sp->active_links_rx = sta->valid_links; } + spin_lock_init(&sp->nan_sched.lock); + return 0; } @@ -4245,6 +4242,7 @@ static int mac80211_hwsim_set_radar_background(struct ieee80211_hw *hw, .start_nan = mac80211_hwsim_nan_start, \ .stop_nan = mac80211_hwsim_nan_stop, \ .nan_change_conf = mac80211_hwsim_nan_change_config, \ + .nan_peer_sched_changed = mac80211_hwsim_nan_peer_sched_changed, \ HWSIM_DEBUGFS_OPS #define HWSIM_NON_MLO_OPS \ diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c index 6053b6f8f91f..16883edd2215 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.c @@ -1008,3 +1008,83 @@ bool mac80211_hwsim_nan_receive(struct ieee80211_hw *hw, return false; } + +void mac80211_hwsim_nan_local_sched_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_nan_channel **slots = vif->cfg.nan_sched.schedule; + + if (WARN_ON(vif->type != NL80211_IFTYPE_NAN)) + return; + + spin_lock_bh(&data->nan.state_lock); + + for (int i = 0; i < ARRAY_SIZE(data->nan.local_sched); i++) { + struct ieee80211_chanctx_conf *chanctx; + + if (!slots[i] || IS_ERR(slots[i])) { + memset(&data->nan.local_sched[i], 0, + sizeof(data->nan.local_sched[i])); + continue; + } + + chanctx = slots[i]->chanctx_conf; + if (!chanctx) { + memset(&data->nan.local_sched[i], 0, + sizeof(data->nan.local_sched[i])); + continue; + } + + data->nan.local_sched[i] = chanctx->def; + } + + spin_unlock_bh(&data->nan.state_lock); +} + +int mac80211_hwsim_nan_peer_sched_changed(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct hwsim_sta_priv *sp = (void *)sta->drv_priv; + struct ieee80211_nan_peer_sched *sched = sta->nan_sched; + + spin_lock_bh(&sp->nan_sched.lock); + + /* Clear existing schedule */ + sp->nan_sched.committed_dw = 0; + for (int i = 0; i < CFG80211_NAN_MAX_PEER_MAPS; i++) { + sp->nan_sched.maps[i].map_id = CFG80211_NAN_INVALID_MAP_ID; + memset(sp->nan_sched.maps[i].chans, 0, + sizeof(sp->nan_sched.maps[i].chans)); + } + + if (!sched) + goto out; + + sp->nan_sched.committed_dw = sched->committed_dw; + + for (int i = 0; i < CFG80211_NAN_MAX_PEER_MAPS; i++) { + struct ieee80211_nan_peer_map *map = &sched->maps[i]; + + if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) + continue; + + sp->nan_sched.maps[i].map_id = map->map_id; + + for (int j = 0; j < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; j++) { + struct ieee80211_nan_channel *peer_chan = + map->slots[j]; + + if (peer_chan && peer_chan->chanreq.oper.chan) + sp->nan_sched.maps[i].chans[j] = + peer_chan->chanreq.oper; + else + memset(&sp->nan_sched.maps[i].chans[j], 0, + sizeof(sp->nan_sched.maps[i].chans[j])); + } + } + +out: + spin_unlock_bh(&sp->nan_sched.lock); + return 0; +} diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h index 3199e5c5376b..eb53bacee206 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_nan.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim_nan.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * mac80211_hwsim_nan - NAN software simulation for mac80211_hwsim - * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2025-2026 Intel Corporation */ #ifndef __MAC80211_HWSIM_NAN_H @@ -52,6 +52,13 @@ struct mac80211_hwsim_nan_data { bool tsf_adjusted; bool tsf_discontinuity; + + /* + * Local schedule - stores channel definition for each 16TU slot. + * Derived from NMI vif->cfg.nan_schedule. chan == NULL means not + * available in that slot (except DW which is implicit). + */ + struct cfg80211_chan_def local_sched[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; }; enum hrtimer_restart @@ -73,6 +80,9 @@ int mac80211_hwsim_nan_change_config(struct ieee80211_hw *hw, struct cfg80211_nan_conf *conf, u32 changes); +int mac80211_hwsim_nan_peer_sched_changed(struct ieee80211_hw *hw, + struct ieee80211_sta *sta); + bool mac80211_hwsim_nan_txq_transmitting(struct ieee80211_hw *hw, struct ieee80211_txq *txq); @@ -86,4 +96,7 @@ bool mac80211_hwsim_nan_receive(struct ieee80211_hw *hw, void mac80211_hwsim_nan_rx(struct ieee80211_hw *hw, struct sk_buff *skb); +void mac80211_hwsim_nan_local_sched_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + #endif /* __MAC80211_HWSIM_NAN_H */ -- 2.34.1