2013-01-02 22:55:51

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 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



2013-01-04 13:05:51

by Johannes Berg

[permalink] [raw]

2013-01-07 01:35:51

by Thomas Pedersen

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

Hi Johannes,

On Fri, Jan 4, 2013 at 5:05 AM, Johannes Berg <[email protected]> wrote:
> On Wed, 2013-01-02 at 14:55 -0800, Thomas Pedersen wrote:
>
>> @@ -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;
>
> This can't work if you have multiple interfaces, as far as I can tell.

In practice, I think it'll be fine. abs_bcn_tstamp is only relevant
from the beacon timestamp to the rx mactime code, of which you have a
single (non-preemptible) path per hwsim hw. Per-vif beaconing (was) is
already not supported.

>> + /*
>> + * 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;
>
> Uhh.
> now -= now - data->abs_bcn_tstamp;
> <=> now = now - now + data->abs_bcn_tstamp;
> <=> now = dat->abs_bcn_tstamp;

Oops. I guess that factors down to what I was really trying to do. No
wonder the test passed :P

> No? But it seems to me that you're trying to timestamp based on theT
> transmitter? This is weird anyway?

The global hwsim tsf is just ktime, so all interfaces have the same
reference. This might cause the beacon mactime to show as earlier than
just-received non-beacons, but it's only on the order of ~10 us, and
I'd rather have that uncertainty there than Toffset.

Will you take this patch after a little refactoring?

Thomas

2013-01-04 13:05:34

by Johannes Berg

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

On Wed, 2013-01-02 at 14:55 -0800, Thomas Pedersen wrote:

> @@ -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;

This can't work if you have multiple interfaces, as far as I can tell.

> + /*
> + * 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;

Uhh.
now -= now - data->abs_bcn_tstamp;
<=> now = now - now + data->abs_bcn_tstamp;
<=> now = dat->abs_bcn_tstamp;

No? But it seems to me that you're trying to timestamp based on the
transmitter? This is weird anyway?

johannes


2013-01-02 22:55:56

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 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 | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index bccd17c..7b2acdd 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,12 @@ mac80211_hwsim_beacon(struct hrtimer *timer)
hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_beacon_tx, hw);

+ /* 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));
tasklet_hrtimer_start(ttimer, next_bcn, HRTIMER_MODE_ABS);
@@ -1045,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);
}

@@ -1106,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


2013-01-02 22:55:58

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 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]>

---
v2:
respin cleanly (Johannes)

drivers/net/wireless/mac80211_hwsim.c | 52 +++++++++++++++++++++------------
1 file changed, 34 insertions(+), 18 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7b2acdd..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);
@@ -1003,7 +1019,7 @@ mac80211_hwsim_beacon(struct hrtimer *timer)

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

/* beacon at new TBTT + beacon interval */
if (data->bcn_delta) {
--
1.7.10.4


2013-01-04 12:59:10

by Johannes Berg

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

On Wed, 2013-01-02 at 14:55 -0800, Thomas Pedersen wrote:

> - 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);

I simplified this to just use "beacon_timer.timer" in the second
container_of()

johannes


2013-01-02 22:55:54

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 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 | 66 ++++++++++++++++++++++-----------
1 file changed, 45 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 59761fb..bccd17c 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,31 @@ 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);

- 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 +1043,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 +1098,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 +2394,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