Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Jan 2009 17:12:47 +0000 (UTC)
From:      Sam Leffler <sam@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r186904 - in head: sbin/ifconfig sys/conf sys/dev/ath sys/net80211 tools/tools/ath/athdebug tools/tools/ath/athstats usr.sbin/wlandebug
Message-ID:  <200901081712.n08HClhX028057@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sam
Date: Thu Jan  8 17:12:47 2009
New Revision: 186904
URL: http://svn.freebsd.org/changeset/base/186904

Log:
  TDMA support for long distance point-to-point links using ath devices:
  o add net80211 support for a tdma vap that is built on top of the
    existing adhoc-demo support
  o add tdma scheduling of frame transmission to the ath driver; it's
    conceivable other devices might be capable of this too in which case
    they can make use of the 802.11 protocol additions etc.
  o add minor bits to user tools that need to know: ifconfig to setup and
    configure, new statistics in athstats, and new debug mask bits
  
  While the architecture can support >2 slots in a TDMA BSS the current
  design is intended (and tested) for only 2 slots.
  
  Sponsored by:	Intel

Added:
  head/sys/net80211/ieee80211_tdma.c   (contents, props changed)
  head/sys/net80211/ieee80211_tdma.h   (contents, props changed)
Modified:
  head/sbin/ifconfig/ifconfig.8
  head/sbin/ifconfig/ifieee80211.c
  head/sys/conf/files
  head/sys/conf/options
  head/sys/dev/ath/if_ath.c
  head/sys/dev/ath/if_athioctl.h
  head/sys/dev/ath/if_athvar.h
  head/sys/net80211/ieee80211.c
  head/sys/net80211/ieee80211.h
  head/sys/net80211/ieee80211_adhoc.c
  head/sys/net80211/ieee80211_ddb.c
  head/sys/net80211/ieee80211_freebsd.c
  head/sys/net80211/ieee80211_input.c
  head/sys/net80211/ieee80211_input.h
  head/sys/net80211/ieee80211_ioctl.c
  head/sys/net80211/ieee80211_ioctl.h
  head/sys/net80211/ieee80211_node.c
  head/sys/net80211/ieee80211_node.h
  head/sys/net80211/ieee80211_output.c
  head/sys/net80211/ieee80211_proto.h
  head/sys/net80211/ieee80211_scan.h
  head/sys/net80211/ieee80211_scan_sta.c
  head/sys/net80211/ieee80211_var.h
  head/tools/tools/ath/athdebug/athdebug.c
  head/tools/tools/ath/athstats/Makefile
  head/tools/tools/ath/athstats/athstats.c
  head/tools/tools/ath/athstats/main.c
  head/usr.sbin/wlandebug/wlandebug.c

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8	Thu Jan  8 15:20:32 2009	(r186903)
+++ head/sbin/ifconfig/ifconfig.8	Thu Jan  8 17:12:47 2009	(r186904)
@@ -28,7 +28,7 @@
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
 .\" $FreeBSD$
 .\"
-.Dd October 19, 2008
+.Dd January 7, 2009
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -610,9 +610,15 @@ is one of
 (or
 .Cm hostap ),
 .Cm wds ,
+.Cm tdma ,
 and
 .Cm monitor .
 The operating mode of a cloned interface cannot be changed.
+The
+.Cm tdma
+mode is actually implemented as an
+.Cm adhoc-demo
+interface with special properties.
 .It Cm wlanbssid Ar bssid
 The 802.11 mac address to use for the bssid.
 This must be specified at create time for a legacy
@@ -1530,6 +1536,60 @@ hexadecimal when preceded by
 .Ql 0x .
 Additionally, the SSID may be cleared by setting it to
 .Ql - .
+.It Cm tdmaslot Ar slot
+When operating with TDMA, use the specified
+.Ar slot
+configuration.
+The
+.Ar slot
+is a number between 0 and the maximum number of slots in the BSS.
+Note that a station configured as slot 0 is a master and
+will broadcast beacon frames advertising the BSS;
+stations configured to use other slots will always
+scan to locate a master before they ever transmit.
+By default
+.Cm tdmaslot
+is set to 1.
+.It Cm tdmaslotcnt Ar cnt
+When operating with TDMA, setup a BSS with
+.Ar cnt
+slots.
+The slot count may be at most 8.
+The current implementation is only tested with two stations
+(i.e. point to point applications).
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotcnt
+is set to 2.
+.It Cm tdmaslotlen Ar len
+When operating with TDMA, setup a BSS such that each station has a slot
+.Ar len
+microseconds long.
+The slot length must be at least 150 microseconds (1/8 TU)
+and no more than 65 milliseconds.
+Note that setting too small a slot length may result in poor channel
+bandwidth utilization due to factors such as timer granularity and
+guard time.
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotlen
+is set to 10 milliseconds.
+.It Cm tdmabintval Ar intval
+When operating with TDMA, setup a BSS such that beacons are transmitted every
+.Ar intval
+superframes to synchronize the TDMA slot timing.
+A superframe is defined as the number of slots times the slot length; e.g.
+a BSS with two slots of 10 milliseconds has a 20 millisecond superframe.
+The beacon interval may not be zero.
+A lower setting of
+.Cm tdmabintval
+causes the timers to be resynchronized more often; this can be help if
+significant timer drift is observed.
+By default
+.Cm tdmabintval
+is set to 5.
 .It Cm tsn
 When operating as an access point with WPA/802.11i allow legacy
 stations to associate using static key WEP and open authentication.

