|
@@ -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) {
|