2012-12-27 21:44:29

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 1/4] mac80211_hwsim: fix tsf adjustment

Make hwsim TSF offset adjustments cumulative and relative
to the fake PHY TSF. Now adding 1000us, then adding -1000us
doesn't result in a tsf_offset of -1000. Also the beacon
timestamp can now correctly be expressed as (tsf +
data->tsf_offset), which will be done in a later patch.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ff90855..59761fb 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -357,7 +357,7 @@ struct mac80211_hwsim_data {
int power_level;

/* difference between this hw's clock and the real clock, in usecs */
- u64 tsf_offset;
+ s64 tsf_offset;
};


@@ -423,9 +423,10 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u64 tsf)
{
struct mac80211_hwsim_data *data = hw->priv;
- struct timeval tv = ktime_to_timeval(ktime_get_real());
- u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
- data->tsf_offset = tsf - now;
+ u64 now = mac80211_hwsim_get_tsf(hw, vif);
+ s64 delta = tsf - now;
+
+ data->tsf_offset += delta;
}

static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
--
1.7.10.4



2012-12-27 21:44:31

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 2/4] mac80211_hwsim: hrtimer beacon

For testing various timing-sensitive protocols (power
save, MBCA, etc.), a beacon accuracy of jiffies is not
sufficient. A tasklet_hrtimer is used for the beacon since
it runs the callback in soft-IRQ context with hrtimer
resolution.

Also handle BSS_CHANGED_BEACON_ENABLED for hwsim.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 69 ++++++++++++++++++++++-----------
1 file changed, 47 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 59761fb..f353d5e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -333,11 +333,11 @@ struct mac80211_hwsim_data {
int scan_chan_idx;

struct ieee80211_channel *channel;
- unsigned long beacon_int; /* in jiffies unit */
+ u64 beacon_int /* beacon interval in us */;
unsigned int rx_filter;
bool started, idle, scanning;
struct mutex mutex;
- struct timer_list beacon_timer;
+ struct tasklet_hrtimer beacon_timer;
enum ps_mode {
PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
} ps;
@@ -897,7 +897,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{
struct mac80211_hwsim_data *data = hw->priv;
data->started = false;
- del_timer(&data->beacon_timer);
+ tasklet_hrtimer_cancel(&data->beacon_timer);
wiphy_debug(hw->wiphy, "%s\n", __func__);
}

@@ -981,21 +981,32 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
rcu_dereference(vif->chanctx_conf)->def.chan);
}

-
-static void mac80211_hwsim_beacon(unsigned long arg)
+static enum hrtimer_restart
+mac80211_hwsim_beacon(struct hrtimer *timer)
{
- struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
- struct mac80211_hwsim_data *data = hw->priv;
+ struct tasklet_hrtimer *ttimer = container_of(timer,
+ struct tasklet_hrtimer,
+ timer);
+ struct mac80211_hwsim_data *data = container_of(ttimer,
+ struct mac80211_hwsim_data,
+ beacon_timer);
+ struct ieee80211_hw *hw = data->hw;
+ u64 bcn_int = data->beacon_int;
+ ktime_t next_bcn;

if (!data->started)
- return;
+ goto out;

ieee80211_iterate_active_interfaces_atomic(
hw, IEEE80211_IFACE_ITER_NORMAL,
- mac80211_hwsim_beacon_tx, hw);
+ mac80211_hwsim_beacon_tx, data);
+

- data->beacon_timer.expires = jiffies + data->beacon_int;
- add_timer(&data->beacon_timer);
+ next_bcn = ktime_add(hrtimer_get_expires(timer),
+ ns_to_ktime(bcn_int * 1000));
+ tasklet_hrtimer_start(ttimer, next_bcn, HRTIMER_MODE_ABS);
+out:
+ return HRTIMER_NORESTART;
}

static const char *hwsim_chantypes[] = {
@@ -1033,9 +1044,12 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)

data->power_level = conf->power_level;
if (!data->started || !data->beacon_int)
- del_timer(&data->beacon_timer);
- else
- mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
+ tasklet_hrtimer_cancel(&data->beacon_timer);
+ else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+ tasklet_hrtimer_start(&data->beacon_timer,
+ ns_to_ktime(data->beacon_int * 1000),
+ HRTIMER_MODE_REL);
+ }

return 0;
}
@@ -1085,12 +1099,22 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,

