return ktime_to_us(ktime_get_boottime());
}
-static ktime_t mac80211_hwsim_tsf_to_boottime(struct mac80211_hwsim_data *data,
- u64 tsf)
+ktime_t mac80211_hwsim_tsf_to_boottime(struct mac80211_hwsim_data *data,
+ u64 tsf)
{
return us_to_ktime(tsf - data->tsf_offset);
}
+u64 mac80211_hwsim_boottime_to_tsf(struct mac80211_hwsim_data *data,
+ ktime_t ts)
+{
+ return ktime_to_us(ts + data->tsf_offset);
+}
+
u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
* on channel 6 or channel 149, unless a ROC is in progress (for
* USD use cases).
*/
- if (data->nan.curr_dw_band == NL80211_BAND_2GHZ)
- channel = ieee80211_get_channel(hw->wiphy, 2437);
- else if (data->nan.curr_dw_band == NL80211_BAND_5GHZ)
- channel = ieee80211_get_channel(hw->wiphy, 5745);
- else
- channel = NULL;
+ channel = data->nan.channel;
if (WARN_ON(!channel)) {
ieee80211_free_txskb(hw, skb);
NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED |
NAN_DEV_CAPA_NDPE_SUPPORTED;
- hrtimer_setup(&data->nan.timer, mac80211_hwsim_nan_dw_start,
- CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT);
+ hrtimer_setup(&data->nan.slot_timer,
+ mac80211_hwsim_nan_slot_timer,
+ CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
}
data->if_combination.radar_detect_widths =
#include "mac80211_hwsim_i.h"
+/* Defined as the lower 23 bits being zero */
+#define DW0_TSF_MASK GENMASK(22, 0)
+
+/* DWs are repeated every 512 TUs */
+#define DWST_TU 512
+#define DWST_TSF_MASK (ieee80211_tu_to_usec(DWST_TU) - 1)
+
+#define SLOT_TU 16
+#define SLOT_TSF_MASK (ieee80211_tu_to_usec(DWST_TU) - 1)
+
+/* The 2.4 GHz DW is at the start, the 5 GHz is in slot 8 (after 128 TUs) */
+#define DW_5G_OFFSET_TU 128
+
+#define SLOT_24GHZ_DW 0
+#define SLOT_5GHZ_DW (DW_5G_OFFSET_TU / SLOT_TU)
+
+/* The special DW0 happens every 16 DWSTs (8192 TUs) */
+static_assert(16 * DWST_TU * 1024 == 8192 * 1024);
+static_assert(DW0_TSF_MASK + 1 == 8192 * 1024);
+
static u8 hwsim_nan_cluster_id[ETH_ALEN];
+static u64 hwsim_nan_get_timer_tsf(struct mac80211_hwsim_data *data)
+{
+ ktime_t expires = hrtimer_get_expires(&data->nan.slot_timer);
+
+ return mac80211_hwsim_boottime_to_tsf(data, expires);
+}
+
+static u8 hwsim_nan_slot_from_tsf(u64 tsf)
+{
+ return (tsf & DWST_TSF_MASK) / ieee80211_tu_to_usec(SLOT_TU);
+}
+
+static void
+mac80211_hwsim_nan_schedule_slot(struct mac80211_hwsim_data *data, u8 slot)
+{
+ u64 tsf = hwsim_nan_get_timer_tsf(data);
+
+ /* Only called by mac80211_hwsim_nan_dw_timer from softirq context */
+ lockdep_assert_in_softirq();
+
+ tsf &= ~DWST_TSF_MASK;
+ tsf += ieee80211_tu_to_usec(slot * SLOT_TU);
+
+ hrtimer_set_expires(&data->nan.slot_timer,
+ mac80211_hwsim_tsf_to_boottime(data, tsf));
+}
+
+static void
+mac80211_hwsim_nan_exec_state_transitions(struct mac80211_hwsim_data *data)
+{
+ /*
+ * Handle NAN role and state transitions at the end of the DW period
+ * in accordance to Wi-Fi Aware version 4.0 section 3.3.7 point 2, i.e.
+ * end of 5 GHz DW if enabled else at the end of the 2.4 GHz DW.
+ *
+ * TODO: Implement
+ */
+}
+
enum hrtimer_restart
-mac80211_hwsim_nan_dw_start(struct hrtimer *timer)
+mac80211_hwsim_nan_slot_timer(struct hrtimer *timer)
{
struct mac80211_hwsim_data *data =
container_of(timer, struct mac80211_hwsim_data,
- nan.timer);
+ nan.slot_timer);
struct ieee80211_hw *hw = data->hw;
- u64 orig_tsf = mac80211_hwsim_get_tsf(hw, NULL), tsf = orig_tsf;
- u32 dw_int = 512 * 1024;
- u64 until_dw;
+ struct ieee80211_channel *notify_dw_chan = NULL;
+ u64 tsf = hwsim_nan_get_timer_tsf(data);
+ u8 slot = hwsim_nan_slot_from_tsf(tsf);
+ bool dwst_of_dw0 = false;
+ bool dw_end = false;
if (!data->nan.device_vif)
return HRTIMER_NORESTART;
- if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) {
- if (data->nan.curr_dw_band == NL80211_BAND_2GHZ) {
- dw_int = 128 * 1024;
- data->nan.curr_dw_band = NL80211_BAND_5GHZ;
- } else if (data->nan.curr_dw_band == NL80211_BAND_5GHZ) {
- data->nan.curr_dw_band = NL80211_BAND_2GHZ;
- }
- }
+ if ((tsf & DW0_TSF_MASK & ~DWST_TSF_MASK) == 0)
+ dwst_of_dw0 = true;
- until_dw = dw_int - do_div(tsf, dw_int);
- /* The timer might fire just before the actual DW, in which case
- * update the timeout to the actual next DW
- */
- if (until_dw < dw_int / 2)
- until_dw += dw_int;
+ switch (slot) {
+ case SLOT_24GHZ_DW:
+ wiphy_dbg(data->hw->wiphy, "Start of 2.4 GHz DW, is DW0=%d\n",
+ dwst_of_dw0);
+ data->nan.channel = ieee80211_get_channel(hw->wiphy, 2437);
+ break;
- /* The above do_div() call directly modifies the 'tsf' variable, thus,
- * use a copy so that the print below would show the original TSF.
- */
- wiphy_debug(hw->wiphy,
- "%s: tsf=%llx, curr_dw_band=%u, next_dw=%llu\n",
- __func__, orig_tsf, data->nan.curr_dw_band,
- until_dw);
+ case SLOT_24GHZ_DW + 1:
+ if (!(data->nan.bands & BIT(NL80211_BAND_5GHZ))) {
+ notify_dw_chan = ieee80211_get_channel(hw->wiphy, 2437);
+ dw_end = true;
+ } else {
+ notify_dw_chan = ieee80211_get_channel(hw->wiphy, 5745);
+ }
+ break;
- hrtimer_forward_now(&data->nan.timer,
- ns_to_ktime(until_dw * NSEC_PER_USEC));
+ case SLOT_5GHZ_DW:
+ if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) {
+ wiphy_dbg(data->hw->wiphy, "Start of 5 GHz DW\n");
+ data->nan.channel =
+ ieee80211_get_channel(hw->wiphy, 5745);
+ }
+ break;
+
+ case SLOT_5GHZ_DW + 1:
+ if (data->nan.bands & BIT(NL80211_BAND_5GHZ)) {
+ notify_dw_chan =
+ ieee80211_get_channel(hw->wiphy, 2437);
+ dw_end = true;
+ }
+ break;
+ }
+
+ if (dw_end)
+ mac80211_hwsim_nan_exec_state_transitions(data);
- if (data->nan.notify_dw) {
- struct ieee80211_channel *ch;
+ if (data->nan.notify_dw && notify_dw_chan) {
struct wireless_dev *wdev =
ieee80211_vif_to_wdev(data->nan.device_vif);
- if (data->nan.curr_dw_band == NL80211_BAND_5GHZ)
- ch = ieee80211_get_channel(hw->wiphy, 5745);
- else
- ch = ieee80211_get_channel(hw->wiphy, 2437);
-
- cfg80211_next_nan_dw_notif(wdev, ch, GFP_ATOMIC);
+ cfg80211_next_nan_dw_notif(wdev, notify_dw_chan, GFP_ATOMIC);
}
+ mac80211_hwsim_nan_schedule_slot(data, slot + 1);
+
return HRTIMER_RESTART;
}
struct cfg80211_nan_conf *conf)
{
struct mac80211_hwsim_data *data = hw->priv;
- u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
- u32 dw_int = 512 * 1000;
- u64 until_dw = dw_int - do_div(tsf, dw_int);
struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
if (vif->type != NL80211_IFTYPE_NAN)
/* set this before starting the timer, as preemption might occur */
data->nan.device_vif = vif;
data->nan.bands = conf->bands;
- data->nan.curr_dw_band = NL80211_BAND_2GHZ;
+ data->nan.channel = ieee80211_get_channel(hw->wiphy, 2437);
- wiphy_debug(hw->wiphy, "nan_started, next_dw=%llu\n",
- until_dw);
-
- hrtimer_start(&data->nan.timer,
- ns_to_ktime(until_dw * NSEC_PER_USEC),
+ /* Just run this "soon" and start in a random schedule position */
+ hrtimer_start(&data->nan.slot_timer,
+ ns_to_ktime(10 * NSEC_PER_USEC),
HRTIMER_MODE_REL_SOFT);
if (!is_zero_ether_addr(conf->cluster_id) &&
data->nan.device_vif != vif)
return -EINVAL;
- hrtimer_cancel(&data->nan.timer);
+ hrtimer_cancel(&data->nan.slot_timer);
data->nan.device_vif = NULL;
spin_lock_bh(&hwsim_radio_lock);
wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes);
/* Handle only the changes we care about for simulation purposes */
- if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) {
+ if (changes & CFG80211_NAN_CONF_CHANGED_BANDS)
data->nan.bands = conf->bands;
- data->nan.curr_dw_band = NL80211_BAND_2GHZ;
- }
if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG)
data->nan.notify_dw = conf->enable_dw_notification;