Modified: head/sbin/ifconfig/ifieee80211.c
==============================================================================
--- head/sbin/ifconfig/ifieee80211.c	Thu Jan  8 15:20:32 2009	(r186903)
+++ head/sbin/ifconfig/ifieee80211.c	Thu Jan  8 17:12:47 2009	(r186904)
@@ -1711,6 +1711,30 @@ set80211rifs(const char *val, int d, int
 	set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
 }
 
+static
+DECL_CMD_FUNC(set80211tdmaslot, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotcnt, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotlen, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmabintval, val, d)
+{
+	set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
+}
+
 static int
 regdomain_sort(const void *a, const void *b)
 {
@@ -2558,6 +2582,22 @@ printwpsie(const char *tag, const u_int8
 #undef N
 }
 
+static void
+printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
+		const struct ieee80211_tdma_param *tdma =
+		   (const struct ieee80211_tdma_param *) ie;
+
+		/* XXX tstamp */
+		printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
+		    tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
+		    LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
+		    tdma->tdma_inuse[0]);
+	}
+}
+
 /*
  * Copy the ssid string contents into buf, truncating to fit.  If the
  * ssid is entirely printable then just copy intact.  Otherwise convert
@@ -2681,6 +2721,12 @@ isatherosoui(const u_int8_t *frm)
 }
 
 static __inline int
+istdmaoui(const uint8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
+}
+
+static __inline int
 iswpsoui(const uint8_t *frm)
 {
 	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
@@ -2749,6 +2795,8 @@ printies(const u_int8_t *vp, int ielen, 
 				printathie(" ATH", vp, 2+vp[1], maxcols);
 			else if (iswpsoui(vp))
 				printwpsie(" WPS", vp, 2+vp[1], maxcols);
+			else if (istdmaoui(vp))
+				printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
 			else if (verbose)
 				printie(" VEN", vp, 2+vp[1], maxcols);
 			break;
@@ -3192,7 +3240,7 @@ list_keys(int s)
 	"\20\1STA\7FF\10TURBOP\11IBSS\12PMGT" \
 	"\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
 	"\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
-	"\37TXFRAG"
+	"\37TXFRAG\40TDMA"
 
 #define	IEEE80211_CRYPTO_BITS \
 	"\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT"
@@ -4263,7 +4311,16 @@ end:
 		}
 	}
 
-	if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
+	if (opmode == IEEE80211_M_AHDEMO) {
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOT, &val) != -1)
+			LINE_CHECK("tdmaslot %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1)
+			LINE_CHECK("tdmaslotcnt %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1)
+			LINE_CHECK("tdmaslotlen %u", val);
+		if (get80211val(s, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1)
+			LINE_CHECK("tdmabintval %u", val);
+	} else if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
 		/* XXX default define not visible */
 		if (val != 100 || verbose)
 			LINE_CHECK("bintval %u", val);
