From: Bruno Randolf <[EMAIL PROTECTED]>

atheros hardware seems to have a problem with the rx timestamp of IBSS beacons.
unfortunately this is the case where rx timestamps count most in order to
correctly merge IBSS. specifically it looks like the rx timestamp is wrong for
*some* IBSS beacons which have the same BSSID and which cause the HW to adapt
the TSF of the beacon. in that case ath5k_extend_tsf() will assume a rs_tstamp
overflow and give us a timestamp too far in the past which will cause mac80211
to merge IBSS (which is not necessary since the BSSID already matches). but in
this case we know that the HW must have synced to the beacons TSF and can
adjust mactime accordingly - it can't be earlier than the beacon's timestamp.

also rename the function to ath5k_check_ibss_tsf() since "hw merge" is an odd
term.
---

 drivers/net/wireless/ath5k/base.c |   48 ++++++++++++++++++++++++++++++-------
 1 files changed, 39 insertions(+), 9 deletions(-)


diff --git a/drivers/net/wireless/ath5k/base.c 
b/drivers/net/wireless/ath5k/base.c
index 1d4c612..bdb8e93 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1709,8 +1709,10 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct 
ath5k_desc *ds,
 
 
 static void
-ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
+ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
+                    struct ieee80211_rx_status *rxs)
 {
+       u64 tsf, bc_tstamp;
        u32 hw_tu;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 
@@ -1721,16 +1723,44 @@ ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, 
struct sk_buff *skb)
            mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
            memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
                /*
-                * Received an IBSS beacon with the same BSSID. Hardware might
-                * have updated the TSF, check if we need to update timers.
+                * Received an IBSS beacon with the same BSSID. Hardware will
+                * have updated the local TSF. We have to work around various
+                * hardware bugs, though...
                 */
-               hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
-               if (hw_tu >= sc->nexttbtt) {
-                       ath5k_beacon_update_timers(sc,
-                               mgmt->u.beacon.timestamp);
+               tsf = ath5k_hw_get_tsf64(sc->ah);
+               bc_tstamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+               hw_tu = TSF_TO_TU(tsf);
+
+               ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+                       "beacon %llx mactime %llx (diff %lld) tsf now %llx\n",
+                       bc_tstamp, rxs->mactime,
+                       (rxs->mactime - bc_tstamp), tsf);
+
+               /*
+                * Sometimes the HW will give us a wrong tstamp in the rx
+                * descriptor, causing the timestamp extension to go wrong.
+                * (This seems to happen especially with beacon frames bigger
+                * than 74 byte.)
+                * But we know that the receive timestamp must be later than the
+                * timestamp of the beacon since HW must have synced to that.
+                *
+                * NOTE: here we assume mactime to be after the frame was
+                * received, not like mac80211 which defines it at the start.
+                */
+               if (bc_tstamp > rxs->mactime) {
                        ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
-                               "detected HW merge from received beacon\n");
+                               "fixing mactime from %llx to %llx\n",
+                               rxs->mactime, tsf);
+                       rxs->mactime = tsf;
                }
+               
+               /*
+                * Local TSF might have moved higher than our beacon timers,
+                * in that case we update them. This also takes care of
+                * synchronizing beacon sending times with other stations.
+                */
+               if (hw_tu >= sc->nexttbtt)
+                       ath5k_beacon_update_timers(sc, bc_tstamp);
        }
 }
 
@@ -1882,7 +1912,7 @@ accept:
 
                /* check beacons in IBSS mode */
                if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
-                       ath5k_check_ibss_hw_merge(sc, skb);
+                       ath5k_check_ibss_tsf(sc, skb, &rxs);
 
                __ieee80211_rx(sc->hw, skb, &rxs);
                sc->led_rxrate = ds->ds_rxstat.rs_rate;

_______________________________________________
ath5k-devel mailing list
[email protected]
https://lists.ath5k.org/mailman/listinfo/ath5k-devel

Reply via email to