if (changed & BSS_CHANGED_BEACON_INT) {
wiphy_debug(hw->wiphy, " BCNINT: %d\n", info->beacon_int);
- data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000;
- if (WARN_ON(!data->beacon_int))
- data->beacon_int = 1;
- if (data->started)
- mod_timer(&data->beacon_timer,
- jiffies + data->beacon_int);
+ data->beacon_int = info->beacon_int * 1024;
+ }
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ wiphy_debug(hw->wiphy, " BCN EN: %d\n", info->enable_beacon);
+ if (data->started &&
+ !hrtimer_is_queued(&data->beacon_timer.timer) &&
+ info->enable_beacon) {
+ if (WARN_ON(!data->beacon_int))
+ data->beacon_int = 1000 * 1024;
+ tasklet_hrtimer_start(&data->beacon_timer,
+ ns_to_ktime(data->beacon_int *
+ 1000),
+ HRTIMER_MODE_REL);
+ } else if (!info->enable_beacon)
+ tasklet_hrtimer_cancel(&data->beacon_timer);
}

if (changed & BSS_CHANGED_ERP_CTS_PROT) {
@@ -2371,8 +2395,9 @@ static int __init init_mac80211_hwsim(void)
data->debugfs, data,
&hwsim_fops_group);

- setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
- (unsigned long) hw);
+ tasklet_hrtimer_init(&data->beacon_timer,
+ mac80211_hwsim_beacon,
+ CLOCK_REALTIME, HRTIMER_MODE_ABS);

list_add_tail(&data->list, &hwsim_radios);
}
--
1.7.10.4


2012-12-27 21:44:34

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 3/4] mac80211_hwsim: fix beacon timing

A beacon period starts at TSF time 0. Spoof this by
rounding the starting beacon time to a multiple of the
beacon interval, and keep TBTT aligned on TSF adjustment.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index f353d5e..d513c3e 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -358,6 +358,7 @@ struct mac80211_hwsim_data {

/* difference between this hw's clock and the real clock, in usecs */
s64 tsf_offset;
+ s64 bcn_delta;
};


@@ -424,9 +425,12 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
{
struct mac80211_hwsim_data *data = hw->priv;
u64 now = mac80211_hwsim_get_tsf(hw, vif);
+ u32 bcn_int = data->beacon_int;
s64 delta = tsf - now;

data->tsf_offset += delta;
+ /* adjust after beaconing with new timestamp at old TBTT */
+ data->bcn_delta = do_div(delta, bcn_int);
}

static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
@@ -1001,6 +1005,11 @@ mac80211_hwsim_beacon(struct hrtimer *timer)
hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_beacon_tx, data);

+ /* beacon at new TBTT + beacon interval */
+ if (data->bcn_delta) {
+ bcn_int -= data->bcn_delta;
+ data->bcn_delta = 0;
+ }

next_bcn = ktime_add(hrtimer_get_expires(timer),
ns_to_ktime(bcn_int * 1000));
@@ -1046,8 +1055,12 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
if (!data->started || !data->beacon_int)
tasklet_hrtimer_cancel(&data->beacon_timer);
else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
+ u64 tsf = mac80211_hwsim_get_tsf(hw, NULL);
+ u32 bcn_int = data->beacon_int;
+ u64 until_tbtt = bcn_int - do_div(tsf, bcn_int);
+
tasklet_hrtimer_start(&data->beacon_timer,
- ns_to_ktime(data->beacon_int * 1000),
+ ns_to_ktime(until_tbtt * 1000),
HRTIMER_MODE_REL);
}

@@ -1107,11 +1120,15 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
if (data->started &&
!hrtimer_is_queued(&data->beacon_timer.timer) &&
info->enable_beacon) {
+ u64 tsf, until_tbtt;
+ u32 bcn_int;
if (WARN_ON(!data->beacon_int))
data->beacon_int = 1000 * 1024;
+ tsf = mac80211_hwsim_get_tsf(hw, vif);
+ bcn_int = data->beacon_int;
+ until_tbtt = bcn_int - do_div(tsf, bcn_int);
tasklet_hrtimer_start(&data->beacon_timer,
- ns_to_ktime(data->beacon_int *
- 1000),
+ ns_to_ktime(until_tbtt * 1000),
HRTIMER_MODE_REL);
} else if (!info->enable_beacon)
tasklet_hrtimer_cancel(&data->beacon_timer);
--
1.7.10.4


2012-12-27 21:44:36

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 4/4] mac80211_hwsim: streamline beacon timestamp

Set the beacon timestamp once during "transmission" so the
monitor interface also gets a timestamped beacon.

Since the adjusted TSF is now used for the timestamp, we
must account for any delay in the global TSF time between
setting the timestamp and filling in RX mactime.