@@ -4486,7 +4543,10 @@ DECL_CMD_FUNC(set80211clone_wlanmode, ar
 		params.icp_opmode = IEEE80211_M_WDS;
 	else if (iseq(arg, "monitor"))
 		params.icp_opmode = IEEE80211_M_MONITOR;
-	else
+	else if (iseq(arg, "tdma")) {
+		params.icp_opmode = IEEE80211_M_AHDEMO;
+		params.icp_flags |= IEEE80211_CLONE_TDMA;
+	} else
 		errx(1, "Don't know to create %s for %s", arg, name);
 	clone_setcallback(wlan_create);
 #undef iseq
@@ -4662,6 +4722,11 @@ static struct cmd ieee80211_cmds[] = {
 	/* XXX for testing */
 	DEF_CMD_ARG("chanswitch",	set80211chanswitch),
 
+	DEF_CMD_ARG("tdmaslot",		set80211tdmaslot),
+	DEF_CMD_ARG("tdmaslotcnt",	set80211tdmaslotcnt),
+	DEF_CMD_ARG("tdmaslotlen",	set80211tdmaslotlen),
+	DEF_CMD_ARG("tdmabintval",	set80211tdmabintval),
+
 	/* vap cloning support */
 	DEF_CLONE_CMD_ARG("wlanaddr",	set80211clone_wlanaddr),
 	DEF_CLONE_CMD_ARG("wlanbssid",	set80211clone_wlanbssid),

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Thu Jan  8 15:20:32 2009	(r186903)
+++ head/sys/conf/files	Thu Jan  8 17:12:47 2009	(r186904)
@@ -2232,6 +2232,7 @@ net80211/ieee80211_rssadapt.c	optional w
 net80211/ieee80211_scan.c	optional wlan
 net80211/ieee80211_scan_sta.c	optional wlan
 net80211/ieee80211_sta.c	optional wlan
+net80211/ieee80211_tdma.c	optional wlan
 net80211/ieee80211_wds.c	optional wlan
 net80211/ieee80211_xauth.c	optional wlan_xauth
 netatalk/aarp.c			optional netatalk

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options	Thu Jan  8 15:20:32 2009	(r186903)
+++ head/sys/conf/options	Thu Jan  8 17:12:47 2009	(r186904)
@@ -741,6 +741,7 @@ ATH_TXBUF		opt_ath.h
 ATH_RXBUF		opt_ath.h
 ATH_DIAGAPI		opt_ath.h
 ATH_TX99_DIAG		opt_ath.h
+ATH_SUPPORT_TDMA	opt_ath.h
 
 # options for the Atheros hal
 AH_SUPPORT_AR5416	opt_ah.h
@@ -784,6 +785,15 @@ INTR_FILTER
 IEEE80211_DEBUG		opt_wlan.h
 IEEE80211_DEBUG_REFCNT	opt_wlan.h
 IEEE80211_AMPDU_AGE	opt_wlan.h
+IEEE80211_SUPPORT_TDMA	opt_wlan.h
+
+# 802.11 TDMA support
+TDMA_SLOTLEN_DEFAULT	opt_tdma.h
+TDMA_SLOTCNT_DEFAULT	opt_tdma.h
+TDMA_BINTVAL_DEFAULT	opt_tdma.h
+TDMA_TXRATE_11B_DEFAULT	opt_tdma.h
+TDMA_TXRATE_11G_DEFAULT	opt_tdma.h
+TDMA_TXRATE_11A_DEFAULT	opt_tdma.h
 
 # Virtualize the network stack
 VIMAGE			opt_global.h

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Thu Jan  8 15:20:32 2009	(r186903)
+++ head/sys/dev/ath/if_ath.c	Thu Jan  8 17:12:47 2009	(r186904)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -68,6 +68,9 @@ __FBSDID("$FreeBSD$");
 #include <net/if_llc.h>
 
 #include <net80211/ieee80211_var.h>
+#ifdef ATH_SUPPORT_TDMA
+#include <net80211/ieee80211_tdma.h>
+#endif
 
 #include <net/bpf.h>
 
@@ -216,6 +219,50 @@ static int	ath_raw_xmit(struct ieee80211
 static void	ath_bpfattach(struct ath_softc *);
 static void	ath_announce(struct ath_softc *);
 
+#ifdef ATH_SUPPORT_TDMA
+static void	ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt,
+		    u_int32_t bintval);
+static void	ath_tdma_bintvalsetup(struct ath_softc *sc,
+		    const struct ieee80211_tdma_state *tdma);
+static void	ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap);
+static void	ath_tdma_update(struct ieee80211_node *ni,
+		    const struct ieee80211_tdma_param *tdma);
+static void	ath_tdma_beacon_send(struct ath_softc *sc,
+		    struct ieee80211vap *vap);
+
+static __inline void
+ath_hal_setcca(struct ath_hal *ah, int ena)
+{
+	/*
+	 * NB: fill me in; this is not provided by default because disabling
+	 *     CCA in most locales violates regulatory.
+	 */
+}
+
+static __inline int
+ath_hal_getcca(struct ath_hal *ah)
+{
+	u_int32_t diag;
+	if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK)
+		return 1;
+	return ((diag & 0x500000) == 0);
+}
+
+#define	TDMA_EP_MULTIPLIER	(1<<10) /* pow2 to optimize out * and / */
+#define	TDMA_LPF_LEN		6
+#define	TDMA_DUMMY_MARKER	0x127
+#define	TDMA_EP_MUL(x, mul)	((x) * (mul))
+#define	TDMA_IN(x)		(TDMA_EP_MUL((x), TDMA_EP_MULTIPLIER))
+#define	TDMA_LPF(x, y, len) \
+    ((x != TDMA_DUMMY_MARKER) ? (((x) * ((len)-1) + (y)) / (len)) : (y))
+#define	TDMA_SAMPLE(x, y) do {					\
+	x = TDMA_LPF((x), TDMA_IN(y), TDMA_LPF_LEN);		\
+} while (0)
+#define	TDMA_EP_RND(x,mul) \
+	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+#define	TDMA_AVG(x)		TDMA_EP_RND(x, TDMA_EP_MULTIPLIER)
+#endif /* ATH_SUPPORT_TDMA */
+
 SYSCTL_DECL(_hw_ath);
 
 /* XXX validate sysctl values */
