Index: madwifi-ng-r2568-20070710/ath/if_ath.c
===================================================================
--- madwifi-ng-r2568-20070710.orig/ath/if_ath.c	2007-07-23 01:48:41.230329754 +0200
+++ madwifi-ng-r2568-20070710/ath/if_ath.c	2007-07-23 01:48:41.758359843 +0200
@@ -4426,16 +4426,31 @@
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ath_hal *ah = sc->sc_ah;
 	struct ieee80211_node *ni;
-	u_int32_t nexttbtt, intval;
+	u_int32_t nexttbtt = 0;
+	u_int32_t intval;
+	u_int64_t tsf, hw_tsf;
+	u_int32_t tsftu, hw_tsftu;
+	int should_reset_tsf = 0;
 
 	if (vap == NULL)
 		vap = TAILQ_FIRST(&ic->ic_vaps);   /* XXX */
 
 	ni = vap->iv_bss;
 
-	/* extract tstamp from last beacon and convert to TU */
-	nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
-			     LE_READ_4(ni->ni_tstamp.data));
+	hw_tsf = ath_hal_gettsf64(ah);
+	tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+	hw_tsftu = hw_tsf >> 10;
+	tsftu = tsf >> 10;
+
+	/* we should reset hw TSF only once, so we increment
+	   ni_tstamp.tsf to avoid resetting the hw TSF multiple
+	   times */
+
+	if (tsf == 0) {
+		should_reset_tsf = 1;
+		ni->ni_tstamp.tsf = cpu_to_le64(1);
+	}
+
 	/* XXX conditionalize multi-bss support? */
 	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
 		/*
@@ -4449,20 +4464,61 @@
 		if (sc->sc_stagbeacons)
 			intval /= ATH_BCBUF;	/* for staggered beacons */
 		if ((sc->sc_nostabeacons) &&
-		    (vap->iv_opmode == IEEE80211_M_HOSTAP))
-			nexttbtt = 0;
+			(vap->iv_opmode == IEEE80211_M_HOSTAP))
+			should_reset_tsf = 1;
 	} else
 		intval = ni->ni_intval & HAL_BEACON_PERIOD;
-	if (nexttbtt == 0)		/* e.g. for ap mode */
+
+#define	FUDGE	2
+	sc->sc_syncbeacon = 0;
+	if (should_reset_tsf) {
+
+		/* We just created the interface and TSF will be reset to
+		   zero, so next beacon will be sent at the next intval
+		   time */
+
 		nexttbtt = intval;
-	else if (intval)		/* NB: can be 0 for monitor mode */
-		nexttbtt = roundup(nexttbtt, intval);
-	DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
-		__func__, nexttbtt, intval, ni->ni_intval);
+	} else if (intval) {	/* NB: can be 0 for monitor mode */
+		if (tsf == 1) {
+ 	
+			/* We do not receive any beacons or probe response. Since
+			   a beacon should be sent every 'intval' ms, we compute
+			   the next beacon timestamp using the hardware TSF. We
+			   ensure that it is at least FUDGE ms ahead of the
+			   current TSF. Otherwise, we use the next beacon
+			   timestamp again */
+
+			nexttbtt = roundup(hw_tsftu +1, intval);
+			while (nexttbtt <= hw_tsftu + FUDGE) {
+				nexttbtt += intval;
+			}
+		} else {
+			if (tsf > hw_tsf) {
+
+			/* We do receive a beacon from someone else in the past,
+			   but the hw TSF has not been updated (otherwise we
+			   would have tsf >= hw_tsf). Since we cannot use the
+			   hardware TSF, we will do nothing and wait for the
+			   next beacon. In order to do so, we set sc->syncbeacon
+			   again */
+
+				sc->sc_syncbeacon = 1;
+				goto ath_beacon_config_debug;
+			} else {
+				/* We do receive a beacon in the past, normal case. We
+				   make sure that the timestamp is at least FUDGE ms
+				   ahead of the hardware TSF */
+
+				nexttbtt = tsftu + intval;
+				while (nexttbtt <= hw_tsftu + FUDGE) {
+					nexttbtt += intval;
+				}
+			}
+		}
+	}
+
 	if (ic->ic_opmode == IEEE80211_M_STA &&	!(sc->sc_nostabeacons)) {
 		HAL_BEACON_STATE bs;
-		u_int64_t tsf;
-		u_int32_t tsftu;
 		int dtimperiod, dtimcount;
 		int cfpperiod, cfpcount;
 
@@ -4478,13 +4534,13 @@
 			dtimcount = 0;		/* XXX? */
 		cfpperiod = 1;			/* NB: no PCF support yet */
 		cfpcount = 0;
-#define	FUDGE	2
 		/*
 		 * Pull nexttbtt forward to reflect the current
 		 * TSF and calculate dtim+cfp state for the result.
 		 */
-		tsf = ath_hal_gettsf64(ah);
-		tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+		nexttbtt = tsftu;
+		if (nexttbtt == 0)		/* e.g. for ap mode */
+			nexttbtt = intval;
 		do {
 			nexttbtt += intval;
 			if (--dtimcount < 0) {
@@ -4492,7 +4548,7 @@
 				if (--cfpcount < 0)
 					cfpcount = cfpperiod - 1;
 			}
-		} while (nexttbtt < tsftu);
+		} while (nexttbtt < hw_tsftu + FUDGE);
 #undef FUDGE
 		memset(&bs, 0, sizeof(bs));
 		bs.bs_intval = intval;
