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
This commit is contained in:
Sam Leffler 2009-01-08 17:12:47 +00:00
parent ba181a0efd
commit 10ad9a77f3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=186904
30 changed files with 1922 additions and 81 deletions

View File

@ -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.

View File

@ -1711,6 +1711,30 @@ set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
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_t *ie, size_t ielen, int maxlen)
#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
@ -2680,6 +2720,12 @@ isatherosoui(const u_int8_t *frm)
return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
}
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)
{
@ -2749,6 +2795,8 @@ printies(const u_int8_t *vp, int ielen, int maxcols)
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 @@ ieee80211_status(int s)
}
}
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, arg, d)
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),

View File

@ -2232,6 +2232,7 @@ net80211/ieee80211_rssadapt.c optional wlan_rssadapt
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

View File

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

View File

@ -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_node *,
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_softc *sc)
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, struct ath_txq *txq,
}
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, struct ath_txq *txq,
* 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, struct ath_txq *txq,
}
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, struct ath_txq *txq,
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, ath_bufhead *frags,
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 @@ ath_rx_proc(void *arg, int npending)
/*
* 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 ac)
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, struct ath_txq *txq, struct ath_buf *bf)
* 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, struct ath_txq *txq, struct ath_buf *bf)
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, struct ieee80211_node *ni, struct ath_buf *bf
}
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, struct ath_txq *txq)
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, struct ath_txq *txq)
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, struct ath_txq *txq)
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, struct ath_txq *txq)
* 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, struct ath_txq *txq)
}
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, enum ieee80211_state nstate, int arg)
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, enum ieee80211_state nstate, int arg)
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, enum ieee80211_state nstate, int arg)
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, caddr_t data)
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, struct mbuf *m,
/*
* 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, struct mbuf *m,
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)
/*
* Setup initially for tdma operation. Start the beacon
* timers and enable SWBA if we are slot 0. Otherwise
* we wait for slot 0 to arrive so we can sync up before
* starting to transmit.
*/
static void
ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap)
{
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
const struct ieee80211_txparam *tp;
const struct ieee80211_tdma_state *tdma = NULL;
int rix;
if (vap == NULL) {
vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
if (vap == NULL) {
if_printf(ifp, "%s: no vaps?\n", __func__);
return;
}
}
tp = vap->iv_bss->ni_txparms;
/*
* Calculate the guard time for each slot. This is the
* time to send a maximal-size frame according to the
* fixed/lowest transmit rate. Note that the interface
* mtu does not include the 802.11 overhead so we must
* tack that on (ath_hal_computetxtime includes the
* preamble and plcp in it's calculation).
*/
tdma = vap->iv_tdma;
if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
rix = ath_tx_findrix(sc->sc_currates, tp->ucastrate);
else
rix = ath_tx_findrix(sc->sc_currates, tp->mcastrate);
/* XXX short preamble assumed */
sc->sc_tdmaguard = ath_hal_computetxtime(ah, sc->sc_currates,
ifp->if_mtu + IEEE80211_MAXOVERHEAD, rix, AH_TRUE);
ath_hal_intrset(ah, 0);
ath_beaconq_config(sc); /* setup h/w beacon q */
ath_hal_setcca(ah, AH_FALSE); /* disable CCA */
ath_tdma_bintvalsetup(sc, tdma); /* calculate beacon interval */
ath_tdma_settimers(sc, sc->sc_tdmabintval,
sc->sc_tdmabintval | HAL_BEACON_RESET_TSF);
sc->sc_syncbeacon = 0;
sc->sc_avgtsfdeltap = TDMA_DUMMY_MARKER;
sc->sc_avgtsfdeltam = TDMA_DUMMY_MARKER;
ath_hal_intrset(ah, sc->sc_imask);
DPRINTF(sc, ATH_DEBUG_TDMA, "%s: slot %u len %uus cnt %u "
"bsched %u guard %uus bintval %u TU dba prep %u\n", __func__,
tdma->tdma_slot, tdma->tdma_slotlen, tdma->tdma_slotcnt,
tdma->tdma_bintval, sc->sc_tdmaguard, sc->sc_tdmabintval,
sc->sc_tdmadbaprep);
}
/*
* Update tdma operation. Called from the 802.11 layer
* when a beacon is received from the TDMA station operating
* in the slot immediately preceding us in the bss. Use
* the rx timestamp for the beacon frame to update our
* beacon timers so we follow their schedule. Note that
* by using the rx timestamp we implicitly include the
* propagation delay in our schedule.
*/
static void
ath_tdma_update(struct ieee80211_node *ni,
const struct ieee80211_tdma_param *tdma)
{
#define TSF_TO_TU(_h,_l) \
((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ath_softc *sc = ic->ic_ifp->if_softc;
struct ath_hal *ah = sc->sc_ah;
const HAL_RATE_TABLE *rt = sc->sc_currates;
u_int64_t tsf, rstamp, nextslot;
u_int32_t txtime, nextslottu, timer0;
int32_t tudelta, tsfdelta;
const struct ath_rx_status *rs;
int rix;
sc->sc_stats.ast_tdma_update++;
/*
* Check for and adopt configuration changes.
*/
if (isset(ATH_VAP(vap)->av_boff.bo_flags, IEEE80211_BEACON_TDMA)) {
const struct ieee80211_tdma_state *ts = vap->iv_tdma;
ath_tdma_bintvalsetup(sc, ts);
DPRINTF(sc, ATH_DEBUG_TDMA,
"%s: adopt slot %u slotcnt %u slotlen %u us "
"bintval %u TU\n", __func__,
ts->tdma_slot, ts->tdma_slotcnt, ts->tdma_slotlen,
sc->sc_tdmabintval);
ath_beaconq_config(sc);
/* XXX right? */
ath_hal_intrset(ah, sc->sc_imask);
/* NB: beacon timers programmed below */
}
/* extend rx timestamp to 64 bits */
tsf = ath_hal_gettsf64(ah);
rstamp = ath_extend_tsf(ni->ni_rstamp, tsf);
/*
* The rx timestamp is set by the hardware on completing
* reception (at the point where the rx descriptor is DMA'd
* to the host). To find the start of our next slot we
* must adjust this time by the time required to send
* the packet just received.
*/
rs = sc->sc_tdmars;
rix = rt->rateCodeToIndex[rs->rs_rate];
txtime = ath_hal_computetxtime(ah, rt, rs->rs_datalen, rix,
rt->info[rix].shortPreamble);
/* NB: << 9 is to cvt to TU and /2 */
nextslot = (rstamp - txtime) + (sc->sc_tdmabintval << 9);
nextslottu = TSF_TO_TU(nextslot>>32, nextslot) & HAL_BEACON_PERIOD;
/*
* TIMER0 is the h/w's idea of NextTBTT (in TU's). Convert
* to usecs and calculate the difference between what the
* other station thinks and what we have programmed. This
* lets us figure how to adjust our timers to match. The
* adjustments are done by pulling the TSF forward and possibly
* rewriting the beacon timers.
*/
timer0 = ath_hal_getnexttbtt(ah);
tsfdelta = (int32_t)((nextslot % TU_TO_TSF(HAL_BEACON_PERIOD+1)) - TU_TO_TSF(timer0));
DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
"tsfdelta %d avg +%d/-%d\n", tsfdelta,
TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam));
if (tsfdelta < 0) {
TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
TDMA_SAMPLE(sc->sc_avgtsfdeltam, -tsfdelta);
tsfdelta = -tsfdelta % 1024;
nextslottu++;
} else if (tsfdelta > 0) {
TDMA_SAMPLE(sc->sc_avgtsfdeltap, tsfdelta);
TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
tsfdelta = 1024 - (tsfdelta % 1024);
nextslottu++;
} else {
TDMA_SAMPLE(sc->sc_avgtsfdeltap, 0);
TDMA_SAMPLE(sc->sc_avgtsfdeltam, 0);
}
tudelta = nextslottu - timer0;
/*
* Copy sender's timetstamp into tdma ie so they can
* calculate roundtrip time. We submit a beacon frame
* below after any timer adjustment. The frame goes out
* at the next TBTT so the sender can calculate the
* roundtrip by inspecting the tdma ie in our beacon frame.
*
* NB: This tstamp is subtlely preserved when
* IEEE80211_BEACON_TDMA is marked (e.g. when the
* slot position changes) because ieee80211_add_tdma
* skips over the data.
*/
memcpy(ATH_VAP(vap)->av_boff.bo_tdma +
__offsetof(struct ieee80211_tdma_param, tdma_tstamp),
&ni->ni_tstamp.data, 8);
#if 0
DPRINTF(sc, ATH_DEBUG_TDMA_TIMER,
"tsf %llu nextslot %llu (%d, %d) nextslottu %u timer0 %u (%d)\n",
(unsigned long long) tsf, (unsigned long long) nextslot,
(int)(nextslot - tsf), tsfdelta,
nextslottu, timer0, tudelta);
#endif
/*
* Adjust the beacon timers only when pulling them forward
* or when going back by less than the beacon interval.
* Negative jumps larger than the beacon interval seem to
* cause the timers to stop and generally cause instability.
* This basically filters out jumps due to missed beacons.
*/
if (tudelta != 0 && (tudelta > 0 || -tudelta < sc->sc_tdmabintval)) {
ath_tdma_settimers(sc, nextslottu, sc->sc_tdmabintval);
sc->sc_stats.ast_tdma_timers++;
}
if (tsfdelta > 0) {
ath_hal_adjusttsf(ah, tsfdelta);
sc->sc_stats.ast_tdma_tsf++;
}
ath_tdma_beacon_send(sc, vap); /* prepare response */
#undef TU_TO_TSF
#undef TSF_TO_TU
}
/*
* Transmit a beacon frame at SWBA. Dynamic updates
* to the frame contents are done as needed.
*/
static void
ath_tdma_beacon_send(struct ath_softc *sc, struct ieee80211vap *vap)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
int otherant;
/*
* Check if the previous beacon has gone out. If
* not don't try to post another, skip this period
* and wait for the next. Missed beacons indicate
* a problem and should not occur. If we miss too
* many consecutive beacons reset the device.
*/
if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
sc->sc_bmisscount++;
DPRINTF(sc, ATH_DEBUG_BEACON,
"%s: missed %u consecutive beacons\n",
__func__, sc->sc_bmisscount);
if (sc->sc_bmisscount > 3) /* NB: 3 is a guess */
taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask);
return;
}
if (sc->sc_bmisscount != 0) {
DPRINTF(sc, ATH_DEBUG_BEACON,
"%s: resume beacon xmit after %u misses\n",
__func__, sc->sc_bmisscount);
sc->sc_bmisscount = 0;
}
/*
* Check recent per-antenna transmit statistics and flip
* the default antenna if noticeably more frames went out
* on the non-default antenna.
* XXX assumes 2 anntenae
*/
if (!sc->sc_diversity) {
otherant = sc->sc_defant & 1 ? 2 : 1;
if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
ath_setdefantenna(sc, otherant);
sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
}
bf = ath_beacon_generate(sc, vap);
if (bf != NULL) {
/*
* Stop any current dma and put the new frame on the queue.
* This should never fail since we check above that no frames
* are still pending on the queue.
*/
if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
DPRINTF(sc, ATH_DEBUG_ANY,
"%s: beacon queue %u did not stop?\n",
__func__, sc->sc_bhalq);
/* NB: the HAL still stops DMA, so proceed */
}
ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
ath_hal_txstart(ah, sc->sc_bhalq);
sc->sc_stats.ast_be_xmit++; /* XXX per-vap? */
/*
* Record local TSF for our last send for use
* in arbitrating slot collisions.
*/
vap->iv_bss->ni_tstamp.tsf = ath_hal_gettsf64(ah);
}
}
#endif /* ATH_SUPPORT_TDMA */