@@ -260,6 +307,8 @@ enum {
 	ATH_DEBUG_LED		= 0x00100000,	/* led management */
 	ATH_DEBUG_FF		= 0x00200000,	/* fast frames */
 	ATH_DEBUG_DFS		= 0x00400000,	/* DFS processing */
+	ATH_DEBUG_TDMA		= 0x00800000,	/* TDMA processing */
+	ATH_DEBUG_TDMA_TIMER	= 0x01000000,	/* TDMA timer processing */
 	ATH_DEBUG_REGDOMAIN	= 0x02000000,	/* regulatory processing */
 	ATH_DEBUG_FATAL		= 0x80000000,	/* fatal errors */
 	ATH_DEBUG_ANY		= 0xffffffff
@@ -615,7 +664,12 @@ ath_attach(u_int16_t devid, struct ath_s
 	wmodes = ath_hal_getwirelessmodes(ah, ic->ic_regdomain.country);
 	if (wmodes & (HAL_MODE_108G|HAL_MODE_TURBO))
 		ic->ic_caps |= IEEE80211_C_TURBOP;
-
+#ifdef ATH_SUPPORT_TDMA
+	if (ath_hal_macversion(ah) > 0x78) {
+		ic->ic_caps |= IEEE80211_C_TDMA; /* capable of TDMA */
+		ic->ic_tdma_update = ath_tdma_update;
+	}
+#endif
 	/*
 	 * Indicate we need the 802.11 header padded to a
 	 * 32-bit boundary for 4-address and QoS frames.
@@ -824,10 +878,9 @@ ath_vap_create(struct ieee80211com *ic,
 			 */
 			flags |= IEEE80211_CLONE_NOBEACONS;
 		}
-		if (flags & IEEE80211_CLONE_NOBEACONS) {
-			sc->sc_swbmiss = 1;
+		if (flags & IEEE80211_CLONE_NOBEACONS)
 			ic_opmode = IEEE80211_M_HOSTAP;
-		} else
+		else
 			ic_opmode = opmode;
 		break;
 	case IEEE80211_M_IBSS:
@@ -840,7 +893,13 @@ ath_vap_create(struct ieee80211com *ic,
 		needbeacon = 1;
 		break;
 	case IEEE80211_M_AHDEMO:
+#ifdef ATH_SUPPORT_TDMA
+		if (flags & IEEE80211_CLONE_TDMA) {
+			needbeacon = 1;
+			flags |= IEEE80211_CLONE_NOBEACONS;
+		}
 		/* fall thru... */
+#endif
 	case IEEE80211_M_MONITOR:
 		if (sc->sc_nvaps != 0 && ic->ic_opmode != opmode) {
 			/* XXX not right for monitor mode */
@@ -959,6 +1018,18 @@ ath_vap_create(struct ieee80211com *ic,
 		sc->sc_opmode = HAL_M_STA;
 		break;
 	case IEEE80211_M_AHDEMO:
+#ifdef ATH_SUPPORT_TDMA
+		if (vap->iv_caps & IEEE80211_C_TDMA) {
+			sc->sc_tdma = 1;
+			/* NB: disable tsf adjust */
+			sc->sc_stagbeacons = 0;
+		}
+		/*
+		 * NB: adhoc demo mode is a pseudo mode; to the hal it's
+		 * just ap mode.
+		 */
+		/* fall thru... */
+#endif
 	case IEEE80211_M_HOSTAP:
 		sc->sc_opmode = HAL_M_HOSTAP;
 		break;
@@ -975,6 +1046,12 @@ ath_vap_create(struct ieee80211com *ic,
 		 */
 		ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons);
 	}
+	if (flags & IEEE80211_CLONE_NOBEACONS) {
+		/*
+		 * Enable s/w beacon miss handling.
+		 */
+		sc->sc_swbmiss = 1;
+	}
 	ATH_UNLOCK(sc);
 
 	/* complete setup */
@@ -1047,6 +1124,13 @@ ath_vap_delete(struct ieee80211vap *vap)
 	}
 	if (vap->iv_opmode != IEEE80211_M_WDS)
 		sc->sc_nvaps--;
+#ifdef ATH_SUPPORT_TDMA
+	/* TDMA operation ceases when the last vap is destroyed */
+	if (sc->sc_tdma && sc->sc_nvaps == 0) {
+		sc->sc_tdma = 0;
+		sc->sc_swbmiss = 0;
+	}
+#endif
 	ATH_UNLOCK(sc);
 	free(avp, M_80211_VAP);
 
@@ -1198,7 +1282,20 @@ ath_intr(void *arg)
 			 * this is too slow to meet timing constraints
 			 * under load.
 			 */
-			ath_beacon_proc(sc, 0);
+#ifdef ATH_SUPPORT_TDMA
+			if (sc->sc_tdma) {
+				if (sc->sc_tdmaswba == 0) {
+					struct ieee80211com *ic = ifp->if_l2com;
+					struct ieee80211vap *vap =
+					    TAILQ_FIRST(&ic->ic_vaps);
+					ath_tdma_beacon_send(sc, vap);
+					sc->sc_tdmaswba =
+					    vap->iv_tdma->tdma_bintval;
+				} else
+					sc->sc_tdmaswba--;
+			} else
+#endif
+				ath_beacon_proc(sc, 0);
 		}
 		if (status & HAL_INT_RXEOL) {
 			/*
@@ -1581,8 +1678,14 @@ ath_reset(struct ifnet *ifp)
 	 * might change as a result.
 	 */
 	ath_chan_change(sc, ic->ic_curchan);
-	if (sc->sc_beacons)
-		ath_beacon_config(sc, NULL);	/* restart beacons */
+	if (sc->sc_beacons) {
+#ifdef ATH_SUPPORT_TDMA
+		if (sc->sc_tdma)
+			ath_tdma_config(sc, NULL);
+		else
+#endif
+			ath_beacon_config(sc, NULL);	/* restart beacons */
+	}
 	ath_hal_intrset(ah, sc->sc_imask);
 
 	ath_start(ifp);			/* restart xmit */
@@ -1688,7 +1791,7 @@ ath_ff_stageq_flush(struct ath_softc *sc
 		}
 
 		ATH_TXBUF_LOCK(sc);
-		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+		STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
 		ATH_TXBUF_UNLOCK(sc);
 	}
 }
@@ -1829,7 +1932,7 @@ ath_ff_check(struct ath_softc *sc, struc
 			 * Return bfstaged to the free list.
 			 */
 			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bfstaged, bf_list);
+			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bfstaged, bf_list);
 			ATH_TXBUF_UNLOCK(sc);
 
 			return m;		/* ready to go */
