mac80211_hwsim: fix beacon timestamp and mactime
authorThomas Pedersen <thomas@cozybit.com>
Mon, 7 Jan 2013 22:48:07 +0000 (14:48 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 11 Jan 2013 19:49:58 +0000 (14:49 -0500)
Set the beacon timestamp once during "transmission" so the
monitor interface also gets a timestamped beacon.

Also use a common base between TX timestamp and RX
mactime. This eliminates "TX" path delay, which shows up
as a constant error in Toffset.

Get the global TSF once before iterating over all RX HWs,
so they all set a mactime with the same time base.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mac80211_hwsim.c

index b6e2caa..b73e497 100644 (file)
@@ -363,6 +363,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_ts;
 };
 
 
@@ -410,15 +412,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));
@@ -705,7 +711,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,11 +737,23 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        secpath_reset(skb);
        nf_reset(skb);
 
+       /*
+        * Get absolute mactime here so all HWs RX at the "same time", and
+        * absolute TX time for beacon mactime so the timestamp matches.
+        * Giving beacons a different mactime than non-beacons looks messy, but
+        * it helps the Toffset be exact and a ~10us mactime discrepancy
+        * probably doesn't really matter.
+        */
+       if (ieee80211_is_beacon(hdr->frame_control) ||
+           ieee80211_is_probe_resp(hdr->frame_control))
+               now = data->abs_bcn_ts;
+       else
+               now = mac80211_hwsim_get_tsf_raw();
+
        /* Copy skb to all enabled radios that are on the current frequency */
        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,
@@ -787,17 +805,7 @@ 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);
-
+               rx_status.mactime = now + data2->tsf_offset;
 #if 0
                /*
                 * Don't enable this code by default as the OUI 00:00:00
@@ -987,7 +995,11 @@ 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;
 
        hwsim_check_magic(vif);
@@ -1000,6 +1012,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 */
+       data->abs_bcn_ts = mac80211_hwsim_get_tsf_raw();
+       mgmt->u.beacon.timestamp = cpu_to_le64(data->abs_bcn_ts +
+                                              data->tsf_offset +
+                                              24 * 8 * 10 / txrate->bitrate);
 
        mac80211_hwsim_tx_frame(hw, skb,
                                rcu_dereference(vif->chanctx_conf)->def.chan);
@@ -1020,7 +1041,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) {