@@ -4544,7 +4600,7 @@
 		DPRINTF(sc, ATH_DEBUG_BEACON,
 			"%s: tsf %llu tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n",
 			__func__,
-			(unsigned long long) tsf, tsftu,
+			(unsigned long long) hw_tsf, hw_tsftu,
 			bs.bs_intval,
 			bs.bs_nexttbtt,
 			bs.bs_dtimperiod,
@@ -4566,7 +4622,7 @@
 		ath_hal_intrset(ah, sc->sc_imask);
 	} else {
 		ath_hal_intrset(ah, 0);
-		if (nexttbtt == intval)
+		if (should_reset_tsf)
 			intval |= HAL_BEACON_RESET_TSF;
 		if (ic->ic_opmode == IEEE80211_M_IBSS) {
 			/*
@@ -4603,8 +4659,40 @@
 		if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
 			ath_beacon_start_adhoc(sc, vap);
 	}
-	sc->sc_syncbeacon = 0;
 #undef TSF_TO_TU
+
+	ath_beacon_config_debug:
+
+	/* we print all debug messages here, in order to preserve the
+	   time critical aspect of this function */
+
+	DPRINTF(sc, ATH_DEBUG_BEACON,
+		"%s: ni=%p tsf=%llu hw_tsf=%llu tsftu=%u hw_tsftu=%u\n",
+		__func__, ni, tsf, hw_tsf, tsftu, hw_tsftu);
+
+	if (should_reset_tsf) {
+		/* we just created the interface */
+		DPRINTF(sc, ATH_DEBUG_BEACON, "%s: first beacon\n",__func__);
+	} else {
+		if (tsf == 1) {
+			/* we do not receive any beacons or probe response */
+			DPRINTF(sc, ATH_DEBUG_BEACON,
+				"%s: no beacon received...\n",__func__);
+		} else {
+			if (tsf > hw_tsf) {
+				/* we do receive a beacon and the hw TSF has not been updated */
+				DPRINTF(sc, ATH_DEBUG_BEACON,
+					"%s: beacon received, but TSF is incorrect\n",__func__);
+			} else {
+				/* we do receive a beacon in the past, normal case */
+				DPRINTF(sc, ATH_DEBUG_BEACON,
+					"%s: beacon received, TSF is correct\n",__func__);
+			}
+		}
+	}
+
+	DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt=%u intval=%u\n",
+		__func__,nexttbtt, intval & HAL_BEACON_PERIOD);
 }
 
 static int