@@ -1902,7 +2005,7 @@ ath_ff_check(struct ath_softc *sc, struc
 			}
 
 			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bfstaged, bf_list);
+			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bfstaged, bf_list);
 			ATH_TXBUF_UNLOCK(sc);
 		} else {
 #if 0
@@ -1925,6 +2028,45 @@ ath_ff_check(struct ath_softc *sc, struc
 	return m;
 }
 
+static struct ath_buf *
+_ath_getbuf_locked(struct ath_softc *sc)
+{
+	struct ath_buf *bf;
+
+	ATH_TXBUF_LOCK_ASSERT(sc);
+
+	bf = STAILQ_FIRST(&sc->sc_txbuf);
+	if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0)
+		STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+	else
+		bf = NULL;
+	if (bf == NULL) {
+		DPRINTF(sc, ATH_DEBUG_XMIT, "%s: %s\n", __func__,
+		    STAILQ_FIRST(&sc->sc_txbuf) == NULL ?
+			"out of xmit buffers" : "xmit buffer busy");
+		sc->sc_stats.ast_tx_nobuf++;
+	}
+	return bf;
+}
+
+static struct ath_buf *
+ath_getbuf(struct ath_softc *sc)
+{
+	struct ath_buf *bf;
+
+	ATH_TXBUF_LOCK(sc);
+	bf = _ath_getbuf_locked(sc);
+	if (bf == NULL) {
+		struct ifnet *ifp = sc->sc_ifp;
+
+		DPRINTF(sc, ATH_DEBUG_XMIT, "%s: stop queue\n", __func__);
+		sc->sc_stats.ast_tx_qstop++;
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+	}
+	ATH_TXBUF_UNLOCK(sc);
+	return bf;
+}
+
 /*
  * Cleanup driver resources when we run out of buffers
  * while processing fragments; return the tx buffers
@@ -1941,7 +2083,7 @@ ath_txfrag_cleanup(struct ath_softc *sc,
 	STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
 		/* NB: bf assumed clean */
 		STAILQ_REMOVE_HEAD(frags, bf_list);
-		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+		STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
 		ieee80211_node_decref(ni);
 	}
 }
@@ -1960,12 +2102,11 @@ ath_txfrag_setup(struct ath_softc *sc, a
 
 	ATH_TXBUF_LOCK(sc);
 	for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
-		bf = STAILQ_FIRST(&sc->sc_txbuf);
+		bf = _ath_getbuf_locked(sc);
 		if (bf == NULL) {	/* out of buffers, cleanup */
 			ath_txfrag_cleanup(sc, frags, ni);
 			break;
 		}
-		STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
 		ieee80211_node_incref(ni);
 		STAILQ_INSERT_TAIL(frags, bf, bf_list);
 	}
@@ -1992,23 +2133,14 @@ ath_start(struct ifnet *ifp)
 		/*
 		 * Grab a TX buffer and associated resources.
 		 */
-		ATH_TXBUF_LOCK(sc);
-		bf = STAILQ_FIRST(&sc->sc_txbuf);
-		if (bf != NULL)
-			STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
-		ATH_TXBUF_UNLOCK(sc);
-		if (bf == NULL) {
-			DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n",
-				__func__);
-			sc->sc_stats.ast_tx_qstop++;
-			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+		bf = ath_getbuf(sc);
+		if (bf == NULL)
 			break;
-		}
 
 		IFQ_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL) {
 			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
 			ATH_TXBUF_UNLOCK(sc);
 			break;
 		}
@@ -2082,7 +2214,7 @@ ath_start(struct ifnet *ifp)
 			bf->bf_m = NULL;
 			bf->bf_node = NULL;
 			ATH_TXBUF_LOCK(sc);
-			STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+			STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
 			ath_txfrag_cleanup(sc, &frags, ni);
 			ATH_TXBUF_UNLOCK(sc);
 			if (ni != NULL)
@@ -4215,6 +4347,9 @@ rx_accept:
 			/*
 			 * Sending station is known, dispatch directly.
 			 */
+#ifdef ATH_SUPPORT_TDMA
+			sc->sc_tdmars = rs;
+#endif
 			type = ieee80211_input(ni, m,
 			    rs->rs_rssi, nf, rs->rs_tstamp);
 			ieee80211_free_node(ni);
@@ -4387,10 +4522,48 @@ ath_txq_update(struct ath_softc *sc, int
 	HAL_TXQ_INFO qi;
 
 	ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi);