View File

@ -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
@ -109,7 +109,13 @@ struct ath_stats {
u_int32_t ast_ff_flush; /* fast frames flushed from staging q */
u_int32_t ast_tx_qfull; /* tx dropped 'cuz of queue limit */
int8_t ast_rx_noise; /* rx noise floor */
u_int32_t ast_pad[22];
u_int32_t ast_tx_nobuf; /* tx dropped 'cuz no ath buffer */
u_int32_t ast_tdma_update;/* TDMA slot timing updates */
u_int32_t ast_tdma_timers;/* TDMA slot update set beacon timers */
u_int32_t ast_tdma_tsf; /* TDMA slot update set TSF */
u_int16_t ast_tdma_tsfadjp;/* TDMA slot adjust+ (usec, smoothed)*/
u_int16_t ast_tdma_tsfadjm;/* TDMA slot adjust- (usec, smoothed)*/
u_int32_t ast_pad[17];
};
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)

View File

@ -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
@ -109,7 +109,8 @@ struct ath_buf {
TAILQ_ENTRY(ath_buf) bf_stagelist; /* stage queue list */
u_int32_t bf_age; /* age when placed on stageq */
int bf_nseg;
int bf_txflags; /* tx descriptor flags */
uint16_t bf_txflags; /* tx descriptor flags */
uint16_t bf_flags; /* status flags (below) */
struct ath_desc *bf_desc; /* virtual addr of desc */
struct ath_desc_status bf_status; /* tx/rx status */
bus_addr_t bf_daddr; /* physical addr of desc */
@ -122,6 +123,8 @@ struct ath_buf {
};
typedef STAILQ_HEAD(, ath_buf) ath_bufhead;
#define ATH_BUF_BUSY 0x00000002 /* (tx) desc owned by h/w */
/*
* DMA state for tx/rx descriptors.
*/
@ -148,6 +151,8 @@ struct ath_descdma {
struct ath_txq {
u_int axq_qnum; /* hardware q number */
#define ATH_TXQ_SWQ (HAL_NUM_TX_QUEUES+1) /* qnum for s/w only queue */
u_int axq_flags;
#define ATH_TXQ_PUTPENDING 0x0001 /* ath_hal_puttxbuf pending */
u_int axq_depth; /* queue depth (stat only) */
u_int axq_intrcnt; /* interrupt count */
u_int32_t *axq_link; /* link ptr in last TX desc */
@ -249,6 +254,7 @@ struct ath_softc {
sc_stagbeacons:1,/* use staggered beacons */
sc_wmetkipmic:1,/* can do WME+TKIP MIC */
sc_resume_up: 1,/* on resume, start all vaps */
sc_tdma : 1,/* TDMA in use */
sc_resetcal : 1;/* reset cal state next trip */
uint32_t sc_eerd; /* regdomain from EEPROM */
uint32_t sc_eecc; /* country code from EEPROM */
@ -338,6 +344,18 @@ struct ath_softc {
int sc_lastlongcal; /* last long cal completed */
int sc_lastcalreset;/* last cal reset done */
HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */
#ifdef ATH_SUPPORT_TDMA
u_int sc_tdmadbaprep; /* TDMA DBA prep time */
u_int sc_tdmaswbaprep;/* TDMA SWBA prep time */
u_int sc_tdmaswba; /* TDMA SWBA counter */
u_int32_t sc_tdmabintval; /* TDMA beacon interval (TU) */
u_int32_t sc_tdmaguard; /* TDMA guard time (usec) */
u_int sc_tdmaslotlen; /* TDMA slot length (usec) */
u_int sc_tdmabintcnt; /* TDMA beacon intvl (slots) */
struct ath_rx_status *sc_tdmars; /* TDMA status of last rx */
u_int32_t sc_avgtsfdeltap;/* TDMA slot adjust (+) */
u_int32_t sc_avgtsfdeltam;/* TDMA slot adjust (-) */
#endif
};
#define ATH_LOCK_INIT(_sc) \
@ -375,6 +393,8 @@ void ath_intr(void *);
((*(_ah)->ah_detach)((_ah)))
#define ath_hal_reset(_ah, _opmode, _chan, _outdoor, _pstatus) \
((*(_ah)->ah_reset)((_ah), (_opmode), (_chan), (_outdoor), (_pstatus)))
#define ath_hal_macversion(_ah) \
(((_ah)->ah_macVersion << 4) | ((_ah)->ah_macRev))
#define ath_hal_getratetable(_ah, _mode) \
((*(_ah)->ah_getRateTable)((_ah), (_mode)))
#define ath_hal_getmac(_ah, _mac) \
@ -417,8 +437,10 @@ void ath_intr(void *);
((*(_ah)->ah_waitForBeaconDone)((_ah), (_bf)->bf_daddr))
#define ath_hal_putrxbuf(_ah, _bufaddr) \
((*(_ah)->ah_setRxDP)((_ah), (_bufaddr)))
/* NB: common across all chips */
#define AR_TSF_L32 0x804c /* MAC local clock lower 32 bits */
#define ath_hal_gettsf32(_ah) \
((*(_ah)->ah_getTsf32)((_ah)))
OS_REG_READ(_ah, AR_TSF_L32)
#define ath_hal_gettsf64(_ah) \
((*(_ah)->ah_getTsf64)((_ah)))
#define ath_hal_resettsf(_ah) \
@ -455,6 +477,8 @@ void ath_intr(void *);
((*(_ah)->ah_beaconInit)((_ah), (_nextb), (_bperiod)))
#define ath_hal_beaconreset(_ah) \
((*(_ah)->ah_resetStationBeaconTimers)((_ah)))
#define ath_hal_beaconsettimers(_ah, _bt) \
((*(_ah)->ah_setBeaconTimers)((_ah), (_bt)))
#define ath_hal_beacontimers(_ah, _bs) \
((*(_ah)->ah_setStationBeaconTimers)((_ah), (_bs)))
#define ath_hal_setassocid(_ah, _bss, _associd) \
@ -486,6 +510,10 @@ void ath_intr(void *);
((*(_ah)->ah_getTxQueueProps)((_ah), (_q), (_qi)))
#define ath_hal_settxqueueprops(_ah, _q, _qi) \
((*(_ah)->ah_setTxQueueProps)((_ah), (_q), (_qi)))
/* NB: common across all chips */
#define AR_Q_TXE 0x0840 /* MAC Transmit Queue enable */
#define ath_hal_txqenabled(_ah, _qnum) \
(OS_REG_READ(_ah, AR_Q_TXE) & (1<<(_qnum)))
#define ath_hal_getrfgain(_ah) \
((*(_ah)->ah_getRfGain)((_ah)))
#define ath_hal_getdefantenna(_ah) \

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -362,6 +362,21 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
if (flags & IEEE80211_CLONE_WDSLEGACY)
vap->iv_flags_ext |= IEEE80211_FEXT_WDSLEGACY;
break;
#ifdef IEEE80211_SUPPORT_TDMA
case IEEE80211_M_AHDEMO:
if (flags & IEEE80211_CLONE_TDMA) {
/* NB: checked before clone operation allowed */
KASSERT(ic->ic_caps & IEEE80211_C_TDMA,
("not TDMA capable, ic_caps 0x%x", ic->ic_caps));
/*
* Propagate TDMA capability to mark vap; this
* cannot be removed and is used to distinguish
* regular ahdemo operation from ahdemo+tdma.
*/
vap->iv_caps |= IEEE80211_C_TDMA;
}
break;
#endif
}
/* auto-enable s/w beacon miss support */
if (flags & IEEE80211_CLONE_NOBEACONS)

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -1064,4 +1064,26 @@ struct ieee80211_duration {
#define ATH_FF_SNAP_ORGCODE_1 0x03
#define ATH_FF_SNAP_ORGCODE_2 0x7f
struct ieee80211_tdma_param {
u_int8_t tdma_id; /* IEEE80211_ELEMID_VENDOR */
u_int8_t tdma_len;
u_int8_t tdma_oui[3]; /* 0x00, 0x03, 0x7f */
u_int8_t tdma_type; /* OUI type */
u_int8_t tdma_subtype; /* OUI subtype */
u_int8_t tdma_version; /* spec revision */
u_int8_t tdma_slot; /* station slot # */
u_int8_t tdma_slotcnt; /* bss slot count */
u_int16_t tdma_slotlen; /* bss slot len (100us) */
u_int8_t tdma_bintval; /* beacon interval (superframes) */
u_int8_t tdma_inuse[1]; /* slot occupancy map */
u_int8_t tdma_pad[2];
u_int8_t tdma_tstamp[8]; /* timestamp from last beacon */
} __packed;
/* NB: Atheros allocated the OUI for this purpose ~3 years ago but beware ... */
#define TDMA_OUI ATH_OUI
#define TDMA_OUI_TYPE 0x02
#define TDMA_SUBTYPE_PARAM 0x01
#define TDMA_VERSION 2
#endif /* _NET80211_IEEE80211_H_ */

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -57,6 +57,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_adhoc.h>
#include <net80211/ieee80211_input.h>
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2)
@ -96,6 +99,15 @@ adhoc_vattach(struct ieee80211vap *vap)
else
vap->iv_recv_mgmt = ahdemo_recv_mgmt;
vap->iv_opdetach = adhoc_vdetach;
#ifdef IEEE80211_SUPPORT_TDMA
/*
* Throw control to tdma support. Note we do this
* after setting up our callbacks so it can piggyback
* on top of us.
*/
if (vap->iv_caps & IEEE80211_C_TDMA)
ieee80211_tdma_vattach(vap);
#endif
}
/*
@ -354,6 +366,19 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
if (type == IEEE80211_FC0_TYPE_DATA &&
ni == vap->iv_bss &&
!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
/*
* Beware of frames that come in too early; we
* can receive broadcast frames and creating sta
* entries will blow up because there is no bss
* channel yet.
*/
if (vap->iv_state != IEEE80211_S_RUN) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, "data", "not in RUN state (%s)",
ieee80211_state_name[vap->iv_state]);
vap->iv_stats.is_rx_badstate++;
goto err;
}
/*
* Fake up a node for this newly
* discovered member of the IBSS.

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -76,7 +76,7 @@ __FBSDID("$FreeBSD$");
"\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_C_CRYPTO_BITS \
"\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT"

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2003-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -124,6 +124,16 @@ wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
ieee80211_opmode_name[cp.icp_opmode]);
return EOPNOTSUPP;
}
if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
#ifdef IEEE80211_SUPPORT_TDMA
(ic->ic_caps & IEEE80211_C_TDMA) == 0
#else
(1)
#endif
) {
if_printf(ifp, "TDMA not supported\n");
return EOPNOTSUPP;
}
vap = ic->ic_vap_create(ic, ifc->ifc_name, unit,
cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
cp.icp_flags & IEEE80211_CLONE_MACADDR ?

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -635,6 +635,10 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
scan->wme = frm;
else if (isatherosoui(frm))
scan->ath = frm;
#ifdef IEEE80211_SUPPORT_TDMA
else if (istdmaoui(frm))
scan->tdma = frm;
#endif
else if (vap->iv_flags_ext & IEEE80211_FEXT_HTCOMPAT) {
/*
* Accept pre-draft HT ie's if the

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -124,6 +124,12 @@ isatherosoui(const uint8_t *frm)
return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
}
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
ishtcapoui(const uint8_t *frm)
{

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -62,6 +62,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_ioctl.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_input.h>
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#define IS_UP_AUTO(_vap) \
(IFNET_IS_UP_RUNNING(vap->iv_ifp) && \
@ -1089,6 +1092,14 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
ireq->i_val =
(vap->iv_flags_ext & IEEE80211_FEXT_RIFS) != 0;
break;
#ifdef IEEE80211_SUPPORT_TDMA
case IEEE80211_IOC_TDMA_SLOT:
case IEEE80211_IOC_TDMA_SLOTCNT:
case IEEE80211_IOC_TDMA_SLOTLEN:
case IEEE80211_IOC_TDMA_BINTERVAL:
error = ieee80211_tdma_ioctl_get80211(vap, ireq);
break;
#endif
default:
error = EINVAL;
break;
@ -3105,6 +3116,14 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
if (isvapht(vap))
error = ERESTART;
break;
#ifdef IEEE80211_SUPPORT_TDMA
case IEEE80211_IOC_TDMA_SLOT:
case IEEE80211_IOC_TDMA_SLOTCNT:
case IEEE80211_IOC_TDMA_SLOTLEN:
case IEEE80211_IOC_TDMA_BINTERVAL:
error = ieee80211_tdma_ioctl_set80211(vap, ireq);
break;
#endif
default:
error = EINVAL;
break;

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -216,7 +216,8 @@ struct ieee80211_stats {
uint8_t is_rx_disassoc_code; /* last rx'd disassoc reason */
uint8_t is_rx_authfail_code; /* last rx'd auth fail reason */
uint32_t is_beacon_miss; /* beacon miss notification */
uint32_t is_spare[13];
uint32_t is_rx_badstate; /* rx discard state != RUN */
uint32_t is_spare[12];
};
/*
@ -612,6 +613,11 @@ struct ieee80211req {
#define IEEE80211_IOC_SMPS 110 /* MIMO power save */
#define IEEE80211_IOC_RIFS 111 /* RIFS config (on, off) */
#define IEEE80211_IOC_TDMA_SLOT 201 /* TDMA: assigned slot */
#define IEEE80211_IOC_TDMA_SLOTCNT 202 /* TDMA: slots in bss */
#define IEEE80211_IOC_TDMA_SLOTLEN 203 /* TDMA: slot length (usecs) */
#define IEEE80211_IOC_TDMA_BINTERVAL 204 /* TDMA: beacon intvl (slots) */
/*
* Parameters for controlling a scan requested with
* IEEE80211_IOC_SCAN_REQ.
@ -738,6 +744,7 @@ struct ieee80211_clone_params {
#define IEEE80211_CLONE_NOBEACONS 0x0002 /* don't setup beacon timers */
#define IEEE80211_CLONE_WDSLEGACY 0x0004 /* legacy WDS processing */
#define IEEE80211_CLONE_MACADDR 0x0008 /* use specified mac addr */
#define IEEE80211_CLONE_TDMA 0x0010 /* operate in TDMA mode */
#endif /* __FreeBSD__ */
#endif /* _NET80211_IEEE80211_IOCTL_H_ */

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -43,6 +43,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_input.h>
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#include <net80211/ieee80211_wds.h>
#include <net/bpf.h>
@ -337,6 +340,9 @@ ieee80211_create_ibss(struct ieee80211vap* vap, struct ieee80211_channel *chan)
if (vap->iv_flags & IEEE80211_F_DESBSSID)
IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_des_bssid);
else
#ifdef IEEE80211_SUPPORT_TDMA
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
#endif
memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN);
}
/*
@ -745,6 +751,10 @@ ieee80211_sta_join(struct ieee80211vap *vap, struct ieee80211_channel *chan,
ieee80211_parse_htcap(ni, ni->ni_ies.htcap_ie);
if (ni->ni_ies.htinfo_ie != NULL)
ieee80211_parse_htinfo(ni, ni->ni_ies.htinfo_ie);
#ifdef IEEE80211_SUPPORT_TDMA
if (ni->ni_ies.tdma_ie != NULL)
ieee80211_parse_tdma(ni, ni->ni_ies.tdma_ie);
#endif
}
vap->iv_dtim_period = se->se_dtimperiod;
@ -858,6 +868,10 @@ ieee80211_ies_expand(struct ieee80211_ies *ies)
ies->wme_ie = ie;
else if (isatherosoui(ie))
ies->ath_ie = ie;
#ifdef IEEE80211_SUPPORT_TDMA
else if (istdmaoui(ie))
ies->tdma_ie = ie;
#endif
break;
case IEEE80211_ELEMID_RSN:
ies->rsn_ie = ie;

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -80,6 +80,7 @@ struct ieee80211_ies {
uint8_t *ath_ie; /* captured Atheros ie */
uint8_t *htcap_ie; /* captured HTCAP ie */
uint8_t *htinfo_ie; /* captured HTINFO ie */
uint8_t *tdma_ie; /* captured TDMA ie */
/* NB: these must be the last members of this structure */
uint8_t *data; /* frame data > 802.11 header */
int len; /* data size in bytes */

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_regdomain.h>
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#include <net80211/ieee80211_wds.h>
#ifdef INET
@ -2500,6 +2503,7 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
* [tlv] WME parameters
* [tlv] Vendor OUI HT capabilities (optional)
* [tlv] Vendor OUI HT information (optional)
* [tlv] TDMA parameters (optional)
* [tlv] application data (optional)
*/
@ -2589,6 +2593,12 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
frm = ieee80211_add_htcap_vendor(frm, ni);
frm = ieee80211_add_htinfo_vendor(frm, ni);
}
#ifdef IEEE80211_SUPPORT_TDMA
if (vap->iv_caps & IEEE80211_C_TDMA) {
bo->bo_tdma = frm;
frm = ieee80211_add_tdma(frm, vap);
}
#endif
if (vap->iv_appie_beacon != NULL) {
bo->bo_appie = frm;
bo->bo_appie_len = vap->iv_appie_beacon->ie_len;
@ -2637,6 +2647,7 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
* XXX Vendor-specific OIDs (e.g. Atheros)
* [tlv] WPA parameters
* [tlv] WME parameters
* [tlv] TDMA parameters (optional)
* [tlv] application data (optional)
* NB: we allocate the max space required for the TIM bitmap.
* XXX how big is this?
@ -2661,6 +2672,10 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
+ 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */
+ (vap->iv_caps & IEEE80211_C_WME ? /* WME */
sizeof(struct ieee80211_wme_param) : 0)
#ifdef IEEE80211_SUPPORT_TDMA
+ (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */
sizeof(struct ieee80211_tdma_param) : 0)
#endif
+ IEEE80211_MAX_APPIE
;
m = ieee80211_getmgtframe(&frm,
@ -2779,7 +2794,14 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
ieee80211_ht_update_beacon(vap, bo);
clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO);
}
#ifdef IEEE80211_SUPPORT_TDMA
if (vap->iv_caps & IEEE80211_C_TDMA) {
/*
* NB: the beacon is potentially updated every TBTT.
*/
ieee80211_tdma_update_beacon(vap, bo);
}
#endif
if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/
struct ieee80211_tim_ie *tie =
(struct ieee80211_tim_ie *) bo->bo_tim;

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -291,6 +291,7 @@ struct ieee80211_beacon_offsets {
uint8_t *bo_cfp; /* start of CFParms element */
uint8_t *bo_tim; /* start of atim/dtim */
uint8_t *bo_wme; /* start of WME parameters */
uint8_t *bo_tdma; /* start of TDMA parameters */
uint8_t *bo_tim_trailer;/* start of fixed-size trailer */
uint16_t bo_tim_len; /* atim/dtim length in bytes */
uint16_t bo_tim_trailer_len;/* tim trailer length in bytes */
@ -325,6 +326,7 @@ enum {
IEEE80211_BEACON_APPIE = 5, /* Application IE's */
IEEE80211_BEACON_CFP = 6, /* CFParms */
IEEE80211_BEACON_CSA = 7, /* Channel Switch Announcement */
IEEE80211_BEACON_TDMA = 9, /* TDMA Info */
};
int ieee80211_beacon_update(struct ieee80211_node *,
struct ieee80211_beacon_offsets *, struct mbuf *, int mcast);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Sam Leffler, Errno Consulting
* Copyright (c) 2005-2009 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -209,6 +209,7 @@ struct ieee80211_scanparams {
uint8_t *htcap;
uint8_t *htinfo;
uint8_t *ath;
uint8_t *tdma;
};
/*

View File

@ -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
@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_input.h>
#include <net80211/ieee80211_regdomain.h>
#ifdef IEEE80211_SUPPORT_TDMA
#include <net80211/ieee80211_tdma.h>
#endif
#include <net/bpf.h>
@ -119,6 +122,10 @@ static void sta_flush_table(struct sta_table *);
#define MATCH_NOTSEEN 0x0080 /* not seen in recent scans */
#define MATCH_RSSI 0x0100 /* rssi deemed too low to use */
#define MATCH_CC 0x0200 /* country code mismatch */
#define MATCH_TDMA_NOIE 0x0400 /* no TDMA ie */
#define MATCH_TDMA_NOTMASTER 0x0800 /* not TDMA master */
#define MATCH_TDMA_NOSLOT 0x1000 /* all TDMA slots occupied */
#define MATCH_TDMA_LOCAL 0x2000 /* local address */
static int match_bss(struct ieee80211vap *,
const struct ieee80211_scan_state *, struct sta_entry *, int);
static void adhoc_age(struct ieee80211_scan_state *);
@ -870,6 +877,20 @@ match_ssid(const uint8_t *ie,
return 0;
}
#ifdef IEEE80211_SUPPORT_TDMA
static int
tdma_isfull(const struct ieee80211_tdma_param *tdma)
{
int slot, slotcnt;
slotcnt = tdma->tdma_slotcnt;
for (slot = slotcnt-1; slot >= 0; slot--)
if (isclr(tdma->tdma_inuse, slot))
return 0;
return 1;
}
#endif /* IEEE80211_SUPPORT_TDMA */
/*
* Test a scan candidate for suitability/compatibility.
*/
@ -900,6 +921,36 @@ match_bss(struct ieee80211vap *vap,
if (vap->iv_opmode == IEEE80211_M_IBSS) {
if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
fail |= MATCH_CAPINFO;
#ifdef IEEE80211_SUPPORT_TDMA
} else if (vap->iv_opmode == IEEE80211_M_AHDEMO) {
/*
* Adhoc demo network setup shouldn't really be scanning
* but just in case skip stations operating in IBSS or
* BSS mode.
*/
if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS))
fail |= MATCH_CAPINFO;
/*
* TDMA operation cannot coexist with a normal 802.11 network;
* skip if IBSS or ESS capabilities are marked and require
* the beacon have a TDMA ie present.
*/
if (vap->iv_caps & IEEE80211_C_TDMA) {
const struct ieee80211_tdma_param *tdma =
(const struct ieee80211_tdma_param *)se->se_ies.tdma_ie;
if (tdma == NULL)
fail |= MATCH_TDMA_NOIE;
else if (tdma->tdma_slot != 0)
fail |= MATCH_TDMA_NOTMASTER;
else if (tdma_isfull(tdma))
fail |= MATCH_TDMA_NOSLOT;
#if 0
else if (ieee80211_local_address(se->se_macaddr))
fail |= MATCH_TDMA_LOCAL;
#endif
}
#endif /* IEEE80211_SUPPORT_TDMA */
} else {
if ((se->se_capinfo & IEEE80211_CAPINFO_ESS) == 0)
fail |= MATCH_CAPINFO;
@ -977,6 +1028,12 @@ match_bss(struct ieee80211vap *vap,
fail & MATCH_FAILS ? '=' :
fail & MATCH_NOTSEEN ? '^' :
fail & MATCH_CC ? '$' :
#ifdef IEEE80211_SUPPORT_TDMA
fail & MATCH_TDMA_NOIE ? '&' :
fail & MATCH_TDMA_NOTMASTER ? ':' :
fail & MATCH_TDMA_NOSLOT ? '@' :
fail & MATCH_TDMA_LOCAL ? '#' :
#endif
fail ? '-' : '+', ether_sprintf(se->se_macaddr));
printf(" %s%c", ether_sprintf(se->se_bssid),
fail & MATCH_BSSID ? '!' : ' ');
@ -1449,7 +1506,14 @@ adhoc_pick_bss(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
if (ss->ss_flags & IEEE80211_SCAN_NOJOIN)
return 0;
notfound:
/* NB: never auto-start a tdma network for slot !0 */
#ifdef IEEE80211_SUPPORT_TDMA
if (vap->iv_des_nssid &&
((vap->iv_caps & IEEE80211_C_TDMA) == 0 ||
ieee80211_tdma_getslot(vap) == 0)) {
#else
if (vap->iv_des_nssid) {
#endif
/*
* No existing adhoc network to join and we have
* an ssid; start one up. If no channel was

View File

@ -0,0 +1,715 @@
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifdef __FreeBSD__
__FBSDID("$FreeBSD$");
#endif
/*
* IEEE 802.11 TDMA mode support.
*/
#include "opt_inet.h"
#include "opt_wlan.h"
#ifdef IEEE80211_SUPPORT_TDMA
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_llc.h>
#include <net/ethernet.h>
#include <net/bpf.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_tdma.h>
#include <net80211/ieee80211_input.h>
#include "opt_tdma.h"
#ifndef TDMA_SLOTLEN_DEFAULT
#define TDMA_SLOTLEN_DEFAULT 10*1000 /* 10ms */
#endif
#ifndef TDMA_SLOTCNT_DEFAULT
#define TDMA_SLOTCNT_DEFAULT 2 /* 2x (pt-to-pt) */
#endif
#ifndef TDMA_BINTVAL_DEFAULT
#define TDMA_BINTVAL_DEFAULT 5 /* 5x ~= 100TU beacon intvl */
#endif
#ifndef TDMA_TXRATE_11B_DEFAULT
#define TDMA_TXRATE_11B_DEFAULT 2*11
#endif
#ifndef TDMA_TXRATE_11G_DEFAULT
#define TDMA_TXRATE_11G_DEFAULT 2*24
#endif
#ifndef TDMA_TXRATE_11A_DEFAULT
#define TDMA_TXRATE_11A_DEFAULT 2*24
#endif
static void tdma_vdetach(struct ieee80211vap *vap);
static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void tdma_beacon_miss(struct ieee80211vap *vap);
static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int rssi, int noise, uint32_t rstamp);
static int tdma_update(struct ieee80211vap *vap,
const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni,
int pickslot);
static int tdma_process_params(struct ieee80211_node *ni,
const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh);
static void
setackpolicy(struct ieee80211com *ic, int noack)
{
struct ieee80211_wme_state *wme = &ic->ic_wme;
int ac;
for (ac = 0; ac < WME_NUM_AC; ac++) {
wme->wme_chanParams.cap_wmeParams[ac].wmep_noackPolicy = noack;
wme->wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy = noack;
}
}
void
ieee80211_tdma_vattach(struct ieee80211vap *vap)
{
struct ieee80211_tdma_state *ts;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
ts = (struct ieee80211_tdma_state *) malloc(
sizeof(struct ieee80211_tdma_state), M_80211_VAP, M_NOWAIT | M_ZERO);
if (ts == NULL) {
printf("%s: cannot allocate TDMA state block\n", __func__);
/* NB: fall back to adhdemo mode */
vap->iv_caps &= ~IEEE80211_C_TDMA;
return;
}
/* NB: default configuration is passive so no beacons */
ts->tdma_slotlen = TDMA_SLOTLEN_DEFAULT;
ts->tdma_slotcnt = TDMA_SLOTCNT_DEFAULT;
ts->tdma_bintval = TDMA_BINTVAL_DEFAULT;
ts->tdma_slot = 1; /* passive operation */
/* setup default fixed rates */
vap->iv_txparms[IEEE80211_MODE_11B].ucastrate = TDMA_TXRATE_11B_DEFAULT;
vap->iv_txparms[IEEE80211_MODE_11B].mcastrate = TDMA_TXRATE_11B_DEFAULT;
vap->iv_txparms[IEEE80211_MODE_11G].ucastrate = TDMA_TXRATE_11G_DEFAULT;
vap->iv_txparms[IEEE80211_MODE_11G].mcastrate = TDMA_TXRATE_11G_DEFAULT;
vap->iv_txparms[IEEE80211_MODE_11A].ucastrate = TDMA_TXRATE_11A_DEFAULT;
vap->iv_txparms[IEEE80211_MODE_11A].mcastrate = TDMA_TXRATE_11A_DEFAULT;
setackpolicy(vap->iv_ic, 1); /* disable ACK's */
ts->tdma_opdetach = vap->iv_opdetach;
vap->iv_opdetach = tdma_vdetach;
ts->tdma_newstate = vap->iv_newstate;
vap->iv_newstate = tdma_newstate;
vap->iv_bmiss = tdma_beacon_miss;
ts->tdma_recv_mgmt = vap->iv_recv_mgmt;
vap->iv_recv_mgmt = tdma_recv_mgmt;
vap->iv_tdma = ts;
}
static void
tdma_vdetach(struct ieee80211vap *vap)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
ts->tdma_opdetach(vap);
free(vap->iv_tdma, M_80211_VAP);
setackpolicy(vap->iv_ic, 0); /* enable ACK's */
}
/*
* TDMA state machine handler.
*/
static int
tdma_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
enum ieee80211_state ostate;
int status;
IEEE80211_LOCK_ASSERT(vap->iv_ic);
ostate = vap->iv_state;
IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
__func__, ieee80211_state_name[ostate],
ieee80211_state_name[nstate], arg);
if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
callout_stop(&vap->iv_swbmiss);
if (nstate == IEEE80211_S_SCAN &&
(ostate == IEEE80211_S_INIT || ostate == IEEE80211_S_RUN) &&
ts->tdma_slot != 0) {
/*
* Override adhoc behaviour when operating as a slave;
* we need to scan even if the channel is locked.
*/
vap->iv_state = nstate; /* state transition */
ieee80211_cancel_scan(vap); /* background scan */
if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
ieee80211_check_scan(vap,
vap->iv_scanreq_flags,
vap->iv_scanreq_duration,
vap->iv_scanreq_mindwell,
vap->iv_scanreq_maxdwell,
vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
} else
ieee80211_check_scan_current(vap);
status = 0;
} else {
status = ts->tdma_newstate(vap, nstate, arg);
}
if (status == 0 &&
nstate == IEEE80211_S_RUN && ostate != IEEE80211_S_RUN &&
(vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) &&
ts->tdma_slot != 0) {
/*
* Start s/w beacon miss timer for slave devices w/o
* hardware support. The 2x is a fudge for our doing
* this in software.
*/
vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
2 * vap->iv_bmissthreshold * ts->tdma_bintval *
((ts->tdma_slotcnt * ts->tdma_slotlen) / 1024));
vap->iv_swbmiss_count = 0;
callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
ieee80211_swbmiss, vap);
}
return status;
}
static void
tdma_beacon_miss(struct ieee80211vap *vap)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
KASSERT((vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
KASSERT(vap->iv_state == IEEE80211_S_RUN,
("wrong state %d", vap->iv_state));
IEEE80211_DPRINTF(vap,
IEEE80211_MSG_STATE | IEEE80211_MSG_TDMA | IEEE80211_MSG_DEBUG,
"beacon miss, mode %u state %s\n",
vap->iv_opmode, ieee80211_state_name[vap->iv_state]);
if (ts->tdma_peer != NULL) { /* XXX? can this be null? */
ieee80211_notify_node_leave(vap->iv_bss);
ts->tdma_peer = NULL;
/*
* Treat beacon miss like an associate failure wrt the
* scan policy; this forces the entry in the scan cache
* to be ignored after several tries.
*/
ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr,
IEEE80211_STATUS_TIMEOUT);
}
#if 0
ts->tdma_inuse = 0; /* clear slot usage */
#endif
ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
}
static void
tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
int subtype, int rssi, int noise, uint32_t rstamp)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tdma_state *ts = vap->iv_tdma;
if (subtype == IEEE80211_FC0_SUBTYPE_BEACON &&
(ic->ic_flags & IEEE80211_F_SCAN) == 0) {
struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
struct ieee80211_scanparams scan;
if (ieee80211_parse_beacon(ni, m0, &scan) != 0)
return;
if (scan.tdma == NULL) {
/*
* TDMA stations must beacon a TDMA ie; ignore
* any other station.
* XXX detect overlapping bss and change channel
*/
IEEE80211_DISCARD(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
wh, ieee80211_mgt_subtype_name[subtype >>
IEEE80211_FC0_SUBTYPE_SHIFT],
"%s", "no TDMA ie");
vap->iv_stats.is_rx_mgtdiscard++;
return;
}
if (ni == vap->iv_bss &&
!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
/*
* Fake up a node for this newly
* discovered member of the IBSS.
*/
ni = ieee80211_add_neighbor(vap, wh, &scan);
if (ni == NULL) {
/* NB: stat kept for alloc failure */
return;
}
}
/*
* Check for state updates.
*/
if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
/*
* Count frame now that we know it's to be processed.
*/
vap->iv_stats.is_rx_beacon++;
IEEE80211_NODE_STAT(ni, rx_beacons);
/*
* Record tsf of last beacon. NB: this must be
* done before calling tdma_process_params
* as deeper routines reference it.
*/
memcpy(&ni->ni_tstamp.data, scan.tstamp,
sizeof(ni->ni_tstamp.data));
/*
* Count beacon frame for s/w bmiss handling.
*/
vap->iv_swbmiss_count++;
vap->iv_bmiss_count = 0;
/*
* Process tdma ie. The contents are used to sync
* the slot timing, reconfigure the bss, etc.
*/
(void) tdma_process_params(ni, scan.tdma, rstamp, wh);
return;
}
/*
* NB: defer remaining work to the adhoc code; this causes
* 2x parsing of the frame but should happen infrequently
*/
}
ts->tdma_recv_mgmt(ni, m0, subtype, rssi, noise, rstamp);
}
/*
* Update TDMA state on receipt of a beacon frame with
* a TDMA information element. The sender's identity
* is provided so we can track who our peer is. If pickslot
* is non-zero we scan the slot allocation state in the ie
* locate a free slot for our use.
*/
static int
tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma,
struct ieee80211_node *ni, int pickslot)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
int slotlen, slotcnt, slot, bintval;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
slotlen = le16toh(tdma->tdma_slotlen);
slotcnt = tdma->tdma_slotcnt;
bintval = tdma->tdma_bintval;
/* XXX rate-limit printf's */
if (!(2 <= slotcnt && slotcnt <= IEEE80211_TDMA_MAXSLOTS)) {
printf("%s: bogus slot cnt %u\n", __func__, slotcnt);
return 0;
}
/* XXX magic constants */
if (slotlen < 2 || slotlen > (0xfffff/100)) {
printf("%s: bogus slot len %u\n", __func__, slotlen);
return 0;
}
if (bintval < 1) {
printf("%s: bogus beacon interval %u\n", __func__, bintval);
return 0;
}
if (pickslot) {
/*
* Pick unoccupied slot. Note we never choose slot 0.
*/
for (slot = slotcnt-1; slot > 0; slot--)
if (isclr(tdma->tdma_inuse, slot))
break;
if (slot <= 0) {
printf("%s: no free slot, slotcnt %u inuse: 0x%x\n",
__func__, slotcnt, tdma->tdma_inuse[0]);
/* XXX need to do something better */
return 0;
}
} else
slot = ts->tdma_slot;
if (slotcnt != ts->tdma_slotcnt ||
100*slotlen != ts->tdma_slotlen ||
bintval != ts->tdma_bintval ||
slot != ts->tdma_slot ||
ts->tdma_peer != ni) {
/*
* New/changed parameters; update runtime state.
*/
/* XXX overwrites user parameters */
ts->tdma_slotcnt = slotcnt;
ts->tdma_slotlen = 100*slotlen;
ts->tdma_slot = slot;
ts->tdma_bintval = bintval;
/* mark beacon to be updated before next xmit */
ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA);
IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA,
"%s: slot %u slotcnt %u slotlen %u us bintval %u\n",
__func__, slot, slotcnt, 100*slotlen, tdma->tdma_bintval);
}
/*
* Notify driver. Note we can be called before
* entering RUN state if we scanned and are
* joining an existing bss. In that case do not
* call the driver because not all necessary state
* has been setup. The next beacon will dtrt.
*/
if (vap->iv_state == IEEE80211_S_RUN)
vap->iv_ic->ic_tdma_update(ni, tdma);
/*
* Dispatch join event on first beacon from new master.
*/
if (ts->tdma_peer != ni) {
if (ts->tdma_peer != NULL)
ieee80211_notify_node_leave(vap->iv_bss);
ieee80211_notify_node_join(ni, 1);
/* NB: no reference, we just use the address */
ts->tdma_peer = ni;
}
return 1;
}
/*
* Process received TDMA parameters.
*/
static int
tdma_process_params(struct ieee80211_node *ni,
const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tdma_state *ts = vap->iv_tdma;
const struct ieee80211_tdma_param *tdma =
(const struct ieee80211_tdma_param *) ie;
u_int len = ie[1];
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
if (len < sizeof(*tdma) - 2) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA,
wh, "tdma", "too short, len %u", len);
return IEEE80211_REASON_IE_INVALID;
}
if (tdma->tdma_version != TDMA_VERSION) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA,
wh, "tdma", "bad version %u", tdma->tdma_version);
return IEEE80211_REASON_IE_INVALID;
}
/*
* Can reach here while scanning, update
* operational state only in RUN state.
*/
if (vap->iv_state == IEEE80211_S_RUN) {
if (tdma->tdma_slot != ts->tdma_slot &&
isclr(ts->tdma_inuse, tdma->tdma_slot)) {
IEEE80211_NOTE(vap, IEEE80211_MSG_TDMA, ni,
"discovered in slot %u", tdma->tdma_slot);
setbit(ts->tdma_inuse, tdma->tdma_slot);
/* XXX dispatch event only when operating as master */
if (ts->tdma_slot == 0)
ieee80211_notify_node_join(ni, 1);
}
setbit(ts->tdma_active, tdma->tdma_slot);
if (tdma->tdma_slot == ts->tdma_slot-1) {
/*
* Slave tsf synchronization to station
* just before us in the schedule. The driver
* is responsible for copying the timestamp
* of the received beacon into our beacon
* frame so the sender can calculate round
* trip time. We cannot do that here because
* we don't know how to update our beacon frame.
*/
(void) tdma_update(vap, tdma, ni, 0);
/* XXX reschedule swbmiss timer on parameter change */
} else if (tdma->tdma_slot == ts->tdma_slot+1) {
uint64_t tstamp;
int32_t rtt;
/*
* Use returned timstamp to calculate the
* roundtrip time.
*/
memcpy(&tstamp, tdma->tdma_tstamp, 8);
/* XXX use only 15 bits of rstamp */
rtt = rstamp - (le64toh(tstamp) & 0x7fff);
if (rtt < 0)
rtt += 0x7fff;
/* XXX hack to quiet normal use */
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOT1X,
"tdma rtt %5u [rstamp %5u tstamp %llu]\n",
rtt, rstamp,
(unsigned long long) le64toh(tstamp));
} else if (tdma->tdma_slot == ts->tdma_slot &&
le64toh(ni->ni_tstamp.tsf) > vap->iv_bss->ni_tstamp.tsf) {
/*
* Station using the same slot as us and has
* been around longer than us; we must move.
* Note this can happen if stations do not
* see each other while scanning.
*/
IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA,
"slot %u collision rxtsf %llu tsf %llu\n",
tdma->tdma_slot,
(unsigned long long) le64toh(ni->ni_tstamp.tsf),
vap->iv_bss->ni_tstamp.tsf);
setbit(ts->tdma_inuse, tdma->tdma_slot);
(void) tdma_update(vap, tdma, ni, 1);
}
}
return 0;
}
int
ieee80211_tdma_getslot(struct ieee80211vap *vap)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
return ts->tdma_slot;
}
/*
* Parse a TDMA ie on station join and use it to setup node state.
*/
void
ieee80211_parse_tdma(struct ieee80211_node *ni, const uint8_t *ie)
{
struct ieee80211vap *vap = ni->ni_vap;
if (vap->iv_caps & IEEE80211_C_TDMA) {
const struct ieee80211_tdma_param *tdma =
(const struct ieee80211_tdma_param *)ie;
struct ieee80211_tdma_state *ts = vap->iv_tdma;
/*
* Adopt TDMA configuration when joining an
* existing network.
*/
setbit(ts->tdma_inuse, tdma->tdma_slot);
(void) tdma_update(vap, tdma, ni, 1);
/*
* Propagate capabilities based on the local
* configuration and the remote station's advertised
* capabilities. In particular this permits us to
* enable use of QoS to disable ACK's.
*/
if ((vap->iv_flags & IEEE80211_F_WME) &&
ni->ni_ies.wme_ie != NULL)
ni->ni_flags |= IEEE80211_NODE_QOS;
}
}
#define TDMA_OUI_BYTES 0x00, 0x03, 0x7f
/*
* Add a TDMA parameters element to a frame.
*/
uint8_t *
ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap)
{
#define ADDSHORT(frm, v) do { \
frm[0] = (v) & 0xff; \
frm[1] = (v) >> 8; \
frm += 2; \
} while (0)
static const struct ieee80211_tdma_param param = {
.tdma_id = IEEE80211_ELEMID_VENDOR,
.tdma_len = sizeof(struct ieee80211_tdma_param) - 2,
.tdma_oui = { TDMA_OUI_BYTES },
.tdma_type = TDMA_OUI_TYPE,
.tdma_subtype = TDMA_SUBTYPE_PARAM,
.tdma_version = TDMA_VERSION,
};
const struct ieee80211_tdma_state *tdma = vap->iv_tdma;
uint16_t slotlen;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
memcpy(frm, &param, sizeof(param));
frm += __offsetof(struct ieee80211_tdma_param, tdma_slot);
*frm++ = tdma->tdma_slot;
*frm++ = tdma->tdma_slotcnt;
/* NB: convert units to fit in 16-bits */
slotlen = tdma->tdma_slotlen / 100; /* 100us units */
ADDSHORT(frm, slotlen);
*frm++ = tdma->tdma_bintval;
*frm++ = tdma->tdma_inuse[0];
frm += 10; /* pad+timestamp */
return frm;
#undef ADDSHORT
}
#undef TDMA_OUI_BYTES
/*
* Update TDMA state at TBTT.
*/
void
ieee80211_tdma_update_beacon(struct ieee80211vap *vap,
struct ieee80211_beacon_offsets *bo)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
if (isset(bo->bo_flags, IEEE80211_BEACON_TDMA)) {
(void) ieee80211_add_tdma(bo->bo_tdma, vap);
clrbit(bo->bo_flags, IEEE80211_BEACON_TDMA);
}
if (ts->tdma_slot != 0) /* only on master */
return;
if (ts->tdma_count <= 0) {
/*
* Time to update the mask of active/inuse stations.
* We track stations that we've received a beacon
* frame from and update this mask periodically.
* This allows us to miss a few beacons before marking
* a slot free for re-use.
*/
ts->tdma_inuse[0] = ts->tdma_active[0];
ts->tdma_active[0] = 0x01;
/* update next time 'round */
/* XXX use notify framework */
setbit(bo->bo_flags, IEEE80211_BEACON_TDMA);
/* NB: use s/w beacon miss threshold; may be too high */
ts->tdma_count = vap->iv_bmissthreshold-1;
} else
ts->tdma_count--;
}
int
ieee80211_tdma_ioctl_get80211(struct ieee80211vap *vap,
struct ieee80211req *ireq)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
return EOPNOTSUPP;
switch (ireq->i_type) {
case IEEE80211_IOC_TDMA_SLOT:
ireq->i_val = ts->tdma_slot;
break;
case IEEE80211_IOC_TDMA_SLOTCNT:
ireq->i_val = ts->tdma_slotcnt;
break;
case IEEE80211_IOC_TDMA_SLOTLEN:
ireq->i_val = ts->tdma_slotlen;
break;
case IEEE80211_IOC_TDMA_BINTERVAL:
ireq->i_val = ts->tdma_bintval;
break;
default:
return EINVAL;
}
return 0;
}
int
ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap,
struct ieee80211req *ireq)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
if ((vap->iv_caps & IEEE80211_C_TDMA) == 0)
return EOPNOTSUPP;
switch (ireq->i_type) {
case IEEE80211_IOC_TDMA_SLOT:
if (!(0 <= ireq->i_val && ireq->i_val <= ts->tdma_slotcnt))
return EINVAL;
if (ireq->i_val != ts->tdma_slot) {
ts->tdma_slot = ireq->i_val;
return ERESTART;
}
break;
case IEEE80211_IOC_TDMA_SLOTCNT:
if (!(2 <= ireq->i_val &&
ireq->i_val <= IEEE80211_TDMA_MAXSLOTS))
return EINVAL;
if (ireq->i_val != ts->tdma_slotcnt) {
ts->tdma_slotcnt = ireq->i_val;
return ERESTART;
}
break;
case IEEE80211_IOC_TDMA_SLOTLEN:
/*
* XXX
* 150 insures at least 1/8 TU
* 0xfffff is the max duration for bursting
* (implict by way of 16-bit data type for i_val)
*/
if (ireq->i_val < 150)
return EINVAL;
if (ireq->i_val != ts->tdma_slotlen) {
ts->tdma_slotlen = ireq->i_val;
return ERESTART;
}
break;
case IEEE80211_IOC_TDMA_BINTERVAL:
if (ireq->i_val < 1)
return EINVAL;
if (ireq->i_val != ts->tdma_bintval) {
ts->tdma_bintval = ireq->i_val;
return ERESTART;
}
break;
default:
return EINVAL;
}
return 0;
}
#endif /* IEEE80211_SUPPORT_TDMA */