Signed-off-by: Thomas Pedersen <[email protected]>
---
drivers/net/wireless/mac80211_hwsim.c | 50 ++++++++++++++++++++++-----------
1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index d513c3e..2508249 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -359,6 +359,8 @@ struct mac80211_hwsim_data {
/* difference between this hw's clock and the real clock, in usecs */
s64 tsf_offset;
s64 bcn_delta;
+ /* absolute beacon transmission time. Used to cover up "tx" delay. */
+ u64 abs_bcn_tstamp;
};


@@ -406,15 +408,19 @@ static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}

+static inline u64 mac80211_hwsim_get_tsf_raw(void)
+{
+ return ktime_to_us(ktime_get_real());
+}
+
static __le64 __mac80211_hwsim_get_tsf(struct mac80211_hwsim_data *data)
{
- struct timeval tv = ktime_to_timeval(ktime_get_real());
- u64 now = tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+ u64 now = mac80211_hwsim_get_tsf_raw();
return cpu_to_le64(now + data->tsf_offset);
}

static u64 mac80211_hwsim_get_tsf(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = hw->priv;
return le64_to_cpu(__mac80211_hwsim_get_tsf(data));
@@ -701,7 +707,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rx_status rx_status;
- struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
+ u64 now;

memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_START;
@@ -731,7 +737,6 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
struct sk_buff *nskb;
- struct ieee80211_mgmt *mgmt;
struct tx_iter_data tx_iter_data = {
.receive = false,
.channel = chan,
@@ -767,17 +772,14 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
if (mac80211_hwsim_addr_match(data2, hdr->addr1))
ack = true;

- /* set bcn timestamp relative to receiver mactime */
- rx_status.mactime =
- le64_to_cpu(__mac80211_hwsim_get_tsf(data2));
- mgmt = (struct ieee80211_mgmt *) nskb->data;
- if (ieee80211_is_beacon(mgmt->frame_control) ||
- ieee80211_is_probe_resp(mgmt->frame_control))
- mgmt->u.beacon.timestamp = cpu_to_le64(
- rx_status.mactime +
- (data->tsf_offset - data2->tsf_offset) +
- 24 * 8 * 10 / txrate->bitrate);
-
+ /*
+ * Account for delay from filling in the timestamp to mactime.
+ */
+ now = mac80211_hwsim_get_tsf_raw();
+ if (ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control))
+ now -= now - data->abs_bcn_tstamp;
+ rx_status.mactime = now + data2->tsf_offset;
#if 0
/*
* Don't enable this code by default as the OUI 00:00:00
@@ -967,8 +969,13 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
struct ieee80211_vif *vif)
{
- struct ieee80211_hw *hw = arg;
+ struct mac80211_hwsim_data *data = arg;
+ struct ieee80211_hw *hw = data->hw;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_rate *txrate;
+ struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
+ u64 now;

hwsim_check_magic(vif);

@@ -980,6 +987,15 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
skb = ieee80211_beacon_get(hw, vif);
if (skb == NULL)
return;
+ info = IEEE80211_SKB_CB(skb);
+ txrate = ieee80211_get_tx_rate(hw, info);
+
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ /* fake header transmission time */
+ now = mac80211_hwsim_get_tsf_raw();
+ mgmt->u.beacon.timestamp = cpu_to_le64(now + data->tsf_offset +
+ 24 * 8 * 10 / txrate->bitrate);
+ data->abs_bcn_tstamp = now;

mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
--
1.7.10.4


2013-01-02 12:50:46

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/4] mac80211_hwsim: hrtimer beacon

On Thu, 2012-12-27 at 13:43 -0800, Thomas Pedersen wrote:

> ieee80211_iterate_active_interfaces_atomic(
> hw, IEEE80211_IFACE_ITER_NORMAL,
> - mac80211_hwsim_beacon_tx, hw);
> + mac80211_hwsim_beacon_tx, data);

This change belongs to another patch, please respin cleanly.

johannes


2013-01-02 22:45:07

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 2/4] mac80211_hwsim: hrtimer beacon

On Wed, Jan 2, 2013 at 4:51 AM, Johannes Berg <[email protected]> wrote:
> On Thu, 2012-12-27 at 13:43 -0800, Thomas Pedersen wrote:
>
>> ieee80211_iterate_active_interfaces_atomic(
>> hw, IEEE80211_IFACE_ITER_NORMAL,
>> - mac80211_hwsim_beacon_tx, hw);
>> + mac80211_hwsim_beacon_tx, data);
>
> This change belongs to another patch, please respin cleanly.

D'oh. Yes it does, will send a v2 shortly.

Thanks,

Thomas