-	qi.tqi_aifs = wmep->wmep_aifsn;
-	qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
-	qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
-	qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit);
+#ifdef ATH_SUPPORT_TDMA
+	if (sc->sc_tdma) {
+		/*
+		 * AIFS is zero so there's no pre-transmit wait.  The
+		 * burst time defines the slot duration and is configured
+		 * via sysctl.  The QCU is setup to not do post-xmit
+		 * back off, lockout all lower-priority QCU's, and fire
+		 * off the DMA beacon alert timer which is setup based
+		 * on the slot configuration.
+		 */
+		qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE
+			      | HAL_TXQ_TXERRINT_ENABLE
+			      | HAL_TXQ_TXURNINT_ENABLE
+			      | HAL_TXQ_TXEOLINT_ENABLE
+			      | HAL_TXQ_DBA_GATED
+			      | HAL_TXQ_BACKOFF_DISABLE
+			      | HAL_TXQ_ARB_LOCKOUT_GLOBAL
+			      ;
+		qi.tqi_aifs = 0;
+		/* XXX +dbaprep? */
+		qi.tqi_readyTime = sc->sc_tdmaslotlen;
+		qi.tqi_burstTime = qi.tqi_readyTime;
+	} else {
+#endif
+		qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE
+			      | HAL_TXQ_TXERRINT_ENABLE
+			      | HAL_TXQ_TXDESCINT_ENABLE
+			      | HAL_TXQ_TXURNINT_ENABLE
+			      ;
+		qi.tqi_aifs = wmep->wmep_aifsn;
+		qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
+		qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
+		qi.tqi_readyTime = 0;
+		qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit);
+#ifdef ATH_SUPPORT_TDMA
+	}
+#endif
+
+	DPRINTF(sc, ATH_DEBUG_RESET,
+	    "%s: Q%u qflags 0x%x aifs %u cwmin %u cwmax %u burstTime %u\n",
+	    __func__, txq->axq_qnum, qi.tqi_qflags,
+	    qi.tqi_aifs, qi.tqi_cwmin, qi.tqi_cwmax, qi.tqi_burstTime);
 
 	if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) {
 		if_printf(ifp, "unable to update hardware queue "
@@ -4570,13 +4743,71 @@ ath_tx_handoff(struct ath_softc *sc, str
 	 * to avoid possible races.
 	 */
 	ATH_TXQ_LOCK(txq);
+	KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+	     ("busy status 0x%x", bf->bf_flags));
 	if (txq->axq_qnum != ATH_TXQ_SWQ) {
+#ifdef ATH_SUPPORT_TDMA
+		int qbusy;
+
+		ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+		qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
+		if (txq->axq_link == NULL) {
+			/*
+			 * Be careful writing the address to TXDP.  If
+			 * the tx q is enabled then this write will be
+			 * ignored.  Normally this is not an issue but
+			 * when tdma is in use and the q is beacon gated
+			 * this race can occur.  If the q is busy then
+			 * defer the work to later--either when another
+			 * packet comes along or when we prepare a beacon
+			 * frame at SWBA.
+			 */
+			if (!qbusy) {
+				ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+				txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
+				DPRINTF(sc, ATH_DEBUG_XMIT,
+				    "%s: TXDP[%u] = %p (%p) depth %d\n",
+				    __func__, txq->axq_qnum,
+				    (caddr_t)bf->bf_daddr, bf->bf_desc,
+				    txq->axq_depth);
+			} else {
+				txq->axq_flags |= ATH_TXQ_PUTPENDING;
+				DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
+				    "%s: Q%u busy, defer enable\n", __func__,
+				    txq->axq_qnum);
+			}
+		} else {
+			*txq->axq_link = bf->bf_daddr;
+			DPRINTF(sc, ATH_DEBUG_XMIT,
+			    "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
+			    txq->axq_qnum, txq->axq_link,
+			    (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
+			if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) {
+				/*
+				 * The q was busy when we previously tried
+				 * to write the address of the first buffer
+				 * in the chain.  Since it's not busy now
+				 * handle this chore.  We are certain the
+				 * buffer at the front is the right one since
+				 * axq_link is NULL only when the buffer list
+				 * is/was empty.
+				 */
+				ath_hal_puttxbuf(ah, txq->axq_qnum,
+					STAILQ_FIRST(&txq->axq_q)->bf_daddr);
+				txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
+				DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
+				    "%s: Q%u restarted\n", __func__,
+				    txq->axq_qnum);
+			}
+		}
+#else
 		ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
 		if (txq->axq_link == NULL) {
 			ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
 			DPRINTF(sc, ATH_DEBUG_XMIT,
-			    "%s: TXDP[%u] = %p (%p) depth %d\n", __func__,
-			    txq->axq_qnum, (caddr_t)bf->bf_daddr, bf->bf_desc,
+			    "%s: TXDP[%u] = %p (%p) depth %d\n",
+			    __func__, txq->axq_qnum,
+			    (caddr_t)bf->bf_daddr, bf->bf_desc,
 			    txq->axq_depth);
 		} else {
 			*txq->axq_link = bf->bf_daddr;
@@ -4585,6 +4816,7 @@ ath_tx_handoff(struct ath_softc *sc, str
 			    txq->axq_qnum, txq->axq_link,
 			    (caddr_t)bf->bf_daddr, bf->bf_desc, txq->axq_depth);
 		}
+#endif /* ATH_SUPPORT_TDMA */
 		txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
 		ath_hal_txstart(ah, txq->axq_qnum);
 	} else {
@@ -4819,6 +5051,15 @@ ath_tx_start(struct ath_softc *sc, struc
 	}
 	if (flags & HAL_TXDESC_NOACK)		/* NB: avoid double counting */
 		sc->sc_stats.ast_tx_noack++;
+#ifdef ATH_SUPPORT_TDMA
+	if (sc->sc_tdma && (flags & HAL_TXDESC_NOACK) == 0) {
+		DPRINTF(sc, ATH_DEBUG_XMIT, "%s: ACK required w/ TDMA\n",
+		    __func__);
+		/* XXX statistic */
+		ath_freetx(m0);
+		return EIO;
+	}
+#endif
 
 	/*
 	 * If 802.11g protection is enabled, determine whether
@@ -5017,7 +5258,7 @@ ath_tx_processq(struct ath_softc *sc, st
 	struct ath_hal *ah = sc->sc_ah;
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
-	struct ath_buf *bf;
+	struct ath_buf *bf, *last;
 	struct ath_desc *ds, *ds0;
 	struct ath_tx_status *ts;
 	struct ieee80211_node *ni;
@@ -5052,7 +5293,18 @@ ath_tx_processq(struct ath_softc *sc, st
 			break;
 		}
 		ATH_TXQ_REMOVE_HEAD(txq, bf_list);
+#ifdef ATH_SUPPORT_TDMA
+		if (txq->axq_depth > 0) {
+			/*
+			 * More frames follow.  Mark the buffer busy
+			 * so it's not re-used while the hardware may
+			 * still re-read the link field in the descriptor.
+			 */
+			bf->bf_flags |= ATH_BUF_BUSY;
+		} else
+#else
 		if (txq->axq_depth == 0)
+#endif
 			txq->axq_link = NULL;
 		ATH_TXQ_UNLOCK(txq);
 
@@ -5128,6 +5380,9 @@ ath_tx_processq(struct ath_softc *sc, st
 		bf->bf_node = NULL;
 
 		ATH_TXBUF_LOCK(sc);
+		last = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list);
+		if (last != NULL)
+			last->bf_flags &= ~ATH_BUF_BUSY;
 		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
 		ATH_TXBUF_UNLOCK(sc);
 	}