View File

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
* Copyright (c) 2007-2009 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _NET80211_IEEE80211_TDMA_H_
#define _NET80211_IEEE80211_TDMA_H_
/*
* TDMA-mode implementation definitions.
*/
struct ieee80211_tdma_state {
u_int tdma_slotlen; /* bss slot length (us) */
uint8_t tdma_slotcnt; /* bss slot count */
uint8_t tdma_bintval; /* beacon interval (slots) */
uint8_t tdma_slot; /* station slot # */
uint8_t tdma_inuse[1]; /* mask of slots in use */
#define IEEE80211_TDMA_MAXSLOTS 8
void *tdma_peer; /* peer station cookie */
uint8_t tdma_active[1]; /* mask of active slots */
int tdma_count; /* active/inuse countdown */
/* parent method pointers */
int (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state,
int arg);
void (*tdma_recv_mgmt)(struct ieee80211_node *,
struct mbuf *, int, int, int, uint32_t);
void (*tdma_opdetach)(struct ieee80211vap *);
};
void ieee80211_tdma_vattach(struct ieee80211vap *);
int ieee80211_tdma_getslot(struct ieee80211vap *vap);
void ieee80211_parse_tdma(struct ieee80211_node *ni, const uint8_t *ie);
uint8_t *ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap);
struct ieee80211_beacon_offsets;
void ieee80211_tdma_update_beacon(struct ieee80211vap *vap,
struct ieee80211_beacon_offsets *bo);
struct ieee80211req;
int ieee80211_tdma_ioctl_get80211(struct ieee80211vap *vap,
struct ieee80211req *ireq);
int ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap,
struct ieee80211req *ireq);
#endif /* !_NET80211_IEEE80211_TDMA_H_ */

