#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 */;
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;
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);
sp->active_links_rx = sta->valid_links;
}
+ spin_lock_init(&sp->nan_sched.lock);
+
return 0;
}
.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 \
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;
+}
// 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
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
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);
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 */