@@ -5250,6 +5505,11 @@ ath_tx_draintxq(struct ath_softc *sc, st
 	 * NB: this assumes output has been stopped and
 	 *     we do not need to block ath_tx_proc
 	 */
+	ATH_TXBUF_LOCK(sc);
+	bf = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list);
+	if (bf != NULL)
+		bf->bf_flags &= ~ATH_BUF_BUSY;
+	ATH_TXBUF_UNLOCK(sc);
 	for (ix = 0;; ix++) {
 		ATH_TXQ_LOCK(txq);
 		bf = STAILQ_FIRST(&txq->axq_q);
@@ -5284,6 +5544,7 @@ ath_tx_draintxq(struct ath_softc *sc, st
 		}
 		m_freem(bf->bf_m);
 		bf->bf_m = NULL;
+		bf->bf_flags &= ~ATH_BUF_BUSY;
 
 		ATH_TXBUF_LOCK(sc);
 		STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
@@ -5760,6 +6021,12 @@ ath_newstate(struct ieee80211vap *vap, e
 		    ni->ni_capinfo, ieee80211_chan2ieee(ic, ic->ic_curchan));
 
 		switch (vap->iv_opmode) {
+#ifdef ATH_SUPPORT_TDMA
+		case IEEE80211_M_AHDEMO:
+			if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
+				break;
+			/* fall thru... */
+#endif
 		case IEEE80211_M_HOSTAP:
 		case IEEE80211_M_IBSS:
 			/*
@@ -5788,7 +6055,12 @@ ath_newstate(struct ieee80211vap *vap, e
 			    ni->ni_tstamp.tsf != 0) {
 				sc->sc_syncbeacon = 1;
 			} else if (!sc->sc_beacons) {
-				ath_beacon_config(sc, vap);
+#ifdef ATH_SUPPORT_TDMA
+				if (vap->iv_caps & IEEE80211_C_TDMA)
+					ath_tdma_config(sc, vap);
+				else
+#endif
+					ath_beacon_config(sc, vap);
 				sc->sc_beacons = 1;
 			}
 			break;
@@ -5851,6 +6123,9 @@ ath_newstate(struct ieee80211vap *vap, e
 			taskqueue_block(sc->sc_tq);
 			sc->sc_beacons = 0;
 		}
+#ifdef ATH_SUPPORT_TDMA
+		ath_hal_setcca(ah, AH_TRUE);
+#endif
 	}
 bad:
 	return error;
@@ -6500,6 +6775,10 @@ ath_ioctl(struct ifnet *ifp, u_long cmd,
 		sc->sc_stats.ast_rx_packets = ifp->if_ipackets;
 		sc->sc_stats.ast_tx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgtxrssi);
 		sc->sc_stats.ast_rx_rssi = ATH_RSSI(sc->sc_halstats.ns_avgrssi);
+#ifdef ATH_SUPPORT_TDMA
+		sc->sc_stats.ast_tdma_tsfadjp = TDMA_AVG(sc->sc_avgtsfdeltap);
+		sc->sc_stats.ast_tdma_tsfadjm = TDMA_AVG(sc->sc_avgtsfdeltam);
+#endif
 		rt = sc->sc_currates;
 		/* XXX HT rates */
 		sc->sc_stats.ast_tx_rate =
@@ -6876,6 +7155,24 @@ ath_sysctlattach(struct ath_softc *sc)
 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 		"monpass", CTLFLAG_RW, &sc->sc_monpass, 0,
 		"mask of error frames to pass when monitoring");
+#ifdef ATH_SUPPORT_TDMA
+	if (ath_hal_macversion(ah) > 0x78) {
+		sc->sc_tdmadbaprep = 2;
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"dbaprep", CTLFLAG_RW, &sc->sc_tdmadbaprep, 0,
+			"TDMA DBA preparation time");
+		sc->sc_tdmaswbaprep = 10;
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"swbaprep", CTLFLAG_RW, &sc->sc_tdmaswbaprep, 0,
+			"TDMA SWBA preparation time");
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"guardtime", CTLFLAG_RW, &sc->sc_tdmaguard, 0,
+			"TDMA slot guard time");
+		SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+			"superframe", CTLFLAG_RD, &sc->sc_tdmabintval, 0,
+			"TDMA calculated super frame");
+	}
+#endif
 }
 
 static void