View File

@ -1,6 +1,6 @@
/*-
* Copyright (c) 2001 Atsushi Onoe
* 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
@ -105,6 +105,8 @@ struct ieee80211_appie {
uint8_t ie_data[]; /* user-specified IE's */
};
struct ieee80211_tdma_param;
struct ieee80211com {
struct ifnet *ic_ifp; /* associated device */
ieee80211_com_lock_t ic_comlock; /* state update lock */
@ -226,6 +228,9 @@ struct ieee80211com {
void (*ic_update_promisc)(struct ifnet *);
/* new station association callback/notification */
void (*ic_newassoc)(struct ieee80211_node *, int);
/* TDMA update notification */
void (*ic_tdma_update)(struct ieee80211_node *,
const struct ieee80211_tdma_param *);
/* node state management */
struct ieee80211_node* (*ic_node_alloc)(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);
@ -279,6 +284,7 @@ struct ieee80211com {
};
struct ieee80211_aclator;
struct ieee80211_tdma_state;
struct ieee80211vap {
struct ifmedia iv_media; /* interface media config */
@ -389,6 +395,8 @@ struct ieee80211vap {
const struct ieee80211_aclator *iv_acl; /* acl glue */
void *iv_as; /* private aclator state */
struct ieee80211_tdma_state *iv_tdma; /* tdma state */
/* operate-mode detach hook */
void (*iv_opdetach)(struct ieee80211vap *);
/* receive processing */
@ -522,11 +530,13 @@ MALLOC_DECLARE(M_80211_VAP);
/* 0x10000000 reserved */
#define IEEE80211_C_BGSCAN 0x20000000 /* CAPABILITY: bg scanning */
#define IEEE80211_C_TXFRAG 0x40000000 /* CAPABILITY: tx fragments */
#define IEEE80211_C_TDMA 0x80000000 /* CAPABILITY: TDMA avail */
/* XXX protection/barker? */
#define IEEE80211_C_OPMODE \
(IEEE80211_C_STA | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | \
IEEE80211_C_AHDEMO | IEEE80211_C_MONITOR | IEEE80211_C_WDS)
IEEE80211_C_AHDEMO | IEEE80211_C_MONITOR | IEEE80211_C_WDS | \
IEEE80211_C_TDMA)
/*
* ic_htcaps/iv_htcaps: HT-specific device/driver capabilities
@ -680,6 +690,7 @@ ieee80211_htchanflags(const struct ieee80211_channel *c)
#define IEEE80211_MSG_ACTION 0x00000010 /* action frame handling */
#define IEEE80211_MSG_WDS 0x00000008 /* WDS handling */
#define IEEE80211_MSG_IOCTL 0x00000004 /* ioctl handling */
#define IEEE80211_MSG_TDMA 0x00000002 /* TDMA handling */
#define IEEE80211_MSG_ANY 0xffffffff /* anything */

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2002-2007 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
@ -69,6 +69,7 @@ enum {
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
@ -99,6 +100,7 @@ static struct {
{ "ff", ATH_DEBUG_FF },
{ "dfs", ATH_DEBUG_DFS },
{ "tdma", ATH_DEBUG_TDMA },
{ "tdma_timer", ATH_DEBUG_TDMA_TIMER },
{ "regdomain", ATH_DEBUG_REGDOMAIN },
{ "fatal", ATH_DEBUG_FATAL },
};

View File

@ -11,6 +11,7 @@ SRCDIR= ${.CURDIR}/../../../..
CLEANFILES+= opt_ah.h ah_osdep.h
CFLAGS+=-DATH_SUPPORT_ANI
CFLAGS+=-DATH_SUPPORT_TDMA
CFLAGS+=-I${.CURDIR}
CFLAGS+=-I${SRCDIR}/sys/net80211

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2002-2007 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
@ -215,7 +215,9 @@ static const struct fmt athstats[] = {
{ 5, "tdmab", "tdmab", "TDMA slot update set beacon timers" },
#define S_TDMA_TSF AFTER(S_TDMA_TIMERS)
{ 5, "tdmat", "tdmat", "TDMA slot update set TSF" },
#define S_RATE_CALLS AFTER(S_TDMA_TSF)
#define S_TDMA_TSFADJ AFTER(S_TDMA_TSF)
{ 8, "tdmadj", "tdmadj", "TDMA slot adjust (usecs, smoothed)" },
#define S_RATE_CALLS AFTER(S_TDMA_TSFADJ)
#else
#define S_RATE_CALLS AFTER(S_PER_RFGAIN)
#endif
@ -603,6 +605,10 @@ ath_get_curstat(struct statfoo *sf, int s, char b[], size_t bs)
case S_TDMA_UPDATE: STAT(tdma_update);
case S_TDMA_TIMERS: STAT(tdma_timers);
case S_TDMA_TSF: STAT(tdma_tsf);
case S_TDMA_TSFADJ:
snprintf(b, bs, "-%d/+%d",
wf->cur.ath.ast_tdma_tsfadjm, wf->cur.ath.ast_tdma_tsfadjp);
return 1;
#endif
case S_RATE_CALLS: STAT(rate_calls);
case S_RATE_RAISE: STAT(rate_raise);
@ -813,6 +819,11 @@ ath_get_totstat(struct statfoo *sf, int s, char b[], size_t bs)
case S_TDMA_UPDATE: STAT(tdma_update);
case S_TDMA_TIMERS: STAT(tdma_timers);
case S_TDMA_TSF: STAT(tdma_tsf);
case S_TDMA_TSFADJ:
snprintf(b, bs, "-%d/+%d",
wf->total.ath.ast_tdma_tsfadjm,
wf->total.ath.ast_tdma_tsfadjp);
return 1;
#endif
case S_RATE_CALLS: STAT(rate_calls);
case S_RATE_RAISE: STAT(rate_raise);

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2002-2007 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
@ -59,6 +59,9 @@ static struct {
{ "ani",
"avgbrssi,avgrssi,avgtxrssi,NI,SI,step,owsd,cwst,NI+,NI-,SI+,SI-,OFDM,CCK,LISTEN"
},
{ "tdma",
"input,output,bexmit,tdmau,tdmadj,crcerr,phyerr,phytor,rssi,noise,rate"
},
};
static const char *

View File

@ -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
@ -77,7 +77,7 @@ const char *progname;
#define IEEE80211_MSG_ACTION 0x00000010 /* action frame handling */
#define IEEE80211_MSG_WDS 0x00000008 /* WDS handling */
#define IEEE80211_MSG_IOCTL 0x00000004 /* ioctl handling */
#define IEEE80211_MSG_ADDBA 0x00000002 /* ADDBA handling */
#define IEEE80211_MSG_TDMA 0x00000002 /* TDMA handling */
static struct {
const char *name;
@ -113,7 +113,7 @@ static struct {
{ "action", IEEE80211_MSG_ACTION },
{ "wds", IEEE80211_MSG_WDS },
{ "ioctl", IEEE80211_MSG_IOCTL },
{ "addba", IEEE80211_MSG_ADDBA },
{ "tdma", IEEE80211_MSG_TDMA },
};
static u_int