@@ -7123,16 +7420,8 @@ ath_raw_xmit(struct ieee80211_node *ni, 
 	/*
 	 * Grab a TX buffer and associated resources.
 	 */
-	ATH_TXBUF_LOCK(sc);
-	bf = STAILQ_FIRST(&sc->sc_txbuf);
-	if (bf != NULL)
-		STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
-	ATH_TXBUF_UNLOCK(sc);
+	bf = ath_getbuf(sc);
 	if (bf == NULL) {
-		DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n",
-			__func__);
-		sc->sc_stats.ast_tx_qstop++;
-		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 		ieee80211_free_node(ni);
 		m_freem(m);
 		return ENOBUFS;
@@ -7162,7 +7451,7 @@ ath_raw_xmit(struct ieee80211_node *ni, 
 bad:
 	ifp->if_oerrors++;
 	ATH_TXBUF_LOCK(sc);
-	STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+	STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
 	ATH_TXBUF_UNLOCK(sc);
 	ieee80211_free_node(ni);
 	return EIO;		/* XXX */
@@ -7220,3 +7509,364 @@ ath_announce(struct ath_softc *sc)
 		if_printf(ifp, "using %u tx buffers\n", ath_txbuf);
 #undef HAL_MODE_DUALBAND
 }
+
+#ifdef ATH_SUPPORT_TDMA
+static __inline uint32_t
+ath_hal_getnexttbtt(struct ath_hal *ah)
+{
+#define	AR_TIMER0	0x8028
+	return OS_REG_READ(ah, AR_TIMER0);
+}
+
+static __inline void
+ath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta)
+{
+	/* XXX handle wrap/overflow */
+	OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta);
+}
+
+static void
+ath_tdma_settimers(struct ath_softc *sc, u_int32_t nexttbtt, u_int32_t bintval)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	HAL_BEACON_TIMERS bt;
+
+	bt.bt_intval = bintval | HAL_BEACON_ENA;
+	bt.bt_nexttbtt = nexttbtt;
+	bt.bt_nextdba = (nexttbtt<<3) - sc->sc_tdmadbaprep;
+	bt.bt_nextswba = (nexttbtt<<3) - sc->sc_tdmaswbaprep;
+	bt.bt_nextatim = nexttbtt+1;
+	ath_hal_beaconsettimers(ah, &bt);
+}
+
+/*
+ * Calculate the beacon interval.  This is periodic in the
+ * superframe for the bss.  We assume each station is configured
+ * identically wrt transmit rate so the guard time we calculate
+ * above will be the same on all stations.  Note we need to
+ * factor in the xmit time because the hardware will schedule
+ * a frame for transmit if the start of the frame is within
+ * the burst time.  When we get hardware that properly kills
+ * frames in the PCU we can reduce/eliminate the guard time.
+ *
+ * Roundup to 1024 is so we have 1 TU buffer in the guard time
+ * to deal with the granularity of the nexttbtt timer.  11n MAC's
+ * with 1us timer granularity should allow us to reduce/eliminate
+ * this.
+ */
+static void
+ath_tdma_bintvalsetup(struct ath_softc *sc,
+	const struct ieee80211_tdma_state *tdma)
+{
+	/* copy from vap state (XXX check all vaps have same value?) */
+	sc->sc_tdmaslotlen = tdma->tdma_slotlen;
+	sc->sc_tdmabintcnt = tdma->tdma_bintval;
+
+	sc->sc_tdmabintval = roundup((sc->sc_tdmaslotlen+sc->sc_tdmaguard) *
+		tdma->tdma_slotcnt, 1024);
+	sc->sc_tdmabintval >>= 10;		/* TSF -> TU */
+	if (sc->sc_tdmabintval & 1)
+		sc->sc_tdmabintval++;
+
+	if (tdma->tdma_slot == 0) {
+		/*
+		 * Only slot 0 beacons; other slots respond.
+		 */
+		sc->sc_imask |= HAL_INT_SWBA;
+		sc->sc_tdmaswba = 0;		/* beacon immediately */
+	} else {
+		/* XXX all vaps must be slot 0 or slot !0 */
+		sc->sc_imask &= ~HAL_INT_SWBA;
+	}
+}
+
+/*
+ * Max 802.11 overhead.  This assumes no 4-address frames and
+ * the encapsulation done by ieee80211_encap (llc).  We also
+ * include potential crypto overhead.
+ */
+#define	IEEE80211_MAXOVERHEAD \
+	(sizeof(struct ieee80211_qosframe) \
+	 + sizeof(struct llc) \
+	 + IEEE80211_ADDR_LEN \
+	 + IEEE80211_WEP_IVLEN \
+	 + IEEE80211_WEP_KIDLEN \
+	 + IEEE80211_WEP_CRCLEN \
+	 + IEEE80211_WEP_MICLEN \
+	 + IEEE80211_CRC_LEN)
+
+/*

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901081712.n08HClhX028057>