Update 802.11 wireless support:

o major overhaul of the way channels are handled: channels are now
  fully enumerated and uniquely identify the operating characteristics;
  these changes are visible to user applications which require changes
o make scanning support independent of the state machine to enable
  background scanning and roaming
o move scanning support into loadable modules based on the operating
  mode to enable different policies and reduce the memory footprint
  on systems w/ constrained resources
o add background scanning in station mode (no support for adhoc/ibss
  mode yet)
o significantly speedup sta mode scanning with a variety of techniques
o add roaming support when background scanning is supported; for now
  we use a simple algorithm to trigger a roam: we threshold the rssi
  and tx rate, if either drops too low we try to roam to a new ap
o add tx fragmentation support
o add first cut at 802.11n support: this code works with forthcoming
  drivers but is incomplete; it's included now to establish a baseline
  for other drivers to be developed and for user applications
o adjust max_linkhdr et. al. to reflect 802.11 requirements; this eliminates
  prepending mbufs for traffic generated locally
o add support for Atheros protocol extensions; mainly the fast frames
  encapsulation (note this can be used with any card that can tx+rx
  large frames correctly)
o add sta support for ap's that beacon both WPA1+2 support
o change all data types from bsd-style to posix-style
o propagate noise floor data from drivers to net80211 and on to user apps
o correct various issues in the sta mode state machine related to handling
  authentication and association failures
o enable the addition of sta mode power save support for drivers that need
  net80211 support (not in this commit)
o remove old WI compatibility ioctls (wicontrol is officially dead)
o change the data structures returned for get sta info and get scan
  results so future additions will not break user apps
o fixed tx rate is now maintained internally as an ieee rate and not an
  index into the rate set; this needs to be extended to deal with
  multi-mode operation
o add extended channel specifications to radiotap to enable 11n sniffing

Drivers:
o ath: add support for bg scanning, tx fragmentation, fast frames,
       dynamic turbo (lightly tested), 11n (sniffing only and needs
       new hal)
o awi: compile tested only
o ndis: lightly tested
o ipw: lightly tested
o iwi: add support for bg scanning (well tested but may have some
       rough edges)
o ral, ural, rum: add suppoort for bg scanning, calibrate rssi data
o wi: lightly tested

This work is based on contributions by Atheros, kmacy, sephe, thompsa,
mlaier, kevlo, and others.  Much of the scanning work was supported by
Atheros.  The 11n work was supported by Marvell.
This commit is contained in:
Sam Leffler 2007-06-11 03:36:55 +00:00
parent ad7a4c3acd
commit 68e8e04e93
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=170530
69 changed files with 13053 additions and 4878 deletions

View File

@ -786,6 +786,8 @@ device wlan_tkip #802.11 TKIP support
device wlan_xauth #802.11 external authenticator support
device wlan_acl #802.11 MAC ACL support
device wlan_amrr #AMRR transmit rate control algorithm
device wlan_scan_ap #802.11 AP mode scanning
device wlan_scan_sta #802.11 STA mode scanning
device token #Generic TokenRing
device fddi #Generic FDDI
device arcnet #Generic Arcnet

View File

@ -1613,11 +1613,17 @@ net80211/ieee80211_crypto_none.c optional wlan
net80211/ieee80211_crypto_tkip.c optional wlan_tkip
net80211/ieee80211_crypto_wep.c optional wlan_wep
net80211/ieee80211_freebsd.c optional wlan
net80211/ieee80211_ht.c optional wlan
net80211/ieee80211_input.c optional wlan
net80211/ieee80211_ioctl.c optional wlan
net80211/ieee80211_node.c optional wlan
net80211/ieee80211_output.c optional wlan
net80211/ieee80211_power.c optional wlan
net80211/ieee80211_proto.c optional wlan
net80211/ieee80211_regdomain.c optional wlan
net80211/ieee80211_scan.c optional wlan
net80211/ieee80211_scan_ap.c optional wlan_scan_ap
net80211/ieee80211_scan_sta.c optional wlan_scan_sta
net80211/ieee80211_xauth.c optional wlan_xauth
netatalk/aarp.c optional netatalk
netatalk/at_control.c optional netatalk

View File

@ -297,27 +297,27 @@ ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
/* NB: the rate set is assumed sorted */
for (; srate >= 0 && RATE(srate) > 72; srate--)
;
KASSERT(srate >= 0, ("bogus rate set"));
}
} else {
/*
* A fixed rate is to be used; ic_fixed_rate is an
* index into the supported rate set. Convert this
* A fixed rate is to be used; ic_fixed_rate is the
* IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node. We know the rate is there because the
* rate set is checked when the station associates.
*/
const struct ieee80211_rateset *rs =
&ic->ic_sup_rates[ic->ic_curmode];
int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
for (; srate >= 0 && RATE(srate) != r; srate--)
for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
KASSERT(srate >= 0,
("fixed rate %d not in rate set", ic->ic_fixed_rate));
}
ath_rate_update(sc, ni, srate);
/*
* The selected rate may not be available due to races
* and mode settings. Also orphaned nodes created in
* adhoc mode may not have any rate set so this lookup
* can fail. This is not fatal.
*/
ath_rate_update(sc, ni, srate < 0 ? 0 : srate);
#undef RATE
}

View File

@ -274,27 +274,27 @@ ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
/* NB: the rate set is assumed sorted */
for (; srate >= 0 && RATE(srate) > 72; srate--)
;
KASSERT(srate >= 0, ("bogus rate set"));
}
} else {
/*
* A fixed rate is to be used; ic_fixed_rate is an
* index into the supported rate set. Convert this
* A fixed rate is to be used; ic_fixed_rate is the
* IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node. We know the rate is there because the
* rate set is checked when the station associates.
*/
const struct ieee80211_rateset *rs =
&ic->ic_sup_rates[ic->ic_curmode];
int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
for (; srate >= 0 && RATE(srate) != r; srate--)
for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
KASSERT(srate >= 0,
("fixed rate %d not in rate set", ic->ic_fixed_rate));
}
ath_rate_update(sc, ni, srate);
/*
* The selected rate may not be available due to races
* and mode settings. Also orphaned nodes created in
* adhoc mode may not have any rate set so this lookup
* can fail. This is not fatal.
*/
ath_rate_update(sc, ni, srate < 0 ? 0 : srate);
#undef RATE
}

View File

@ -32,6 +32,7 @@
* 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 DAMAGES.
*
*/
#include <sys/cdefs.h>
@ -680,21 +681,23 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
sn->static_rate_ndx = -1;
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
/*
* A fixed rate is to be used; ic_fixed_rate is an
* index into the supported rate set. Convert this
* A fixed rate is to be used; ic_fixed_rate is the
* IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node.
*/
const struct ieee80211_rateset *rs =
&ic->ic_sup_rates[ic->ic_curmode];
int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
for (; srate >= 0 && RATE(srate) != r; srate--)
for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
KASSERT(srate >= 0,
("fixed rate %d not in rate set", ic->ic_fixed_rate));
sn->static_rate_ndx = srate;
/*
* The fixed rate may not be available due to races
* and mode settings. Also orphaned nodes created in
* adhoc mode may not have any rate set so this lookup
* can fail.
*/
if (srate >= 0)
sn->static_rate_ndx = srate;
}
DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s size 1600 rate/tt",

File diff suppressed because it is too large Load Diff

View File

@ -69,8 +69,8 @@ struct ath_stats {
u_int32_t ast_tx_shortpre;/* tx frames with short preamble */
u_int32_t ast_tx_altrate; /* tx frames with alternate rate */
u_int32_t ast_tx_protect; /* tx frames with protection */
u_int32_t ast_unused1;
u_int32_t ast_unused2;
u_int32_t ast_tx_ctsburst;/* tx frames with cts and bursting */
u_int32_t ast_tx_ctsext; /* tx frames with cts extension */
u_int32_t ast_rx_nombuf; /* rx setup failed 'cuz no mbuf */
u_int32_t ast_rx_busdma; /* rx setup failed for dma resrcs */
u_int32_t ast_rx_orn; /* rx failed 'cuz of desc overrun */
@ -87,7 +87,6 @@ struct ath_stats {
u_int32_t ast_rx_ctl; /* rx discarded 'cuz ctl frame */
int8_t ast_tx_rssi; /* tx rssi of last ack */
int8_t ast_rx_rssi; /* rx rssi from histogram */
int8_t ast_rx_noise; /* rx noise floor */
u_int8_t ast_tx_rate; /* IEEE rate of last unicast tx */
u_int32_t ast_be_xmit; /* beacons transmitted */
u_int32_t ast_be_nombuf; /* beacon setup failed 'cuz no mbuf */
@ -104,7 +103,13 @@ struct ath_stats {
u_int32_t ast_cabq_xmit; /* cabq frames transmitted */
u_int32_t ast_cabq_busy; /* cabq found busy */
u_int32_t ast_tx_raw; /* tx frames through raw api */
u_int32_t ast_pad[29];
u_int32_t ast_ff_txok; /* fast frames tx'd successfully */
u_int32_t ast_ff_txerr; /* fast frames tx'd w/ error */
u_int32_t ast_ff_rx; /* fast frames rx'd */
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];
};
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
@ -131,10 +136,10 @@ struct ath_diag {
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
(1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct ath_rx_radiotap_header {
@ -142,20 +147,23 @@ struct ath_rx_radiotap_header {
u_int64_t wr_tsf;
u_int8_t wr_flags;
u_int8_t wr_rate;
u_int16_t wr_chan_freq;
u_int16_t wr_chan_flags;
u_int8_t wr_antsignal;
u_int8_t wr_antnoise;
int8_t wr_antsignal;
int8_t wr_antnoise;
u_int8_t wr_antenna;
};
u_int8_t wr_pad[3];
u_int32_t wr_chan_flags;
u_int16_t wr_chan_freq;
u_int8_t wr_chan_ieee;
int8_t wr_chan_maxpow;
} __packed;
#define ATH_TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct ath_tx_radiotap_header {
@ -163,10 +171,12 @@ struct ath_tx_radiotap_header {
u_int64_t wt_tsf;
u_int8_t wt_flags;
u_int8_t wt_rate;
u_int16_t wt_chan_freq;
u_int16_t wt_chan_flags;
u_int8_t wt_txpower;
u_int8_t wt_antenna;
};
u_int32_t wt_chan_flags;
u_int16_t wt_chan_freq;
u_int8_t wt_chan_ieee;
int8_t wt_chan_maxpow;
} __packed;
#endif /* _DEV_ATH_ATHIOCTL_H */

View File

@ -35,8 +35,6 @@
#ifndef _DEV_ATH_ATHVAR_H
#define _DEV_ATH_ATHVAR_H
#include <sys/taskqueue.h>
#include <contrib/dev/ath/ah.h>
#include <contrib/dev/ath/ah_desc.h>
#include <net80211/ieee80211_radiotap.h>
@ -49,7 +47,7 @@
#define ATH_RXBUF 40 /* number of RX buffers */
#endif
#ifndef ATH_TXBUF
#define ATH_TXBUF 100 /* number of TX buffers */
#define ATH_TXBUF 200 /* number of TX buffers */
#endif
#define ATH_TXDESC 10 /* number of descriptors per buffer */
#define ATH_TXMAXTRY 11 /* max number of transmit attempts */
@ -71,10 +69,19 @@
#define ATH_KEYMAX 128 /* max key cache size we handle */
#define ATH_KEYBYTES (ATH_KEYMAX/NBBY) /* storage space in bytes */
#define ATH_FF_TXQMIN 2 /* min txq depth for staging */
#define ATH_FF_TXQMAX 50 /* maximum # of queued frames allowed */
#define ATH_FF_STAGEMAX 5 /* max waiting period for staged frame*/
struct taskqueue;
struct kthread;
struct ath_buf;
/* driver-specific node state */
struct ath_node {
struct ieee80211_node an_node; /* base class */
u_int32_t an_avgrssi; /* average rssi over all rx frames */
struct ath_buf *an_ff_buf[WME_NUM_AC]; /* ff staging area */
/* variable-length rate control state follows */
};
#define ATH_NODE(ni) ((struct ath_node *)(ni))
@ -93,6 +100,8 @@ struct ath_node {
struct ath_buf {
STAILQ_ENTRY(ath_buf) bf_list;
TAILQ_ENTRY(ath_buf) bf_stagelist; /* stage queue list */
u_int32_t bf_age; /* age when placed on stageq */
int bf_nseg;
int bf_flags; /* tx descriptor flags */
struct ath_desc *bf_desc; /* virtual addr of desc */
@ -138,6 +147,13 @@ struct ath_txq {
STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */
struct mtx axq_lock; /* lock on q and link */
char axq_name[12]; /* e.g. "ath0_txq4" */
/*
* Fast-frame state. The staging queue holds awaiting
* a fast-frame pairing. Buffers on this queue are
* assigned an ``age'' and flushed when they wait too long.
*/
TAILQ_HEAD(axq_headtype, ath_buf) axq_stageq;
u_int32_t axq_curage; /* queue age */
};
#define ATH_TXQ_LOCK_INIT(_sc, _tq) do { \
@ -153,6 +169,7 @@ struct ath_txq {
#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \
(_tq)->axq_curage++; \
} while (0)
#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
@ -172,7 +189,7 @@ struct ath_softc {
void (*sc_recv_mgmt)(struct ieee80211com *,
struct mbuf *,
struct ieee80211_node *,
int, int, u_int32_t);
int, int, int, u_int32_t);
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*sc_node_free)(struct ieee80211_node *);
@ -196,10 +213,12 @@ struct ath_softc {
sc_ledstate: 1, /* LED on/off state */
sc_blinking: 1, /* LED blink operation active */
sc_mcastkey: 1, /* mcast key cache search */
sc_scanning: 1, /* scanning active */
sc_syncbeacon:1,/* sync/resync beacon timers */
sc_hasclrkey:1, /* CLR key supported */
sc_xchanmode: 1,/* extended channel mode */
sc_outdoor : 1;/* outdoor operation */
sc_outdoor : 1,/* outdoor operation */
sc_dturbo : 1; /* dynamic turbo in use */
/* rate tables */
#define IEEE80211_MODE_HALF (IEEE80211_MODE_MAX+0)
#define IEEE80211_MODE_QUARTER (IEEE80211_MODE_MAX+1)
@ -208,7 +227,9 @@ struct ath_softc {
enum ieee80211_phymode sc_curmode; /* current phy mode */
HAL_OPMODE sc_opmode; /* current operating mode */
u_int16_t sc_curtxpow; /* current tx power limit */
u_int16_t sc_curaid; /* current association id */
HAL_CHANNEL sc_curchan; /* current h/w channel */
u_int8_t sc_curbssid[IEEE80211_ADDR_LEN];
u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */
struct {
u_int8_t ieeerate; /* IEEE rate */
@ -220,7 +241,10 @@ struct ath_softc {
u_int8_t sc_minrateix; /* min h/w rate index */
u_int8_t sc_mcastrix; /* mcast h/w rate index */
u_int8_t sc_protrix; /* protection rate index */
u_int8_t sc_lastdatarix; /* last data frame rate index */
u_int sc_mcastrate; /* ieee rate for mcastrateix */
u_int sc_fftxqmin; /* min frames before staging */
u_int sc_fftxqmax; /* max frames before drop */
u_int sc_txantenna; /* tx antenna (fixed or auto) */
HAL_INT sc_imask; /* interrupt mask copy */
u_int sc_keymax; /* size of key cache */
@ -253,6 +277,7 @@ struct ath_softc {
struct ath_descdma sc_rxdma; /* RX descriptos */
ath_bufhead sc_rxbuf; /* receive buffer */
struct mbuf *sc_rxpending; /* pending receive data */
u_int32_t *sc_rxlink; /* link ptr in last RX desc */
struct task sc_rxtask; /* rx int processing */
struct task sc_rxorntask; /* rxorn int processing */
@ -264,7 +289,6 @@ struct ath_softc {
ath_bufhead sc_txbuf; /* transmit buffer */
struct mtx sc_txbuflock; /* txbuf lock */
char sc_txname[12]; /* e.g. "ath0_buf" */
int sc_tx_timer; /* transmit timeout */
u_int sc_txqsetup; /* h/w queues setup */
u_int sc_txintrperiod;/* tx interrupt batching */
struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
@ -291,7 +315,6 @@ struct ath_softc {
int sc_calinterval; /* current polling interval */
int sc_caltries; /* cals at current interval */
HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */
struct callout sc_scan_ch; /* callout handle for scan */
struct callout sc_dfs_ch; /* callout handle for dfs */
};
#define sc_tx_th u_tx_rt.th
@ -418,7 +441,7 @@ void ath_intr(void *);
((*(_ah)->ah_getDiagState)((_ah), (_id), \
(_indata), (_insize), (_outdata), (_outsize)))
#define ath_hal_getfatalstate(_ah, _outdata, _outsize) \
ath_hal_getdiagstate(_ah, 29, NULL, 0, (void **)(_outdata), _outsize)
ath_hal_getdiagstate(_ah, 29, NULL, 0, (_outdata), _outsize)
#define ath_hal_setuptxqueue(_ah, _type, _irq) \
((*(_ah)->ah_setupTxQueue)((_ah), (_type), (_irq)))
#define ath_hal_resettxqueue(_ah, _q) \
@ -517,6 +540,8 @@ void ath_intr(void *);
#else
#define ath_hal_getmcastkeysearch(_ah) 0
#endif
#define ath_hal_hasfastframes(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK)
#define ath_hal_hasrfsilent(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK)
#define ath_hal_getrfkill(_ah) \
@ -535,15 +560,8 @@ void ath_intr(void *);
(ath_hal_getcapability(_ah, HAL_CAP_TPC_CTS, 0, _ptpcts) == HAL_OK)
#define ath_hal_settpcts(_ah, _tpcts) \
ath_hal_setcapability(_ah, HAL_CAP_TPC_CTS, 0, _tpcts, NULL)
#if HAL_ABI_VERSION < 0x05120700
#define ath_hal_process_noisefloor(_ah)
#define ath_hal_getchannoise(_ah, _c) (-96)
#define HAL_CAP_TPC_ACK 100
#define HAL_CAP_TPC_CTS 101
#else
#define ath_hal_getchannoise(_ah, _c) \
((*(_ah)->ah_getChanNoise)((_ah), (_c)))
#endif
#if HAL_ABI_VERSION < 0x05122200
#define HAL_TXQ_TXOKINT_ENABLE TXQ_FLAG_TXOKINT_ENABLE
#define HAL_TXQ_TXERRINT_ENABLE TXQ_FLAG_TXERRINT_ENABLE
@ -561,6 +579,14 @@ void ath_intr(void *);
#define ath_hal_isgsmsku(ah) \
((ah)->ah_countryCode == 843)
#endif
#if HAL_ABI_VERSION < 0x07050400
/* compat shims so code compilers--it won't work though */
#define CHANNEL_HT20 0x10000
#define CHANNEL_HT40PLUS 0x20000
#define CHANNEL_HT40MINUS 0x40000
#define HAL_MODE_11NG_HT20 0x008000
#define HAL_MODE_11NA_HT20 0x010000
#endif
#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))

View File

@ -181,7 +181,7 @@ static int awi_intr_lock(struct awi_softc *);
static void awi_intr_unlock(struct awi_softc *);
static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int);
static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, int, u_int32_t);
struct ieee80211_node *, int, int, int, u_int32_t);
static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int,
int);
static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *);
@ -525,9 +525,10 @@ awi_intr(void *arg)
if (status & AWI_INT_CMD)
awi_cmd_done(sc);
if (status & AWI_INT_SCAN_CMPLT) {
/* XXX revisit scanning */
if (sc->sc_ic.ic_state == IEEE80211_S_SCAN &&
sc->sc_substate == AWI_ST_NONE)
ieee80211_next_scan(&sc->sc_ic);
;
}
}
sc->sc_cansleep = ocansleep;
@ -589,6 +590,7 @@ awi_init(struct ifnet *ifp)
sc->sc_mib_local.Acting_as_AP = 1;
break;
case IEEE80211_M_MONITOR:
case IEEE80211_M_WDS:
return ENODEV;
}
#if 0
@ -596,9 +598,9 @@ awi_init(struct ifnet *ifp)
#endif
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen;
memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid,
ic->ic_des_esslen);
sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_ssid[0].len;
memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_ssid[0].ssid,
ic->ic_des_ssid[0].len);
/* configure basic rate */
if (ic->ic_phytype == IEEE80211_T_FH)
@ -606,7 +608,7 @@ awi_init(struct ifnet *ifp)
else
rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
rate = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
rate = ic->ic_fixed_rate;
} else {
rate = 0;
for (i = 0; i < rs->rs_nrates; i++) {
@ -659,18 +661,18 @@ awi_init(struct ifnet *ifp)
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
ic->ic_opmode == IEEE80211_M_HOSTAP) {
ni->ni_chan = ic->ic_ibss_chan;
ni->ni_chan = ic->ic_des_chan; /* XXX? */
ni->ni_intval = ic->ic_bintval;
ni->ni_rssi = 0;
ni->ni_rstamp = 0;
memset(&ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
ni->ni_rates =
ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
ic->ic_sup_rates[ieee80211_chan2mode(ni->ni_chan)];
IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
ni->ni_esslen = ic->ic_des_esslen;
memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
ni->ni_esslen = ic->ic_des_ssid[0].len;
memcpy(ni->ni_essid, ic->ic_des_ssid[0].ssid, ni->ni_esslen);
ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
if (ic->ic_phytype == IEEE80211_T_FH) {
ni->ni_fhdwell = 200; /* XXX */
@ -812,7 +814,7 @@ awi_start(struct ifnet *ifp)
goto bad;
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m0->m_flags & M_PWR_SAV) == 0) {
ieee80211_pwrsave(ic, ni, m0);
ieee80211_pwrsave(ni, m0);
continue;
}
m0 = ieee80211_encap(ic, m0, ni);
@ -865,7 +867,7 @@ awi_start(struct ifnet *ifp)
#endif
if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2))
ieee80211_dump_pkt(m0->m_data, m0->m_len,
ieee80211_dump_pkt(ic, m0->m_data, m0->m_len,
ic->ic_bss->ni_rates.
rs_rates[ic->ic_bss->ni_txrate] &
IEEE80211_RATE_VAL, -1);
@ -930,7 +932,6 @@ awi_watchdog(struct ifnet *ifp)
ifp->if_timer = 1;
}
/* TODO: rate control */
ieee80211_watchdog(&sc->sc_ic);
out:
sc->sc_cansleep = ocansleep;
}
@ -1016,6 +1017,7 @@ awi_media_change(struct ifnet *ifp)
ime = ic->ic_media.ifm_cur;
if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
i = -1;
rate = ic->ic_fixed_rate;
} else {
struct ieee80211_rateset *rs =
&ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH)
@ -1030,8 +1032,8 @@ awi_media_change(struct ifnet *ifp)
if (i == rs->rs_nrates)
return EINVAL;
}
if (ic->ic_fixed_rate != i) {
ic->ic_fixed_rate = i;
if (ic->ic_fixed_rate != rate) {
ic->ic_fixed_rate = rate;
error = ENETRESET;
}
@ -1098,12 +1100,12 @@ awi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rate = 0;
else
rate = ic->ic_sup_rates[mode].
rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
rate = ic->ic_fixed_rate;
}
imr->ifm_active |= ieee80211_rate2media(ic, rate, mode);
switch (ic->ic_opmode) {
case IEEE80211_M_MONITOR: /* we should never reach here */
case IEEE80211_M_WDS:
break;
case IEEE80211_M_STA:
break;
@ -1240,7 +1242,8 @@ awi_rx_int(struct awi_softc *sc)
}
if ((ifp->if_flags & IFF_DEBUG) &&
(ifp->if_flags & IFF_LINK2))
ieee80211_dump_pkt(m->m_data, m->m_len,
ieee80211_dump_pkt(ic,
m->m_data, m->m_len,
rate / 5, rssi);
if ((ifp->if_flags & IFF_LINK0) ||
sc->sc_adhoc_ap)
@ -1254,7 +1257,8 @@ awi_rx_int(struct awi_softc *sc)
}
ni = ieee80211_find_rxnode(ic,
mtod(m, struct ieee80211_frame_min *));
ieee80211_input(ic, m, ni, rssi, rstamp);
/* XXX 0 for noise floor */
ieee80211_input(ic, m, ni, rssi, 0, rstamp);
ieee80211_free_node(ni);
} else
sc->sc_rxpend = m;
@ -1337,7 +1341,6 @@ awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len)
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = len;
m->m_len = MHLEN;
m->m_flags |= M_HASFCS;
} else {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
@ -1367,6 +1370,10 @@ awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len)
*mp = m;
mp = &m->m_next;
}
if (top != NULL) {
/* Strip trailing 802.11 MAC FCS. */
m_adj(top, -IEEE80211_CRC_LEN);
}
return top;
}
@ -1534,7 +1541,7 @@ awi_init_mibs(struct awi_softc *sc)
}
}
sc->sc_cur_chan = cs->cs_def;
ic->ic_ibss_chan = &ic->ic_channels[cs->cs_def];
ic->ic_curchan = &ic->ic_channels[cs->cs_def]; /* XXX? */
sc->sc_mib_local.Fragmentation_Dis = 1;
sc->sc_mib_local.Add_PLCP_Dis = 0;
@ -1942,7 +1949,7 @@ awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
case IEEE80211_S_INIT:
ieee80211_begin_scan(ic, 0);
/* XXX revisit scanning */;
break;
case IEEE80211_S_SCAN:
/* scan next */
@ -2112,14 +2119,14 @@ awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
static void
awi_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni,
int subtype, int rssi, u_int32_t rstamp)
int subtype, int rssi, int nf, u_int32_t rstamp)
{
struct awi_softc *sc = ic->ic_ifp->if_softc;
/* probe request is handled by hardware */
if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_REQ)
return;
(*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, rstamp);
(*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, nf, rstamp);
}
static int

View File

@ -92,7 +92,7 @@ struct awi_softc {
enum ieee80211_state, int);
void (*sc_recv_mgmt)(struct ieee80211com *,
struct mbuf *, struct ieee80211_node *,
int, int, u_int32_t);
int, int, int, u_int32_t);
int (*sc_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);

View File

@ -478,7 +478,7 @@ ndis_attach(dev)
device_object *pdo;
struct ifnet *ifp = NULL;
int error = 0, len;
int i;
int i, j;
sc = device_get_softc(dev);
#if __FreeBSD_version < 600031
@ -817,10 +817,11 @@ ndis_attach(dev)
}
#undef SETRATE
#undef INCRATE
ic->ic_nchans = 12;
/*
* Taking yet more guesses here.
*/
for (i = 1; i < IEEE80211_CHAN_MAX; i++) {
for (j = 0, i = 1; i <= 12; i++, j++) {
int chanflag = 0;
if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
@ -829,12 +830,11 @@ ndis_attach(dev)
chanflag |= IEEE80211_CHAN_B;
if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
i > 14)
chanflag = IEEE80211_CHAN_A;
chanflag = IEEE80211_CHAN_A;
if (chanflag == 0)
break;
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, chanflag);
ic->ic_channels[i].ic_flags = chanflag;
ic->ic_channels[j].ic_freq = ieee80211_ieee2mhz(i, chanflag);
ic->ic_channels[j].ic_flags = chanflag;
}
/*
@ -897,8 +897,8 @@ ndis_attach(dev)
ieee80211_media_init(ic, ieee80211_media_change,
ndis_media_status);
#endif
ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
ic->ic_bsschan = IEEE80211_CHAN_ANYC;
ic->ic_bss->ni_chan = ic->ic_bsschan;
#ifdef IEEE80211_F_WPA
/* install key handing routines */
ic->ic_crypto.cs_key_set = ndis_add_key;
@ -2392,16 +2392,16 @@ ndis_setstate_80211(sc)
config.nc_atimwin = 100;
if (config.nc_fhconfig.ncf_dwelltime == 0)
config.nc_fhconfig.ncf_dwelltime = 200;
if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) {
if (rval == 0 && ic->ic_bsschan != IEEE80211_CHAN_ANYC) {
int chan, chanflag;
chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
chan = ieee80211_chan2ieee(ic, ic->ic_bsschan);
chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
IEEE80211_CHAN_5GHZ;
if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
config.nc_dsconfig =
ic->ic_ibss_chan->ic_freq * 1000;
ic->ic_bss->ni_chan = ic->ic_ibss_chan;
ic->ic_bsschan->ic_freq * 1000;
ic->ic_bss->ni_chan = ic->ic_bsschan;
len = sizeof(config);
config.nc_length = len;
config.nc_fhconfig.ncf_length =
@ -2447,11 +2447,11 @@ ndis_setstate_80211(sc)
len = sizeof(ssid);
bzero((char *)&ssid, len);
ssid.ns_ssidlen = ic->ic_des_esslen;
ssid.ns_ssidlen = ic->ic_des_ssid[0].len;
if (ssid.ns_ssidlen == 0) {
ssid.ns_ssidlen = 1;
} else
bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
bcopy(ic->ic_des_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen);
rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
@ -2497,6 +2497,9 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
break;
case IEEE80211_M_WDS:
printf("WARNING: WDS operation mode not supported by NDIS\n");
break;
}
switch (ic->ic_curmode) {
case IEEE80211_MODE_11A:
@ -2682,7 +2685,7 @@ ndis_getstate_80211(sc)
ic->ic_bss->ni_chan = &ic->ic_channels[chan];
ic->ic_des_chan = &ic->ic_channels[chan];
ic->ic_ibss_chan = &ic->ic_channels[chan];
ic->ic_bsschan = &ic->ic_channels[chan];
#if __FreeBSD_version >= 600007
ic->ic_curchan = &ic->ic_channels[chan];
#endif
@ -3190,6 +3193,8 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
bcopy((char *)wb->nwbx_ies +
sizeof(struct ndis_80211_fixed_ies),
cp, sr->isr_ie_len);
} else {
sr->isr_ie_len = 0;
}
sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len
+ sr->isr_ie_len, sizeof(uint32_t));

View File

@ -197,6 +197,7 @@ ipw_attach(device_t dev)
struct ipw_softc *sc = device_get_softc(dev);
struct ifnet *ifp;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_channel *c;
uint16_t val;
int error, i;
@ -287,11 +288,17 @@ ipw_attach(device_t dev)
ic->ic_myaddr[4] = val >> 8;
ic->ic_myaddr[5] = val & 0xff;
/* set supported .11b channels */
for (i = 1; i < 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
/* set supported .11b channels (read from EEPROM) */
if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0)
val = 0x7ff; /* default to channels 1-11 */
val <<= 1;
for (i = 1; i < 16; i++) {
if (val & (1 << i)) {
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
c->ic_flags = IEEE80211_CHAN_B;
c->ic_ieee = i;
}
}
/* check support for radio transmitter switch in EEPROM */
@ -791,6 +798,7 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_WDS:
/* should not get there */
break;
}
@ -802,7 +810,6 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ifnet *ifp = ic->ic_ifp;
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211_node *ni;
uint8_t macaddr[IEEE80211_ADDR_LEN];
uint32_t len;
@ -813,6 +820,7 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
len = IEEE80211_ADDR_LEN;
ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
#if 0
ni = ieee80211_find_node(&ic->ic_scan, macaddr);
if (ni == NULL)
break;
@ -823,6 +831,7 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
if (ic->ic_opmode == IEEE80211_M_STA)
ieee80211_notify_node_join(ic, ni, 1);
#endif
break;
case IEEE80211_S_INIT:
@ -980,7 +989,9 @@ ipw_fix_channel(struct ieee80211com *ic, struct mbuf *m)
#if IEEE80211_CHAN_MAX < 255
if (frm[2] <= IEEE80211_CHAN_MAX)
#endif
ic->ic_curchan = &ic->ic_channels[frm[2]];
ic->ic_bsschan = ieee80211_find_channel(ic,
ieee80211_ieee2mhz(frm[2], 0),
IEEE80211_MODE_AUTO);
frm += frm[1] + 2;
}
@ -1069,7 +1080,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
ieee80211_input(ic, m, ni, status->rssi, 0);
ieee80211_input(ic, m, ni, status->rssi, -95/*XXX*/, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@ -1162,6 +1173,8 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
bus_dmamap_unload(sc->txbuf_dmat, sbuf->map);
SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
if (sbuf->m->m_flags & M_TXCB)
ieee80211_process_callback(sbuf->ni, sbuf->m, 0/*XXX*/);
m_freem(sbuf->m);
ieee80211_free_node(sbuf->ni);
@ -1514,7 +1527,6 @@ static void
ipw_watchdog(struct ifnet *ifp)
{
struct ipw_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
mtx_lock(&sc->sc_mtx);
@ -1532,8 +1544,6 @@ ipw_watchdog(struct ifnet *ifp)
ifp->if_timer = 1;
}
ieee80211_watchdog(ic);
mtx_unlock(&sc->sc_mtx);
}
@ -1744,6 +1754,7 @@ ipw_config(struct ipw_softc *sc)
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
case IEEE80211_M_HOSTAP:
case IEEE80211_M_WDS: /* XXX */
data = htole32(IPW_MODE_BSS);
break;
case IEEE80211_M_IBSS:
@ -1839,8 +1850,8 @@ ipw_config(struct ipw_softc *sc)
printf("\n");
}
#endif
error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_essid,
ic->ic_des_esslen);
error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_ssid[0].ssid,
ic->ic_des_ssid[0].len);
if (error != 0)
return error;

File diff suppressed because it is too large Load Diff

View File

@ -213,7 +213,7 @@ struct iwi_notif_authentication {
/* structure for notification IWI_NOTIF_TYPE_ASSOCIATION */
struct iwi_notif_association {
uint8_t state;
#define IWI_ASSOC_FAIL 0
#define IWI_ASSOC_INIT 0
#define IWI_ASSOC_SUCCESS 12
uint8_t pad[11];
} __packed;
@ -417,6 +417,10 @@ struct iwi_scan {
#define IWI_SCAN_TYPE_BDIRECTED 4 /* active, directed+bcast probe */
#define IWI_SCAN_TYPES 5
/* scan result codes */
#define IWI_SCAN_COMPLETED 1 /* scan compeleted sucessfully */
#define IWI_SCAN_ABORTED 2 /* scan was aborted by the driver */
/* structure for command IWI_CMD_SCAN_EXT */
struct iwi_scan_ext {
uint32_t full_scan_index;

View File

@ -123,6 +123,8 @@ struct iwi_softc {
device_t sc_dev;
struct mtx sc_mtx;
struct mtx sc_cmdlock;
char sc_cmdname[12]; /* e.g. "iwi0_cmd" */
uint8_t sc_mcast[IEEE80211_ADDR_LEN];
struct unrhdr *sc_unr;
struct taskqueue *sc_tq; /* private task queue */
@ -132,11 +134,15 @@ struct iwi_softc {
uint32_t flags;
#define IWI_FLAG_FW_INITED (1 << 0)
#define IWI_FLAG_SCANNING (1 << 1)
#define IWI_FLAG_FW_LOADING (1 << 2)
#define IWI_FLAG_BUSY (1 << 3) /* busy sending a command */
#define IWI_FLAG_ASSOCIATED (1 << 4) /* currently associated */
#define IWI_FLAG_CHANNEL_SCAN (1 << 5)
uint32_t fw_state;
#define IWI_FW_IDLE 0
#define IWI_FW_LOADING 1
#define IWI_FW_ASSOCIATING 2
#define IWI_FW_DISASSOCIATING 3
#define IWI_FW_SCANNING 4
struct iwi_cmd_ring cmdq;
struct iwi_tx_ring txq[WME_NUM_AC];
struct iwi_rx_ring rxq;
@ -176,20 +182,16 @@ struct iwi_softc {
int curchan; /* current h/w channel # */
int antenna;
int dwelltime;
int bluetooth;
struct iwi_associate assoc;
struct iwi_wme_params wme[3];
u_int sc_scangen;
struct task sc_radiontask; /* radio on processing */
struct task sc_radiofftask; /* radio off processing */
struct task sc_scanstarttask;/* scan start processing */
struct task sc_scanaborttask;/* scan abort processing */
struct task sc_scandonetask;/* scan completed processing */
struct task sc_scantask; /* scan channel processing */
struct task sc_setwmetask; /* set wme params processing */
struct task sc_downtask; /* disassociate processing */
struct task sc_scanaborttask; /* cancel active scan */
struct task sc_restarttask; /* restart adapter processing */
struct task sc_opstask; /* scan / auth processing */
unsigned int sc_softled : 1, /* enable LED gpio status */
sc_ledstate: 1, /* LED on/off state */
@ -204,11 +206,26 @@ struct iwi_softc {
u_int8_t sc_txrix;
u_int16_t sc_ledoff; /* off time for current blink */
struct callout sc_ledtimer; /* led off timer */
struct callout sc_wdtimer; /* watchdog timer */
int sc_tx_timer;
int sc_rfkill_timer;/* poll for rfkill change */
int sc_scan_timer; /* scan request timeout */
int sc_state_timer; /* firmware state timer */
int sc_busy_timer; /* firmware cmd timer */
#define IWI_SCAN_START (1 << 0)
#define IWI_SET_CHANNEL (1 << 1)
#define IWI_SCAN_END (1 << 2)
#define IWI_ASSOC (1 << 3)
#define IWI_DISASSOC (1 << 4)
#define IWI_SCAN_CURCHAN (1 << 5)
#define IWI_SCAN_ALLCHAN (1 << 6)
#define IWI_SET_WME (1 << 7)
#define IWI_CMD_MAXOPS 10
int sc_cmd[IWI_CMD_MAXOPS];
int sc_cmd_cur; /* current queued scan task */
int sc_cmd_next; /* last queued scan task */
unsigned long sc_maxdwell; /* max dwell time for curchan */
struct bpf_if *sc_drvbpf;
union {
@ -226,15 +243,34 @@ struct iwi_softc {
int sc_txtap_len;
};
#define IWI_STATE_BEGIN(_sc, _state) do { \
KASSERT(_sc->fw_state == IWI_FW_IDLE, \
("iwi firmware not idle")); \
_sc->fw_state = _state; \
_sc->sc_state_timer = 5; \
DPRINTF(("enter FW state %d\n", _state)); \
} while (0)
#define IWI_STATE_END(_sc, _state) do { \
if (_sc->fw_state == _state) \
DPRINTF(("exit FW state %d\n", _state)); \
else \
DPRINTF(("expected FW state %d, got %d\n", \
_state, _sc->fw_state)); \
_sc->fw_state = IWI_FW_IDLE; \
wakeup(_sc); \
_sc->sc_state_timer = 0; \
} while (0)
/*
* NB.: This models the only instance of async locking in iwi_init_locked
* and must be kept in sync.
*/
#define IWI_LOCK_INIT(sc) \
mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \
MTX_NETWORK_LOCK, MTX_DEF)
#define IWI_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
#define IWI_LOCK_DECL int __waslocked = 0
#define IWI_LOCK_CHECK(sc) do { \
if (!mtx_owned(&(sc)->sc_mtx)) \
DPRINTF(("%s iwi_lock not held\n", __func__)); \
} while (0)
#define IWI_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
#define IWI_LOCK(sc) do { \
if (!(__waslocked = mtx_owned(&(sc)->sc_mtx))) \
mtx_lock(&(sc)->sc_mtx); \
@ -243,3 +279,11 @@ struct iwi_softc {
if (!__waslocked) \
mtx_unlock(&(sc)->sc_mtx); \
} while (0)
#define IWI_CMD_LOCK_INIT(sc) do { \
snprintf((sc)->sc_cmdname, sizeof((sc)->sc_cmdname), "%s_cmd", \
device_get_nameunit((sc)->sc_dev)); \
mtx_init(&(sc)->sc_cmdlock, (sc)->sc_cmdname, NULL, MTX_DEF); \
} while (0)
#define IWI_CMD_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_cmdlock)
#define IWI_CMD_LOCK(sc) mtx_lock(&(sc)->sc_cmdlock)
#define IWI_CMD_UNLOCK(sc) mtx_unlock(&(sc)->sc_cmdlock)

View File

@ -87,8 +87,8 @@ static struct ral_opns {
} ral_rt2560_opns = {
rt2560_attach,
rt2560_detach,
rt2560_shutdown,
rt2560_suspend,
rt2560_stop,
rt2560_stop,
rt2560_resume,
rt2560_intr
@ -192,7 +192,8 @@ ral_pci_attach(device_t dev)
sc->sc_st = rman_get_bustag(psc->mem);
sc->sc_sh = rman_get_bushandle(psc->mem);
sc->sc_invalid = 1;
psc->irq_rid = 0;
psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid,
RF_ACTIVE | RF_SHAREABLE);
@ -214,7 +215,8 @@ ral_pci_attach(device_t dev)
device_printf(dev, "could not set up interrupt\n");
return error;
}
sc->sc_invalid = 0;
return 0;
}
@ -222,7 +224,11 @@ static int
ral_pci_detach(device_t dev)
{
struct ral_pci_softc *psc = device_get_softc(dev);
struct rt2560_softc *sc = &psc->u.sc_rt2560;
/* check if device was removed */
sc->sc_invalid = !bus_child_present(dev);
(*psc->sc_opns->detach)(psc);
bus_generic_detach(dev);

View File

@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@ -64,6 +65,10 @@ __FBSDID("$FreeBSD$");
#include <dev/ral/rt2560reg.h>
#include <dev/ral/rt2560var.h>
#define RT2560_RSSI(sc, rssi) \
((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \
((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0)
#ifdef RAL_DEBUG
#define DPRINTF(x) do { if (ral_debug > 0) printf x; } while (0)
#define DPRINTFN(n, x) do { if (ral_debug >= (n)) printf x; } while (0)
@ -90,7 +95,6 @@ static void rt2560_free_rx_ring(struct rt2560_softc *,
static struct ieee80211_node *rt2560_node_alloc(
struct ieee80211_node_table *);
static int rt2560_media_change(struct ifnet *);
static void rt2560_next_scan(void *);
static void rt2560_iter_func(void *, struct ieee80211_node *);
static void rt2560_update_rssadapt(void *);
static int rt2560_newstate(struct ieee80211com *,
@ -105,6 +109,9 @@ static void rt2560_beacon_expire(struct rt2560_softc *);
static void rt2560_wakeup_expire(struct rt2560_softc *);
static uint8_t rt2560_rxrate(struct rt2560_rx_desc *);
static int rt2560_ack_rate(struct ieee80211com *, int);
static void rt2560_scan_start(struct ieee80211com *);
static void rt2560_scan_end(struct ieee80211com *);
static void rt2560_set_channel(struct ieee80211com *);
static uint16_t rt2560_txtime(int, int, uint32_t);
static uint8_t rt2560_plcp_signal(int);
static void rt2560_setup_tx_desc(struct rt2560_softc *,
@ -137,7 +144,7 @@ static void rt2560_update_plcp(struct rt2560_softc *);
static void rt2560_update_slot(struct ifnet *);
static void rt2560_set_basicrates(struct rt2560_softc *);
static void rt2560_update_led(struct rt2560_softc *, int, int);
static void rt2560_set_bssid(struct rt2560_softc *, uint8_t *);
static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *);
static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *);
static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *);
static void rt2560_update_promisc(struct rt2560_softc *);
@ -147,7 +154,6 @@ static int rt2560_bbp_init(struct rt2560_softc *);
static void rt2560_set_txantenna(struct rt2560_softc *, int);
static void rt2560_set_rxantenna(struct rt2560_softc *, int);
static void rt2560_init(void *);
static void rt2560_stop(void *);
static int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
@ -187,7 +193,7 @@ rt2560_attach(device_t dev, int id)
struct rt2560_softc *sc = device_get_softc(dev);
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp;
int error, i;
int error, bands;
sc->sc_dev = dev;
@ -195,7 +201,6 @@ rt2560_attach(device_t dev, int id)
MTX_DEF | MTX_RECURSE);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE);
/* retrieve RT2560 rev. no */
@ -272,37 +277,20 @@ rt2560_attach(device_t dev, int id)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_BGSCAN | /* bg scanning support */
IEEE80211_C_WPA; /* 802.11i */
if (sc->rf_rev == RT2560_RF_5222) {
/* set supported .11a channels */
for (i = 36; i <= 64; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 100; i <= 140; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 149; i <= 161; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
}
/* set supported .11b and .11g channels (1 through 14) */
for (i = 1; i <= 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
ic->ic_channels[i].ic_flags =
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
if (sc->rf_rev == RT2560_RF_5222)
setbit(&bands, IEEE80211_MODE_11A);
ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_scan_start = rt2560_scan_start;
ic->ic_scan_end = rt2560_scan_end;
ic->ic_set_channel = rt2560_set_channel;
ic->ic_node_alloc = rt2560_node_alloc;
ic->ic_updateslot = rt2560_update_slot;
ic->ic_reset = rt2560_reset;
@ -365,10 +353,9 @@ rt2560_detach(void *xsc)
struct rt2560_softc *sc = xsc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
rt2560_stop(sc);
callout_stop(&sc->watchdog_ch);
callout_stop(&sc->scan_ch);
callout_stop(&sc->rssadapt_ch);
bpfdetach(ifp);
@ -387,22 +374,6 @@ rt2560_detach(void *xsc)
return 0;
}
void
rt2560_shutdown(void *xsc)
{
struct rt2560_softc *sc = xsc;
rt2560_stop(sc);
}
void
rt2560_suspend(void *xsc)
{
struct rt2560_softc *sc = xsc;
rt2560_stop(sc);
}
void
rt2560_resume(void *xsc)
{
@ -733,28 +704,13 @@ rt2560_media_change(struct ifnet *ifp)
int error;
error = ieee80211_media_change(ifp);
if (error != ENETRESET)
return error;
if ((ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING))
rt2560_init(sc);
return 0;
}
/*
* This function is called periodically (every 200ms) during scanning to
* switch from one channel to another.
*/
static void
rt2560_next_scan(void *arg)
{
struct rt2560_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
if (error == ENETRESET) {
if ((ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING))
rt2560_init(sc);
}
return error;
}
/*
@ -796,7 +752,6 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
int error = 0;
ostate = ic->ic_state;
callout_stop(&sc->scan_ch);
switch (nstate) {
case IEEE80211_S_INIT:
@ -810,24 +765,7 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2560_update_led(sc, 0, 0);
}
break;
case IEEE80211_S_SCAN:
rt2560_set_chan(sc, ic->ic_curchan);
callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000,
rt2560_next_scan, sc);
break;
case IEEE80211_S_AUTH:
rt2560_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_ASSOC:
rt2560_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_RUN:
rt2560_set_chan(sc, ic->ic_curchan);
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@ -862,6 +800,10 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2560_enable_tsf_sync(sc);
}
break;
case IEEE80211_S_SCAN:
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
break;
}
return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
@ -1060,6 +1002,9 @@ rt2560_prio_intr(struct rt2560_softc *sc)
struct ifnet *ifp = ic->ic_ifp;
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct ieee80211_node *ni;
struct mbuf *m;
int flags;
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
BUS_DMASYNC_POSTREAD);
@ -1068,18 +1013,18 @@ rt2560_prio_intr(struct rt2560_softc *sc)
desc = &sc->prioq.desc[sc->prioq.next];
data = &sc->prioq.data[sc->prioq.next];
if ((le32toh(desc->flags) & RT2560_TX_BUSY) ||
!(le32toh(desc->flags) & RT2560_TX_VALID))
flags = le32toh(desc->flags);
if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0)
break;
switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) {
switch (flags & RT2560_TX_RESULT_MASK) {
case RT2560_TX_SUCCESS:
DPRINTFN(10, ("mgt frame sent successfully\n"));
break;
case RT2560_TX_SUCCESS_RETRY:
DPRINTFN(9, ("mgt frame sent after %u retries\n",
(le32toh(desc->flags) >> 5) & 0x7));
(flags >> 5) & 0x7));
break;
case RT2560_TX_FAIL_RETRY:
@ -1091,15 +1036,17 @@ rt2560_prio_intr(struct rt2560_softc *sc)
case RT2560_TX_FAIL_OTHER:
default:
device_printf(sc->sc_dev, "sending mgt frame failed "
"0x%08x\n", le32toh(desc->flags));
"0x%08x\n", flags);
break;
}
bus_dmamap_sync(sc->prioq.data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->prioq.data_dmat, data->map);
m_freem(data->m);
m = data->m;
data->m = NULL;
ieee80211_free_node(data->ni);
ni = data->ni;
data->ni = NULL;
/* descriptor is no longer valid */
@ -1109,6 +1056,13 @@ rt2560_prio_intr(struct rt2560_softc *sc)
sc->prioq.queued--;
sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT;
if (m->m_flags & M_TXCB)
ieee80211_process_callback(ni, m,
(flags & RT2560_TX_RESULT_MASK) &~
(RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY));
m_freem(m);
ieee80211_free_node(ni);
}
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
@ -1227,25 +1181,31 @@ rt2560_decryption_intr(struct rt2560_softc *sc)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
tap->wr_antsignal = desc->rssi;
tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
sc->sc_flags |= RAL_INPUT_RUNNING;
RAL_UNLOCK(sc);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic,
(struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
ieee80211_input(ic, m, ni, desc->rssi, 0);
ieee80211_input(ic, m, ni, RT2560_RSSI(sc, desc->rssi),
RT2560_NOISE_FLOOR, 0);
/* give rssi to the rate adatation algorithm */
rn = (struct rt2560_node *)ni;
ral_rssadapt_input(ic, ni, &rn->rssadapt, desc->rssi);
ral_rssadapt_input(ic, ni, &rn->rssadapt,
RT2560_RSSI(sc, desc->rssi));
/* node is no longer needed */
ieee80211_free_node(ni);
RAL_LOCK(sc);
sc->sc_flags &= ~RAL_INPUT_RUNNING;
skip: desc->flags = htole32(RT2560_RX_BUSY);
DPRINTFN(15, ("decryption done idx=%u\n", sc->rxq.cur_decrypt));
@ -1324,9 +1284,14 @@ rt2560_beacon_expire(struct rt2560_softc *sc)
if (ic->ic_opmode != IEEE80211_M_IBSS &&
ic->ic_opmode != IEEE80211_M_HOSTAP)
return;
return;
data = &sc->bcnq.data[sc->bcnq.next];
/*
* Don't send beacon if bsschan isn't set
*/
if (data->ni == NULL)
return;
bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->bcnq.data_dmat, data->map);
@ -1808,7 +1773,6 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct rt2560_node *rn;
struct ieee80211_rateset *rs;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
struct mbuf *mnew;
@ -1820,9 +1784,10 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
rs = &ic->ic_sup_rates[ic->ic_curmode];
rate = rs->rs_rates[ic->ic_fixed_rate];
rate = ic->ic_fixed_rate;
} else {
struct ieee80211_rateset *rs;
rs = &ni->ni_rates;
rn = (struct rt2560_node *)ni;
ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh,
@ -2020,9 +1985,10 @@ rt2560_start(struct ifnet *ifp)
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
if (rt2560_tx_mgt(sc, m0, ni) != 0)
if (rt2560_tx_mgt(sc, m0, ni) != 0) {
ieee80211_free_node(ni);
break;
}
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
@ -2045,6 +2011,28 @@ rt2560_start(struct ifnet *ifp)
m_freem(m0);
continue;
}
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m0->m_flags & M_PWR_SAV) == 0) {
/*
* Station in power save mode; pass the frame
* to the 802.11 layer and continue. We'll get
* the frame back when the time is right.
*/
ieee80211_pwrsave(ni, m0);
/*
* If we're in power save mode 'cuz of a bg
* scan cancel it so the traffic can flow.
* The packet we just queued will automatically
* get sent when we drop out of power save.
* XXX locking
*/
if (ic->ic_flags & IEEE80211_F_SCAN)
ieee80211_cancel_scan(ic);
ieee80211_free_node(ni);
continue;
}
BPF_MTAP(ifp, m0);
m0 = ieee80211_encap(ic, m0, ni);
@ -2052,7 +2040,7 @@ rt2560_start(struct ifnet *ifp)
ieee80211_free_node(ni);
continue;
}
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
@ -2074,7 +2062,6 @@ static void
rt2560_watchdog(void *arg)
{
struct rt2560_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
@ -2085,8 +2072,6 @@ rt2560_watchdog(void *arg)
}
callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc);
}
ieee80211_watchdog(ic);
}
/*
@ -2115,19 +2100,22 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ieee80211com *ic = &sc->sc_ic;
int error = 0;
RAL_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
RAL_LOCK(sc);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2560_update_promisc(sc);
else
rt2560_init(sc);
RAL_UNLOCK(sc);
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2560_stop(sc);
}
break;
default:
@ -2142,7 +2130,6 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
}
RAL_UNLOCK(sc);
return error;
}
@ -2295,6 +2282,8 @@ rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c)
rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4);
break;
default:
printf("unknown ral rev=%d\n", sc->rf_rev);
}
if (ic->ic_state != IEEE80211_S_SCAN) {
@ -2312,6 +2301,18 @@ rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c)
}
}
static void
rt2560_set_channel(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2560_softc *sc = ifp->if_softc;
RAL_LOCK(sc);
rt2560_set_chan(sc, ic->ic_curchan);
RAL_UNLOCK(sc);
}
#if 0
/*
* Disable RF auto-tuning.
@ -2456,7 +2457,7 @@ rt2560_update_led(struct rt2560_softc *sc, int led1, int led2)
}
static void
rt2560_set_bssid(struct rt2560_softc *sc, uint8_t *bssid)
rt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid)
{
uint32_t tmp;
@ -2559,6 +2560,37 @@ rt2560_read_eeprom(struct rt2560_softc *sc)
sc->txpow[i * 2] = val >> 8;
sc->txpow[i * 2 + 1] = val & 0xff;
}
val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE);
if ((val & 0xff) == 0xff)
sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR;
else
sc->rssi_corr = val & 0xff;
DPRINTF(("rssi correction %d, calibrate 0x%02x\n",
sc->rssi_corr, val));
}
static void
rt2560_scan_start(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2560_softc *sc = ifp->if_softc;
/* abort TSF synchronization */
RAL_WRITE(sc, RT2560_CSR14, 0);
rt2560_set_bssid(sc, ifp->if_broadcastaddr);
}
static void
rt2560_scan_end(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2560_softc *sc = ifp->if_softc;
rt2560_enable_tsf_sync(sc);
/* XXX keep local copy */
rt2560_set_bssid(sc, ic->ic_bss->ni_bssid);
}
static int
@ -2653,10 +2685,11 @@ rt2560_init(void *priv)
uint32_t tmp;
int i;
RAL_LOCK(sc);
rt2560_stop(sc);
RAL_LOCK(sc);
/* setup tx rings */
tmp = RT2560_PRIO_RING_COUNT << 24 |
RT2560_ATIM_RING_COUNT << 16 |
@ -2739,36 +2772,44 @@ rt2560_init(void *priv)
}
void
rt2560_stop(void *priv)
rt2560_stop(void *arg)
{
struct rt2560_softc *sc = priv;
struct rt2560_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
volatile int *flags = &sc->sc_flags;
sc->sc_tx_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
while (*flags & RAL_INPUT_RUNNING) {
tsleep(sc, 0, "ralrunning", hz/10);
}
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
RAL_LOCK(sc);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
sc->sc_tx_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
/* abort Tx */
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX);
/* abort Tx */
RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX);
/* disable Rx */
RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX);
/* disable Rx */
RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX);
/* reset ASIC (imply reset BBP) */
RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
RAL_WRITE(sc, RT2560_CSR1, 0);
/* reset ASIC (imply reset BBP) */
RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
RAL_WRITE(sc, RT2560_CSR1, 0);
/* disable interrupts */
RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
/* reset Tx and Rx rings */
rt2560_reset_tx_ring(sc, &sc->txq);
rt2560_reset_tx_ring(sc, &sc->atimq);
rt2560_reset_tx_ring(sc, &sc->prioq);
rt2560_reset_tx_ring(sc, &sc->bcnq);
rt2560_reset_rx_ring(sc, &sc->rxq);
/* disable interrupts */
RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
/* reset Tx and Rx rings */
rt2560_reset_tx_ring(sc, &sc->txq);
rt2560_reset_tx_ring(sc, &sc->atimq);
rt2560_reset_tx_ring(sc, &sc->prioq);
rt2560_reset_tx_ring(sc, &sc->bcnq);
rt2560_reset_rx_ring(sc, &sc->rxq);
}
RAL_UNLOCK(sc);
}
static int
@ -2828,3 +2869,4 @@ rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
RAL_UNLOCK(sc);
return EIO; /* XXX */
}

View File

@ -17,6 +17,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RT2560_DEFAULT_RSSI_CORR 0x79
#define RT2560_NOISE_FLOOR -95
#define RT2560_TX_RING_COUNT 48
#define RT2560_ATIM_RING_COUNT 4
#define RT2560_PRIO_RING_COUNT 16
@ -296,6 +299,7 @@ struct rt2560_rx_desc {
#define RT2560_EEPROM_CONFIG0 16
#define RT2560_EEPROM_BBP_BASE 19
#define RT2560_EEPROM_TXPOWER 35
#define RT2560_EEPROM_CALIBRATE 62
/*
* control and status registers access macros

View File

@ -109,14 +109,18 @@ struct rt2560_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
struct callout scan_ch;
struct callout rssadapt_ch;
int sc_tx_timer;
int sc_invalid;
/*
* The same in both up to here
* ------------------------------------------------
*/
uint32_t asic_rev;
uint32_t eeprom_rev;
uint8_t rf_rev;
uint8_t rssi_corr;
struct rt2560_tx_ring txq;
struct rt2560_tx_ring prioq;
@ -157,12 +161,13 @@ struct rt2560_softc {
} sc_txtapu;
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
#define RAL_INPUT_RUNNING 1
int sc_flags;
};
int rt2560_attach(device_t, int);
int rt2560_detach(void *);
void rt2560_shutdown(void *);
void rt2560_suspend(void *);
void rt2560_stop(void *);
void rt2560_resume(void *);
void rt2560_intr(void *);

View File

@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@ -92,7 +93,6 @@ static void rt2661_free_rx_ring(struct rt2661_softc *,
static struct ieee80211_node *rt2661_node_alloc(
struct ieee80211_node_table *);
static int rt2661_media_change(struct ifnet *);
static void rt2661_next_scan(void *);
static int rt2661_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static uint16_t rt2661_eeprom_read(struct rt2661_softc *, uint8_t);
@ -104,6 +104,9 @@ static void rt2661_mcu_beacon_expire(struct rt2661_softc *);
static void rt2661_mcu_wakeup(struct rt2661_softc *);
static void rt2661_mcu_cmd_intr(struct rt2661_softc *);
static int rt2661_ack_rate(struct ieee80211com *, int);
static void rt2661_scan_start(struct ieee80211com *);
static void rt2661_scan_end(struct ieee80211com *);
static void rt2661_set_channel(struct ieee80211com *);
static uint16_t rt2661_txtime(int, int, uint32_t);
static uint8_t rt2661_rxrate(struct rt2661_rx_desc *);
static uint8_t rt2661_plcp_signal(int);
@ -148,6 +151,7 @@ static void rt2661_read_eeprom(struct rt2661_softc *);
static int rt2661_bbp_init(struct rt2661_softc *);
static void rt2661_init(void *);
static void rt2661_stop(void *);
static void rt2661_stop_locked(struct rt2661_softc *);
static int rt2661_load_microcode(struct rt2661_softc *,
const uint8_t *, int);
#ifdef notyet
@ -190,7 +194,7 @@ rt2661_attach(device_t dev, int id)
struct ifnet *ifp;
uint32_t val;
const uint8_t *ucode = NULL;
int error, i, ac, ntries, size = 0;
int bands, error, ac, ntries, size = 0;
sc->sc_dev = dev;
@ -198,7 +202,6 @@ rt2661_attach(device_t dev, int id)
MTX_DEF | MTX_RECURSE);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE);
/* wait for NIC to initialize */
@ -302,39 +305,22 @@ rt2661_attach(device_t dev, int id)
#ifdef notyet
IEEE80211_C_WME | /* 802.11e */
#endif
IEEE80211_C_BGSCAN | /* bg scanning support */
IEEE80211_C_WPA; /* 802.11i */
if (sc->rf_rev == RT2661_RF_5225 || sc->rf_rev == RT2661_RF_5325) {
/* set supported .11a channels */
for (i = 36; i <= 64; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 100; i <= 140; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 149; i <= 165; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
}
/* set supported .11b and .11g channels (1 through 14) */
for (i = 1; i <= 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
ic->ic_channels[i].ic_flags =
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
if (sc->rf_rev == RT2661_RF_5225 || sc->rf_rev == RT2661_RF_5325)
setbit(&bands, IEEE80211_MODE_11A);
ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_node_alloc = rt2661_node_alloc;
/* ic->ic_wme.wme_update = rt2661_wme_update;*/
ic->ic_scan_start = rt2661_scan_start;
ic->ic_scan_end = rt2661_scan_end;
ic->ic_set_channel = rt2661_set_channel;
ic->ic_updateslot = rt2661_update_slot;
ic->ic_reset = rt2661_reset;
/* enable s/w bmiss handling in sta mode */
@ -356,6 +342,7 @@ rt2661_attach(device_t dev, int id)
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
sc->sc_txtap.wt_ihdr.it_present = htole32(RT2661_TX_RADIOTAP_PRESENT);
/*
* Add a few sysctl knobs.
*/
@ -376,7 +363,6 @@ fail3: rt2661_free_tx_ring(sc, &sc->mgtq);
fail2: while (--ac >= 0)
rt2661_free_tx_ring(sc, &sc->txq[ac]);
fail1: mtx_destroy(&sc->sc_mtx);
return error;
}
@ -386,10 +372,9 @@ rt2661_detach(void *xsc)
struct rt2661_softc *sc = xsc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
rt2661_stop(sc);
callout_stop(&sc->watchdog_ch);
callout_stop(&sc->scan_ch);
callout_stop(&sc->rssadapt_ch);
bpfdetach(ifp);
@ -758,20 +743,6 @@ rt2661_media_change(struct ifnet *ifp)
return 0;
}
/*
* This function is called periodically (every 200ms) during scanning to
* switch from one channel to another.
*/
static void
rt2661_next_scan(void *arg)
{
struct rt2661_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
}
/*
* This function is called for each node present in the node station table.
*/
@ -811,7 +782,6 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
int error = 0;
ostate = ic->ic_state;
callout_stop(&sc->scan_ch);
switch (nstate) {
case IEEE80211_S_INIT:
@ -823,21 +793,7 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0x00ffffff);
}
break;
case IEEE80211_S_SCAN:
rt2661_set_chan(sc, ic->ic_curchan);
callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000,
rt2661_next_scan, sc);
break;
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
rt2661_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_RUN:
rt2661_set_chan(sc, ic->ic_curchan);
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@ -859,6 +815,10 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2661_enable_tsf_sync(sc);
}
break;
case IEEE80211_S_SCAN:
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
break;
}
return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
@ -934,6 +894,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
int qid, retrycnt;
for (;;) {
struct ieee80211_node *ni;
struct mbuf *m;
val = RAL_READ(sc, RT2661_STA_CSR4);
if (!(val & RT2661_TX_STAT_VALID))
break;
@ -944,12 +907,17 @@ rt2661_tx_intr(struct rt2661_softc *sc)
/* retrieve rate control algorithm context */
data = &txq->data[txq->stat];
rn = (struct rt2661_node *)data->ni;
m = data->m;
data->m = NULL;
ni = data->ni;
data->ni = NULL;
/* if no frame has been sent, ignore */
if (rn == NULL)
if (ni == NULL)
continue;
rn = (struct rt2661_node *)ni;
switch (RT2661_TX_RESULT(val)) {
case RT2661_TX_SUCCESS:
retrycnt = RT2661_TX_RETRYCNT(val);
@ -967,7 +935,7 @@ rt2661_tx_intr(struct rt2661_softc *sc)
DPRINTFN(9, ("sending data frame failed (too much "
"retries)\n"));
if (data->id.id_node != NULL) {
ral_rssadapt_lower_rate(ic, data->ni,
ral_rssadapt_lower_rate(ic, ni,
&rn->rssadapt, &data->id);
}
ifp->if_oerrors++;
@ -980,14 +948,17 @@ rt2661_tx_intr(struct rt2661_softc *sc)
ifp->if_oerrors++;
}
ieee80211_free_node(data->ni);
data->ni = NULL;
DPRINTFN(15, ("tx done q=%d idx=%u\n", qid, txq->stat));
txq->queued--;
if (++txq->stat >= txq->count) /* faster than % count */
txq->stat = 0;
if (m->m_flags & M_TXCB)
ieee80211_process_callback(ni, m,
RT2661_TX_RESULT(val) != RT2661_TX_SUCCESS);
m_freem(m);
ieee80211_free_node(ni);
}
sc->sc_tx_timer = 0;
@ -1014,9 +985,6 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2661_tx_ring *txq)
bus_dmamap_sync(txq->data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(txq->data_dmat, data->map);
m_freem(data->m);
data->m = NULL;
/* node reference is released in rt2661_tx_intr() */
/* descriptor is no longer valid */
desc->flags &= ~htole32(RT2661_TX_VALID);
@ -1048,6 +1016,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
BUS_DMASYNC_POSTREAD);
for (;;) {
int rssi;
desc = &sc->rxq.desc[sc->rxq.cur];
data = &sc->rxq.data[sc->rxq.cur];
@ -1120,6 +1090,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
m->m_pkthdr.len = m->m_len =
(le32toh(desc->flags) >> 16) & 0xfff;
rssi = rt2661_get_rssi(sc, desc->rssi);
if (bpf_peers_present(sc->sc_drvbpf)) {
struct rt2661_rx_radiotap_header *tap = &sc->sc_rxtap;
uint32_t tsf_lo, tsf_hi;
@ -1134,22 +1106,28 @@ rt2661_rx_intr(struct rt2661_softc *sc)
tap->wr_rate = rt2661_rxrate(desc);
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antsignal = desc->rssi;
tap->wr_antsignal = rssi < 0 ? 0 : rssi;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
sc->sc_flags |= RAL_INPUT_RUNNING;
RAL_UNLOCK(sc);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic,
(struct ieee80211_frame_min *)wh);
/* Error happened during RSSI conversion. */
if (rssi < 0)
rssi = ni->ni_rssi;
/* send the frame to the 802.11 layer */
ieee80211_input(ic, m, ni, desc->rssi, 0);
ieee80211_input(ic, m, ni, rssi, RT2661_NOISE_FLOOR, 0);
/* give rssi to the rate adatation algorithm */
rn = (struct rt2661_node *)ni;
ral_rssadapt_input(ic, ni, &rn->rssadapt,
rt2661_get_rssi(sc, desc->rssi));
RAL_LOCK(sc);
sc->sc_flags &= ~RAL_INPUT_RUNNING;
ral_rssadapt_input(ic, ni, &rn->rssadapt, rssi);
/* node is no longer needed */
ieee80211_free_node(ni);
@ -1556,7 +1534,6 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
struct rt2661_tx_desc *desc;
struct rt2661_tx_data *data;
struct rt2661_node *rn;
struct ieee80211_rateset *rs;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
const struct chanAccParams *cap;
@ -1569,9 +1546,10 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
rs = &ic->ic_sup_rates[ic->ic_curmode];
rate = rs->rs_rates[ic->ic_fixed_rate];
rate = ic->ic_fixed_rate;
} else {
struct ieee80211_rateset *rs;
rs = &ni->ni_rates;
rn = (struct rt2661_node *)ni;
ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs,
@ -1753,7 +1731,7 @@ rt2661_start(struct ifnet *ifp)
RAL_LOCK(sc);
/* prevent management frames from being sent if we're not ready */
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->sc_invalid) {
RAL_UNLOCK(sc);
return;
}
@ -1773,9 +1751,10 @@ rt2661_start(struct ifnet *ifp)
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
if (rt2661_tx_mgt(sc, m0, ni) != 0)
if (rt2661_tx_mgt(sc, m0, ni) != 0) {
ieee80211_free_node(ni);
break;
}
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
@ -1812,6 +1791,7 @@ rt2661_start(struct ifnet *ifp)
/* there is no place left in this ring */
IFQ_DRV_PREPEND(&ifp->if_snd, m0);
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
ieee80211_free_node(ni);
break;
}
@ -1845,9 +1825,8 @@ static void
rt2661_watchdog(void *arg)
{
struct rt2661_softc *sc = (struct rt2661_softc *)arg;
struct ieee80211com *ic = &sc->sc_ic;
if (sc->sc_tx_timer > 0) {
if (sc->sc_tx_timer > 0 && !sc->sc_invalid) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
rt2661_init(sc);
@ -1856,8 +1835,6 @@ rt2661_watchdog(void *arg)
}
callout_reset(&sc->watchdog_ch, hz, rt2661_watchdog, sc);
}
ieee80211_watchdog(ic);
}
/*
@ -1886,8 +1863,6 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ieee80211com *ic = &sc->sc_ic;
int error = 0;
RAL_LOCK(sc);
switch (cmd) {
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
@ -1913,8 +1888,6 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
}
RAL_UNLOCK(sc);
return error;
}
@ -2066,6 +2039,12 @@ rt2661_set_txpreamble(struct rt2661_softc *sc)
RAL_WRITE(sc, RT2661_TXRX_CSR4, tmp);
}
/*
* Supported rates for 802.11g. XXX should use ic_sup_rates.
*/
static const struct ieee80211_rateset rt2661_rateset_11g =
{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
static void
rt2661_set_basicrates(struct rt2661_softc *sc,
const struct ieee80211_rateset *rs)
@ -2373,10 +2352,18 @@ rt2661_read_eeprom(struct rt2661_softc *sc)
if ((val & 0xff) != 0xff)
sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */
/* Only [-10, 10] is valid */
if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10)
sc->rssi_2ghz_corr = 0;
val = rt2661_eeprom_read(sc, RT2661_EEPROM_RSSI_5GHZ_OFFSET);
if ((val & 0xff) != 0xff)
sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */
/* Only [-10, 10] is valid */
if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10)
sc->rssi_5ghz_corr = 0;
/* adjust RSSI correction for external low-noise amplifier */
if (sc->ext_2ghz_lna)
sc->rssi_2ghz_corr -= 14;
@ -2465,7 +2452,7 @@ rt2661_init(void *priv)
RAL_LOCK(sc);
rt2661_stop(sc);
rt2661_stop_locked(sc);
/* initialize Tx rings */
RAL_WRITE(sc, RT2661_AC1_BASE_CSR, sc->txq[1].physaddr);
@ -2525,13 +2512,13 @@ rt2661_init(void *priv)
}
if (ntries == 1000) {
printf("timeout waiting for BBP/RF to wakeup\n");
rt2661_stop(sc);
rt2661_stop_locked(sc);
RAL_UNLOCK(sc);
return;
}
if (rt2661_bbp_init(sc) != 0) {
rt2661_stop(sc);
rt2661_stop_locked(sc);
RAL_UNLOCK(sc);
return;
}
@ -2572,6 +2559,7 @@ rt2661_init(void *priv)
/* kick Rx */
RAL_WRITE(sc, RT2661_RX_CNTL_CSR, 1);
RAL_UNLOCK(sc);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@ -2582,7 +2570,7 @@ rt2661_init(void *priv)
} else
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
RAL_UNLOCK(sc);
#undef N
}
@ -2590,41 +2578,57 @@ void
rt2661_stop(void *priv)
{
struct rt2661_softc *sc = priv;
RAL_LOCK(sc);
rt2661_stop_locked(sc);
RAL_UNLOCK(sc);
}
void
rt2661_stop_locked(struct rt2661_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
uint32_t tmp;
volatile int *flags = &sc->sc_flags;
sc->sc_tx_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
while (*flags & RAL_INPUT_RUNNING) {
msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10);
}
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
/* abort Tx (for all 5 Tx rings) */
RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 0x1f << 16);
/* disable Rx (value remains after reset!) */
tmp = RAL_READ(sc, RT2661_TXRX_CSR0);
RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp | RT2661_DISABLE_RX);
/* reset ASIC */
RAL_WRITE(sc, RT2661_MAC_CSR1, 3);
RAL_WRITE(sc, RT2661_MAC_CSR1, 0);
/* disable interrupts */
RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0xffffffff);
RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff);
/* clear any pending interrupt */
RAL_WRITE(sc, RT2661_INT_SOURCE_CSR, 0xffffffff);
RAL_WRITE(sc, RT2661_MCU_INT_SOURCE_CSR, 0xffffffff);
/* reset Tx and Rx rings */
rt2661_reset_tx_ring(sc, &sc->txq[0]);
rt2661_reset_tx_ring(sc, &sc->txq[1]);
rt2661_reset_tx_ring(sc, &sc->txq[2]);
rt2661_reset_tx_ring(sc, &sc->txq[3]);
rt2661_reset_tx_ring(sc, &sc->mgtq);
rt2661_reset_rx_ring(sc, &sc->rxq);
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
sc->sc_tx_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
/* abort Tx (for all 5 Tx rings) */
RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 0x1f << 16);
/* disable Rx (value remains after reset!) */
tmp = RAL_READ(sc, RT2661_TXRX_CSR0);
RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp | RT2661_DISABLE_RX);
/* reset ASIC */
RAL_WRITE(sc, RT2661_MAC_CSR1, 3);
RAL_WRITE(sc, RT2661_MAC_CSR1, 0);
/* disable interrupts */
RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0xffffffff);
RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff);
/* clear any pending interrupt */
RAL_WRITE(sc, RT2661_INT_SOURCE_CSR, 0xffffffff);
RAL_WRITE(sc, RT2661_MCU_INT_SOURCE_CSR, 0xffffffff);
/* reset Tx and Rx rings */
rt2661_reset_tx_ring(sc, &sc->txq[0]);
rt2661_reset_tx_ring(sc, &sc->txq[1]);
rt2661_reset_tx_ring(sc, &sc->txq[2]);
rt2661_reset_tx_ring(sc, &sc->txq[3]);
rt2661_reset_tx_ring(sc, &sc->mgtq);
rt2661_reset_rx_ring(sc, &sc->rxq);
}
}
static int
@ -2858,7 +2862,17 @@ rt2661_get_rssi(struct rt2661_softc *sc, uint8_t raw)
lna = (raw >> 5) & 0x3;
agc = raw & 0x1f;
rssi = 2 * agc;
if (lna == 0) {
/*
* No mapping available.
*
* NB: Since RSSI is relative to noise floor, -1 is
* adequate for caller to know error happened.
*/
return -1;
}
rssi = (2 * agc) - RT2661_NOISE_FLOOR;
if (IEEE80211_IS_CHAN_2GHZ(sc->sc_curchan)) {
rssi += sc->rssi_2ghz_corr;
@ -2881,3 +2895,39 @@ rt2661_get_rssi(struct rt2661_softc *sc, uint8_t raw)
}
return rssi;
}
static void
rt2661_scan_start(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2661_softc *sc = ifp->if_softc;
uint32_t tmp;
/* abort TSF synchronization */
tmp = RAL_READ(sc, RT2661_TXRX_CSR9);
RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0xffffff);
rt2661_set_bssid(sc, ifp->if_broadcastaddr);
}
static void
rt2661_scan_end(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2661_softc *sc = ifp->if_softc;
rt2661_enable_tsf_sync(sc);
/* XXX keep local copy */
rt2661_set_bssid(sc, ic->ic_bss->ni_bssid);
}
static void
rt2661_set_channel(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct rt2661_softc *sc = ifp->if_softc;
RAL_LOCK(sc);
rt2661_set_chan(sc, ic->ic_curchan);
RAL_UNLOCK(sc);
}

View File

@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RT2661_NOISE_FLOOR -95
#define RT2661_TX_RING_COUNT 32
#define RT2661_MGT_RING_COUNT 32
#define RT2661_RX_RING_COUNT 64

View File

@ -102,11 +102,15 @@ struct rt2661_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
struct callout scan_ch;
struct callout rssadapt_ch;
int sc_tx_timer;
int sc_invalid;
/*
* The same in both up to here
* ------------------------------------------------
*/
struct ieee80211_channel *sc_curchan;
uint8_t rf_rev;
@ -159,6 +163,8 @@ struct rt2661_softc {
} sc_txtapu;
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
#define RAL_INPUT_RUNNING 1
int sc_flags;
};
int rt2661_attach(device_t, int);

View File

@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@ -128,8 +129,8 @@ static void rum_free_tx_list(struct rum_softc *);
static int rum_alloc_rx_list(struct rum_softc *);
static void rum_free_rx_list(struct rum_softc *);
static int rum_media_change(struct ifnet *);
static void rum_next_scan(void *);
static void rum_task(void *);
static void rum_scantask(void *);
static int rum_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static void rum_txeof(usbd_xfer_handle, usbd_private_handle,
@ -187,11 +188,15 @@ static int rum_load_microcode(struct rum_softc *, const u_char *,
static int rum_prepare_beacon(struct rum_softc *);
static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
static void rum_scan_start(struct ieee80211com *);
static void rum_scan_end(struct ieee80211com *);
static void rum_set_channel(struct ieee80211com *);
static int rum_get_rssi(struct rum_softc *, uint8_t);
static void rum_amrr_start(struct rum_softc *,
struct ieee80211_node *);
static void rum_amrr_timeout(void *);
static void rum_amrr_update(usbd_xfer_handle, usbd_private_handle,
usbd_status status);
usbd_status);
static const struct {
uint32_t reg;
@ -374,7 +379,7 @@ USB_ATTACH(rum)
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
int i, ntries, size;
int i, ntries, size, bands;
uint32_t tmp;
sc->sc_udev = uaa->device;
@ -426,9 +431,8 @@ USB_ATTACH(rum)
MTX_DEF | MTX_RECURSE);
usb_init_task(&sc->sc_task, rum_task, sc);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
usb_init_task(&sc->sc_scantask, rum_scantask, sc);
callout_init(&sc->watchdog_ch, 0);
callout_init(&sc->amrr_ch, 0);
/* retrieve RT2573 rev. no */
@ -490,42 +494,49 @@ USB_ATTACH(rum)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_BGSCAN | /* bg scanning supported */
IEEE80211_C_WPA; /* 802.11i */
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) {
struct ieee80211_channel *c;
/* set supported .11a channels */
for (i = 34; i <= 46; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
c->ic_flags = IEEE80211_CHAN_A;
c->ic_ieee = i;
}
for (i = 36; i <= 64; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
c->ic_flags = IEEE80211_CHAN_A;
c->ic_ieee = i;
}
for (i = 100; i <= 140; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
c->ic_flags = IEEE80211_CHAN_A;
c->ic_ieee = i;
}
for (i = 149; i <= 165; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
c->ic_flags = IEEE80211_CHAN_A;
c->ic_ieee = i;
}
}
/* set supported .11b and .11g channels (1 through 14) */
for (i = 1; i <= 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
ic->ic_channels[i].ic_flags =
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
ieee80211_ifattach(ic);
ic->ic_scan_start = rum_scan_start;
ic->ic_scan_end = rum_scan_end;
ic->ic_set_channel = rum_set_channel;
/* enable s/w bmiss handling in sta mode */
ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
@ -535,7 +546,9 @@ USB_ATTACH(rum)
ic->ic_raw_xmit = rum_raw_xmit;
ieee80211_media_init(ic, rum_media_change, ieee80211_media_status);
ieee80211_amrr_init(&sc->amrr, ic, 1, 10);
ieee80211_amrr_init(&sc->amrr, ic,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD);
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
@ -563,8 +576,8 @@ USB_DETACH(rum)
rum_stop(sc);
usb_rem_task(sc->sc_udev, &sc->sc_task);
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
callout_stop(&sc->watchdog_ch);
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
if (sc->amrr_xfer != NULL) {
@ -737,20 +750,6 @@ rum_media_change(struct ifnet *ifp)
return 0;
}
/*
* This function is called periodically (every 200ms) during scanning to
* switch from one channel to another.
*/
static void
rum_next_scan(void *arg)
{
struct rum_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
}
static void
rum_task(void *arg)
{
@ -773,22 +772,7 @@ rum_task(void *arg)
}
break;
case IEEE80211_S_SCAN:
rum_set_chan(sc, ic->ic_curchan);
callout_reset(&sc->scan_ch, hz / 5, rum_next_scan, sc);
break;
case IEEE80211_S_AUTH:
rum_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_ASSOC:
rum_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_RUN:
rum_set_chan(sc, ic->ic_curchan);
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@ -811,6 +795,8 @@ rum_task(void *arg)
ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rum_amrr_start(sc, ni);
break;
default:
break;
}
RUM_UNLOCK(sc);
@ -823,7 +809,6 @@ rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct rum_softc *sc = ic->ic_ifp->if_softc;
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
/* do it in a process context */
@ -851,6 +836,10 @@ rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct rum_softc *sc = data->sc;
struct ifnet *ifp = sc->sc_ic.ic_ifp;
if (data->m->m_flags & M_TXCB)
ieee80211_process_callback(data->ni, data->m,
status == USBD_NORMAL_COMPLETION ? 0 : ETIMEDOUT);
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
@ -891,7 +880,7 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct mbuf *mnew, *m;
int len;
int len, rssi;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
@ -938,6 +927,15 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
m->m_data = (caddr_t)(desc + 1);
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
rssi = rum_get_rssi(sc, desc->rssi);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* Error happened during RSSI conversion. */
if (rssi < 0)
rssi = ni->ni_rssi;
if (bpf_peers_present(sc->sc_drvbpf)) {
struct rum_rx_radiotap_header *tap = &sc->sc_rxtap;
@ -946,16 +944,13 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
tap->wr_antsignal = desc->rssi;
tap->wr_antsignal = rssi;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
ieee80211_input(ic, m, ni, desc->rssi, 0);
ieee80211_input(ic, m, ni, rssi, RT2573_NOISE_FLOOR, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@ -1293,7 +1288,7 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
rate = ic->ic_fixed_rate;
else
rate = ni->ni_rates.rs_rates[ni->ni_txrate];
@ -1378,8 +1373,6 @@ rum_start(struct ifnet *ifp)
struct mbuf *m0;
struct ether_header *eh;
RUM_LOCK(sc);
for (;;) {
IF_POLL(&ic->ic_mgtq, m0);
if (m0 != NULL) {
@ -1442,27 +1435,27 @@ rum_start(struct ifnet *ifp)
sc->sc_tx_timer = 5;
callout_reset(&sc->watchdog_ch, hz, rum_watchdog, sc);
}
RUM_UNLOCK(sc);
}
static void
rum_watchdog(void *arg)
{
struct rum_softc *sc = (struct rum_softc *)arg;
struct ieee80211com *ic = &sc->sc_ic;
struct rum_softc *sc = arg;
RUM_LOCK(sc);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
/*rum_init(ifp); XXX needs a process context! */
sc->sc_ifp->if_oerrors++;
RUM_UNLOCK(sc);
return;
}
callout_reset(&sc->watchdog_ch, hz, rum_watchdog, sc);
}
ieee80211_watchdog(ic);
RUM_UNLOCK(sc);
}
static int
@ -1984,11 +1977,24 @@ rum_read_eeprom(struct rum_softc *sc)
if ((val & 0xff) != 0xff)
sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */
/* Only [-10, 10] is valid */
if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10)
sc->rssi_2ghz_corr = 0;
rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2);
val = le16toh(val);
if ((val & 0xff) != 0xff)
sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */
/* Only [-10, 10] is valid */
if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10)
sc->rssi_5ghz_corr = 0;
if (sc->ext_2ghz_lna)
sc->rssi_2ghz_corr -= 14;
if (sc->ext_5ghz_lna)
sc->rssi_5ghz_corr -= 14;
DPRINTF(("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n",
sc->rssi_2ghz_corr, sc->rssi_5ghz_corr));
@ -2407,4 +2413,124 @@ rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc);
}
static void
rum_scan_start(struct ieee80211com *ic)
{
struct rum_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = RUM_SCAN_START;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
rum_scan_end(struct ieee80211com *ic)
{
struct rum_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = RUM_SCAN_END;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
rum_set_channel(struct ieee80211com *ic)
{
struct rum_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = RUM_SET_CHANNEL;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
rum_scantask(void *arg)
{
struct rum_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
uint32_t tmp;
RUM_LOCK(sc);
switch (sc->sc_scan_action) {
case RUM_SCAN_START:
/* abort TSF synchronization */
tmp = rum_read(sc, RT2573_TXRX_CSR9);
rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff);
rum_set_bssid(sc, ifp->if_broadcastaddr);
break;
case RUM_SCAN_END:
rum_enable_tsf_sync(sc);
/* XXX keep local copy */
rum_set_bssid(sc, ic->ic_bss->ni_bssid);
break;
case RUM_SET_CHANNEL:
mtx_lock(&Giant);
rum_set_chan(sc, ic->ic_curchan);
mtx_unlock(&Giant);
break;
default:
panic("unknown scan action %d\n", sc->sc_scan_action);
/* NEVER REACHED */
break;
}
RUM_UNLOCK(sc);
}
static int
rum_get_rssi(struct rum_softc *sc, uint8_t raw)
{
int lna, agc, rssi;
lna = (raw >> 5) & 0x3;
agc = raw & 0x1f;
if (lna == 0) {
/*
* No RSSI mapping
*
* NB: Since RSSI is relative to noise floor, -1 is
* adequate for caller to know error happened.
*/
return -1;
}
rssi = (2 * agc) - RT2573_NOISE_FLOOR;
if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)) {
rssi += sc->rssi_2ghz_corr;
if (lna == 1)
rssi -= 64;
else if (lna == 2)
rssi -= 74;
else if (lna == 3)
rssi -= 90;
} else {
rssi += sc->rssi_5ghz_corr;
if (!sc->ext_5ghz_lna && lna != 1)
rssi += 4;
if (lna == 1)
rssi -= 64;
else if (lna == 2)
rssi -= 86;
else if (lna == 3)
rssi -= 100;
}
return rssi;
}
DRIVER_MODULE(rum, uhub, rum_driver, rum_devclass, usbd_driver_load, 0);

View File

@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RT2573_NOISE_FLOOR -95
#define RT2573_TX_DESC_SIZE (sizeof (struct rum_tx_desc))
#define RT2573_RX_DESC_SIZE (sizeof (struct rum_rx_desc))

View File

@ -97,6 +97,12 @@ struct rum_softc {
struct ieee80211_amrr amrr;
struct ieee80211_amrr_node amn;
struct usb_task sc_scantask;
int sc_scan_action;
#define RUM_SCAN_START 0
#define RUM_SCAN_END 1
#define RUM_SET_CHANNEL 2
struct rum_rx_data rx_data[RUM_RX_LIST_COUNT];
struct rum_tx_data tx_data[RUM_TX_LIST_COUNT];
int tx_queued;
@ -106,7 +112,6 @@ struct rum_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
struct callout scan_ch;
struct callout amrr_ch;
int sc_tx_timer;

View File

@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_regdomain.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@ -73,6 +74,10 @@ SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &uraldebug, 0,
#define DPRINTFN(n, x)
#endif
#define URAL_RSSI(rssi) \
((rssi) > (RAL_NOISE_FLOOR + RAL_RSSI_CORR) ? \
((rssi) - RAL_NOISE_FLOOR + RAL_RSSI_CORR) : 0)
/* various supported device vendors/products */
static const struct usb_devno ural_devs[] = {
{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL167G },
@ -113,8 +118,8 @@ static void ural_free_tx_list(struct ural_softc *);
static int ural_alloc_rx_list(struct ural_softc *);
static void ural_free_rx_list(struct ural_softc *);
static int ural_media_change(struct ifnet *);
static void ural_next_scan(void *);
static void ural_task(void *);
static void ural_scantask(void *);
static int ural_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static int ural_rxrate(struct ural_rx_desc *);
@ -149,6 +154,9 @@ static void ural_write_multi(struct ural_softc *, uint16_t, void *,
static void ural_bbp_write(struct ural_softc *, uint8_t, uint8_t);
static uint8_t ural_bbp_read(struct ural_softc *, uint8_t);
static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t);
static void ural_scan_start(struct ieee80211com *);
static void ural_scan_end(struct ieee80211com *);
static void ural_set_channel(struct ieee80211com *);
static void ural_set_chan(struct ural_softc *,
struct ieee80211_channel *);
static void ural_disable_rf_tune(struct ural_softc *);
@ -156,7 +164,7 @@ static void ural_enable_tsf_sync(struct ural_softc *);
static void ural_update_slot(struct ifnet *);
static void ural_set_txpreamble(struct ural_softc *);
static void ural_set_basicrates(struct ural_softc *);
static void ural_set_bssid(struct ural_softc *, uint8_t *);
static void ural_set_bssid(struct ural_softc *, const uint8_t *);
static void ural_set_macaddr(struct ural_softc *, uint8_t *);
static void ural_update_promisc(struct ural_softc *);
static const char *ural_get_rf(int);
@ -357,7 +365,7 @@ USB_ATTACH(ural)
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
int i;
int i, bands;
sc->sc_udev = uaa->device;
sc->sc_dev = self;
@ -399,7 +407,8 @@ USB_ATTACH(ural)
sc->sc_tx_no = ed->bEndpointAddress;
}
if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) {
printf("%s: missing endpoint\n", device_get_nameunit(sc->sc_dev));
printf("%s: missing endpoint\n",
device_get_nameunit(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
@ -407,8 +416,8 @@ USB_ATTACH(ural)
MTX_DEF | MTX_RECURSE);
usb_init_task(&sc->sc_task, ural_task, sc);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
usb_init_task(&sc->sc_scantask, ural_scantask, sc);
callout_init(&sc->watchdog_ch, 0);
callout_init(&sc->amrr_ch, 0);
/* retrieve RT2570 rev. no */
@ -418,11 +427,13 @@ USB_ATTACH(ural)
ural_read_eeprom(sc);
printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
device_get_nameunit(sc->sc_dev), sc->asic_rev, ural_get_rf(sc->rf_rev));
device_get_nameunit(sc->sc_dev), sc->asic_rev,
ural_get_rf(sc->rf_rev));
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
printf("%s: can not if_alloc()\n", device_get_nameunit(sc->sc_dev));
printf("%s: can not if_alloc()\n",
device_get_nameunit(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
@ -444,46 +455,30 @@ USB_ATTACH(ural)
/* set device capabilities */
ic->ic_caps =
IEEE80211_C_IBSS | /* IBSS mode supported */
IEEE80211_C_MONITOR | /* monitor mode supported */
IEEE80211_C_HOSTAP | /* HostAp mode supported */
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_WPA; /* 802.11i */
IEEE80211_C_IBSS /* IBSS mode supported */
| IEEE80211_C_MONITOR /* monitor mode supported */
| IEEE80211_C_HOSTAP /* HostAp mode supported */
| IEEE80211_C_TXPMGT /* tx power management */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_BGSCAN /* bg scanning supported */
| IEEE80211_C_WPA /* 802.11i */
;
if (sc->rf_rev == RAL_RF_5222) {
/* set supported .11a channels */
for (i = 36; i <= 64; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 100; i <= 140; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
for (i = 149; i <= 161; i += 4) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
}
}
/* set supported .11b and .11g channels (1 through 14) */
for (i = 1; i <= 14; i++) {
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
ic->ic_channels[i].ic_flags =
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
}
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
if (sc->rf_rev == RAL_RF_5222)
setbit(&bands, IEEE80211_MODE_11A);
ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_reset = ural_reset;
/* enable s/w bmiss handling in sta mode */
ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
ic->ic_scan_start = ural_scan_start;
ic->ic_scan_end = ural_scan_end;
ic->ic_set_channel = ural_set_channel;
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
@ -491,7 +486,9 @@ USB_ATTACH(ural)
ic->ic_raw_xmit = ural_raw_xmit;
ieee80211_media_init(ic, ural_media_change, ieee80211_media_status);
ieee80211_amrr_init(&sc->amrr, ic, 1, 15);
ieee80211_amrr_init(&sc->amrr, ic,
IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD);
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
@ -519,7 +516,6 @@ USB_DETACH(ural)
ural_stop(sc);
usb_rem_task(sc->sc_udev, &sc->sc_task);
callout_stop(&sc->watchdog_ch);
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
if (sc->amrr_xfer != NULL) {
@ -694,24 +690,10 @@ ural_media_change(struct ifnet *ifp)
return 0;
}
/*
* This function is called periodically (every 200ms) during scanning to
* switch from one channel to another.
*/
static void
ural_next_scan(void *arg)
ural_task(void *xarg)
{
struct ural_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
if (ic->ic_state == IEEE80211_S_SCAN)
ieee80211_next_scan(ic);
}
static void
ural_task(void *arg)
{
struct ural_softc *sc = arg;
struct ural_softc *sc = xarg;
struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_state ostate;
struct ieee80211_node *ni;
@ -720,7 +702,6 @@ ural_task(void *arg)
ostate = ic->ic_state;
RAL_LOCK(sc);
switch (sc->sc_state) {
case IEEE80211_S_INIT:
if (ostate == IEEE80211_S_RUN) {
@ -732,22 +713,7 @@ ural_task(void *arg)
}
break;
case IEEE80211_S_SCAN:
ural_set_chan(sc, ic->ic_curchan);
callout_reset(&sc->scan_ch, hz / 5, ural_next_scan, sc);
break;
case IEEE80211_S_AUTH:
ural_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_ASSOC:
ural_set_chan(sc, ic->ic_curchan);
break;
case IEEE80211_S_RUN:
ural_set_chan(sc, ic->ic_curchan);
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@ -785,18 +751,44 @@ ural_task(void *arg)
ural_amrr_start(sc, ni);
break;
default:
break;
}
RAL_UNLOCK(sc);
sc->sc_newstate(ic, sc->sc_state, sc->sc_arg);
}
static void
ural_scantask(void *arg)
{
struct ural_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
RAL_LOCK(sc);
if (sc->sc_scan_action == URAL_SCAN_START) {
/* abort TSF synchronization */
ural_write(sc, RAL_TXRX_CSR19, 0);
ural_set_bssid(sc, ifp->if_broadcastaddr);
} else if (sc->sc_scan_action == URAL_SET_CHANNEL) {
mtx_lock(&Giant);
ural_set_chan(sc, ic->ic_curchan);
mtx_unlock(&Giant);
} else {
ural_enable_tsf_sync(sc);
/* XXX keep local copy */
ural_set_bssid(sc, ic->ic_bss->ni_bssid);
}
RAL_UNLOCK(sc);
}
static int
ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ural_softc *sc = ic->ic_ifp->if_softc;
callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
/* do it in a process context */
@ -859,6 +851,9 @@ ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct ural_softc *sc = data->sc;
struct ifnet *ifp = sc->sc_ic.ic_ifp;
if (data->m->m_flags & M_TXCB)
ieee80211_process_callback(data->ni, data->m,
status == USBD_NORMAL_COMPLETION ? 0 : ETIMEDOUT);
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
@ -870,6 +865,7 @@ ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
ifp->if_oerrors++;
/* XXX mbuf leak? */
return;
}
@ -946,7 +942,6 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
/* finalize mbuf */
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
m->m_flags |= M_HASFCS; /* h/w leaves FCS */
if (bpf_peers_present(sc->sc_drvbpf)) {
struct ural_rx_radiotap_header *tap = &sc->sc_rxtap;
@ -956,16 +951,19 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
tap->wr_antsignal = desc->rssi;
tap->wr_antsignal = URAL_RSSI(desc->rssi);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
/* Strip trailing 802.11 MAC FCS. */
m_adj(m, -IEEE80211_CRC_LEN);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
ieee80211_input(ic, m, ni, desc->rssi, 0);
ieee80211_input(ic, m, ni, URAL_RSSI(desc->rssi), RAL_NOISE_FLOOR, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@ -1303,8 +1301,12 @@ ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
ural_txeof);
error = usbd_transfer(data->xfer);
if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
m_freem(m0);
data->m = NULL;
data->ni = NULL;
return error;
}
sc->tx_queued++;
@ -1327,7 +1329,7 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
rate = ic->ic_fixed_rate;
else
rate = ni->ni_rates.rs_rates[ni->ni_txrate];
@ -1481,19 +1483,21 @@ static void
ural_watchdog(void *arg)
{
struct ural_softc *sc = (struct ural_softc *)arg;
struct ieee80211com *ic = &sc->sc_ic;
RAL_LOCK(sc);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
/*ural_init(sc); XXX needs a process context! */
sc->sc_ifp->if_oerrors++;
RAL_UNLOCK(sc);
return;
}
callout_reset(&sc->watchdog_ch, hz, ural_watchdog, sc);
}
ieee80211_watchdog(ic);
RAL_UNLOCK(sc);
}
/*
@ -1737,6 +1741,45 @@ ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff));
}
static void
ural_scan_start(struct ieee80211com *ic)
{
struct ural_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = URAL_SCAN_START;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
ural_scan_end(struct ieee80211com *ic)
{
struct ural_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = URAL_SCAN_END;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
ural_set_channel(struct ieee80211com *ic)
{
struct ural_softc *sc = ic->ic_ifp->if_softc;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
/* do it in a process context */
sc->sc_scan_action = URAL_SET_CHANNEL;
usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
}
static void
ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
{
@ -1820,7 +1863,7 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
}
if (ic->ic_opmode != IEEE80211_M_MONITOR &&
ic->ic_state != IEEE80211_S_SCAN) {
(ic->ic_flags & IEEE80211_F_SCAN) == 0) {
/* set Japan filter bit for channel 14 */
tmp = ural_bbp_read(sc, 70);
@ -1836,6 +1879,18 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
DELAY(10000);
ural_disable_rf_tune(sc);
}
/* update basic rate set */
if (IEEE80211_IS_CHAN_B(c)) {
/* 11b basic rates: 1, 2Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x3);
} else if (IEEE80211_IS_CHAN_A(c)) {
/* 11a basic rates: 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x150);
} else {
/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
ural_write(sc, RAL_TXRX_CSR11, 0x15f);
}
}
/*
@ -1948,7 +2003,7 @@ ural_set_basicrates(struct ural_softc *sc)
}
static void
ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
ural_set_bssid(struct ural_softc *sc, const uint8_t *bssid)
{
uint16_t tmp;
@ -2166,7 +2221,6 @@ ural_init(void *priv)
if (ural_bbp_init(sc) != 0)
goto fail;
/* set default BSS channel */
ural_set_chan(sc, ic->ic_curchan);
/* clear statistic registers (STA_CSR0 to STA_CSR10) */

View File

@ -17,6 +17,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define RAL_NOISE_FLOOR -95
#define RAL_RSSI_CORR 120
#define RAL_RX_DESC_SIZE (sizeof (struct ural_rx_desc))
#define RAL_TX_DESC_SIZE (sizeof (struct ural_tx_desc))

View File

@ -20,6 +20,11 @@
#define RAL_RX_LIST_COUNT 1
#define RAL_TX_LIST_COUNT 1
#define URAL_SCAN_START 1
#define URAL_SCAN_END 2
#define URAL_SET_CHANNEL 3
struct ural_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint8_t wr_flags;
@ -91,7 +96,9 @@ struct ural_softc {
enum ieee80211_state sc_state;
int sc_arg;
int sc_scan_action; /* should be an enum */
struct usb_task sc_task;
struct usb_task sc_scantask;
struct ieee80211_amrr amrr;
struct ieee80211_amrr_node amn;
@ -105,9 +112,7 @@ struct ural_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
struct callout scan_ch;
struct callout amrr_ch;
int sc_tx_timer;
uint16_t sta[11];

View File

@ -118,7 +118,7 @@ static int wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr,
struct mbuf *m0);
static int wi_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
static int wi_reset(struct wi_softc *);
static int wi_reset(struct ifnet *);
static void wi_watchdog(void *);
static int wi_ioctl(struct ifnet *, u_long, caddr_t);
static int wi_media_change(struct ifnet *);
@ -164,6 +164,14 @@ static int wi_symbol_write_firm(struct wi_softc *, const void *, int,
const void *, int);
static int wi_symbol_set_hcr(struct wi_softc *, int);
static void wi_scan_start(struct ieee80211com *);
static void wi_scan_end(struct ieee80211com *);
static void wi_set_channel(struct ieee80211com *);
static void wi_update_slot(struct ifnet *);
static struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *);
static int wi_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data);
static int wi_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data);
static __inline int
wi_write_val(struct wi_softc *sc, int rid, u_int16_t val)
{
@ -253,6 +261,7 @@ wi_attach(device_t dev)
int error;
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
ifp->if_softc = sc;
if (ifp == NULL) {
device_printf(dev, "can not if_alloc\n");
wi_free(dev);
@ -279,7 +288,7 @@ wi_attach(device_t dev)
sc->sc_firmware_type = WI_NOTYPE;
sc->wi_cmd_count = 500;
/* Reset the NIC. */
if (wi_reset(sc) != 0)
if (wi_reset(ifp) != 0)
return ENXIO; /* XXX */
/*
@ -308,7 +317,6 @@ wi_attach(device_t dev)
/* Read NIC identification */
wi_read_nicid(sc);
ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = wi_ioctl;
@ -338,11 +346,14 @@ wi_attach(device_t dev)
val <<= 1; /* shift for base 1 indices */
for (i = 1; i < 16; i++) {
struct ieee80211_channel *c;
if (!isset((u_int8_t*)&val, i))
continue;
ic->ic_channels[i].ic_freq =
ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
c->ic_flags = IEEE80211_CHAN_B;
c->ic_ieee = i;
}
/*
@ -356,14 +367,14 @@ wi_attach(device_t dev)
buflen = sizeof(val);
if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0) {
val = le16toh(val);
KASSERT(val < IEEE80211_CHAN_MAX &&
ic->ic_channels[val].ic_flags != 0,
("wi_attach: invalid own channel %u!", val));
ic->ic_ibss_chan = &ic->ic_channels[val];
ic->ic_bsschan = ieee80211_find_channel(ic,
ieee80211_ieee2mhz(val, IEEE80211_CHAN_B),
IEEE80211_MODE_AUTO);
/* XXX check return value */
} else {
device_printf(dev,
"WI_RID_OWN_CHNL failed, using first channel!\n");
ic->ic_ibss_chan = &ic->ic_channels[0];
ic->ic_bsschan = &ic->ic_channels[0];
}
/*
@ -469,7 +480,7 @@ wi_attach(device_t dev)
sc->sc_system_scale = 1;
sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
sc->sc_roaming_mode = 1;
sc->wi_channel = IEEE80211_CHAN_ANYC;
sc->sc_portnum = WI_DEFAULT_PORT;
sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
@ -491,6 +502,14 @@ wi_attach(device_t dev)
ic->ic_crypto.cs_key_alloc = wi_key_alloc;
ic->ic_newstate = wi_newstate;
ic->ic_raw_xmit = wi_raw_xmit;
ic->ic_scan_start = wi_scan_start;
ic->ic_scan_end = wi_scan_end;
ic->ic_set_channel = wi_set_channel;
ic->ic_node_alloc = wi_node_alloc;
ic->ic_updateslot = wi_update_slot;
ic->ic_reset = wi_reset;
ieee80211_media_init(ic, wi_media_change, wi_media_status);
#if NBPFILTER > 0
@ -650,19 +669,20 @@ wi_init(void *arg)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = &sc->sc_ic;
struct wi_joinreq join;
struct ieee80211_channel *chan;
int i;
int error = 0, wasenabled;
WI_LOCK(sc);
if (sc->wi_gone) {
WI_UNLOCK(sc);
if (sc->wi_gone)
return;
}
if ((wasenabled = sc->sc_enabled))
wi_stop(ifp, 1);
wi_reset(sc);
WI_LOCK(sc);
wi_reset(ifp);
/* common 802.11 configuration */
ic->ic_flags &= ~IEEE80211_F_IBSSON;
@ -684,9 +704,9 @@ wi_init(void *arg)
* HostAP mode the controller will lock up otherwise.
*/
if (sc->sc_firmware_type == WI_INTERSIL &&
ic->ic_des_esslen == 0) {
ic->ic_des_essid[0] = ' ';
ic->ic_des_esslen = 1;
ic->ic_des_ssid[0].len == 0) {
ic->ic_des_ssid[0].ssid[0] = ' ';
ic->ic_des_ssid[0].len = 1;
}
wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
break;
@ -703,20 +723,24 @@ wi_init(void *arg)
wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
break;
case IEEE80211_M_WDS:
/* XXXX */
break;
}
/* Intersil interprets this RID as joining ESS even in IBSS mode */
if (sc->sc_firmware_type == WI_LUCENT &&
(ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0)
(ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_ssid[0].len > 0)
wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
else
wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid,
ic->ic_des_esslen);
wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_ssid[0].ssid,
ic->ic_des_ssid[0].len);
wi_write_val(sc, WI_RID_OWN_CHNL,
ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen);
ieee80211_chan2ieee(ic, ic->ic_bsschan));
wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_ssid[0].ssid,
ic->ic_des_ssid[0].len);
IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
@ -803,9 +827,11 @@ wi_init(void *arg)
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_MONITOR ||
ic->ic_opmode == IEEE80211_M_HOSTAP)
ieee80211_create_ibss(ic, ic->ic_ibss_chan);
ic->ic_opmode == IEEE80211_M_HOSTAP) {
chan = (sc->wi_channel == IEEE80211_CHAN_ANYC) ?
ic->ic_curchan : sc->wi_channel;
ieee80211_create_ibss(ic, chan);
}
/* Enable interrupts */
CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
@ -851,11 +877,10 @@ wi_stop(struct ifnet *ifp, int disable)
struct wi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
WI_LOCK(sc);
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
DELAY(100000);
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
WI_LOCK(sc);
if (sc->sc_enabled && !sc->wi_gone) {
CSR_WRITE_2(sc, WI_INT_EN, 0);
wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
@ -973,8 +998,7 @@ wi_start_locked(struct ifnet *ifp)
k = ieee80211_crypto_encap(ic, ni, m0);
if (k == NULL) {
if (ni != NULL)
ieee80211_free_node(ni);
ieee80211_free_node(ni);
m_freem(m0);
continue;
}
@ -994,8 +1018,7 @@ wi_start_locked(struct ifnet *ifp)
frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
if (IFF_DUMPPKTS(ifp))
wi_dump_pkt(&frmhdr, NULL, -1);
if (ni != NULL)
ieee80211_free_node(ni);
ieee80211_free_node(ni);
if (wi_start_tx(ifp, &frmhdr, m0))
continue;
sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
@ -1131,9 +1154,9 @@ wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0,
}
static int
wi_reset(struct wi_softc *sc)
wi_reset(struct ifnet *ifp)
{
struct ifnet *ifp = sc->sc_ifp;
struct wi_softc *sc = ifp->if_softc;
#define WI_INIT_TRIES 3
int i;
int error = 0;
@ -1196,7 +1219,6 @@ wi_watchdog(void *arg)
}
/* TODO: rate control */
ieee80211_watchdog(&sc->sc_ic);
callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc);
}
@ -1207,8 +1229,6 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct wi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifreq *ifr = (struct ifreq *)data;
struct ieee80211req *ireq;
u_int8_t nodename[IEEE80211_NWID_LEN];
int error = 0;
struct thread *td = curthread;
struct wi_req wreq;
@ -1289,47 +1309,19 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
WI_UNLOCK(sc);
break;
case SIOCG80211:
ireq = (struct ieee80211req *) data;
if (ireq->i_type == IEEE80211_IOC_STATIONNAME) {
ireq->i_len = sc->sc_nodelen + 1;
error = copyout(sc->sc_nodename, ireq->i_data,
ireq->i_len);
break;
}
goto ioctl_common;
error = wi_ioctl_get(ifp, cmd, data);
break;
case SIOCS80211:
ireq = (struct ieee80211req *) data;
if (ireq->i_type == IEEE80211_IOC_STATIONNAME) {
error = priv_check(td, PRIV_NET80211_MANAGE);
if (error)
break;
if (ireq->i_val != 0 ||
ireq->i_len > IEEE80211_NWID_LEN) {
error = EINVAL;
break;
}
memset(nodename, 0, IEEE80211_NWID_LEN);
error = copyin(ireq->i_data, nodename, ireq->i_len);
if (error)
break;
WI_LOCK(sc);
if (sc->sc_enabled) {
error = wi_write_ssid(sc, WI_RID_NODENAME,
nodename, ireq->i_len);
}
if (error == 0) {
memcpy(sc->sc_nodename, nodename,
IEEE80211_NWID_LEN);
sc->sc_nodelen = ireq->i_len;
}
WI_UNLOCK(sc);
error = priv_check(td, PRIV_NET80211_MANAGE);
if (error)
break;
error = wi_ioctl_set(ifp, cmd, data);
break;
}
goto ioctl_common;
default:
ioctl_common:
WI_LOCK(sc);
error = ieee80211_ioctl(ic, cmd, data);
WI_LOCK(sc);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
@ -1341,6 +1333,101 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return (error);
}
static int
wi_ioctl_get(struct ifnet *ifp, u_long cmd, caddr_t data)
{
int error;
struct wi_softc *sc;
struct ieee80211req *ireq;
struct ieee80211com *ic;
sc = ifp->if_softc;
ic = &sc->sc_ic;
ireq = (struct ieee80211req *) data;
switch (ireq->i_type) {
case IEEE80211_IOC_STATIONNAME:
ireq->i_len = sc->sc_nodelen + 1;
error = copyout(sc->sc_nodename, ireq->i_data,
ireq->i_len);
break;
default:
error = ieee80211_ioctl(ic, cmd, data);
WI_LOCK(sc);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
error = 0;
}
WI_UNLOCK(sc);
break;
}
return (error);
}
static int
wi_ioctl_set(struct ifnet *ifp, u_long cmd, caddr_t data)
{
int error;
struct wi_softc *sc;
struct ieee80211req *ireq;
u_int8_t nodename[IEEE80211_NWID_LEN];
sc = ifp->if_softc;
ireq = (struct ieee80211req *) data;
switch (ireq->i_type) {
case IEEE80211_IOC_STATIONNAME:
if (ireq->i_val != 0 ||
ireq->i_len > IEEE80211_NWID_LEN) {
error = EINVAL;
break;
}
memset(nodename, 0, IEEE80211_NWID_LEN);
error = copyin(ireq->i_data, nodename, ireq->i_len);
if (error)
break;
WI_LOCK(sc);
if (sc->sc_enabled) {
error = wi_write_ssid(sc, WI_RID_NODENAME,
nodename, ireq->i_len);
}
if (error == 0) {
memcpy(sc->sc_nodename, nodename,
IEEE80211_NWID_LEN);
sc->sc_nodelen = ireq->i_len;
}
WI_UNLOCK(sc);
break;
default:
error = ieee80211_ioctl(&sc->sc_ic, cmd, data);
WI_LOCK(sc);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
error = 0;
}
WI_UNLOCK(sc);
break;
}
return (error);
}
static struct ieee80211_node *
wi_node_alloc(struct ieee80211_node_table *nt)
{
struct wi_node *rn;
rn = malloc(sizeof (struct wi_node), M_80211_NODE,
M_NOWAIT | M_ZERO);
return (rn != NULL) ? &rn->ni : NULL;
}
static int
wi_media_change(struct ifnet *ifp)
{
@ -1413,6 +1500,9 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
break;
case IEEE80211_M_WDS:
/* XXXX */
break;
}
}
@ -1439,6 +1529,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
return;
sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1);
#if 0
/*
* XXX hack; we should create a new node with the new bssid
* and replace the existing ic_bss with it but since we don't
@ -1447,6 +1538,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
* called and it will overwrite the node state.
*/
ieee80211_sta_join(ic, ieee80211_ref_node(ni));
#endif
}
static void
@ -1666,7 +1758,7 @@ wi_rx_intr(struct wi_softc *sc)
/*
* Send frame up for processing.
*/
ieee80211_input(ic, m, ni, rssi, rstamp);
ieee80211_input(ic, m, ni, rssi, -95/*XXXXwi_rx_silence?*/, rstamp);
/*
* The frame may have caused the node to be marked for
* reclamation (e.g. in response to a DEAUTH message)
@ -1826,8 +1918,9 @@ wi_info_intr(struct wi_softc *sc)
case WI_INFO_SCAN_RESULTS:
case WI_INFO_HOST_SCAN_RESULTS:
wi_scan_result(sc, fid, le16toh(ltbuf[0]));
ieee80211_notify_scan_done(ic);
break;
default:
DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid,
le16toh(ltbuf[1]), le16toh(ltbuf[0])));
@ -1992,7 +2085,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
case WI_RID_TX_CRYPT_KEY:
case WI_RID_DEFLT_CRYPT_KEYS:
case WI_RID_TX_RATE:
return ieee80211_cfgget(ic, cmd, data);
return ieee80211_ioctl(ic, cmd, data);
case WI_RID_MICROWAVE_OVEN:
if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
@ -2046,7 +2139,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
case WI_RID_READ_APS:
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
return ieee80211_cfgget(ic, cmd, data);
return ieee80211_ioctl(ic, cmd, data);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@ -2083,11 +2176,11 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case WI_RID_READ_CACHE:
return ieee80211_cfgget(ic, cmd, data);
return ieee80211_ioctl(ic, cmd, data);
case WI_RID_SCAN_RES: /* compatibility interface */
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
return ieee80211_cfgget(ic, cmd, data);
return ieee80211_ioctl(ic, cmd, data);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@ -2169,7 +2262,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_nodelen);
break;
default:
return ieee80211_cfgget(ic, cmd, data);
return ieee80211_ioctl(ic, cmd, data);
}
break;
}
@ -2289,7 +2382,7 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
WI_UNLOCK(sc);
return EINVAL;
}
ic->ic_fixed_rate = i;
ic->ic_fixed_rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
}
if (sc->sc_enabled)
error = wi_write_txrate(sc);
@ -2347,9 +2440,10 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
WI_LOCK(sc);
memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
ic->ic_des_ssid[0].len = le16toh(wreq.wi_val[0]) * 2;
memcpy(ic->ic_des_ssid[0].ssid, &wreq.wi_val[1],
ic->ic_des_ssid[0].len);
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
WI_UNLOCK(sc);
@ -2361,8 +2455,8 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
len);
if (error == 0) {
/* XXX ieee80211_cfgset does a copyin */
error = ieee80211_cfgset(ic, cmd, data);
/* XXX ieee80211_ioctl does a copyin */
error = ieee80211_ioctl(ic, cmd, data);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc);
@ -2385,8 +2479,7 @@ wi_write_txrate(struct wi_softc *sc)
if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rate = 0; /* auto */
else
rate = (ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ic->ic_fixed_rate] &
IEEE80211_RATE_VAL) / 2;
rate = ic->ic_fixed_rate / 2;
/* rate: 0, 1, 2, 5, 11 */
@ -2868,8 +2961,7 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
/* XXX validate channel */
ni->ni_chan = &ic->ic_channels[le16toh(val)];
ic->ic_curchan = ni->ni_chan;
ic->ic_ibss_chan = ni->ni_chan;
ic->ic_curchan = ic->ic_bsschan = ni->ni_chan;
#if NBPFILTER > 0
sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
htole16(ni->ni_chan->ic_freq);
@ -2944,6 +3036,16 @@ wi_scan_result(struct wi_softc *sc, int fid, int cnt)
struct wi_scan_header ws_hdr; /* Prism2 header */
struct wi_scan_data_p2 ws_dat; /* Prism2 scantable*/
struct wi_apinfo *ap;
struct ieee80211_scanparams sp;
struct ieee80211_frame wh;
static long rstamp;
struct ieee80211com *ic;
uint8_t ssid[2+IEEE80211_NWID_LEN];
printf("wi_scan_result\n");
ic = &sc->sc_ic;
rstamp++;
memset(&sp, 0, sizeof(sp));
off = sizeof(u_int16_t) * 2;
memset(&ws_hdr, 0, sizeof(ws_hdr));
@ -2973,25 +3075,45 @@ wi_scan_result(struct wi_softc *sc, int fid, int cnt)
/* Read Data */
ap = sc->sc_aps;
memset(&ws_dat, 0, sizeof(ws_dat));
for (i = 0; i < naps; i++, ap++) {
uint8_t rates[2];
uint16_t *bssid;
wi_read_bap(sc, fid, off, &ws_dat,
(sizeof(ws_dat) < szbuf ? sizeof(ws_dat) : szbuf));
DPRINTF2(("wi_scan_result: #%d: off %d bssid %s\n", i, off,
ether_sprintf(ws_dat.wi_bssid)));
off += szbuf;
ap->scanreason = le16toh(ws_hdr.wi_reason);
ap->scanreason = le16toh(ws_hdr.wi_reason);
memcpy(ap->bssid, ws_dat.wi_bssid, sizeof(ap->bssid));
ap->channel = le16toh(ws_dat.wi_chid);
bssid = (uint16_t *)&ap->bssid;
if (bssid[0] == 0 && bssid[1] == 0 && bssid[2] == 0)
break;
memcpy(wh.i_addr2, ws_dat.wi_bssid, sizeof(ap->bssid));
memcpy(wh.i_addr3, ws_dat.wi_bssid, sizeof(ap->bssid));
sp.chan = ap->channel = le16toh(ws_dat.wi_chid);
ap->signal = le16toh(ws_dat.wi_signal);
ap->noise = le16toh(ws_dat.wi_noise);
ap->quality = ap->signal - ap->noise;
ap->capinfo = le16toh(ws_dat.wi_capinfo);
ap->interval = le16toh(ws_dat.wi_interval);
ap->rate = le16toh(ws_dat.wi_rate);
sp.capinfo = ap->capinfo = le16toh(ws_dat.wi_capinfo);
sp.bintval = ap->interval = le16toh(ws_dat.wi_interval);
ap->rate = le16toh(ws_dat.wi_rate);
rates[1] = 1;
rates[2] = (uint8_t)ap->rate;
ap->namelen = le16toh(ws_dat.wi_namelen);
if (ap->namelen > sizeof(ap->name))
ap->namelen = sizeof(ap->name);
memcpy(ap->name, ws_dat.wi_name, ap->namelen);
sp.ssid = (uint8_t *)&ssid[0];
memcpy(sp.ssid + 2, ap->name, ap->namelen);
sp.ssid[1] = ap->namelen;
sp.rates = &rates[0];
sp.tstamp = (uint8_t *)&rstamp;
printf("calling add_scan \n");
ieee80211_add_scan(ic, &sp, &wh, 0, ap->signal, ap->noise, rstamp);
}
done:
/* Done scanning */
@ -3003,8 +3125,11 @@ wi_scan_result(struct wi_softc *sc, int fid, int cnt)
static void
wi_dump_pkt(struct wi_frame *wh, struct ieee80211_node *ni, int rssi)
{
ieee80211_dump_pkt((u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
ni ? ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL : -1, rssi);
if (ni != NULL)
ieee80211_dump_pkt(ni->ni_ic,
(u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL,
rssi);
printf(" status 0x%x rx_tstamp1 %u rx_tstamp0 0x%u rx_silence %u\n",
le16toh(wh->wi_status), le16toh(wh->wi_rx_tstamp1),
le16toh(wh->wi_rx_tstamp0), wh->wi_rx_silence);
@ -3364,3 +3489,50 @@ wi_symbol_set_hcr(struct wi_softc *sc, int mode)
tsleep(sc, PWAIT, "wiinit", 1);
return 0;
}
/*
* This function can be called by ieee80211_set_shortslottime(). Refer to
* IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
*/
static void
wi_update_slot(struct ifnet *ifp)
{
DPRINTF(("wi update slot unimplemented\n"));
}
static void
wi_set_channel(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct wi_softc *sc = ifp->if_softc;
WI_LOCK(sc);
if (!(sc->sc_flags & WI_FLAGS_SCANNING)) {
sc->wi_channel = ic->ic_curchan;
}
WI_UNLOCK(sc);
}
static void
wi_scan_start(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct wi_softc *sc = ifp->if_softc;
WI_LOCK(sc);
sc->sc_flags |= WI_FLAGS_SCANNING;
wi_scan_ap(sc, 0x3fff, 0x000f);
WI_UNLOCK(sc);
}
static void
wi_scan_end(struct ieee80211com *ic)
{
struct ifnet *ifp = ic->ic_ifp;
struct wi_softc *sc = ifp->if_softc;
WI_LOCK(sc);
sc->sc_flags &= ~WI_FLAGS_SCANNING;
WI_UNLOCK(sc);
}

View File

@ -100,6 +100,7 @@ struct wi_softc {
bus_space_handle_t wi_bmemhandle;
bus_space_tag_t wi_bmemtag;
void * wi_intrhand;
struct ieee80211_channel *wi_channel;
int wi_io_addr;
int wi_cmd_count;
@ -108,7 +109,7 @@ struct wi_softc {
int sc_if_flags;
int sc_bap_id;
int sc_bap_off;
u_int16_t sc_procframe;
u_int16_t sc_portnum;
@ -201,6 +202,13 @@ struct wi_softc {
#define WI_FLAGS_BUG_AUTOINC 0x0100
#define WI_FLAGS_HAS_FRAGTHR 0x0200
#define WI_FLAGS_HAS_DBMADJUST 0x0400
#define WI_FLAGS_SCANNING 0x0800
/* driver-specific node state */
struct wi_node {
struct ieee80211_node ni; /* base class */
};
struct wi_card_ident {
u_int16_t card_id;

View File

@ -363,6 +363,18 @@ static struct witness_order_list_entry order_lists[] = {
{ "nfsd_mtx", &lock_class_mtx_sleep },
{ "so_snd", &lock_class_mtx_sleep },
{ NULL, NULL },
/*
* IEEE 802.11
*/
{ "802.11 com lock", &lock_class_mtx_sleep},
{ NULL, NULL },
/*
* Network drivers
*/
{ "network driver", &lock_class_mtx_sleep},
{ NULL, NULL },
/*
* Netgraph
*/

View File

@ -296,6 +296,8 @@ SUBDIR= ${_3dfx} \
wb \
${_wi} \
wlan \
wlan_scan_ap \
wlan_scan_sta \
wlan_acl \
wlan_amrr \
wlan_ccmp \

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../net80211
KMOD= wlan_scan_ap
SRCS= ieee80211_scan_ap.c
.include <bsd.kmod.mk>

View File

@ -0,0 +1,8 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../net80211
KMOD= wlan_scan_sta
SRCS= ieee80211_scan_sta.c
.include <bsd.kmod.mk>

View File

@ -202,6 +202,8 @@ uint64_t ifmedia_baudrate(int);
#define IFM_IEEE80211_OFDM3 21 /* OFDM 3Mbps */
#define IFM_IEEE80211_OFDM4 22 /* OFDM 4.5Mbps */
#define IFM_IEEE80211_OFDM27 23 /* OFDM 27Mbps */
/* NB: not enough bits to express MCS fully */
#define IFM_IEEE80211_MCS 24 /* HT MCS rate */
#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */
#define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */
@ -209,12 +211,16 @@ uint64_t ifmedia_baudrate(int);
#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */
#define IFM_IEEE80211_TURBO 0x00001000 /* Operate in turbo mode */
#define IFM_IEEE80211_MONITOR 0x00002000 /* Operate in monitor mode */
#define IFM_IEEE80211_HT40PLUS 0x00004000 /* Operate in 11n HT40+ mode */
#define IFM_IEEE80211_HT40MINUS 0x00008000 /* Operate in 11n HT40- mode */
/* operating mode for multi-mode devices */
#define IFM_IEEE80211_11A 0x00010000 /* 5Ghz, OFDM mode */
#define IFM_IEEE80211_11B 0x00020000 /* Direct Sequence mode */
#define IFM_IEEE80211_11G 0x00030000 /* 2Ghz, CCK mode */
#define IFM_IEEE80211_FH 0x00040000 /* 2Ghz, GFSK mode */
#define IFM_IEEE80211_11NA 0x00050000 /* 5Ghz, HT mode */
#define IFM_IEEE80211_11NG 0x00060000 /* 2Ghz, HT mode */
/*
* ATM
@ -494,6 +500,8 @@ struct ifmedia_description {
{ IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \
{ IFM_IEEE80211_TURBO, "turbo" }, \
{ IFM_IEEE80211_MONITOR, "monitor" }, \
{ IFM_IEEE80211_HT40MINUS, "ht-" }, \
{ IFM_IEEE80211_HT40PLUS, "ht+" }, \
{ 0, NULL }, \
}
@ -503,6 +511,8 @@ struct ifmedia_description {
{ IFM_IEEE80211_11B, "11b" }, \
{ IFM_IEEE80211_11G, "11g" }, \
{ IFM_IEEE80211_FH, "fh" }, \
{ IFM_IEEE80211_11NA, "11na" }, \
{ IFM_IEEE80211_11NG, "11ng" }, \
{ 0, NULL }, \
}

View File

@ -33,6 +33,7 @@ enum ieee80211_phytype {
IEEE80211_T_FH, /* frequency hopping */
IEEE80211_T_OFDM, /* frequency division multiplexing */
IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */
IEEE80211_T_HT, /* high throughput, full GI */
};
#define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */
@ -45,20 +46,24 @@ enum ieee80211_phymode {
IEEE80211_MODE_FH = 4, /* 2GHz, GFSK */
IEEE80211_MODE_TURBO_A = 5, /* 5GHz, OFDM, 2x clock */
IEEE80211_MODE_TURBO_G = 6, /* 2GHz, OFDM, 2x clock */
IEEE80211_MODE_STURBO_A = 7, /* 5GHz, OFDM, 2x clock, static */
IEEE80211_MODE_11NA = 8, /* 5GHz, w/ HT */
IEEE80211_MODE_11NG = 9, /* 2GHz, w/ HT */
};
#define IEEE80211_MODE_MAX (IEEE80211_MODE_TURBO_G+1)
#define IEEE80211_MODE_MAX (IEEE80211_MODE_11NG+1)
enum ieee80211_opmode {
IEEE80211_M_STA = 1, /* infrastructure station */
IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */
IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */
IEEE80211_M_HOSTAP = 6, /* Software Access Point */
IEEE80211_M_MONITOR = 8 /* Monitor mode */
IEEE80211_M_MONITOR = 8, /* Monitor mode */
IEEE80211_M_WDS = 2 /* WDS link */
};
#define IEEE80211_OPMODE_MAX (IEEE80211_M_MONITOR+1)
/*
* 802.11g protection mode.
* 802.11g/802.11n protection mode.
*/
enum ieee80211_protmode {
IEEE80211_PROT_NONE = 0, /* no protection */
@ -98,8 +103,13 @@ enum ieee80211_roamingmode {
* Channels are specified by frequency and attributes.
*/
struct ieee80211_channel {
u_int16_t ic_freq; /* setting in Mhz */
u_int16_t ic_flags; /* see below */
uint32_t ic_flags; /* see below */
uint16_t ic_freq; /* setting in Mhz */
uint8_t ic_ieee; /* IEEE channel number */
int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */
int8_t ic_maxpower; /* maximum tx power in .5 dBm */
int8_t ic_minpower; /* minimum tx power in .5 dBm */
/* NB: hole, to be used for dfs */
};
#define IEEE80211_CHAN_MAX 255
@ -110,17 +120,24 @@ struct ieee80211_channel {
/* bits 0-3 are for private use by drivers */
/* channel attributes */
#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
#define IEEE80211_CHAN_GSM 0x1000 /* 900 MHz spectrum channel */
#define IEEE80211_CHAN_HALF 0x4000 /* Half rate channel */
#define IEEE80211_CHAN_QUARTER 0x8000 /* Quarter rate channel */
#define IEEE80211_CHAN_TURBO 0x00010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x00020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x00040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x00080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x00100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x00200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x00400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x00800 /* GFSK channel (FHSS PHY) */
#define IEEE80211_CHAN_GSM 0x01000 /* 900 MHz spectrum channel */
#define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */
#define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */
#define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */
#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */
#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */
#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */
#define IEEE80211_CHAN_HT40 (IEEE80211_CHAN_HT40U | IEEE80211_CHAN_HT40D)
#define IEEE80211_CHAN_HT (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40)
/*
* Useful combinations of channel characteristics.
@ -135,16 +152,19 @@ struct ieee80211_channel {
(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
#define IEEE80211_CHAN_G \
(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
#define IEEE80211_CHAN_T \
#define IEEE80211_CHAN_108A \
(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
#define IEEE80211_CHAN_108G \
(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)
#define IEEE80211_CHAN_ST \
(IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO)
#define IEEE80211_CHAN_ALL \
(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \
IEEE80211_CHAN_HT)
#define IEEE80211_CHAN_ALLTURBO \
(IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO)
(IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)
#define IEEE80211_IS_CHAN_FHSS(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
@ -158,8 +178,10 @@ struct ieee80211_channel {
(((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
#define IEEE80211_IS_CHAN_ANYG(_c) \
(IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c))
#define IEEE80211_IS_CHAN_T(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T)
#define IEEE80211_IS_CHAN_ST(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)
#define IEEE80211_IS_CHAN_108A(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)
#define IEEE80211_IS_CHAN_108G(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)
@ -167,12 +189,21 @@ struct ieee80211_channel {
(((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
#define IEEE80211_IS_CHAN_5GHZ(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
#define IEEE80211_IS_CHAN_PASSIVE(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0)
#define IEEE80211_IS_CHAN_OFDM(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0)
#define IEEE80211_IS_CHAN_CCK(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0)
#define IEEE80211_IS_CHAN_GFSK(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0)
#define IEEE80211_IS_CHAN_TURBO(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0)
#define IEEE80211_IS_CHAN_STURBO(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_STURBO) != 0)
#define IEEE80211_IS_CHAN_DTURBO(_c) \
(((_c)->ic_flags & \
(IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) == IEEE80211_CHAN_TURBO)
#define IEEE80211_IS_CHAN_HALF(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0)
#define IEEE80211_IS_CHAN_QUARTER(_c) \
@ -181,8 +212,22 @@ struct ieee80211_channel {
(((_c)->ic_flags & (IEEE80211_CHAN_QUARTER | IEEE80211_CHAN_HALF)) == 0)
#define IEEE80211_IS_CHAN_GSM(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_GSM) != 0)
#define IEEE80211_IS_CHAN_PASSIVE(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0)
#define IEEE80211_IS_CHAN_HT(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HT) != 0)
#define IEEE80211_IS_CHAN_HT20(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HT20) != 0)
#define IEEE80211_IS_CHAN_HT40(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HT40) != 0)
#define IEEE80211_IS_CHAN_HT40U(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HT40U) != 0)
#define IEEE80211_IS_CHAN_HT40D(_c) \
(((_c)->ic_flags & IEEE80211_CHAN_HT40D) != 0)
#define IEEE80211_IS_CHAN_HTA(_c) \
(IEEE80211_IS_CHAN_5GHZ(_c) && \
((_c)->ic_flags & IEEE80211_CHAN_HT) != 0)
#define IEEE80211_IS_CHAN_HTG(_c) \
(IEEE80211_IS_CHAN_2GHZ(_c) && \
((_c)->ic_flags & IEEE80211_CHAN_HT) != 0)
/* ni_chan encoding for FH phy */
#define IEEE80211_FH_CHANMOD 80
@ -197,8 +242,38 @@ struct ieee80211_channel {
#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
struct ieee80211_rateset {
u_int8_t rs_nrates;
u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE];
uint8_t rs_nrates;
uint8_t rs_rates[IEEE80211_RATE_MAXSIZE];
};
/*
* 802.11n variant of ieee80211_rateset. Instead
* legacy rates the entries are MCS rates. We define
* the structure such that it can be used interchangeably
* with an ieee80211_rateset (modulo structure size).
*/
#define IEEE80211_HTRATE_MAXSIZE 127
struct ieee80211_htrateset {
uint8_t rs_nrates;
uint8_t rs_rates[IEEE80211_HTRATE_MAXSIZE];
};
/*
* Roaming state visible to user space. There are two
* thresholds that control whether roaming is considered;
* when either is exceeded the 802.11 layer will check
* the scan cache for another AP. If the cache is stale
* then a scan may be triggered.
*/
struct ieee80211_roam {
int8_t rssi11a; /* rssi thresh for 11a bss */
int8_t rssi11b; /* for 11g sta in 11b bss */
int8_t rssi11bOnly; /* for 11b sta */
uint8_t pad1;
uint8_t rate11a; /* rate thresh for 11a bss */
uint8_t rate11b; /* for 11g sta in 11b bss */
uint8_t rate11bOnly; /* for 11b sta */
uint8_t pad2;
};
#endif /* _NET80211__IEEE80211_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -38,11 +38,11 @@
/* IEEE 802.11 PLCP header */
struct ieee80211_plcp_hdr {
u_int16_t i_sfd;
u_int8_t i_signal;
u_int8_t i_service;
u_int16_t i_length;
u_int16_t i_crc;
uint16_t i_sfd;
uint8_t i_signal;
uint8_t i_service;
uint16_t i_length;
uint16_t i_crc;
} __packed;
#define IEEE80211_PLCP_SFD 0xF3A0
@ -52,52 +52,52 @@ struct ieee80211_plcp_hdr {
* generic definitions for IEEE 802.11 frames
*/
struct ieee80211_frame {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_addr1[IEEE80211_ADDR_LEN];
u_int8_t i_addr2[IEEE80211_ADDR_LEN];
u_int8_t i_addr3[IEEE80211_ADDR_LEN];
u_int8_t i_seq[2];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_addr1[IEEE80211_ADDR_LEN];
uint8_t i_addr2[IEEE80211_ADDR_LEN];
uint8_t i_addr3[IEEE80211_ADDR_LEN];
uint8_t i_seq[2];
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
/* see below */
} __packed;
struct ieee80211_qosframe {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_addr1[IEEE80211_ADDR_LEN];
u_int8_t i_addr2[IEEE80211_ADDR_LEN];
u_int8_t i_addr3[IEEE80211_ADDR_LEN];
u_int8_t i_seq[2];
u_int8_t i_qos[2];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_addr1[IEEE80211_ADDR_LEN];
uint8_t i_addr2[IEEE80211_ADDR_LEN];
uint8_t i_addr3[IEEE80211_ADDR_LEN];
uint8_t i_seq[2];
uint8_t i_qos[2];
/* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
/* see below */
} __packed;
struct ieee80211_qoscntl {
u_int8_t i_qos[2];
uint8_t i_qos[2];
};
struct ieee80211_frame_addr4 {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_addr1[IEEE80211_ADDR_LEN];
u_int8_t i_addr2[IEEE80211_ADDR_LEN];
u_int8_t i_addr3[IEEE80211_ADDR_LEN];
u_int8_t i_seq[2];
u_int8_t i_addr4[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_addr1[IEEE80211_ADDR_LEN];
uint8_t i_addr2[IEEE80211_ADDR_LEN];
uint8_t i_addr3[IEEE80211_ADDR_LEN];
uint8_t i_seq[2];
uint8_t i_addr4[IEEE80211_ADDR_LEN];
} __packed;
struct ieee80211_qosframe_addr4 {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_addr1[IEEE80211_ADDR_LEN];
u_int8_t i_addr2[IEEE80211_ADDR_LEN];
u_int8_t i_addr3[IEEE80211_ADDR_LEN];
u_int8_t i_seq[2];
u_int8_t i_addr4[IEEE80211_ADDR_LEN];
u_int8_t i_qos[2];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_addr1[IEEE80211_ADDR_LEN];
uint8_t i_addr2[IEEE80211_ADDR_LEN];
uint8_t i_addr3[IEEE80211_ADDR_LEN];
uint8_t i_seq[2];
uint8_t i_addr4[IEEE80211_ADDR_LEN];
uint8_t i_qos[2];
} __packed;
#define IEEE80211_FC0_VERSION_MASK 0x03
@ -123,7 +123,9 @@ struct ieee80211_qosframe_addr4 {
#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0
#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0
#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0
#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0
/* for TYPE_CTL */
#define IEEE80211_FC0_SUBTYPE_BAR 0x80
#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0
#define IEEE80211_FC0_SUBTYPE_RTS 0xb0
#define IEEE80211_FC0_SUBTYPE_CTS 0xc0
@ -159,13 +161,24 @@ struct ieee80211_qosframe_addr4 {
#define IEEE80211_SEQ_FRAG_SHIFT 0
#define IEEE80211_SEQ_SEQ_MASK 0xfff0
#define IEEE80211_SEQ_SEQ_SHIFT 4
#define IEEE80211_SEQ_RANGE 4096
#define IEEE80211_SEQ_ADD(seq, incr) \
(((seq) + (incr)) & (IEEE80211_SEQ_RANGE-1))
#define IEEE80211_SEQ_INC(seq) IEEE80211_SEQ_ADD(seq,1)
#define IEEE80211_SEQ_SUB(a, b) \
(((a) + IEEE80211_SEQ_RANGE - (b)) & (IEEE80211_SEQ_RANGE-1))
#define IEEE80211_NWID_LEN 32
#define IEEE80211_QOS_TXOP 0x00ff
/* bit 8 is reserved */
#define IEEE80211_QOS_AMSDU 0x80
#define IEEE80211_QOS_AMSDU_S 7
#define IEEE80211_QOS_ACKPOLICY 0x60
#define IEEE80211_QOS_ACKPOLICY_S 5
#define IEEE80211_QOS_ACKPOLICY_NOACK 0x20 /* No ACK required */
#define IEEE80211_QOS_ACKPOLICY_BA 0x60 /* Block ACK */
#define IEEE80211_QOS_ESOP 0x10
#define IEEE80211_QOS_ESOP_S 4
#define IEEE80211_QOS_TID 0x0f
@ -180,53 +193,54 @@ struct ieee80211_qosframe_addr4 {
* WME/802.11e information element.
*/
struct ieee80211_wme_info {
u_int8_t wme_id; /* IEEE80211_ELEMID_VENDOR */
u_int8_t wme_len; /* length in bytes */
u_int8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */
u_int8_t wme_type; /* OUI type */
u_int8_t wme_subtype; /* OUI subtype */
u_int8_t wme_version; /* spec revision */
u_int8_t wme_info; /* QoS info */
uint8_t wme_id; /* IEEE80211_ELEMID_VENDOR */
uint8_t wme_len; /* length in bytes */
uint8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */
uint8_t wme_type; /* OUI type */
uint8_t wme_subtype; /* OUI subtype */
uint8_t wme_version; /* spec revision */
uint8_t wme_info; /* QoS info */
} __packed;
/*
* WME/802.11e Tspec Element
*/
struct ieee80211_wme_tspec {
u_int8_t ts_id;
u_int8_t ts_len;
u_int8_t ts_oui[3];
u_int8_t ts_oui_type;
u_int8_t ts_oui_subtype;
u_int8_t ts_version;
u_int8_t ts_tsinfo[3];
u_int8_t ts_nom_msdu[2];
u_int8_t ts_max_msdu[2];
u_int8_t ts_min_svc[4];
u_int8_t ts_max_svc[4];
u_int8_t ts_inactv_intv[4];
u_int8_t ts_susp_intv[4];
u_int8_t ts_start_svc[4];
u_int8_t ts_min_rate[4];
u_int8_t ts_mean_rate[4];
u_int8_t ts_max_burst[4];
u_int8_t ts_min_phy[4];
u_int8_t ts_peak_rate[4];
u_int8_t ts_delay[4];
u_int8_t ts_surplus[2];
u_int8_t ts_medium_time[2];
uint8_t ts_id;
uint8_t ts_len;
uint8_t ts_oui[3];
uint8_t ts_oui_type;
uint8_t ts_oui_subtype;
uint8_t ts_version;
uint8_t ts_tsinfo[3];
uint8_t ts_nom_msdu[2];
uint8_t ts_max_msdu[2];
uint8_t ts_min_svc[4];
uint8_t ts_max_svc[4];
uint8_t ts_inactv_intv[4];
uint8_t ts_susp_intv[4];
uint8_t ts_start_svc[4];
uint8_t ts_min_rate[4];
uint8_t ts_mean_rate[4];
uint8_t ts_max_burst[4];
uint8_t ts_min_phy[4];
uint8_t ts_peak_rate[4];
uint8_t ts_delay[4];
uint8_t ts_surplus[2];
uint8_t ts_medium_time[2];
} __packed;
/*
* WME AC parameter field
*/
struct ieee80211_wme_acparams {
u_int8_t acp_aci_aifsn;
u_int8_t acp_logcwminmax;
u_int16_t acp_txop;
uint8_t acp_aci_aifsn;
uint8_t acp_logcwminmax;
uint16_t acp_txop;
} __packed;
#define WME_NUM_AC 4 /* 4 AC categories */
#define WME_NUM_TID 16 /* 16 tids */
#define WME_PARAM_ACI 0x60 /* Mask for ACI field */
#define WME_PARAM_ACI_S 5 /* Shift for ACI field */
@ -255,15 +269,15 @@ struct ieee80211_wme_acparams {
* WME Parameter Element
*/
struct ieee80211_wme_param {
u_int8_t param_id;
u_int8_t param_len;
u_int8_t param_oui[3];
u_int8_t param_oui_type;
u_int8_t param_oui_sybtype;
u_int8_t param_version;
u_int8_t param_qosInfo;
uint8_t param_id;
uint8_t param_len;
uint8_t param_oui[3];
uint8_t param_oui_type;
uint8_t param_oui_sybtype;
uint8_t param_version;
uint8_t param_qosInfo;
#define WME_QOSINFO_COUNT 0x0f /* Mask for param count field */
u_int8_t param_reserved;
uint8_t param_reserved;
struct ieee80211_wme_acparams params_acParams[WME_NUM_AC];
} __packed;
@ -271,61 +285,168 @@ struct ieee80211_wme_param {
* Management Notification Frame
*/
struct ieee80211_mnf {
u_int8_t mnf_category;
u_int8_t mnf_action;
u_int8_t mnf_dialog;
u_int8_t mnf_status;
uint8_t mnf_category;
uint8_t mnf_action;
uint8_t mnf_dialog;
uint8_t mnf_status;
} __packed;
#define MNF_SETUP_REQ 0
#define MNF_SETUP_RESP 1
#define MNF_TEARDOWN 2
/*
* 802.11n Management Action Frames
*/
/* generic frame format */
struct ieee80211_action {
uint8_t ia_category;
uint8_t ia_action;
} __packed;
#define IEEE80211_ACTION_CAT_QOS 0 /* QoS */
#define IEEE80211_ACTION_CAT_BA 3 /* BA */
#define IEEE80211_ACTION_CAT_HT 5 /* HT */
#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended xmit chan width*/
#define IEEE80211_ACTION_HT_MIMOPWRSAVE 1 /* MIMO power save */
/* HT - recommended transmission channel width */
struct ieee80211_action_ht_txchwidth {
struct ieee80211_action at_header;
uint8_t at_chwidth;
} __packed;
#define IEEE80211_A_HT_TXCHWIDTH_20 0
#define IEEE80211_A_HT_TXCHWIDTH_2040 1
/* HT - MIMO Power Save */
struct ieee80211_action_ht_mimopowersave {
struct ieee80211_action am_header;
uint8_t am_enable;
uint8_t am_mode;
} __packed;
/* Block Ack actions */
#define IEEE80211_ACTION_BA_ADDBA_REQUEST 0 /* ADDBA request */
#define IEEE80211_ACTION_BA_ADDBA_RESPONSE 1 /* ADDBA response */
#define IEEE80211_ACTION_BA_DELBA 2 /* DELBA */
/* Block Ack Parameter Set */
#define IEEE80211_BAPS_BUFSIZ 0xffc0 /* buffer size */
#define IEEE80211_BAPS_BUFSIZ_S 6
#define IEEE80211_BAPS_TID 0x003c /* TID */
#define IEEE80211_BAPS_TID_S 2
#define IEEE80211_BAPS_POLICY 0x0002 /* block ack policy */
#define IEEE80211_BAPS_POLICY_S 1
#define IEEE80211_BAPS_POLICY_DELAYED (0<<IEEE80211_BAPS_POLICY_S)
#define IEEE80211_BAPS_POLICY_IMMEDIATE (1<<IEEE80211_BAPS_POLICY_S)
/* Block Ack Sequence Control */
#define IEEE80211_BASEQ_START 0xfff0 /* starting seqnum */
#define IEEE80211_BASEQ_START_S 4
#define IEEE80211_BASEQ_FRAG 0x000f /* fragment number */
#define IEEE80211_BASEQ_FRAG_S 0
/* Delayed Block Ack Parameter Set */
#define IEEE80211_DELBAPS_TID 0xf000 /* TID */
#define IEEE80211_DELBAPS_TID_S 12
#define IEEE80211_DELBAPS_INIT 0x0800 /* initiator */
#define IEEE80211_DELBAPS_INIT_S 11
/* BA - ADDBA request */
struct ieee80211_action_ba_addbarequest {
struct ieee80211_action rq_header;
uint8_t rq_dialogtoken;
uint16_t rq_baparamset;
uint16_t rq_batimeout; /* in TUs */
uint16_t rq_baseqctl;
} __packed;
/* BA - ADDBA response */
struct ieee80211_action_ba_addbaresponse {
struct ieee80211_action rs_header;
uint8_t rs_dialogtoken;
uint16_t rs_statuscode;
uint16_t rs_baparamset;
uint16_t rs_batimeout; /* in TUs */
} __packed;
/* BA - DELBA */
struct ieee80211_action_ba_delba {
struct ieee80211_action dl_header;
uint16_t dl_baparamset;
uint16_t dl_reasoncode;
} __packed;
/* BAR Control */
#define IEEE80211_BAR_TID 0xf000 /* TID */
#define IEEE80211_BAR_TID_S 12
#define IEEE80211_BAR_COMP 0x0004 /* compressed */
#define IEEE80211_BAR_MTID 0x0002
#define IEEE80211_BAR_NOACK 0x0001 /* no-ack policy */
struct ieee80211_ba_request {
uint16_t rq_barctl;
uint16_t rq_barseqctl;
} __packed;
/*
* Control frames.
*/
struct ieee80211_frame_min {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_addr1[IEEE80211_ADDR_LEN];
u_int8_t i_addr2[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_addr1[IEEE80211_ADDR_LEN];
uint8_t i_addr2[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_rts {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_ra[IEEE80211_ADDR_LEN];
u_int8_t i_ta[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_ra[IEEE80211_ADDR_LEN];
uint8_t i_ta[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_cts {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_ra[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_ra[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_ack {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
u_int8_t i_ra[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_ra[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_pspoll {
u_int8_t i_fc[2];
u_int8_t i_aid[2];
u_int8_t i_bssid[IEEE80211_ADDR_LEN];
u_int8_t i_ta[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_aid[2];
uint8_t i_bssid[IEEE80211_ADDR_LEN];
uint8_t i_ta[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */
u_int8_t i_fc[2];
u_int8_t i_dur[2]; /* should be zero */
u_int8_t i_ra[IEEE80211_ADDR_LEN];
u_int8_t i_bssid[IEEE80211_ADDR_LEN];
uint8_t i_fc[2];
uint8_t i_dur[2]; /* should be zero */
uint8_t i_ra[IEEE80211_ADDR_LEN];
uint8_t i_bssid[IEEE80211_ADDR_LEN];
/* FCS */
} __packed;
struct ieee80211_frame_bar {
uint8_t i_fc[2];
uint8_t i_dur[2];
uint8_t i_ra[IEEE80211_ADDR_LEN];
uint8_t i_ta[IEEE80211_ADDR_LEN];
uint16_t i_ctl;
uint16_t i_seq;
/* FCS */
} __packed;
@ -341,7 +462,7 @@ struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */
* octet information[length]
*/
typedef u_int8_t *ieee80211_mgt_beacon_t;
typedef uint8_t *ieee80211_mgt_beacon_t;
#define IEEE80211_BEACON_INTERVAL(beacon) \
((beacon)[8] | ((beacon)[9] << 8))
@ -367,21 +488,152 @@ typedef u_int8_t *ieee80211_mgt_beacon_t;
* 802.11i/WPA information element (maximally sized).
*/
struct ieee80211_ie_wpa {
u_int8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */
u_int8_t wpa_len; /* length in bytes */
u_int8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */
u_int8_t wpa_type; /* OUI type */
u_int16_t wpa_version; /* spec revision */
u_int32_t wpa_mcipher[1]; /* multicast/group key cipher */
u_int16_t wpa_uciphercnt; /* # pairwise key ciphers */
u_int32_t wpa_uciphers[8];/* ciphers */
u_int16_t wpa_authselcnt; /* authentication selector cnt*/
u_int32_t wpa_authsels[8];/* selectors */
u_int16_t wpa_caps; /* 802.11i capabilities */
u_int16_t wpa_pmkidcnt; /* 802.11i pmkid count */
u_int16_t wpa_pmkids[8]; /* 802.11i pmkids */
uint8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */
uint8_t wpa_len; /* length in bytes */
uint8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */
uint8_t wpa_type; /* OUI type */
uint16_t wpa_version; /* spec revision */
uint32_t wpa_mcipher[1]; /* multicast/group key cipher */
uint16_t wpa_uciphercnt; /* # pairwise key ciphers */
uint32_t wpa_uciphers[8];/* ciphers */
uint16_t wpa_authselcnt; /* authentication selector cnt*/
uint32_t wpa_authsels[8];/* selectors */
uint16_t wpa_caps; /* 802.11i capabilities */
uint16_t wpa_pmkidcnt; /* 802.11i pmkid count */
uint16_t wpa_pmkids[8]; /* 802.11i pmkids */
} __packed;
/*
* 802.11n HT Capability IE
* NB: these reflect D1.10
*/
struct ieee80211_ie_htcap {
uint8_t hc_id; /* element ID */
uint8_t hc_len; /* length in bytes */
uint16_t hc_cap; /* HT caps (see below) */
uint8_t hc_param; /* HT params (see below) */
uint8_t hc_mcsset[16]; /* supported MCS set */
uint16_t hc_extcap; /* extended HT capabilities */
uint32_t hc_txbf; /* txbf capabilities */
uint8_t hc_antenna; /* antenna capabilities */
} __packed;
/* HT capability flags (ht_cap) */
#define IEEE80211_HTCAP_LDPC 0x0001 /* LDPC supported */
#define IEEE80211_HTCAP_CHWIDTH40 0x0002 /* 20/40 supported */
#define IEEE80211_HTCAP_SMPS 0x000c /* SM Power Save mode */
#define IEEE80211_HTCAP_SMPS_OFF 0x0000 /* none (static mode) */
#define IEEE80211_HTCAP_SMPS_DYNAMIC 0x0004 /* send RTS first */
/* NB: SMPS value 2 is reserved */
#define IEEE80211_HTCAP_SMPS_ENA 0x000c /* enabled */
#define IEEE80211_HTCAP_GREENFIELD 0x0010 /* Greenfield supported */
#define IEEE80211_HTCAP_SHORTGI20 0x0020 /* Short GI in 20MHz */
#define IEEE80211_HTCAP_SHORTGI40 0x0040 /* Short GI in 40MHz */
#define IEEE80211_HTCAP_TXSTBC 0x0080 /* STBC tx ok */
#define IEEE80211_HTCAP_RXSTBC 0x0300 /* STBC rx support */
#define IEEE80211_HTCAP_RXSTBC_S 8
#define IEEE80211_HTCAP_RXSTBC_1STREAM 0x0100 /* 1 spatial stream */
#define IEEE80211_HTCAP_RXSTBC_2STREAM 0x0200 /* 1-2 spatial streams*/
#define IEEE80211_HTCAP_RXSTBC_3STREAM 0x0300 /* 1-3 spatial streams*/
#define IEEE80211_HTCAP_DELBA 0x0400 /* HT DELBA supported */
#define IEEE80211_HTCAP_MAXAMSDU 0x0800 /* max A-MSDU length */
#define IEEE80211_HTCAP_MAXAMSDU_7935 0x0800 /* 7935 octets */
#define IEEE80211_HTCAP_MAXAMSDU_3839 0x0000 /* 3839 octets */
#define IEEE80211_HTCAP_DSSSCCK40 0x1000 /* DSSS/CCK in 40MHz */
#define IEEE80211_HTCAP_PSMP 0x2000 /* PSMP supported */
#define IEEE80211_HTCAP_40INTOLERANT 0x4000 /* 40MHz intolerant */
#define IEEE80211_HTCAP_LSIGTXOPPROT 0x8000 /* L-SIG TXOP prot */
/* HT parameters (hc_param) */
#define IEEE80211_HTCAP_MAXRXAMPDU 0x03 /* max rx A-MPDU factor */
#define IEEE80211_HTCAP_MAXRXAMPDU_S 0
#define IEEE80211_HTCAP_MAXRXAMPDU_8K 0x00
#define IEEE80211_HTCAP_MAXRXAMPDU_16K 0x01
#define IEEE80211_HTCAP_MAXRXAMPDU_32K 0x02
#define IEEE80211_HTCAP_MAXRXAMPDU_64K 0x03
#define IEEE80211_HTCAP_MPDUDENSITY 0x1c /* min MPDU start spacing */
#define IEEE80211_HTCAP_MPDUDENSITY_S 2
#define IEEE80211_HTCAP_MPDUDENSITY_NA 0x00 /* no time restriction */
#define IEEE80211_HTCAP_MPDUDENSITY_025 0x04 /* 1/4 us */
#define IEEE80211_HTCAP_MPDUDENSITY_05 0x08 /* 1/2 us */
#define IEEE80211_HTCAP_MPDUDENSITY_1 0x0c /* 1 us */
#define IEEE80211_HTCAP_MPDUDENSITY_2 0x10 /* 2 us */
#define IEEE80211_HTCAP_MPDUDENSITY_4 0x14 /* 4 us */
#define IEEE80211_HTCAP_MPDUDENSITY_8 0x18 /* 8 us */
#define IEEE80211_HTCAP_MPDUDENSITY_16 0x1c /* 16 us */
/* HT extended capabilities (hc_extcap) */
#define IEEE80211_HTCAP_PCO 0x0001 /* PCO capable */
#define IEEE80211_HTCAP_PCOTRANS 0x0006 /* PCO transition time */
#define IEEE80211_HTCAP_PCOTRANS_S 1
#define IEEE80211_HTCAP_PCOTRANS_04 0x0002 /* 400 us */
#define IEEE80211_HTCAP_PCOTRANS_15 0x0004 /* 1.5 ms */
#define IEEE80211_HTCAP_PCOTRANS_5 0x0006 /* 5 ms */
/* bits 3-7 reserved */
#define IEEE80211_HTCAP_MCSFBACK 0x0300 /* MCS feedback */
#define IEEE80211_HTCAP_MCSFBACK_S 8
#define IEEE80211_HTCAP_MCSFBACK_NONE 0x0000 /* nothing provided */
#define IEEE80211_HTCAP_MCSFBACK_UNSOL 0x0200 /* unsolicited feedback */
#define IEEE80211_HTCAP_MCSFBACK_MRQ 0x0300 /* " "+respond to MRQ */
#define IEEE80211_HTCAP_HTC 0x0400 /* +HTC support */
#define IEEE80211_HTCAP_RDR 0x0800 /* reverse direction responder*/
/* bits 12-15 reserved */
/*
* 802.11n HT Information IE
*/
struct ieee80211_ie_htinfo {
uint8_t hi_id; /* element ID */
uint8_t hi_len; /* length in bytes */
uint8_t hi_ctrlchannel; /* primary channel */
uint8_t hi_byte1; /* ht ie byte 1 */
uint16_t hi_byte23; /* ht ie bytes 2+3 */
uint16_t hi_byte45; /* ht ie bytes 4+5 */
uint8_t hi_basicmcsset[16]; /* basic MCS set */
} __packed;
/* byte1 */
#define IEEE80211_HTINFO_2NDCHAN 0x03 /* secondary/ext chan offset */
#define IEEE80211_HTINFO_2NDCHAN_S 0
#define IEEE80211_HTINFO_2NDCHAN_NONE 0x00 /* no secondary/ext channel */
#define IEEE80211_HTINFO_2NDCHAN_ABOVE 0x01 /* above private channel */
/* NB: 2 is reserved */
#define IEEE80211_HTINFO_2NDCHAN_BELOW 0x03 /* below primary channel */
#define IEEE80211_HTINFO_TXWIDTH 0x04 /* tx channel width */
#define IEEE80211_HTINFO_TXWIDTH_20 0x00 /* 20MHz width */
#define IEEE80211_HTINFO_TXWIDTH_2040 0x04 /* any supported width */
#define IEEE80211_HTINFO_RIFSMODE 0x08 /* Reduced IFS (RIFS) use */
#define IEEE80211_HTINFO_RIFSMODE_PROH 0x00 /* RIFS use prohibited */
#define IEEE80211_HTINFO_RIFSMODE_PERM 0x08 /* RIFS use permitted */
#define IEEE80211_HTINFO_PMSPONLY 0x10 /* PSMP required to associate */
#define IEEE80211_HTINFO_SIGRAN 0xe0 /* shortest Service Interval */
#define IEEE80211_HTINFO_SIGRAN_S 5
#define IEEE80211_HTINFO_SIGRAN_5 0x00 /* 5 ms */
/* XXX add rest */
/* bytes 2+3 */
#define IEEE80211_HTINFO_OPMODE 0x03 /* operating mode */
#define IEEE80211_HTINFO_OPMODE_S 0
#define IEEE80211_HTINFO_OPMODE_PURE 0x00 /* no protection */
#define IEEE80211_HTINFO_OPMODE_MIXED 0x01 /* protection required */
#define IEEE80211_HTINFO_OPMODE_PROTOPT 0x02 /* protection optional */
#define IEEE80211_HTINFO_OPMODE_TBD 0x03
#define IEEE80211_HTINFO_NONGF_PRESENT 0x04 /* non-GF sta's present */
#define IEEE80211_HTINFO_TXBL 0x08 /* transmit burst limit */
#define IEEE80211_HTINFO_NONHT_PRESENT 0x10 /* non-HT sta's present */
/* bits 5-15 reserved */
/* bytes 4+5 */
#define IEEE80211_HTINFO_2NDARYBEACON 0x01
#define IEEE80211_HTINFO_LSIGTXOPPROT 0x02
#define IEEE80211_HTINFO_PCO_ACTIVE 0x04
#define IEEE80211_HTINFO_40MHZPHASE 0x08
/* byte5 */
#define IEEE80211_HTINFO_BASIC_STBCMCS 0x7f
#define IEEE80211_HTINFO_BASIC_STBCMCS_S 0
#define IEEE80211_HTINFO_DUALPROTECTED 0x80
/*
* Management information element payloads.
*/
@ -397,34 +649,68 @@ enum {
IEEE80211_ELEMID_COUNTRY = 7,
IEEE80211_ELEMID_CHALLENGE = 16,
/* 17-31 reserved for challenge text extension */
IEEE80211_ELEMID_PWRCNSTR = 32,
IEEE80211_ELEMID_PWRCAP = 33,
IEEE80211_ELEMID_TPCREQ = 34,
IEEE80211_ELEMID_TPCREP = 35,
IEEE80211_ELEMID_SUPPCHAN = 36,
IEEE80211_ELEMID_CHANSWITCHANN = 37,
IEEE80211_ELEMID_MEASREQ = 38,
IEEE80211_ELEMID_MEASREP = 39,
IEEE80211_ELEMID_QUIET = 40,
IEEE80211_ELEMID_IBSSDFS = 41,
IEEE80211_ELEMID_ERP = 42,
IEEE80211_ELEMID_HTCAP = 45,
IEEE80211_ELEMID_RSN = 48,
IEEE80211_ELEMID_XRATES = 50,
IEEE80211_ELEMID_HTINFO = 61,
IEEE80211_ELEMID_TPC = 150,
IEEE80211_ELEMID_CCKM = 156,
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
};
struct ieee80211_tim_ie {
u_int8_t tim_ie; /* IEEE80211_ELEMID_TIM */
u_int8_t tim_len;
u_int8_t tim_count; /* DTIM count */
u_int8_t tim_period; /* DTIM period */
u_int8_t tim_bitctl; /* bitmap control */
u_int8_t tim_bitmap[1]; /* variable-length bitmap */
uint8_t tim_ie; /* IEEE80211_ELEMID_TIM */
uint8_t tim_len;
uint8_t tim_count; /* DTIM count */
uint8_t tim_period; /* DTIM period */
uint8_t tim_bitctl; /* bitmap control */
uint8_t tim_bitmap[1]; /* variable-length bitmap */
} __packed;
struct ieee80211_country_ie {
u_int8_t ie; /* IEEE80211_ELEMID_COUNTRY */
u_int8_t len;
u_int8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */
uint8_t ie; /* IEEE80211_ELEMID_COUNTRY */
uint8_t len;
uint8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */
struct {
u_int8_t schan; /* starting channel */
u_int8_t nchan; /* number channels */
u_int8_t maxtxpwr; /* tx power cap */
uint8_t schan; /* starting channel */
uint8_t nchan; /* number channels */
uint8_t maxtxpwr; /* tx power cap */
} __packed band[4]; /* up to 4 sub bands */
} __packed;
/*
* Atheros advanced capability information element.
*/
struct ieee80211_ath_ie {
uint8_t ath_id; /* IEEE80211_ELEMID_VENDOR */
uint8_t ath_len; /* length in bytes */
uint8_t ath_oui[3]; /* 0x00, 0x03, 0x7f */
uint8_t ath_oui_type; /* OUI type */
uint8_t ath_oui_subtype; /* OUI subtype */
uint8_t ath_version; /* spec revision */
uint8_t ath_capability; /* capability info */
#define ATHEROS_CAP_TURBO_PRIME 0x01 /* dynamic turbo--aka Turbo' */
#define ATHEROS_CAP_COMPRESSION 0x02 /* data compression */
#define ATHEROS_CAP_FAST_FRAME 0x04 /* fast (jumbo) frames */
#define ATHEROS_CAP_XR 0x08 /* Xtended Range support */
#define ATHEROS_CAP_AR 0x10 /* Advanded Radar support */
#define ATHEROS_CAP_BURST 0x20 /* Bursting - not negotiated */
#define ATHEROS_CAP_WME 0x40 /* CWMin tuning */
#define ATHEROS_CAP_BOOST 0x80 /* use turbo/!turbo mode */
uint8_t ath_defkeyix[2];
} __packed;
#define IEEE80211_CHALLENGE_LEN 128
#define IEEE80211_RATE_BASIC 0x80
@ -435,16 +721,14 @@ struct ieee80211_country_ie {
#define IEEE80211_ERP_USE_PROTECTION 0x02
#define IEEE80211_ERP_LONG_PREAMBLE 0x04
/* Atheros private advanced capabilities info */
#define ATHEROS_CAP_TURBO_PRIME 0x01
#define ATHEROS_CAP_COMPRESSION 0x02
#define ATHEROS_CAP_FAST_FRAME 0x04
/* bits 3-6 reserved */
#define ATHEROS_CAP_BOOST 0x80
#define ATH_OUI 0x7f0300 /* Atheros OUI */
#define ATH_OUI 0x7f0300 /* Atheros OUI */
#define ATH_OUI_TYPE 0x01
#define ATH_OUI_VERSION 0x01
#define ATH_OUI_SUBTYPE 0x01
#define ATH_OUI_VERSION 0x00
#define BCM_OUI 0x4c9000 /* Broadcom OUI */
#define BCM_OUI_HTCAP 51 /* pre-draft HTCAP ie */
#define BCM_OUI_HTINFO 52 /* pre-draft HTINFO ie */
#define WPA_OUI 0xf25000
#define WPA_OUI_TYPE 0x01
@ -499,7 +783,7 @@ struct ieee80211_country_ie {
* octet chal.text[253]
*/
typedef u_int8_t *ieee80211_mgt_auth_t;
typedef uint8_t *ieee80211_mgt_auth_t;
#define IEEE80211_AUTH_ALGORITHM(auth) \
((auth)[0] | ((auth)[1] << 8))
@ -654,4 +938,69 @@ enum {
#define IEEE80211_HWBMISS_MIN 1
#define IEEE80211_HWBMISS_MAX 255
/*
* 802.11 frame duration definitions.
*/
struct ieee80211_duration {
uint16_t d_rts_dur;
uint16_t d_data_dur;
uint16_t d_plcp_len;
uint8_t d_residue; /* unused octets in time slot */
};
/* One Time Unit (TU) is 1Kus = 1024 microseconds. */
#define IEEE80211_DUR_TU 1024
/* IEEE 802.11b durations for DSSS PHY in microseconds */
#define IEEE80211_DUR_DS_LONG_PREAMBLE 144
#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72
#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48
#define IEEE80211_DUR_DS_FAST_PLCPHDR 24
#define IEEE80211_DUR_DS_SLOW_ACK 112
#define IEEE80211_DUR_DS_FAST_ACK 56
#define IEEE80211_DUR_DS_SLOW_CTS 112
#define IEEE80211_DUR_DS_FAST_CTS 56
#define IEEE80211_DUR_DS_SLOT 20
#define IEEE80211_DUR_DS_SIFS 10
#define IEEE80211_DUR_DS_PIFS (IEEE80211_DUR_DS_SIFS + IEEE80211_DUR_DS_SLOT)
#define IEEE80211_DUR_DS_DIFS (IEEE80211_DUR_DS_SIFS + \
2 * IEEE80211_DUR_DS_SLOT)
#define IEEE80211_DUR_DS_EIFS (IEEE80211_DUR_DS_SIFS + \
IEEE80211_DUR_DS_SLOW_ACK + \
IEEE80211_DUR_DS_LONG_PREAMBLE + \
IEEE80211_DUR_DS_SLOW_PLCPHDR + \
IEEE80211_DUR_DIFS)
/*
* Atheros fast-frame encapsulation format.
* FF max payload:
* 802.2 + FFHDR + HPAD + 802.3 + 802.2 + 1500 + SPAD + 802.3 + 802.2 + 1500:
* 8 + 4 + 4 + 14 + 8 + 1500 + 6 + 14 + 8 + 1500
* = 3066
*/
/* fast frame header is 32-bits */
#define ATH_FF_PROTO 0x0000003f /* protocol */
#define ATH_FF_PROTO_S 0
#define ATH_FF_FTYPE 0x000000c0 /* frame type */
#define ATH_FF_FTYPE_S 6
#define ATH_FF_HLEN32 0x00000300 /* optional hdr length */
#define ATH_FF_HLEN32_S 8
#define ATH_FF_SEQNUM 0x001ffc00 /* sequence number */
#define ATH_FF_SEQNUM_S 10
#define ATH_FF_OFFSET 0xffe00000 /* offset to 2nd payload */
#define ATH_FF_OFFSET_S 21
#define ATH_FF_MAX_HDR_PAD 4
#define ATH_FF_MAX_SEP_PAD 6
#define ATH_FF_MAX_HDR 30
#define ATH_FF_PROTO_L2TUNNEL 0 /* L2 tunnel protocol */
#define ATH_FF_ETH_TYPE 0x88bd /* Ether type for encapsulated frames */
#define ATH_FF_SNAP_ORGCODE_0 0x00
#define ATH_FF_SNAP_ORGCODE_1 0x03
#define ATH_FF_SNAP_ORGCODE_2 0x7f
#endif /* _NET80211_IEEE80211_H_ */

View File

@ -64,7 +64,7 @@ enum {
struct acl {
TAILQ_ENTRY(acl) acl_list;
LIST_ENTRY(acl) acl_hash;
u_int8_t acl_macaddr[IEEE80211_ADDR_LEN];
uint8_t acl_macaddr[IEEE80211_ADDR_LEN];
};
struct aclstate {
acl_lock_t as_lock;
@ -77,7 +77,7 @@ struct aclstate {
/* simple hash is enough for variation of macaddr */
#define ACL_HASH(addr) \
(((const u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
(((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl");
@ -112,7 +112,7 @@ acl_detach(struct ieee80211com *ic)
}
static __inline struct acl *
_find_acl(struct aclstate *as, const u_int8_t *macaddr)
_find_acl(struct aclstate *as, const uint8_t *macaddr)
{
struct acl *acl;
int hash;
@ -137,7 +137,7 @@ _acl_free(struct aclstate *as, struct acl *acl)
}
static int
acl_check(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
acl_check(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct aclstate *as = ic->ic_as;
@ -153,7 +153,7 @@ acl_check(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
}
static int
acl_add(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
acl_add(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct aclstate *as = ic->ic_as;
struct acl *acl, *new;
@ -191,7 +191,7 @@ acl_add(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
}
static int
acl_remove(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN])
acl_remove(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
{
struct aclstate *as = ic->ic_as;
struct acl *acl;

View File

@ -64,11 +64,11 @@ __FBSDID("$FreeBSD$");
void
ieee80211_amrr_init(struct ieee80211_amrr *amrr,
struct ieee80211com *ic, int min, int max)
struct ieee80211com *ic, int amin, int amax)
{
/* XXX bounds check? */
amrr->amrr_min_success_threshold = min;
amrr->amrr_max_success_threshold = max;
amrr->amrr_min_success_threshold = amin;
amrr->amrr_max_success_threshold = amax;
amrr->amrr_ic = ic;
}

View File

@ -84,7 +84,7 @@ null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
}
static int
null_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
const u_int8_t mac[IEEE80211_ADDR_LEN])
const uint8_t mac[IEEE80211_ADDR_LEN])
{
return 1;
}
@ -125,7 +125,7 @@ dev_key_delete(struct ieee80211com *ic,
static __inline int
dev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key,
const u_int8_t mac[IEEE80211_ADDR_LEN])
const uint8_t mac[IEEE80211_ADDR_LEN])
{
return ic->ic_crypto.cs_key_set(ic, key, mac);
}
@ -461,7 +461,7 @@ ieee80211_crypto_delglobalkeys(struct ieee80211com *ic)
*/
int
ieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key,
const u_int8_t macaddr[IEEE80211_ADDR_LEN])
const uint8_t macaddr[IEEE80211_ADDR_LEN])
{
const struct ieee80211_cipher *cip = key->wk_cipher;
@ -505,7 +505,7 @@ ieee80211_crypto_encap(struct ieee80211com *ic,
struct ieee80211_key *k;
struct ieee80211_frame *wh;
const struct ieee80211_cipher *cip;
u_int8_t keyid;
uint8_t keyid;
/*
* Multicast traffic always uses the multicast key.
@ -549,8 +549,8 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
struct ieee80211_key *k;
struct ieee80211_frame *wh;
const struct ieee80211_cipher *cip;
const u_int8_t *ivp;
u_int8_t keyid;
const uint8_t *ivp;
uint8_t keyid;
/* NB: this minimum size data frame could be bigger */
if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
@ -568,7 +568,7 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
* the key id in the header is meaningless (typically 0).
*/
wh = mtod(m, struct ieee80211_frame *);
ivp = mtod(m, const u_int8_t *) + hdrlen; /* XXX contig */
ivp = mtod(m, const uint8_t *) + hdrlen; /* XXX contig */
keyid = ivp[IEEE80211_WEP_IVLEN];
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey))
@ -586,7 +586,7 @@ ieee80211_crypto_decap(struct ieee80211com *ic,
"[%s] unable to pullup %s header\n",
ether_sprintf(wh->i_addr2), cip->ic_name);
ic->ic_stats.is_rx_wepfail++; /* XXX */
return 0;
return NULL;
}
return (cip->ic_decap(k, m, hdrlen) ? k : NULL);

View File

@ -39,7 +39,7 @@
*/
struct ieee80211_wepkey {
u_int wk_len; /* key length in bytes */
u_int8_t wk_key[IEEE80211_KEYBUF_SIZE];
uint8_t wk_key[IEEE80211_KEYBUF_SIZE];
};
struct ieee80211_cipher;
@ -60,12 +60,12 @@ struct ieee80211_cipher;
* Ciphers such as TKIP may also support mixed hardware/software
* encrypt/decrypt and MIC processing.
*/
typedef u_int16_t ieee80211_keyix; /* h/w key index */
typedef uint16_t ieee80211_keyix; /* h/w key index */
struct ieee80211_key {
u_int8_t wk_keylen; /* key length in bytes */
u_int8_t wk_pad;
u_int16_t wk_flags;
uint8_t wk_keylen; /* key length in bytes */
uint8_t wk_pad;
uint16_t wk_flags;
#define IEEE80211_KEY_XMIT 0x01 /* key used for xmit */
#define IEEE80211_KEY_RECV 0x02 /* key used for recv */
#define IEEE80211_KEY_GROUP 0x04 /* key used for WPA group operation */
@ -73,11 +73,11 @@ struct ieee80211_key {
#define IEEE80211_KEY_SWMIC 0x20 /* host-based enmic/demic */
ieee80211_keyix wk_keyix; /* h/w key index */
ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */
u_int8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
#define wk_txmic wk_key+IEEE80211_KEYBUF_SIZE+0 /* XXX can't () right */
#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */
u_int64_t wk_keyrsc; /* key receive sequence counter */
u_int64_t wk_keytsc; /* key transmit sequence counter */
uint64_t wk_keyrsc; /* key receive sequence counter */
uint64_t wk_keytsc; /* key transmit sequence counter */
const struct ieee80211_cipher *wk_cipher;
void *wk_private; /* private cipher state */
};
@ -116,7 +116,7 @@ struct mbuf;
struct ieee80211_crypto_state {
struct ieee80211_key cs_nw_keys[IEEE80211_WEP_NKID];
ieee80211_keyix cs_def_txkey; /* default/group tx key index */
u_int16_t cs_max_keyix; /* max h/w key index */
uint16_t cs_max_keyix; /* max h/w key index */
int (*cs_key_alloc)(struct ieee80211com *,
const struct ieee80211_key *,
@ -125,7 +125,7 @@ struct ieee80211_crypto_state {
const struct ieee80211_key *);
int (*cs_key_set)(struct ieee80211com *,
const struct ieee80211_key *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
const uint8_t mac[IEEE80211_ADDR_LEN]);
void (*cs_key_update_begin)(struct ieee80211com *);
void (*cs_key_update_end)(struct ieee80211com *);
};
@ -137,7 +137,7 @@ int ieee80211_crypto_newkey(struct ieee80211com *,
int ieee80211_crypto_delkey(struct ieee80211com *,
struct ieee80211_key *);
int ieee80211_crypto_setkey(struct ieee80211com *,
struct ieee80211_key *, const u_int8_t macaddr[IEEE80211_ADDR_LEN]);
struct ieee80211_key *, const uint8_t macaddr[IEEE80211_ADDR_LEN]);
void ieee80211_crypto_delglobalkeys(struct ieee80211com *);
/*
@ -156,7 +156,7 @@ struct ieee80211_cipher {
void (*ic_detach)(struct ieee80211_key *);
int (*ic_setkey)(struct ieee80211_key *);
int (*ic_encap)(struct ieee80211_key *, struct mbuf *,
u_int8_t keyid);
uint8_t keyid);
int (*ic_decap)(struct ieee80211_key *, struct mbuf *, int);
int (*ic_enmic)(struct ieee80211_key *, struct mbuf *, int);
int (*ic_demic)(struct ieee80211_key *, struct mbuf *, int);

View File

@ -60,7 +60,7 @@ struct ccmp_ctx {
static void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
static void ccmp_detach(struct ieee80211_key *);
static int ccmp_setkey(struct ieee80211_key *);
static int ccmp_encap(struct ieee80211_key *k, struct mbuf *, u_int8_t keyid);
static int ccmp_encap(struct ieee80211_key *k, struct mbuf *, uint8_t keyid);
static int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
static int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
static int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
@ -134,11 +134,11 @@ ccmp_setkey(struct ieee80211_key *k)
* Add privacy headers appropriate for the specified key.
*/
static int
ccmp_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
ccmp_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
{
struct ccmp_ctx *ctx = k->wk_private;
struct ieee80211com *ic = ctx->cc_ic;
u_int8_t *ivp;
uint8_t *ivp;
int hdrlen;
hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
@ -149,7 +149,7 @@ ccmp_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
if (m == NULL)
return 0;
ivp = mtod(m, u_int8_t *);
ivp = mtod(m, uint8_t *);
ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen);
ivp += hdrlen;
@ -244,7 +244,7 @@ ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
/*
* Copy up 802.11 header and strip crypto bits.
*/
ovbcopy(mtod(m, void *), mtod(m, u_int8_t *) + ccmp.ic_header, hdrlen);
ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen);
m_adj(m, ccmp.ic_header);
m_adj(m, -ccmp.ic_trailer);
@ -350,7 +350,7 @@ ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh,
b0[1] = aad[30];
aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
} else {
*(u_int16_t *)&aad[30] = 0;
*(uint16_t *)&aad[30] = 0;
b0[1] = 0;
aad[1] = 22 + IEEE80211_ADDR_LEN;
}
@ -363,12 +363,12 @@ ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh,
b0[1] = aad[24];
aad[1] = 22 + 2;
} else {
*(u_int16_t *)&aad[24] = 0;
*(uint16_t *)&aad[24] = 0;
b0[1] = 0;
aad[1] = 22;
}
*(u_int16_t *)&aad[26] = 0;
*(u_int32_t *)&aad[28] = 0;
*(uint16_t *)&aad[26] = 0;
*(uint32_t *)&aad[28] = 0;
}
/* Start with the first block and AAD */
@ -629,32 +629,4 @@ ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen
/*
* Module glue.
*/
static int
ccmp_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
ieee80211_crypto_register(&ccmp);
return 0;
case MOD_UNLOAD:
case MOD_QUIESCE:
if (nrefs) {
printf("wlan_ccmp: still in use (%u dynamic refs)\n",
nrefs);
return EBUSY;
}
if (type == MOD_UNLOAD)
ieee80211_crypto_unregister(&ccmp);
return 0;
}
return EINVAL;
}
static moduledata_t ccmp_mod = {
"wlan_ccmp",
ccmp_modevent,
0
};
DECLARE_MODULE(wlan_ccmp, ccmp_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(wlan_ccmp, 1);
MODULE_DEPEND(wlan_ccmp, wlan, 1, 1, 1);
IEEE80211_CRYPTO_MODULE(ccmp, 1);

View File

@ -45,7 +45,7 @@ __FBSDID("$FreeBSD$");
static void *none_attach(struct ieee80211com *, struct ieee80211_key *);
static void none_detach(struct ieee80211_key *);
static int none_setkey(struct ieee80211_key *);
static int none_encap(struct ieee80211_key *, struct mbuf *, u_int8_t);
static int none_encap(struct ieee80211_key *, struct mbuf *, uint8_t);
static int none_decap(struct ieee80211_key *, struct mbuf *, int);
static int none_enmic(struct ieee80211_key *, struct mbuf *, int);
static int none_demic(struct ieee80211_key *, struct mbuf *, int);
@ -85,7 +85,7 @@ none_setkey(struct ieee80211_key *k)
}
static int
none_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
none_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
{
struct ieee80211com *ic = k->wk_private;
#ifdef IEEE80211_DEBUG
@ -109,7 +109,7 @@ none_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
struct ieee80211com *ic = k->wk_private;
#ifdef IEEE80211_DEBUG
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
const u_int8_t *ivp = (const u_int8_t *)&wh[1];
const uint8_t *ivp = (const uint8_t *)&wh[1];
#endif
/*

View File

@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$");
static void *tkip_attach(struct ieee80211com *, struct ieee80211_key *);
static void tkip_detach(struct ieee80211_key *);
static int tkip_setkey(struct ieee80211_key *);
static int tkip_encap(struct ieee80211_key *, struct mbuf *m, u_int8_t keyid);
static int tkip_encap(struct ieee80211_key *, struct mbuf *m, uint8_t keyid);
static int tkip_enmic(struct ieee80211_key *, struct mbuf *, int);
static int tkip_decap(struct ieee80211_key *, struct mbuf *, int);
static int tkip_demic(struct ieee80211_key *, struct mbuf *, int);
@ -150,11 +150,11 @@ tkip_setkey(struct ieee80211_key *k)
* Add privacy headers and do any s/w encryption required.
*/
static int
tkip_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
tkip_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
{
struct tkip_ctx *ctx = k->wk_private;
struct ieee80211com *ic = ctx->tc_ic;
u_int8_t *ivp;
uint8_t *ivp;
int hdrlen;
/*
@ -179,7 +179,7 @@ tkip_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
M_PREPEND(m, tkip.ic_header, M_NOWAIT);
if (m == NULL)
return 0;
ivp = mtod(m, u_int8_t *);
ivp = mtod(m, uint8_t *);
memmove(ivp, ivp + tkip.ic_header, hdrlen);
ivp += hdrlen;
@ -970,32 +970,4 @@ tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
/*
* Module glue.
*/
static int
tkip_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
ieee80211_crypto_register(&tkip);
return 0;
case MOD_UNLOAD:
case MOD_QUIESCE:
if (nrefs) {
printf("wlan_tkip: still in use (%u dynamic refs)\n",
nrefs);
return EBUSY;
}
if (type == MOD_UNLOAD)
ieee80211_crypto_unregister(&tkip);
return 0;
}
return EINVAL;
}
static moduledata_t tkip_mod = {
"wlan_tkip",
tkip_modevent,
0
};
DECLARE_MODULE(wlan_tkip, tkip_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(wlan_tkip, 1);
MODULE_DEPEND(wlan_tkip, wlan, 1, 1, 1);
IEEE80211_CRYPTO_MODULE(tkip, 1);

View File

@ -48,7 +48,7 @@ __FBSDID("$FreeBSD$");
static void *wep_attach(struct ieee80211com *, struct ieee80211_key *);
static void wep_detach(struct ieee80211_key *);
static int wep_setkey(struct ieee80211_key *);
static int wep_encap(struct ieee80211_key *, struct mbuf *, u_int8_t keyid);
static int wep_encap(struct ieee80211_key *, struct mbuf *, uint8_t keyid);
static int wep_decap(struct ieee80211_key *, struct mbuf *, int hdrlen);
static int wep_enmic(struct ieee80211_key *, struct mbuf *, int);
static int wep_demic(struct ieee80211_key *, struct mbuf *, int);
@ -73,7 +73,7 @@ static int wep_decrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
struct wep_ctx {
struct ieee80211com *wc_ic; /* for diagnostics */
u_int32_t wc_iv; /* initial vector for crypto */
uint32_t wc_iv; /* initial vector for crypto */
};
/* number of references from net80211 layer */
@ -117,12 +117,12 @@ wep_setkey(struct ieee80211_key *k)
* Add privacy headers appropriate for the specified key.
*/
static int
wep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
wep_encap(struct ieee80211_key *k, struct mbuf *m, uint8_t keyid)
{
struct wep_ctx *ctx = k->wk_private;
struct ieee80211com *ic = ctx->wc_ic;
u_int32_t iv;
u_int8_t *ivp;
uint32_t iv;
uint8_t *ivp;
int hdrlen;
hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
@ -133,7 +133,7 @@ wep_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
M_PREPEND(m, wep.ic_header, M_NOWAIT);
if (m == NULL)
return 0;
ivp = mtod(m, u_int8_t *);
ivp = mtod(m, uint8_t *);
ovbcopy(ivp + wep.ic_header, ivp, hdrlen);
ivp += hdrlen;
@ -229,7 +229,7 @@ wep_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
/*
* Copy up 802.11 header and strip crypto bits.
*/
ovbcopy(mtod(m, void *), mtod(m, u_int8_t *) + wep.ic_header, hdrlen);
ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + wep.ic_header, hdrlen);
m_adj(m, wep.ic_header);
m_adj(m, -wep.ic_trailer);
@ -306,7 +306,7 @@ wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
struct wep_ctx *ctx = key->wk_private;
struct mbuf *m = m0;
u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
uint8_t icv[IEEE80211_WEP_CRCLEN];
uint32_t i, j, k, crc;
size_t buflen, data_len;
@ -317,7 +317,7 @@ wep_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
ctx->wc_ic->ic_stats.is_crypto_wep++;
/* NB: this assumes the header was pulled up */
memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
/* Setup RC4 state */
@ -388,7 +388,7 @@ wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
#define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
struct wep_ctx *ctx = key->wk_private;
struct mbuf *m = m0;
u_int8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
uint8_t rc4key[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE];
uint8_t icv[IEEE80211_WEP_CRCLEN];
uint32_t i, j, k, crc;
size_t buflen, data_len;
@ -399,7 +399,7 @@ wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
ctx->wc_ic->ic_stats.is_crypto_wep++;
/* NB: this assumes the header was pulled up */
memcpy(rc4key, mtod(m, u_int8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
memcpy(rc4key, mtod(m, uint8_t *) + hdrlen, IEEE80211_WEP_IVLEN);
memcpy(rc4key + IEEE80211_WEP_IVLEN, key->wk_key, key->wk_keylen);
/* Setup RC4 state */
@ -473,32 +473,4 @@ wep_decrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
/*
* Module glue.
*/
static int
wep_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
ieee80211_crypto_register(&wep);
return 0;
case MOD_UNLOAD:
case MOD_QUIESCE:
if (nrefs) {
printf("wlan_wep: still in use (%u dynamic refs)\n",
nrefs);
return EBUSY;
}
if (type == MOD_UNLOAD)
ieee80211_crypto_unregister(&wep);
return 0;
}
return EINVAL;
}
static moduledata_t wep_mod = {
"wlan_wep",
wep_modevent,
0
};
DECLARE_MODULE(wlan_wep, wep_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(wlan_wep, 1);
MODULE_DEPEND(wlan_wep, wlan, 1, 1, 1);
IEEE80211_CRYPTO_MODULE(wep, 1);

View File

@ -168,6 +168,15 @@ ieee80211_drain_ifq(struct ifqueue *ifq)
}
}
/*
* As above, for mbufs allocated with m_gethdr/MGETHDR
* or initialized by M_COPY_PKTHDR.
*/
#define MC_ALIGN(m, len) \
do { \
(m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1); \
} while (/* CONSTCOND */ 0)
/*
* Allocate and setup a management frame of the specified
* size. We return the mbuf and a pointer to the start
@ -178,7 +187,7 @@ ieee80211_drain_ifq(struct ifqueue *ifq)
* can use this interface too.
*/
struct mbuf *
ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
{
struct mbuf *m;
u_int len;
@ -187,8 +196,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
* NB: we know the mbuf routines will align the data area
* so we don't need to do anything special.
*/
/* XXX 4-address frame? */
len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4);
len = roundup2(headroom + pktlen, 4);
KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
if (len < MINCLSIZE) {
m = m_gethdr(M_NOWAIT, MT_DATA);
@ -200,8 +208,11 @@ ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
*/
if (m != NULL)
MH_ALIGN(m, len);
} else
} else {
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (m != NULL)
MC_ALIGN(m, len);
}
if (m != NULL) {
m->m_data += sizeof(struct ieee80211_frame);
*frm = m->m_data;
@ -209,18 +220,51 @@ ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
return m;
}
int
ieee80211_add_callback(struct mbuf *m,
void (*func)(struct ieee80211_node *, void *, int), void *arg)
{
struct m_tag *mtag;
struct ieee80211_cb *cb;
mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
sizeof(struct ieee80211_cb), M_NOWAIT);
if (mtag == NULL)
return 0;
cb = (struct ieee80211_cb *)(mtag+1);
cb->func = func;
cb->arg = arg;
m_tag_prepend(m, mtag);
m->m_flags |= M_TXCB;
return 1;
}
void
ieee80211_process_callback(struct ieee80211_node *ni,
struct mbuf *m, int status)
{
struct m_tag *mtag;
mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
if (mtag != NULL) {
struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
cb->func(ni, cb->arg, status);
}
}
#include <sys/libkern.h>
void
get_random_bytes(void *p, size_t n)
{
u_int8_t *dp = p;
uint8_t *dp = p;
while (n > 0) {
u_int32_t v = arc4random();
size_t nb = n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n;
bcopy(&v, dp, n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n);
dp += sizeof(u_int32_t), n -= nb;
uint32_t v = arc4random();
size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
dp += sizeof(uint32_t), n -= nb;
}
}

View File

@ -28,6 +28,18 @@
#define _NET80211_IEEE80211_FREEBSD_H_
#ifdef _KERNEL
/*
* Common state locking definitions.
*/
typedef struct mtx ieee80211_com_lock_t;
#define IEEE80211_LOCK_INIT(_ic, _name) \
mtx_init(&(_ic)->ic_comlock, _name, "802.11 com lock", MTX_DEF)
#define IEEE80211_LOCK_DESTROY(_ic) mtx_destroy(&(_ic)->ic_comlock)
#define IEEE80211_LOCK(_ic) mtx_lock(&(_ic)->ic_comlock)
#define IEEE80211_UNLOCK(_ic) mtx_unlock(&(_ic)->ic_comlock)
#define IEEE80211_LOCK_ASSERT(_ic) \
mtx_assert(&(_ic)->ic_comlock, MA_OWNED)
/*
* Beacon locking definitions.
*/
@ -60,7 +72,7 @@ typedef struct mtx ieee80211_node_lock_t;
*/
typedef struct mtx ieee80211_scan_lock_t;
#define IEEE80211_SCAN_LOCK_INIT(_nt, _name) \
mtx_init(&(_nt)->nt_scanlock, _name, "802.11 scangen", MTX_DEF)
mtx_init(&(_nt)->nt_scanlock, _name, "802.11 node scangen", MTX_DEF)
#define IEEE80211_SCAN_LOCK_DESTROY(_nt) mtx_destroy(&(_nt)->nt_scanlock)
#define IEEE80211_SCAN_LOCK(_nt) mtx_lock(&(_nt)->nt_scanlock)
#define IEEE80211_SCAN_UNLOCK(_nt) mtx_unlock(&(_nt)->nt_scanlock)
@ -165,10 +177,21 @@ int ieee80211_node_dectestref(struct ieee80211_node *ni);
struct ifqueue;
void ieee80211_drain_ifq(struct ifqueue *);
struct mbuf *ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen);
#define msecs_to_ticks(ms) ((ms)*1000/hz)
#define time_after(a,b) ((long)(b) - (long)(a) < 0)
#define time_before(a,b) time_after(b,a)
#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)
#define time_before_eq(a,b) time_after_eq(b,a)
struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen);
/* tx path usage */
#define M_LINK0 M_PROTO1 /* WEP requested */
#define M_PWR_SAV M_PROTO4 /* bypass PS handling */
#define M_MORE_DATA M_PROTO5 /* more data frames to follow */
#define M_FF 0x20000 /* fast frame */
#define M_TXCB 0x40000 /* do tx complete callback */
/* rx path usage */
#define M_AMPDU M_PROTO1 /* A-MPDU processing done */
/*
* Encode WME access control bits in the PROTO flags.
* This is safe since it's passed directly in to the
@ -193,6 +216,17 @@ struct mbuf *ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen);
#define M_AGE_GET(m) (m->m_pkthdr.csum_data)
#define M_AGE_SUB(m,adj) (m->m_pkthdr.csum_data -= adj)
#define MTAG_ABI_NET80211 1132948340 /* net80211 ABI */
struct ieee80211_cb {
void (*func)(struct ieee80211_node *, void *, int status);
void *arg;
};
#define NET80211_TAG_CALLBACK 0 /* xmit complete callback */
int ieee80211_add_callback(struct mbuf *m,
void (*func)(struct ieee80211_node *, void *, int), void *arg);
void ieee80211_process_callback(struct ieee80211_node *, struct mbuf *, int);
void get_random_bytes(void *, size_t);
struct ieee80211com;
@ -201,6 +235,36 @@ void ieee80211_sysctl_attach(struct ieee80211com *);
void ieee80211_sysctl_detach(struct ieee80211com *);
void ieee80211_load_module(const char *);
#define IEEE80211_CRYPTO_MODULE(name, version) \
static int \
name##_modevent(module_t mod, int type, void *unused) \
{ \
switch (type) { \
case MOD_LOAD: \
ieee80211_crypto_register(&name); \
return 0; \
case MOD_UNLOAD: \
case MOD_QUIESCE: \
if (nrefs) { \
printf("wlan_##name: still in use (%u dynamic refs)\n",\
nrefs); \
return EBUSY; \
} \
if (type == MOD_UNLOAD) \
ieee80211_crypto_unregister(&name); \
return 0; \
} \
return EINVAL; \
} \
static moduledata_t name##_mod = { \
"wlan_" #name, \
name##_modevent, \
0 \
}; \
DECLARE_MODULE(wlan_##name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);\
MODULE_VERSION(wlan_##name, version); \
MODULE_DEPEND(wlan_##name, wlan, 1, 1, 1)
#endif /* _KERNEL */
/* XXX this stuff belongs elsewhere */

1472
sys/net80211/ieee80211_ht.c Normal file

File diff suppressed because it is too large Load Diff

113
sys/net80211/ieee80211_ht.h Normal file
View File

@ -0,0 +1,113 @@
/*-
* Copyright (c) 2007 Sam Leffler, Errno Consulting
* 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_HT_H_
#define _NET80211_IEEE80211_HT_H_
/*
* 802.11n protocol implementation definitions.
*/
#define IEEE80211_SEND_ACTION(_ni,_cat, _act, _args) \
((*(_ic)->ic_send_action)(_ni, _cat, _act, _args))
#define IEEE80211_AGGR_BAWMAX 64 /* max block ack window size */
typedef uint16_t ieee80211_seq;
struct ieee80211_tx_ampdu {
u_short txa_flags;
#define IEEE80211_AGGR_IMMEDIATE 0x0001 /* BA policy */
#define IEEE80211_AGGR_XCHGPEND 0x0002 /* ADDBA response pending */
#define IEEE80211_AGGR_RUNNING 0x0004 /* ADDBA response received */
#define IEEE80211_AGGR_SETUP 0x0008 /* deferred state setup */
uint8_t txa_ac;
uint8_t txa_token; /* dialog token */
int txa_qbytes; /* data queued (bytes) */
short txa_qframes; /* data queued (frames) */
ieee80211_seq txa_seqstart;
ieee80211_seq txa_start;
uint16_t txa_wnd; /* BA window size */
uint8_t txa_attempts; /* # setup attempts */
int txa_lastrequest;/* time of last ADDBA request */
struct ifqueue txa_q; /* packet queue */
struct callout txa_timer;
};
/* return non-zero if AMPDU tx for the TID is running */
#define IEEE80211_AMPDU_RUNNING(tap) \
(((tap)->txa_flags & IEEE80211_AGGR_RUNNING) != 0)
/* return non-zero if AMPDU tx for the TID is running or started */
#define IEEE80211_AMPDU_REQUESTED(tap) \
(((tap)->txa_flags & \
(IEEE80211_AGGR_RUNNING|IEEE80211_AGGR_XCHGPEND)) != 0)
struct ieee80211_rx_ampdu {
int rxa_flags;
int rxa_qbytes; /* data queued (bytes) */
short rxa_qframes; /* data queued (frames) */
ieee80211_seq rxa_seqstart;
ieee80211_seq rxa_start; /* start of current BA window */
ieee80211_seq rxa_nxt; /* next seq# in BA window */
uint16_t rxa_wnd; /* BA window size */
struct mbuf *rxa_m[IEEE80211_AGGR_BAWMAX];
};
void ieee80211_ht_attach(struct ieee80211com *);
void ieee80211_ht_detach(struct ieee80211com *);
void ieee80211_ht_announce(struct ieee80211com *);
extern const int ieee80211_htrates[16];
const struct ieee80211_htrateset *ieee80211_get_suphtrates(
struct ieee80211com *, const struct ieee80211_channel *);
struct ieee80211_node;
int ieee80211_setup_htrates(struct ieee80211_node *,
const uint8_t *htcap, int flags);
void ieee80211_setup_basic_htrates(struct ieee80211_node *,
const uint8_t *htinfo);
struct mbuf *ieee80211_decap_amsdu(struct ieee80211_node *, struct mbuf *);
int ieee80211_ampdu_reorder(struct ieee80211_node *, struct mbuf *);
void ieee80211_recv_bar(struct ieee80211_node *, struct mbuf *);
void ieee80211_ht_node_init(struct ieee80211_node *, const uint8_t *);
void ieee80211_ht_node_cleanup(struct ieee80211_node *);
void ieee80211_parse_htcap(struct ieee80211_node *, const uint8_t *);
void ieee80211_parse_htinfo(struct ieee80211_node *, const uint8_t *);
void ieee80211_recv_action(struct ieee80211_node *,
const uint8_t *, const uint8_t *);
int ieee80211_ampdu_request(struct ieee80211_node *,
struct ieee80211_tx_ampdu *);
int ieee80211_send_bar(struct ieee80211_node *,
const struct ieee80211_tx_ampdu *);
int ieee80211_send_action(struct ieee80211_node *,
int, int, uint16_t [4]);
uint8_t *ieee80211_add_htcap(uint8_t *, struct ieee80211_node *);
uint8_t *ieee80211_add_htcap_vendor(uint8_t *, struct ieee80211_node *);
uint8_t *ieee80211_add_htinfo(uint8_t *, struct ieee80211_node *);
uint8_t *ieee80211_add_htinfo_vendor(uint8_t *, struct ieee80211_node *);
#endif /* _NET80211_IEEE80211_HT_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -39,146 +39,158 @@
* Per/node (station) statistics.
*/
struct ieee80211_nodestats {
u_int32_t ns_rx_data; /* rx data frames */
u_int32_t ns_rx_mgmt; /* rx management frames */
u_int32_t ns_rx_ctrl; /* rx control frames */
u_int32_t ns_rx_ucast; /* rx unicast frames */
u_int32_t ns_rx_mcast; /* rx multi/broadcast frames */
u_int64_t ns_rx_bytes; /* rx data count (bytes) */
u_int64_t ns_rx_beacons; /* rx beacon frames */
u_int32_t ns_rx_proberesp; /* rx probe response frames */
uint32_t ns_rx_data; /* rx data frames */
uint32_t ns_rx_mgmt; /* rx management frames */
uint32_t ns_rx_ctrl; /* rx control frames */
uint32_t ns_rx_ucast; /* rx unicast frames */
uint32_t ns_rx_mcast; /* rx multi/broadcast frames */
uint64_t ns_rx_bytes; /* rx data count (bytes) */
uint64_t ns_rx_beacons; /* rx beacon frames */
uint32_t ns_rx_proberesp; /* rx probe response frames */
u_int32_t ns_rx_dup; /* rx discard 'cuz dup */
u_int32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */
u_int32_t ns_rx_wepfail; /* rx wep processing failed */
u_int32_t ns_rx_demicfail; /* rx demic failed */
u_int32_t ns_rx_decap; /* rx decapsulation failed */
u_int32_t ns_rx_defrag; /* rx defragmentation failed */
u_int32_t ns_rx_disassoc; /* rx disassociation */
u_int32_t ns_rx_deauth; /* rx deauthentication */
u_int32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */
u_int32_t ns_rx_unauth; /* rx on unauthorized port */
u_int32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */
uint32_t ns_rx_dup; /* rx discard 'cuz dup */
uint32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */
uint32_t ns_rx_wepfail; /* rx wep processing failed */
uint32_t ns_rx_demicfail; /* rx demic failed */
uint32_t ns_rx_decap; /* rx decapsulation failed */
uint32_t ns_rx_defrag; /* rx defragmentation failed */
uint32_t ns_rx_disassoc; /* rx disassociation */
uint32_t ns_rx_deauth; /* rx deauthentication */
uint32_t ns_rx_action; /* rx action */
uint32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */
uint32_t ns_rx_unauth; /* rx on unauthorized port */
uint32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */
u_int32_t ns_tx_data; /* tx data frames */
u_int32_t ns_tx_mgmt; /* tx management frames */
u_int32_t ns_tx_ucast; /* tx unicast frames */
u_int32_t ns_tx_mcast; /* tx multi/broadcast frames */
u_int64_t ns_tx_bytes; /* tx data count (bytes) */
u_int32_t ns_tx_probereq; /* tx probe request frames */
uint32_t ns_tx_data; /* tx data frames */
uint32_t ns_tx_mgmt; /* tx management frames */
uint32_t ns_tx_ucast; /* tx unicast frames */
uint32_t ns_tx_mcast; /* tx multi/broadcast frames */
uint64_t ns_tx_bytes; /* tx data count (bytes) */
uint32_t ns_tx_probereq; /* tx probe request frames */
u_int32_t ns_tx_novlantag; /* tx discard 'cuz no tag */
u_int32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */
uint32_t ns_tx_novlantag; /* tx discard 'cuz no tag */
uint32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */
u_int32_t ns_ps_discard; /* ps discard 'cuz of age */
uint32_t ns_ps_discard; /* ps discard 'cuz of age */
/* MIB-related state */
u_int32_t ns_tx_assoc; /* [re]associations */
u_int32_t ns_tx_assoc_fail; /* [re]association failures */
u_int32_t ns_tx_auth; /* [re]authentications */
u_int32_t ns_tx_auth_fail; /* [re]authentication failures*/
u_int32_t ns_tx_deauth; /* deauthentications */
u_int32_t ns_tx_deauth_code; /* last deauth reason */
u_int32_t ns_tx_disassoc; /* disassociations */
u_int32_t ns_tx_disassoc_code; /* last disassociation reason */
uint32_t ns_tx_assoc; /* [re]associations */
uint32_t ns_tx_assoc_fail; /* [re]association failures */
uint32_t ns_tx_auth; /* [re]authentications */
uint32_t ns_tx_auth_fail; /* [re]authentication failures*/
uint32_t ns_tx_deauth; /* deauthentications */
uint32_t ns_tx_deauth_code; /* last deauth reason */
uint32_t ns_tx_disassoc; /* disassociations */
uint32_t ns_tx_disassoc_code; /* last disassociation reason */
};
/*
* Summary statistics.
*/
struct ieee80211_stats {
u_int32_t is_rx_badversion; /* rx frame with bad version */
u_int32_t is_rx_tooshort; /* rx frame too short */
u_int32_t is_rx_wrongbss; /* rx from wrong bssid */
u_int32_t is_rx_dup; /* rx discard 'cuz dup */
u_int32_t is_rx_wrongdir; /* rx w/ wrong direction */
u_int32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */
u_int32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */
u_int32_t is_rx_noprivacy; /* rx w/ wep but privacy off */
u_int32_t is_rx_unencrypted; /* rx w/o wep and privacy on */
u_int32_t is_rx_wepfail; /* rx wep processing failed */
u_int32_t is_rx_decap; /* rx decapsulation failed */
u_int32_t is_rx_mgtdiscard; /* rx discard mgt frames */
u_int32_t is_rx_ctl; /* rx discard ctrl frames */
u_int32_t is_rx_beacon; /* rx beacon frames */
u_int32_t is_rx_rstoobig; /* rx rate set truncated */
u_int32_t is_rx_elem_missing; /* rx required element missing*/
u_int32_t is_rx_elem_toobig; /* rx element too big */
u_int32_t is_rx_elem_toosmall; /* rx element too small */
u_int32_t is_rx_elem_unknown; /* rx element unknown */
u_int32_t is_rx_badchan; /* rx frame w/ invalid chan */
u_int32_t is_rx_chanmismatch; /* rx frame chan mismatch */
u_int32_t is_rx_nodealloc; /* rx frame dropped */
u_int32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */
u_int32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */
u_int32_t is_rx_auth_fail; /* rx sta auth failure */
u_int32_t is_rx_auth_countermeasures;/* rx auth discard 'cuz CM */
u_int32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */
u_int32_t is_rx_assoc_notauth; /* rx assoc w/o auth */
u_int32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */
u_int32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */
u_int32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */
u_int32_t is_rx_deauth; /* rx deauthentication */
u_int32_t is_rx_disassoc; /* rx disassociation */
u_int32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/
u_int32_t is_rx_nobuf; /* rx failed for lack of buf */
u_int32_t is_rx_decryptcrc; /* rx decrypt failed on crc */
u_int32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/
u_int32_t is_rx_bad_auth; /* rx bad auth request */
u_int32_t is_rx_unauth; /* rx on unauthorized port */
u_int32_t is_rx_badkeyid; /* rx w/ incorrect keyid */
u_int32_t is_rx_ccmpreplay; /* rx seq# violation (CCMP) */
u_int32_t is_rx_ccmpformat; /* rx format bad (CCMP) */
u_int32_t is_rx_ccmpmic; /* rx MIC check failed (CCMP) */
u_int32_t is_rx_tkipreplay; /* rx seq# violation (TKIP) */
u_int32_t is_rx_tkipformat; /* rx format bad (TKIP) */
u_int32_t is_rx_tkipmic; /* rx MIC check failed (TKIP) */
u_int32_t is_rx_tkipicv; /* rx ICV check failed (TKIP) */
u_int32_t is_rx_badcipher; /* rx failed 'cuz key type */
u_int32_t is_rx_nocipherctx; /* rx failed 'cuz key !setup */
u_int32_t is_rx_acl; /* rx discard 'cuz acl policy */
u_int32_t is_tx_nobuf; /* tx failed for lack of buf */
u_int32_t is_tx_nonode; /* tx failed for no node */
u_int32_t is_tx_unknownmgt; /* tx of unknown mgt frame */
u_int32_t is_tx_badcipher; /* tx failed 'cuz key type */
u_int32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */
u_int32_t is_tx_noheadroom; /* tx failed 'cuz no space */
u_int32_t is_tx_fragframes; /* tx frames fragmented */
u_int32_t is_tx_frags; /* tx fragments created */
u_int32_t is_scan_active; /* active scans started */
u_int32_t is_scan_passive; /* passive scans started */
u_int32_t is_node_timeout; /* nodes timed out inactivity */
u_int32_t is_crypto_nomem; /* no memory for crypto ctx */
u_int32_t is_crypto_tkip; /* tkip crypto done in s/w */
u_int32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */
u_int32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */
u_int32_t is_crypto_tkipcm; /* tkip counter measures */
u_int32_t is_crypto_ccmp; /* ccmp crypto done in s/w */
u_int32_t is_crypto_wep; /* wep crypto done in s/w */
u_int32_t is_crypto_setkey_cipher;/* cipher rejected key */
u_int32_t is_crypto_setkey_nokey; /* no key index for setkey */
u_int32_t is_crypto_delkey; /* driver key delete failed */
u_int32_t is_crypto_badcipher; /* unknown cipher */
u_int32_t is_crypto_nocipher; /* cipher not available */
u_int32_t is_crypto_attachfail; /* cipher attach failed */
u_int32_t is_crypto_swfallback; /* cipher fallback to s/w */
u_int32_t is_crypto_keyfail; /* driver key alloc failed */
u_int32_t is_crypto_enmicfail; /* en-MIC failed */
u_int32_t is_ibss_capmismatch; /* merge failed-cap mismatch */
u_int32_t is_ibss_norate; /* merge failed-rate mismatch */
u_int32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
u_int32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
u_int32_t is_ps_qempty; /* ps-poll w/ nothing to send */
u_int32_t is_ff_badhdr; /* fast frame rx'd w/ bad hdr */
u_int32_t is_ff_tooshort; /* fast frame rx decap error */
u_int32_t is_ff_split; /* fast frame rx split error */
u_int32_t is_ff_decap; /* fast frames decap'd */
u_int32_t is_ff_encap; /* fast frames encap'd for tx */
u_int32_t is_rx_badbintval; /* rx frame w/ bogus bintval */
u_int32_t is_rx_demicfail; /* rx demic failed */
u_int32_t is_rx_defrag; /* rx defragmentation failed */
u_int32_t is_rx_mgmt; /* rx management frames */
u_int32_t is_spare[6];
uint32_t is_rx_badversion; /* rx frame with bad version */
uint32_t is_rx_tooshort; /* rx frame too short */
uint32_t is_rx_wrongbss; /* rx from wrong bssid */
uint32_t is_rx_dup; /* rx discard 'cuz dup */
uint32_t is_rx_wrongdir; /* rx w/ wrong direction */
uint32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */
uint32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */
uint32_t is_rx_noprivacy; /* rx w/ wep but privacy off */
uint32_t is_rx_unencrypted; /* rx w/o wep and privacy on */
uint32_t is_rx_wepfail; /* rx wep processing failed */
uint32_t is_rx_decap; /* rx decapsulation failed */
uint32_t is_rx_mgtdiscard; /* rx discard mgt frames */
uint32_t is_rx_ctl; /* rx discard ctrl frames */
uint32_t is_rx_beacon; /* rx beacon frames */
uint32_t is_rx_rstoobig; /* rx rate set truncated */
uint32_t is_rx_elem_missing; /* rx required element missing*/
uint32_t is_rx_elem_toobig; /* rx element too big */
uint32_t is_rx_elem_toosmall; /* rx element too small */
uint32_t is_rx_elem_unknown; /* rx element unknown */
uint32_t is_rx_badchan; /* rx frame w/ invalid chan */
uint32_t is_rx_chanmismatch; /* rx frame chan mismatch */
uint32_t is_rx_nodealloc; /* rx frame dropped */
uint32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */
uint32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */
uint32_t is_rx_auth_fail; /* rx sta auth failure */
uint32_t is_rx_auth_countermeasures;/* rx auth discard 'cuz CM */
uint32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */
uint32_t is_rx_assoc_notauth; /* rx assoc w/o auth */
uint32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */
uint32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */
uint32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */
uint32_t is_rx_deauth; /* rx deauthentication */
uint32_t is_rx_disassoc; /* rx disassociation */
uint32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/
uint32_t is_rx_nobuf; /* rx failed for lack of buf */
uint32_t is_rx_decryptcrc; /* rx decrypt failed on crc */
uint32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/
uint32_t is_rx_bad_auth; /* rx bad auth request */
uint32_t is_rx_unauth; /* rx on unauthorized port */
uint32_t is_rx_badkeyid; /* rx w/ incorrect keyid */
uint32_t is_rx_ccmpreplay; /* rx seq# violation (CCMP) */
uint32_t is_rx_ccmpformat; /* rx format bad (CCMP) */
uint32_t is_rx_ccmpmic; /* rx MIC check failed (CCMP) */
uint32_t is_rx_tkipreplay; /* rx seq# violation (TKIP) */
uint32_t is_rx_tkipformat; /* rx format bad (TKIP) */
uint32_t is_rx_tkipmic; /* rx MIC check failed (TKIP) */
uint32_t is_rx_tkipicv; /* rx ICV check failed (TKIP) */
uint32_t is_rx_badcipher; /* rx failed 'cuz key type */
uint32_t is_rx_nocipherctx; /* rx failed 'cuz key !setup */
uint32_t is_rx_acl; /* rx discard 'cuz acl policy */
uint32_t is_tx_nobuf; /* tx failed for lack of buf */
uint32_t is_tx_nonode; /* tx failed for no node */
uint32_t is_tx_unknownmgt; /* tx of unknown mgt frame */
uint32_t is_tx_badcipher; /* tx failed 'cuz key type */
uint32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */
uint32_t is_tx_noheadroom; /* tx failed 'cuz no space */
uint32_t is_tx_fragframes; /* tx frames fragmented */
uint32_t is_tx_frags; /* tx fragments created */
uint32_t is_scan_active; /* active scans started */
uint32_t is_scan_passive; /* passive scans started */
uint32_t is_node_timeout; /* nodes timed out inactivity */
uint32_t is_crypto_nomem; /* no memory for crypto ctx */
uint32_t is_crypto_tkip; /* tkip crypto done in s/w */
uint32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */
uint32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */
uint32_t is_crypto_tkipcm; /* tkip counter measures */
uint32_t is_crypto_ccmp; /* ccmp crypto done in s/w */
uint32_t is_crypto_wep; /* wep crypto done in s/w */
uint32_t is_crypto_setkey_cipher;/* cipher rejected key */
uint32_t is_crypto_setkey_nokey; /* no key index for setkey */
uint32_t is_crypto_delkey; /* driver key delete failed */
uint32_t is_crypto_badcipher; /* unknown cipher */
uint32_t is_crypto_nocipher; /* cipher not available */
uint32_t is_crypto_attachfail; /* cipher attach failed */
uint32_t is_crypto_swfallback; /* cipher fallback to s/w */
uint32_t is_crypto_keyfail; /* driver key alloc failed */
uint32_t is_crypto_enmicfail; /* en-MIC failed */
uint32_t is_ibss_capmismatch; /* merge failed-cap mismatch */
uint32_t is_ibss_norate; /* merge failed-rate mismatch */
uint32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
uint32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
uint32_t is_ps_qempty; /* ps-poll w/ nothing to send */
uint32_t is_ff_badhdr; /* fast frame rx'd w/ bad hdr */
uint32_t is_ff_tooshort; /* fast frame rx decap error */
uint32_t is_ff_split; /* fast frame rx split error */
uint32_t is_ff_decap; /* fast frames decap'd */
uint32_t is_ff_encap; /* fast frames encap'd for tx */
uint32_t is_rx_badbintval; /* rx frame w/ bogus bintval */
uint32_t is_rx_demicfail; /* rx demic failed */
uint32_t is_rx_defrag; /* rx defragmentation failed */
uint32_t is_rx_mgmt; /* rx management frames */
uint32_t is_rx_action; /* rx action mgt frames */
uint32_t is_amsdu_tooshort; /* A-MSDU rx decap error */
uint32_t is_amsdu_split; /* A-MSDU rx split error */
uint32_t is_amsdu_decap; /* A-MSDU decap'd */
uint32_t is_amsdu_encap; /* A-MSDU encap'd for tx */
uint32_t is_ampdu_bar_bad; /* A-MPDU BAR out of window */
uint32_t is_ampdu_bar_oow; /* A-MPDU BAR before ADDBA */
uint32_t is_ampdu_bar_rx; /* A-MPDU BAR frames handled */
uint32_t is_ampdu_rx_flush; /* A-MPDU frames flushed */
uint32_t is_ampdu_rx_oor; /* A-MPDU frames out-of-order */
uint32_t is_ampdu_rx_copy; /* A-MPDU frames copied down */
uint32_t is_spare[32];
};
/*
@ -199,17 +211,17 @@ struct ieee80211_stats {
more than IEEE80211_KEYBUF_SIZE.
*/
struct ieee80211req_key {
u_int8_t ik_type; /* key/cipher type */
u_int8_t ik_pad;
u_int16_t ik_keyix; /* key index */
u_int8_t ik_keylen; /* key length in bytes */
u_int8_t ik_flags;
uint8_t ik_type; /* key/cipher type */
uint8_t ik_pad;
uint16_t ik_keyix; /* key index */
uint8_t ik_keylen; /* key length in bytes */
uint8_t ik_flags;
/* NB: IEEE80211_KEY_XMIT and IEEE80211_KEY_RECV defined elsewhere */
#define IEEE80211_KEY_DEFAULT 0x80 /* default xmit key */
u_int8_t ik_macaddr[IEEE80211_ADDR_LEN];
u_int64_t ik_keyrsc; /* key receive sequence counter */
u_int64_t ik_keytsc; /* key transmit sequence counter */
u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
uint8_t ik_macaddr[IEEE80211_ADDR_LEN];
uint64_t ik_keyrsc; /* key receive sequence counter */
uint64_t ik_keytsc; /* key transmit sequence counter */
uint8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
};
/*
@ -217,8 +229,8 @@ struct ieee80211req_key {
* to IEEE80211_KEYIX_NONE when deleting a unicast key.
*/
struct ieee80211req_del_key {
u_int8_t idk_keyix; /* key index */
u_int8_t idk_macaddr[IEEE80211_ADDR_LEN];
uint8_t idk_keyix; /* key index */
uint8_t idk_macaddr[IEEE80211_ADDR_LEN];
};
/*
@ -228,16 +240,16 @@ struct ieee80211req_del_key {
* ap (to effect a station).
*/
struct ieee80211req_mlme {
u_int8_t im_op; /* operation to perform */
uint8_t im_op; /* operation to perform */
#define IEEE80211_MLME_ASSOC 1 /* associate station */
#define IEEE80211_MLME_DISASSOC 2 /* disassociate station */
#define IEEE80211_MLME_DEAUTH 3 /* deauthenticate station */
#define IEEE80211_MLME_AUTHORIZE 4 /* authorize station */
#define IEEE80211_MLME_UNAUTHORIZE 5 /* unauthorize station */
u_int8_t im_ssid_len; /* length of optional ssid */
u_int16_t im_reason; /* 802.11 reason code */
u_int8_t im_macaddr[IEEE80211_ADDR_LEN];
u_int8_t im_ssid[IEEE80211_NWID_LEN];
uint8_t im_ssid_len; /* length of optional ssid */
uint16_t im_reason; /* 802.11 reason code */
uint8_t im_macaddr[IEEE80211_ADDR_LEN];
uint8_t im_ssid[IEEE80211_NWID_LEN];
};
/*
@ -254,7 +266,7 @@ enum {
};
struct ieee80211req_maclist {
u_int8_t ml_macaddr[IEEE80211_ADDR_LEN];
uint8_t ml_macaddr[IEEE80211_ADDR_LEN];
};
/*
@ -264,7 +276,7 @@ struct ieee80211req_maclist {
* scanning.
*/
struct ieee80211req_chanlist {
u_int8_t ic_channels[IEEE80211_CHAN_BYTES];
uint8_t ic_channels[IEEE80211_CHAN_BYTES];
};
/*
@ -278,9 +290,14 @@ struct ieee80211req_chaninfo {
/*
* Retrieve the WPA/RSN information element for an associated station.
*/
struct ieee80211req_wpaie {
u_int8_t wpa_macaddr[IEEE80211_ADDR_LEN];
u_int8_t wpa_ie[IEEE80211_MAX_OPT_IE];
struct ieee80211req_wpaie { /* old version w/ only one ie */
uint8_t wpa_macaddr[IEEE80211_ADDR_LEN];
uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
};
struct ieee80211req_wpaie2 {
uint8_t wpa_macaddr[IEEE80211_ADDR_LEN];
uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
uint8_t rsn_ie[IEEE80211_MAX_OPT_IE];
};
/*
@ -289,8 +306,8 @@ struct ieee80211req_wpaie {
struct ieee80211req_sta_stats {
union {
/* NB: explicitly force 64-bit alignment */
u_int8_t macaddr[IEEE80211_ADDR_LEN];
u_int64_t pad;
uint8_t macaddr[IEEE80211_ADDR_LEN];
uint64_t pad;
} is_u;
struct ieee80211_nodestats is_stats;
};
@ -300,27 +317,28 @@ struct ieee80211req_sta_stats {
* to retrieve other data like stats, unicast key, etc.
*/
struct ieee80211req_sta_info {
u_int16_t isi_len; /* length (mult of 4) */
u_int16_t isi_freq; /* MHz */
u_int16_t isi_flags; /* channel flags */
u_int16_t isi_state; /* state flags */
u_int8_t isi_authmode; /* authentication algorithm */
uint16_t isi_len; /* length (mult of 4) */
uint16_t isi_ie_off; /* offset to IE data */
uint16_t isi_ie_len; /* IE length */
uint16_t isi_freq; /* MHz */
uint16_t isi_flags; /* channel flags */
uint16_t isi_state; /* state flags */
uint8_t isi_authmode; /* authentication algorithm */
int8_t isi_rssi; /* receive signal strength */
u_int8_t isi_capinfo; /* capabilities */
u_int8_t isi_erp; /* ERP element */
u_int8_t isi_macaddr[IEEE80211_ADDR_LEN];
u_int8_t isi_nrates;
/* negotiated rates */
u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE];
u_int8_t isi_txrate; /* index to isi_rates[] */
int8_t isi_noise; /* noise floor */
u_int16_t isi_ie_len; /* IE length */
u_int16_t isi_associd; /* assoc response */
u_int16_t isi_txpower; /* current tx power */
u_int16_t isi_vlan; /* vlan tag */
u_int16_t isi_txseqs[17]; /* seq to be transmitted */
u_int16_t isi_rxseqs[17]; /* seq previous for qos frames*/
u_int16_t isi_inact; /* inactivity timer */
uint8_t isi_capinfo; /* capabilities */
uint8_t isi_erp; /* ERP element */
uint8_t isi_macaddr[IEEE80211_ADDR_LEN];
uint8_t isi_nrates;
/* negotiated rates */
uint8_t isi_rates[IEEE80211_RATE_MAXSIZE];
uint8_t isi_txrate; /* index to isi_rates[] */
uint16_t isi_associd; /* assoc response */
uint16_t isi_txpower; /* current tx power */
uint16_t isi_vlan; /* vlan tag */
uint16_t isi_txseqs[17]; /* seq to be transmitted */
uint16_t isi_rxseqs[17]; /* seq previous for qos frames*/
uint16_t isi_inact; /* inactivity timer */
/* XXX frag state? */
/* variable length IE data */
};
@ -332,8 +350,8 @@ struct ieee80211req_sta_info {
struct ieee80211req_sta_req {
union {
/* NB: explicitly force 64-bit alignment */
u_int8_t macaddr[IEEE80211_ADDR_LEN];
u_int64_t pad;
uint8_t macaddr[IEEE80211_ADDR_LEN];
uint64_t pad;
} is_u;
struct ieee80211req_sta_info info[1]; /* variable length */
};
@ -342,8 +360,8 @@ struct ieee80211req_sta_req {
* Get/set per-station tx power cap.
*/
struct ieee80211req_sta_txpow {
u_int8_t it_macaddr[IEEE80211_ADDR_LEN];
u_int8_t it_txpow;
uint8_t it_macaddr[IEEE80211_ADDR_LEN];
uint8_t it_txpow;
};
/*
@ -363,13 +381,14 @@ struct ieee80211req_sta_txpow {
/* the first member must be matched with struct ifreq */
struct ieee80211req {
char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
u_int16_t i_type; /* req type */
uint16_t i_type; /* req type */
int16_t i_val; /* Index or simple value */
int16_t i_len; /* Index or simple value */
void *i_data; /* Extra data */
};
#define SIOCS80211 _IOW('i', 234, struct ieee80211req)
#define SIOCG80211 _IOWR('i', 235, struct ieee80211req)
#define SIOCG80211STATS _IOWR('i', 236, struct ifreq)
#define IEEE80211_IOC_SSID 1
#define IEEE80211_IOC_NUMSSIDS 2
@ -440,12 +459,38 @@ struct ieee80211req {
#define IEEE80211_IOC_ADDMAC 54 /* add sta to MAC ACL table */
#define IEEE80211_IOC_DELMAC 55 /* del sta from MAC ACL table */
#define IEEE80211_IOC_PUREG 56 /* pure 11g (no 11b stations) */
#define IEEE80211_IOC_FF 57 /* ATH fast frames (on, off) */
#define IEEE80211_IOC_TURBOP 58 /* ATH turbo' (on, off) */
#define IEEE80211_IOC_BGSCAN 59 /* bg scanning (on, off) */
#define IEEE80211_IOC_BGSCAN_IDLE 60 /* bg scan idle threshold */
#define IEEE80211_IOC_BGSCAN_INTERVAL 61 /* bg scan interval */
#define IEEE80211_IOC_SCANVALID 65 /* scan cache valid threshold */
#define IEEE80211_IOC_ROAM_RSSI_11A 66 /* rssi threshold in 11a */
#define IEEE80211_IOC_ROAM_RSSI_11B 67 /* rssi threshold in 11b */
#define IEEE80211_IOC_ROAM_RSSI_11G 68 /* rssi threshold in 11g */
#define IEEE80211_IOC_ROAM_RATE_11A 69 /* tx rate threshold in 11a */
#define IEEE80211_IOC_ROAM_RATE_11B 70 /* tx rate threshold in 11b */
#define IEEE80211_IOC_ROAM_RATE_11G 71 /* tx rate threshold in 11g */
#define IEEE80211_IOC_MCAST_RATE 72 /* tx rate for mcast frames */
#define IEEE80211_IOC_FRAGTHRESHOLD 73 /* tx fragmentation threshold */
#define IEEE80211_IOC_BURST 75 /* packet bursting */
#define IEEE80211_IOC_SCAN_RESULTS 76 /* get scan results */
#define IEEE80211_IOC_BMISSTHRESHOLD 77 /* beacon miss threshold */
#define IEEE80211_IOC_STA_INFO 78 /* station/neighbor info */
#define IEEE80211_IOC_WPAIE2 79 /* WPA+RSN info elements */
#define IEEE80211_IOC_CURCHAN 80 /* current channel */
#define IEEE80211_IOC_SHORTGI 81 /* 802.11n half GI */
#define IEEE80211_IOC_AMPDU 82 /* 802.11n A-MPDU (on, off) */
#define IEEE80211_IOC_AMPDU_LIMIT 83 /* A-MPDU length limit */
#define IEEE80211_IOC_AMPDU_DENSITY 84 /* A-MPDU density */
#define IEEE80211_IOC_AMSDU 85 /* 802.11n A-MSDU (on, off) */
#define IEEE80211_IOC_AMSDU_LIMIT 86 /* A-MSDU length limit */
#define IEEE80211_IOC_PUREN 87 /* pure 11n (no legacy sta's) */
#define IEEE80211_IOC_DOTH 88 /* 802.11h (on, off) */
#define IEEE80211_IOC_REGDOMAIN 89 /* regulatory domain */
#define IEEE80211_IOC_COUNTRYCODE 90 /* ISO country code */
#define IEEE80211_IOC_LOCATION 91 /* indoor/outdoor/anywhere */
#define IEEE80211_IOC_HTCOMPAT 92 /* support pre-D1.10 HT ie's */
/*
* Scan result data returned for IEEE80211_IOC_SCAN_RESULTS.
@ -456,24 +501,27 @@ struct ieee80211req {
* in isr_len. Result records are rounded to a multiple of 4 bytes.
*/
struct ieee80211req_scan_result {
u_int16_t isr_len; /* length (mult of 4) */
u_int16_t isr_ie_len; /* IE length */
u_int16_t isr_freq; /* MHz */
u_int16_t isr_flags; /* channel flags */
uint16_t isr_len; /* length (mult of 4) */
uint16_t isr_ie_off; /* offset to IE data */
uint16_t isr_ie_len; /* IE length */
uint16_t isr_freq; /* MHz */
uint16_t isr_flags; /* channel flags */
int8_t isr_noise;
int8_t isr_rssi;
u_int8_t isr_intval; /* beacon interval */
u_int8_t isr_capinfo; /* capabilities */
u_int8_t isr_erp; /* ERP element */
u_int8_t isr_bssid[IEEE80211_ADDR_LEN];
u_int8_t isr_nrates;
u_int8_t isr_rates[IEEE80211_RATE_MAXSIZE];
u_int8_t isr_ssid_len; /* SSID length */
u_int8_t isr_pad[8];
uint8_t isr_intval; /* beacon interval */
uint8_t isr_capinfo; /* capabilities */
uint8_t isr_erp; /* ERP element */
uint8_t isr_bssid[IEEE80211_ADDR_LEN];
uint8_t isr_nrates;
uint8_t isr_rates[IEEE80211_RATE_MAXSIZE];
uint8_t isr_ssid_len; /* SSID length */
/* variable length SSID followed by IE data */
};
#define SIOCG80211STATS _IOWR('i', 236, struct ifreq)
struct ieee80211_clone_params {
char icp_parent[IFNAMSIZ]; /* parent device */
int icp_opmode; /* operating mode */
};
#endif /* __FreeBSD__ */
#endif /* _NET80211_IEEE80211_IOCTL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#define _NET80211_IEEE80211_NODE_H_
#include <net80211/ieee80211_ioctl.h> /* for ieee80211_nodestats */
#include <net80211/ieee80211_ht.h> /* for aggregation state */
/*
* Each ieee80211com instance has a single timer that fires once a
@ -52,23 +53,23 @@
#define IEEE80211_INACT_PROBE (30/IEEE80211_INACT_WAIT) /* probe */
#define IEEE80211_INACT_SCAN (300/IEEE80211_INACT_WAIT) /* scanned */
#define IEEE80211_TRANS_WAIT 5 /* mgt frame tx timer (secs) */
#define IEEE80211_TRANS_WAIT 2 /* mgt frame tx timer (secs) */
#define IEEE80211_NODE_HASHSIZE 32
/* simple hash is enough for variation of macaddr */
#define IEEE80211_NODE_HASH(addr) \
(((const u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % \
(((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % \
IEEE80211_NODE_HASHSIZE)
struct ieee80211_rsnparms {
u_int8_t rsn_mcastcipher; /* mcast/group cipher */
u_int8_t rsn_mcastkeylen; /* mcast key length */
u_int8_t rsn_ucastcipherset; /* unicast cipher set */
u_int8_t rsn_ucastcipher; /* selected unicast cipher */
u_int8_t rsn_ucastkeylen; /* unicast key length */
u_int8_t rsn_keymgmtset; /* key mangement algorithms */
u_int8_t rsn_keymgmt; /* selected key mgmt algo */
u_int16_t rsn_caps; /* capabilities */
uint8_t rsn_mcastcipher; /* mcast/group cipher */
uint8_t rsn_mcastkeylen; /* mcast key length */
uint8_t rsn_ucastcipherset; /* unicast cipher set */
uint8_t rsn_ucastcipher; /* selected unicast cipher */
uint8_t rsn_ucastkeylen; /* unicast key length */
uint8_t rsn_keymgmtset; /* key mangement algorithms */
uint8_t rsn_keymgmt; /* selected key mgmt algo */
uint16_t rsn_caps; /* capabilities */
};
struct ieee80211_node_table;
@ -87,53 +88,82 @@ struct ieee80211_node {
LIST_ENTRY(ieee80211_node) ni_hash;
u_int ni_refcnt;
u_int ni_scangen; /* gen# for timeout scan */
u_int8_t ni_authmode; /* authentication algorithm */
u_int16_t ni_flags; /* special-purpose state */
uint8_t ni_authmode; /* authentication algorithm */
uint8_t ni_ath_flags; /* Atheros feature flags */
/* NB: These must have the same values as IEEE80211_ATHC_* */
#define IEEE80211_NODE_TURBOP 0x0001 /* Turbo prime enable */
#define IEEE80211_NODE_COMP 0x0002 /* Compresssion enable */
#define IEEE80211_NODE_FF 0x0004 /* Fast Frame capable */
#define IEEE80211_NODE_XR 0x0008 /* Atheros WME enable */
#define IEEE80211_NODE_AR 0x0010 /* AR capable */
#define IEEE80211_NODE_BOOST 0x0080
#define IEEE80211_NODE_PSUPDATE 0x0200 /* power save state changed */
#define IEEE80211_NODE_CHWUPDATE 0x0400 /* 11n channel width change */
uint16_t ni_flags; /* special-purpose state */
#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */
#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
/* NB: this must have the same value as IEEE80211_FC1_PWR_MGT */
#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
#define IEEE80211_NODE_AREF 0x0020 /* authentication ref held */
u_int16_t ni_associd; /* assoc response */
u_int16_t ni_txpower; /* current transmit power */
u_int16_t ni_vlan; /* vlan tag */
u_int32_t *ni_challenge; /* shared-key challenge */
u_int8_t *ni_wpa_ie; /* captured WPA/RSN ie */
u_int8_t *ni_wme_ie; /* captured WME ie */
#define IEEE80211_NODE_HT 0x0040 /* HT enabled */
#define IEEE80211_NODE_HTCOMPAT 0x0080 /* HT setup w/ vendor OUI's */
uint16_t ni_ath_defkeyix;/* Atheros def key index */
uint16_t ni_associd; /* assoc response */
uint16_t ni_txpower; /* current transmit power */
uint16_t ni_vlan; /* vlan tag */
uint32_t *ni_challenge; /* shared-key challenge */
uint8_t *ni_wpa_ie; /* captured WPA ie */
uint8_t *ni_rsn_ie; /* captured RSN ie */
uint8_t *ni_wme_ie; /* captured WME ie */
uint8_t *ni_ath_ie; /* captured Atheros ie */
#define IEEE80211_NONQOS_TID 16 /* index for non-QoS sta */
u_int16_t ni_txseqs[17]; /* tx seq per-tid */
u_int16_t ni_rxseqs[17]; /* rx seq previous per-tid*/
u_int32_t ni_rxfragstamp; /* time stamp of last rx frag */
uint16_t ni_txseqs[17]; /* tx seq per-tid */
uint16_t ni_rxseqs[17]; /* rx seq previous per-tid*/
uint32_t ni_rxfragstamp; /* time stamp of last rx frag */
struct mbuf *ni_rxfrag[3]; /* rx frag reassembly */
struct ieee80211_rsnparms ni_rsn; /* RSN/WPA parameters */
struct ieee80211_key ni_ucastkey; /* unicast key */
/* hardware */
u_int32_t ni_rstamp; /* recv timestamp */
u_int8_t ni_rssi; /* recv ssi */
uint32_t ni_rstamp; /* recv timestamp */
int8_t ni_rssi; /* recv ssi */
int8_t ni_noise; /* noise floor */
/* header */
u_int8_t ni_macaddr[IEEE80211_ADDR_LEN];
u_int8_t ni_bssid[IEEE80211_ADDR_LEN];
uint8_t ni_macaddr[IEEE80211_ADDR_LEN];
uint8_t ni_bssid[IEEE80211_ADDR_LEN];
/* beacon, probe response */
union {
u_int8_t data[8];
u_int64_t tsf;
uint8_t data[8];
uint64_t tsf;
} ni_tstamp; /* from last rcv'd beacon */
u_int16_t ni_intval; /* beacon interval */
u_int16_t ni_capinfo; /* capabilities */
u_int8_t ni_esslen;
u_int8_t ni_essid[IEEE80211_NWID_LEN];
uint16_t ni_intval; /* beacon interval */
uint16_t ni_capinfo; /* capabilities */
uint8_t ni_esslen;
uint8_t ni_essid[IEEE80211_NWID_LEN];
struct ieee80211_rateset ni_rates; /* negotiated rate set */
struct ieee80211_channel *ni_chan; /* XXX multiple uses */
u_int16_t ni_fhdwell; /* FH only */
u_int8_t ni_fhindex; /* FH only */
u_int8_t ni_erp; /* ERP from beacon/probe resp */
u_int16_t ni_timoff; /* byte offset to TIM ie */
u_int8_t ni_dtim_period; /* DTIM period */
u_int8_t ni_dtim_count; /* DTIM count for last bcn */
struct ieee80211_channel *ni_chan;
uint16_t ni_fhdwell; /* FH only */
uint8_t ni_fhindex; /* FH only */
uint8_t ni_erp; /* ERP from beacon/probe resp */
uint16_t ni_timoff; /* byte offset to TIM ie */
uint8_t ni_dtim_period; /* DTIM period */
uint8_t ni_dtim_count; /* DTIM count for last bcn */
/* 11n state */
uint16_t ni_htcap; /* HT capabilities */
uint8_t ni_htparam; /* HT params */
uint8_t ni_htctlchan; /* HT control channel */
uint8_t ni_ht2ndchan; /* HT 2nd channel */
uint8_t ni_htopmode; /* HT operating mode */
uint8_t ni_htstbc; /* HT */
uint8_t ni_reqcw; /* requested tx channel width */
uint8_t ni_chw; /* negotiated channel width */
struct ieee80211_htrateset ni_htrates; /* negotiated ht rate set */
struct ieee80211_tx_ampdu ni_tx_ampdu[WME_NUM_AC];
struct ieee80211_rx_ampdu ni_rx_ampdu[WME_NUM_TID];
/* others */
int ni_fails; /* failure count to associate */
@ -145,6 +175,8 @@ struct ieee80211_node {
};
MALLOC_DECLARE(M_80211_NODE);
#define IEEE80211_NODE_ATH (IEEE80211_NODE_FF | IEEE80211_NODE_TURBOP)
#define IEEE80211_NODE_AID(ni) IEEE80211_AID(ni->ni_associd)
#define IEEE80211_NODE_STAT(ni,stat) (ni->ni_stats.ns_##stat++)
@ -180,15 +212,13 @@ ieee80211_node_is_authorized(const struct ieee80211_node *ni)
void ieee80211_node_authorize(struct ieee80211_node *);
void ieee80211_node_unauthorize(struct ieee80211_node *);
void ieee80211_begin_scan(struct ieee80211com *, int);
int ieee80211_next_scan(struct ieee80211com *);
void ieee80211_probe_curchan(struct ieee80211com *, int);
void ieee80211_create_ibss(struct ieee80211com*, struct ieee80211_channel *);
void ieee80211_reset_bss(struct ieee80211com *);
void ieee80211_cancel_scan(struct ieee80211com *);
void ieee80211_end_scan(struct ieee80211com *);
int ieee80211_ibss_merge(struct ieee80211_node *);
int ieee80211_sta_join(struct ieee80211com *, struct ieee80211_node *);
struct ieee80211_scan_entry;
int ieee80211_sta_join(struct ieee80211com *,
const struct ieee80211_scan_entry *);
void ieee80211_sta_leave(struct ieee80211com *, struct ieee80211_node *);
/*
@ -202,46 +232,43 @@ struct ieee80211_node_table {
ieee80211_node_lock_t nt_nodelock; /* on node table */
TAILQ_HEAD(, ieee80211_node) nt_node; /* information of all nodes */
LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
struct ieee80211_node **nt_keyixmap; /* key ix -> node map */
int nt_keyixmax; /* keyixmap size */
const char *nt_name; /* for debugging */
ieee80211_scan_lock_t nt_scanlock; /* on nt_scangen */
u_int nt_scangen; /* gen# for timeout scan */
int nt_inact_timer; /* inactivity timer */
int nt_inact_init; /* initial node inact setting */
struct ieee80211_node **nt_keyixmap; /* key ix -> node map */
int nt_keyixmax; /* keyixmap size */
void (*nt_timeout)(struct ieee80211_node_table *);
};
void ieee80211_node_table_reset(struct ieee80211_node_table *);
struct ieee80211_node *ieee80211_alloc_node(
struct ieee80211_node_table *, const u_int8_t *);
struct ieee80211_node_table *, const uint8_t *);
struct ieee80211_node *ieee80211_tmp_node(struct ieee80211com *,
const u_int8_t *macaddr);
const uint8_t *macaddr);
struct ieee80211_node *ieee80211_dup_bss(struct ieee80211_node_table *,
const u_int8_t *);
const uint8_t *);
#ifdef IEEE80211_DEBUG_REFCNT
void ieee80211_free_node_debug(struct ieee80211_node *,
const char *func, int line);
struct ieee80211_node *ieee80211_find_node_debug(
struct ieee80211_node_table *, const u_int8_t *,
struct ieee80211_node *ieee80211_find_node_debug(struct ieee80211_node_table *,
const uint8_t *,
const char *func, int line);
struct ieee80211_node * ieee80211_find_rxnode_debug(
struct ieee80211com *, const struct ieee80211_frame_min *,
struct ieee80211_node * ieee80211_find_rxnode_debug(struct ieee80211com *,
const struct ieee80211_frame_min *,
const char *func, int line);
struct ieee80211_node * ieee80211_find_rxnode_withkey_debug(
struct ieee80211com *,
const struct ieee80211_frame_min *, u_int16_t keyix,
const struct ieee80211_frame_min *, uint16_t keyix,
const char *func, int line);
struct ieee80211_node *ieee80211_find_txnode_debug(
struct ieee80211com *, const u_int8_t *,
struct ieee80211_node * ieee80211_find_rxnode_withkey_debug(
struct ieee80211com *,
const struct ieee80211_frame_min *, uint16_t keyix,
const char *func, int line);
struct ieee80211_node *ieee80211_find_txnode_debug(struct ieee80211com *,
const uint8_t *,
const char *func, int line);
struct ieee80211_node *ieee80211_find_node_with_channel_debug(
struct ieee80211_node_table *, const u_int8_t *macaddr,
struct ieee80211_channel *, const char *func, int line);
struct ieee80211_node *ieee80211_find_node_with_ssid_debug(
struct ieee80211_node_table *, const u_int8_t *macaddr,
u_int ssidlen, const u_int8_t *ssid,
struct ieee80211_node_table *, const uint8_t *macaddr,
u_int ssidlen, const uint8_t *ssid,
const char *func, int line);
#define ieee80211_free_node(ni) \
ieee80211_free_node_debug(ni, __func__, __LINE__)
@ -253,28 +280,24 @@ struct ieee80211_node *ieee80211_find_node_with_ssid_debug(
ieee80211_find_rxnode_withkey_debug(nt, wh, keyix, __func__, __LINE__)
#define ieee80211_find_txnode(nt, mac) \
ieee80211_find_txnode_debug(nt, mac, __func__, __LINE__)
#define ieee80211_find_node_with_channel(nt, mac, c) \
ieee80211_find_node_with_channel_debug(nt, mac, c, __func__, __LINE__)
#define ieee80211_find_node_with_ssid(nt, mac, sl, ss) \
ieee80211_find_node_with_ssid_debug(nt, mac, sl, ss, __func__, __LINE__)
#else
void ieee80211_free_node(struct ieee80211_node *);
struct ieee80211_node *ieee80211_find_node(
struct ieee80211_node_table *, const u_int8_t *);
struct ieee80211_node * ieee80211_find_rxnode(
struct ieee80211com *, const struct ieee80211_frame_min *);
struct ieee80211_node *ieee80211_find_node(struct ieee80211_node_table *,
const uint8_t *);
struct ieee80211_node * ieee80211_find_rxnode(struct ieee80211com *,
const struct ieee80211_frame_min *);
struct ieee80211_node * ieee80211_find_rxnode_withkey(struct ieee80211com *,
const struct ieee80211_frame_min *, u_int16_t keyix);
struct ieee80211_node *ieee80211_find_txnode(
struct ieee80211com *, const u_int8_t *);
struct ieee80211_node *ieee80211_find_node_with_channel(
struct ieee80211_node_table *, const u_int8_t *macaddr,
struct ieee80211_channel *);
const struct ieee80211_frame_min *, uint16_t keyix);
struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *,
const uint8_t *);
struct ieee80211_node *ieee80211_find_node_with_ssid(
struct ieee80211_node_table *, const u_int8_t *macaddr,
u_int ssidlen, const u_int8_t *ssid);
struct ieee80211_node_table *, const uint8_t *macaddr,
u_int ssidlen, const uint8_t *ssid);
#endif
int ieee80211_node_delucastkey(struct ieee80211_node *);
void ieee80211_node_timeout(void *arg);
typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
@ -285,45 +308,16 @@ void ieee80211_dump_node(struct ieee80211_node_table *,
void ieee80211_dump_nodes(struct ieee80211_node_table *);
struct ieee80211_node *ieee80211_fakeup_adhoc_node(
struct ieee80211_node_table *, const u_int8_t macaddr[]);
void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *,int);
void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *);
u_int8_t ieee80211_getrssi(struct ieee80211com *ic);
/*
* Parameters supplied when adding/updating an entry in a
* scan cache. Pointer variables should be set to NULL
* if no data is available. Pointer references can be to
* local data; any information that is saved will be copied.
* All multi-byte values must be in host byte order.
*/
struct ieee80211_scanparams {
u_int16_t capinfo; /* 802.11 capabilities */
u_int16_t fhdwell; /* FHSS dwell interval */
u_int8_t chan; /* */
u_int8_t bchan;
u_int8_t fhindex;
u_int8_t erp;
u_int16_t bintval;
u_int8_t timoff;
u_int8_t *tim;
u_int8_t *tstamp;
u_int8_t *country;
u_int8_t *ssid;
u_int8_t *rates;
u_int8_t *xrates;
u_int8_t *wpa;
u_int8_t *wme;
};
void ieee80211_add_scan(struct ieee80211com *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
int subtype, int rssi, int rstamp);
struct ieee80211_node_table *, const uint8_t macaddr[]);
struct ieee80211_scanparams;
void ieee80211_init_neighbor(struct ieee80211_node *,
const struct ieee80211_frame *,
const struct ieee80211_scanparams *);
struct ieee80211_node *ieee80211_add_neighbor(struct ieee80211com *,
const struct ieee80211_frame *,
const struct ieee80211_scanparams *);
void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *,int);
void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *);
int8_t ieee80211_getrssi(struct ieee80211com *);
void ieee80211_getsignal(struct ieee80211com *, int8_t *, int8_t *);
#endif /* _NET80211_IEEE80211_NODE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,328 @@
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* 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>
__FBSDID("$FreeBSD$");
/*
* IEEE 802.11 power save support.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
#include <net/bpf.h>
static void ieee80211_set_tim(struct ieee80211_node *ni, int set);
void
ieee80211_power_attach(struct ieee80211com *ic)
{
if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_IBSS) {
/* NB: driver should override */
ic->ic_set_tim = ieee80211_set_tim;
}
}
void
ieee80211_power_lateattach(struct ieee80211com *ic)
{
/*
* Allocate these only if needed. Beware that we
* know adhoc mode doesn't support ATIM yet...
*/
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
ic->ic_tim_len = howmany(ic->ic_max_aid,8) * sizeof(uint8_t);
MALLOC(ic->ic_tim_bitmap, uint8_t *, ic->ic_tim_len,
M_DEVBUF, M_NOWAIT | M_ZERO);
if (ic->ic_tim_bitmap == NULL) {
printf("%s: no memory for TIM bitmap!\n", __func__);
/* XXX good enough to keep from crashing? */
ic->ic_tim_len = 0;
}
}
}
void
ieee80211_power_detach(struct ieee80211com *ic)
{
if (ic->ic_tim_bitmap != NULL) {
FREE(ic->ic_tim_bitmap, M_DEVBUF);
ic->ic_tim_bitmap = NULL;
}
}
/*
* Clear any frames queued on a node's power save queue.
* The number of frames that were present is returned.
*/
int
ieee80211_node_saveq_drain(struct ieee80211_node *ni)
{
int qlen;
IEEE80211_NODE_SAVEQ_LOCK(ni);
qlen = IEEE80211_NODE_SAVEQ_QLEN(ni);
_IF_DRAIN(&ni->ni_savedq);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
return qlen;
}
/*
* Age frames on the power save queue. The aging interval is
* 4 times the listen interval specified by the station. This
* number is factored into the age calculations when the frame
* is placed on the queue. We store ages as time differences
* so we can check and/or adjust only the head of the list.
* If a frame's age exceeds the threshold then discard it.
* The number of frames discarded is returned so the caller
* can check if it needs to adjust the tim.
*/
int
ieee80211_node_saveq_age(struct ieee80211_node *ni)
{
int discard = 0;
if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) {
struct mbuf *m;
IEEE80211_NODE_SAVEQ_LOCK(ni);
while (IF_POLL(&ni->ni_savedq, m) != NULL &&
M_AGE_GET(m) < IEEE80211_INACT_WAIT) {
IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_POWER, "[%s] discard frame, age %u\n", ether_sprintf(ni->ni_macaddr), M_AGE_GET(m));/*XXX*/
_IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m);
m_freem(m);
discard++;
}
if (m != NULL)
M_AGE_SUB(m, IEEE80211_INACT_WAIT);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
IEEE80211_NOTE(ni->ni_ic, IEEE80211_MSG_POWER, ni,
"discard %u frames for age", discard);
IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard);
}
return discard;
}
/*
* Indicate whether there are frames queued for a station in power-save mode.
*/
static void
ieee80211_set_tim(struct ieee80211_node *ni, int set)
{
struct ieee80211com *ic = ni->ni_ic;
uint16_t aid;
KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_IBSS,
("operating mode %u", ic->ic_opmode));
aid = IEEE80211_AID(ni->ni_associd);
KASSERT(aid < ic->ic_max_aid,
("bogus aid %u, max %u", aid, ic->ic_max_aid));
IEEE80211_BEACON_LOCK(ic);
if (set != (isset(ic->ic_tim_bitmap, aid) != 0)) {
if (set) {
setbit(ic->ic_tim_bitmap, aid);
ic->ic_ps_pending++;
} else {
clrbit(ic->ic_tim_bitmap, aid);
ic->ic_ps_pending--;
}
ic->ic_flags |= IEEE80211_F_TIMUPDATE;
}
IEEE80211_BEACON_UNLOCK(ic);
}
/*
* Save an outbound packet for a node in power-save sleep state.
* The new packet is placed on the node's saved queue, and the TIM
* is changed, if necessary.
*/
void
ieee80211_pwrsave(struct ieee80211_node *ni, struct mbuf *m)
{
struct ieee80211com *ic = ni->ni_ic;
int qlen, age;
IEEE80211_NODE_SAVEQ_LOCK(ni);
if (_IF_QFULL(&ni->ni_savedq)) {
_IF_DROP(&ni->ni_savedq);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
"[%s] pwr save q overflow, drops %d (size %d)\n",
ether_sprintf(ni->ni_macaddr),
ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE);
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_dumppkts(ic))
ieee80211_dump_pkt(ic, mtod(m, caddr_t), m->m_len, -1, -1);
#endif
m_freem(m);
return;
}
/*
* Tag the frame with it's expiry time and insert
* it in the queue. The aging interval is 4 times
* the listen interval specified by the station.
* Frames that sit around too long are reclaimed
* using this information.
*/
/* TU -> secs. XXX handle overflow? */
age = IEEE80211_TU_TO_MS((ni->ni_intval * ic->ic_bintval) << 2) / 1000;
_IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER,
"[%s] save frame with age %d, %u now queued\n",
ether_sprintf(ni->ni_macaddr), age, qlen);
if (qlen == 1 && ic->ic_set_tim != NULL)
ic->ic_set_tim(ni, 1);
}
/*
* Handle station power-save state change.
*/
void
ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable)
{
struct ieee80211com *ic = ni->ni_ic;
struct mbuf *m, *mhead, *mtail;
int mcount;
if (enable) {
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0)
ic->ic_ps_sta++;
ni->ni_flags |= IEEE80211_NODE_PWR_MGT;
IEEE80211_NOTE(ic, IEEE80211_MSG_POWER, ni,
"power save mode on, %u sta's in ps mode", ic->ic_ps_sta);
return;
}
if (ni->ni_flags & IEEE80211_NODE_PWR_MGT)
ic->ic_ps_sta--;
ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
IEEE80211_NOTE(ic, IEEE80211_MSG_POWER, ni,
"power save mode off, %u sta's in ps mode", ic->ic_ps_sta);
/* XXX if no stations in ps mode, flush mc frames */
/*
* Flush queued unicast frames.
*/
if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) {
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ni, 0); /* just in case */
return;
}
IEEE80211_NOTE(ic, IEEE80211_MSG_POWER, ni,
"flush ps queue, %u packets queue", IEEE80211_NODE_SAVEQ_QLEN(ni));
/*
* Unload the frames from the ps q but don't send them
* to the driver yet. We do this in two stages to minimize
* locking but also because there's no easy way to preserve
* ordering given the existing ifnet access mechanisms.
* XXX could be optimized
*/
IEEE80211_NODE_SAVEQ_LOCK(ni);
mcount = IEEE80211_NODE_SAVEQ_QLEN(ni);
mhead = mtail = NULL;
for (;;) {
_IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m);
if (m == NULL)
break;
if (mhead == NULL) {
mhead = m;
m->m_nextpkt = NULL;
} else
mtail->m_nextpkt = m;
mtail = m;
}
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
if (mhead != NULL) {
/* XXX need different driver interface */
/* XXX bypasses q max */
IF_PREPEND_LIST(&ic->ic_ifp->if_snd, mhead, mtail, mcount);
}
if (ic->ic_set_tim != NULL)
ic->ic_set_tim(ni, 0);
}
/*
* Handle power-save state change in station mode.
*/
void
ieee80211_sta_pwrsave(struct ieee80211com *ic, int enable)
{
struct ieee80211_node *ni = ic->ic_bss;
int qlen;
if (!((enable != 0) ^ ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) != 0)))
return;
IEEE80211_NOTE(ic, IEEE80211_MSG_POWER, ni,
"sta power save mode %s", enable ? "on" : "off");
if (!enable) {
ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT;
ieee80211_send_nulldata(ieee80211_ref_node(ni));
/*
* Flush any queued frames; we can do this immediately
* because we know they'll be queued behind the null
* data frame we send the ap.
* XXX can we use a data frame to take us out of ps?
*/
qlen = IEEE80211_NODE_SAVEQ_QLEN(ni);
if (qlen != 0) {
IEEE80211_NOTE(ic, IEEE80211_MSG_POWER, ni,
"flush ps queue, %u packets queued", qlen);
for (;;) {
struct mbuf *m;
IEEE80211_NODE_SAVEQ_LOCK(ni);
_IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m);
IEEE80211_NODE_SAVEQ_UNLOCK(ni);
if (m == NULL)
break;
/* XXX need different driver interface */
/* XXX bypasses q max */
IF_ENQUEUE(&ic->ic_ifp->if_snd, m);
}
}
} else {
ni->ni_flags |= IEEE80211_NODE_PWR_MGT;
ieee80211_send_nulldata(ieee80211_ref_node(ni));
}
}

View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* 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_POWER_H_
#define _NET80211_IEEE80211_POWER_H_
struct ieee80211com;
void ieee80211_power_attach(struct ieee80211com *);
void ieee80211_power_lateattach(struct ieee80211com *);
void ieee80211_power_detach(struct ieee80211com *);
int ieee80211_node_saveq_drain(struct ieee80211_node *);
int ieee80211_node_saveq_age(struct ieee80211_node *);
void ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *);
void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
void ieee80211_sta_pwrsave(struct ieee80211com *, int enable);
void ieee80211_power_poll(struct ieee80211com *);
#endif /* _NET80211_IEEE80211_POWER_H_ */

View File

@ -35,8 +35,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <net/if.h>
@ -103,6 +103,7 @@ ieee80211_proto_attach(struct ieee80211com *ic)
ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
ic->ic_bmiss_max = IEEE80211_BMISS_MAX;
callout_init(&ic->ic_swbmiss, CALLOUT_MPSAFE);
callout_init(&ic->ic_mgtsend, CALLOUT_MPSAFE);
ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT;
ic->ic_protmode = IEEE80211_PROT_CTSONLY;
ic->ic_roaming = IEEE80211_ROAMING_AUTO;
@ -237,9 +238,9 @@ ieee80211_aclator_get(const char *name)
}
void
ieee80211_print_essid(const u_int8_t *essid, int len)
ieee80211_print_essid(const uint8_t *essid, int len)
{
const u_int8_t *p;
const uint8_t *p;
int i;
if (len > IEEE80211_NWID_LEN)
@ -262,7 +263,8 @@ ieee80211_print_essid(const u_int8_t *essid, int len)
}
void
ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi)
ieee80211_dump_pkt(struct ieee80211com *ic,
const uint8_t *buf, int len, int rate, int rssi)
{
const struct ieee80211_frame *wh;
int i;
@ -285,7 +287,7 @@ ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi)
printf("(%s)", ether_sprintf(wh->i_addr2));
break;
case IEEE80211_FC1_DIR_DSTODS:
printf("DSDS %s", ether_sprintf((const u_int8_t *)&wh[1]));
printf("DSDS %s", ether_sprintf((const uint8_t *)&wh[1]));
printf("->%s", ether_sprintf(wh->i_addr3));
printf("(%s", ether_sprintf(wh->i_addr2));
printf("->%s)", ether_sprintf(wh->i_addr1));
@ -304,12 +306,22 @@ ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi)
printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
break;
}
if (IEEE80211_QOS_HAS_SEQ(wh)) {
const struct ieee80211_qosframe *qwh =
(const struct ieee80211_qosframe *)buf;
printf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID,
qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : "");
}
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
int i;
printf(" WEP [IV");
for (i = 0; i < IEEE80211_WEP_IVLEN; i++)
printf(" %.02x", buf[sizeof(*wh)+i]);
printf(" KID %u]", buf[sizeof(*wh)+i] >> 6);
int off;
off = ieee80211_anyhdrspace(ic, wh);
printf(" WEP [IV %.02x %.02x %.02x",
buf[off+0], buf[off+1], buf[off+2]);
if (buf[off+IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)
printf(" %.02x %.02x %.02x",
buf[off+4], buf[off+5], buf[off+6]);
printf(" KID %u]", buf[off+IEEE80211_WEP_IVLEN] >> 6);
}
if (rate >= 0)
printf(" %dM", rate / 2);
@ -346,17 +358,11 @@ ieee80211_fix_rate(struct ieee80211_node *ni,
int i, j, rix, error;
int okrate, badrate, fixedrate;
const struct ieee80211_rateset *srs;
u_int8_t r;
uint8_t r;
/*
* If the fixed rate check was requested but no
* fixed has been defined then just remove it.
*/
if ((flags & IEEE80211_F_DOFRATE) &&
ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
flags &= ~IEEE80211_F_DOFRATE;
error = 0;
okrate = badrate = fixedrate = 0;
okrate = badrate = 0;
fixedrate = IEEE80211_FIXED_RATE_NONE;
srs = ieee80211_get_suprates(ic, ni->ni_chan);
for (i = 0; i < nrs->rs_nrates; ) {
if (flags & IEEE80211_F_DOSORT) {
@ -373,13 +379,11 @@ ieee80211_fix_rate(struct ieee80211_node *ni,
}
r = nrs->rs_rates[i] & IEEE80211_RATE_VAL;
badrate = r;
if (flags & IEEE80211_F_DOFRATE) {
/*
* Check any fixed rate is included.
*/
if (r == RV(srs->rs_rates[ic->ic_fixed_rate]))
fixedrate = r;
}
/*
* Check for fixed rate.
*/
if (r == ic->ic_fixed_rate)
fixedrate = r;
/*
* Check against supported rates.
*/
@ -418,7 +422,7 @@ ieee80211_fix_rate(struct ieee80211_node *ni,
i++;
}
if (okrate == 0 || error != 0 ||
((flags & IEEE80211_F_DOFRATE) && fixedrate == 0))
((flags & IEEE80211_F_DOFRATE) && fixedrate != ic->ic_fixed_rate))
return badrate | IEEE80211_RATE_BASIC;
else
return RV(okrate);
@ -440,14 +444,15 @@ ieee80211_reset_erp(struct ieee80211com *ic)
* the driver is capable of doing it.
*/
ieee80211_set_shortslottime(ic,
ic->ic_curmode == IEEE80211_MODE_11A ||
(ic->ic_curmode == IEEE80211_MODE_11G &&
IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
IEEE80211_IS_CHAN_HT(ic->ic_curchan) ||
(IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
ic->ic_opmode == IEEE80211_M_HOSTAP &&
(ic->ic_caps & IEEE80211_C_SHSLOT)));
/*
* Set short preamble and ERP barker-preamble flags.
*/
if (ic->ic_curmode == IEEE80211_MODE_11A ||
if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
(ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
ic->ic_flags &= ~IEEE80211_F_USEBARKER;
@ -511,14 +516,17 @@ ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs)
void
ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode)
{
static const struct ieee80211_rateset basic[] = {
{ 0 }, /* IEEE80211_MODE_AUTO */
static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = {
{ .rs_nrates = 0 }, /* IEEE80211_MODE_AUTO */
{ 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
{ 2, { 2, 4 } }, /* IEEE80211_MODE_11B */
{ 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */
{ 0 }, /* IEEE80211_MODE_FH */
{ .rs_nrates = 0 }, /* IEEE80211_MODE_FH */
/* IEEE80211_MODE_PUREG (not yet) */
{ 7, { 2, 4, 11, 22, 12, 24, 48 } },
{ 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11NA */
/* IEEE80211_MODE_11NG (mixed b/g) */
{ 7, { 2, 4, 11, 22, 12, 24, 48 } },
};
int i, j;
@ -536,76 +544,97 @@ ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode
* WME protocol support. The following parameters come from the spec.
*/
typedef struct phyParamType {
u_int8_t aifsn;
u_int8_t logcwmin;
u_int8_t logcwmax;
u_int16_t txopLimit;
u_int8_t acm;
uint8_t aifsn;
uint8_t logcwmin;
uint8_t logcwmax;
uint16_t txopLimit;
uint8_t acm;
} paramType;
static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = {
{ 3, 4, 6 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 6 }, /* IEEE80211_MODE_11A */
{ 3, 5, 7 }, /* IEEE80211_MODE_11B */
{ 3, 4, 6 }, /* IEEE80211_MODE_11G */
{ 3, 5, 7 }, /* IEEE80211_MODE_FH */
{ 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11A */
{ 3, 5, 7, 0, 0 }, /* IEEE80211_MODE_11B */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11G */
{ 3, 5, 7, 0, 0 }, /* IEEE80211_MODE_FH */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 3, 5, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NA */ /* XXXcheck*/
{ 3, 4, 6, 0, 0 }, /* IEEE80211_MODE_11NG */ /* XXXcheck*/
};
static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = {
{ 7, 4, 10 }, /* IEEE80211_MODE_AUTO */
{ 7, 4, 10 }, /* IEEE80211_MODE_11A */
{ 7, 5, 10 }, /* IEEE80211_MODE_11B */
{ 7, 4, 10 }, /* IEEE80211_MODE_11G */
{ 7, 5, 10 }, /* IEEE80211_MODE_FH */
{ 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */
{ 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
{ 7, 5, 10, 0, 0 }, /* IEEE80211_MODE_11B */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
{ 7, 5, 10, 0, 0 }, /* IEEE80211_MODE_FH */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 7, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
{ 7, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
};
static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = {
{ 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */
{ 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */
{ 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */
{ 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */
{ 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */
{ 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
{ 1, 4, 5, 188, 0 }, /* IEEE80211_MODE_11B */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
{ 1, 4, 5, 188, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
{ 1, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
};
static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = {
{ 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */
{ 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */
{ 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */
{ 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */
{ 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
{ 1, 3, 4, 102, 0 }, /* IEEE80211_MODE_11B */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
{ 1, 3, 4, 102, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
{ 1, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
};
static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = {
{ 3, 4, 10 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 10 }, /* IEEE80211_MODE_11A */
{ 3, 5, 10 }, /* IEEE80211_MODE_11B */
{ 3, 4, 10 }, /* IEEE80211_MODE_11G */
{ 3, 5, 10 }, /* IEEE80211_MODE_FH */
{ 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_AUTO */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11A */
{ 3, 5, 10, 0, 0 }, /* IEEE80211_MODE_11B */
{ 3, 4, 10, 0, 0 }, /* IEEE80211_MODE_11G */
{ 3, 5, 10, 0, 0 }, /* IEEE80211_MODE_FH */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 3, 10, 0, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 1, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NA */
{ 1, 4, 10, 0, 0 }, /* IEEE80211_MODE_11NG */
};
static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = {
{ 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */
{ 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */
{ 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */
{ 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */
{ 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */
{ 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11A */
{ 2, 4, 5, 188, 0 }, /* IEEE80211_MODE_11B */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11G */
{ 2, 4, 5, 188, 0 }, /* IEEE80211_MODE_FH */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 2, 3, 94, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NA */
{ 2, 3, 4, 94, 0 }, /* IEEE80211_MODE_11NG */
};
static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = {
{ 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */
{ 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */
{ 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */
{ 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */
{ 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11A */
{ 2, 3, 4, 102, 0 }, /* IEEE80211_MODE_11B */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11G */
{ 2, 3, 4, 102, 0 }, /* IEEE80211_MODE_FH */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 2, 2, 47, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NA */
{ 2, 2, 3, 47, 0 }, /* IEEE80211_MODE_11NG */
};
void
@ -614,29 +643,40 @@ ieee80211_wme_initparams(struct ieee80211com *ic)
struct ieee80211_wme_state *wme = &ic->ic_wme;
const paramType *pPhyParam, *pBssPhyParam;
struct wmeParams *wmep;
enum ieee80211_phymode mode;
int i;
if ((ic->ic_caps & IEEE80211_C_WME) == 0)
return;
/*
* Select mode; we can be called early in which case we
* always use auto mode. We know we'll be called when
* entering the RUN state with bsschan setup properly
* so state will eventually get set correctly
*/
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
mode = ieee80211_chan2mode(ic->ic_bsschan);
else
mode = IEEE80211_MODE_AUTO;
for (i = 0; i < WME_NUM_AC; i++) {
switch (i) {
case WME_AC_BK:
pPhyParam = &phyParamForAC_BK[ic->ic_curmode];
pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode];
pPhyParam = &phyParamForAC_BK[mode];
pBssPhyParam = &phyParamForAC_BK[mode];
break;
case WME_AC_VI:
pPhyParam = &phyParamForAC_VI[ic->ic_curmode];
pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode];
pPhyParam = &phyParamForAC_VI[mode];
pBssPhyParam = &bssPhyParamForAC_VI[mode];
break;
case WME_AC_VO:
pPhyParam = &phyParamForAC_VO[ic->ic_curmode];
pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode];
pPhyParam = &phyParamForAC_VO[mode];
pBssPhyParam = &bssPhyParamForAC_VO[mode];
break;
case WME_AC_BE:
default:
pPhyParam = &phyParamForAC_BE[ic->ic_curmode];
pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode];
pPhyParam = &phyParamForAC_BE[mode];
pBssPhyParam = &bssPhyParamForAC_BE[mode];
break;
}
@ -704,17 +744,21 @@ void
ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
{
static const paramType phyParam[IEEE80211_MODE_MAX] = {
{ 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */
{ 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */
{ 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */
{ 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */
{ 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */
{ 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_AUTO */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11A */
{ 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_11B */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11G */
{ 2, 5, 10, 64, 0 }, /* IEEE80211_MODE_FH */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_A */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_TURBO_G */
{ 1, 3, 10, 64, 0 }, /* IEEE80211_MODE_STURBO_A */
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NA */ /*XXXcheck*/
{ 2, 4, 10, 64, 0 }, /* IEEE80211_MODE_11NG */ /*XXXcheck*/
};
struct ieee80211_wme_state *wme = &ic->ic_wme;
const struct wmeParams *wmep;
struct wmeParams *chanp, *bssp;
enum ieee80211_phymode mode;
int i;
/* set up the channel access parameters for the physical device */
@ -734,6 +778,17 @@ ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
chanp->wmep_txopLimit = wmep->wmep_txopLimit;
}
/*
* Select mode; we can be called early in which case we
* always use auto mode. We know we'll be called when
* entering the RUN state with bsschan setup properly
* so state will eventually get set correctly
*/
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC)
mode = ieee80211_chan2mode(ic->ic_bsschan);
else
mode = IEEE80211_MODE_AUTO;
/*
* This implements agressive mode as found in certain
* vendors' AP's. When there is significant high
@ -750,15 +805,14 @@ ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
chanp->wmep_aifsn = bssp->wmep_aifsn =
phyParam[ic->ic_curmode].aifsn;
chanp->wmep_aifsn = bssp->wmep_aifsn = phyParam[mode].aifsn;
chanp->wmep_logcwmin = bssp->wmep_logcwmin =
phyParam[ic->ic_curmode].logcwmin;
phyParam[mode].logcwmin;
chanp->wmep_logcwmax = bssp->wmep_logcwmax =
phyParam[ic->ic_curmode].logcwmax;
phyParam[mode].logcwmax;
chanp->wmep_txopLimit = bssp->wmep_txopLimit =
(ic->ic_flags & IEEE80211_F_BURST) ?
phyParam[ic->ic_curmode].txopLimit : 0;
phyParam[mode].txopLimit : 0;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
"%s: %s [acm %u aifsn %u log2(cwmin) %u "
"log2(cwmax) %u txpoLimit %u]\n", __func__
@ -773,7 +827,7 @@ ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
static const u_int8_t logCwMin[IEEE80211_MODE_MAX] = {
static const uint8_t logCwMin[IEEE80211_MODE_MAX] = {
3, /* IEEE80211_MODE_AUTO */
3, /* IEEE80211_MODE_11A */
4, /* IEEE80211_MODE_11B */
@ -781,12 +835,14 @@ ieee80211_wme_updateparams_locked(struct ieee80211com *ic)
4, /* IEEE80211_MODE_FH */
3, /* IEEE80211_MODE_TURBO_A */
3, /* IEEE80211_MODE_TURBO_G */
3, /* IEEE80211_MODE_STURBO_A */
3, /* IEEE80211_MODE_11NA */
3, /* IEEE80211_MODE_11NG */
};
chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
chanp->wmep_logcwmin = bssp->wmep_logcwmin =
logCwMin[ic->ic_curmode];
chanp->wmep_logcwmin = bssp->wmep_logcwmin = logCwMin[mode];
IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME,
"%s: %s log2(cwmin) %u\n", __func__
, ieee80211_wme_acnames[WME_AC_BE]
@ -823,6 +879,85 @@ ieee80211_wme_updateparams(struct ieee80211com *ic)
}
}
/*
* Start a device. If this is the first vap running on the
* underlying device then we first bring it up.
*/
int
ieee80211_init(struct ieee80211com *ic, int forcescan)
{
IEEE80211_DPRINTF(ic,
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
"%s\n", "start running");
/*
* Kick the 802.11 state machine as appropriate.
*/
if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
if (ic->ic_opmode == IEEE80211_M_STA) {
/*
* Try to be intelligent about clocking the state
* machine. If we're currently in RUN state then
* we should be able to apply any new state/parameters
* simply by re-associating. Otherwise we need to
* re-scan to select an appropriate ap.
*/
if (ic->ic_state != IEEE80211_S_RUN || forcescan)
ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
else
ieee80211_new_state(ic, IEEE80211_S_ASSOC, 1);
} else {
/*
* For monitor+wds modes there's nothing to do but
* start running. Otherwise, if this is the first
* vap to be brought up, start a scan which may be
* preempted if the station is locked to a particular
* channel.
*/
if (ic->ic_opmode == IEEE80211_M_MONITOR ||
ic->ic_opmode == IEEE80211_M_WDS) {
ic->ic_state = IEEE80211_S_INIT; /* XXX*/
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
} else
ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
}
}
return 0;
}
/*
* Switch between turbo and non-turbo operating modes.
* Use the specified channel flags to locate the new
* channel, update 802.11 state, and then call back into
* the driver to effect the change.
*/
void
ieee80211_dturbo_switch(struct ieee80211com *ic, int newflags)
{
struct ieee80211_channel *chan;
chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
if (chan == NULL) { /* XXX should not happen */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
"%s: no channel with freq %u flags 0x%x\n",
__func__, ic->ic_bsschan->ic_freq, newflags);
return;
}
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SUPERG,
"%s: %s -> %s (freq %u flags 0x%x)\n", __func__,
ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)],
ieee80211_phymode_name[ieee80211_chan2mode(chan)],
chan->ic_freq, chan->ic_flags);
ic->ic_bsschan = chan;
ic->ic_prevchan = ic->ic_curchan;
ic->ic_curchan = chan;
ic->ic_set_channel(ic);
/* NB: do not need to reset ERP state 'cuz we're in sta mode */
}
void
ieee80211_beacon_miss(struct ieee80211com *ic)
{
@ -831,8 +966,7 @@ ieee80211_beacon_miss(struct ieee80211com *ic)
/* XXX check ic_curchan != ic_bsschan? */
return;
}
IEEE80211_DPRINTF(ic,
IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
"%s\n", "beacon miss");
/*
@ -857,7 +991,28 @@ ieee80211_beacon_miss(struct ieee80211com *ic)
return;
}
ic->ic_bmiss_count = 0;
ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
/*
* If we receive a beacon miss interrupt when using
* dynamic turbo, attempt to switch modes before
* reassociating.
*/
if (IEEE80211_ATH_CAP(ic, ic->ic_bss, IEEE80211_NODE_TURBOP))
ieee80211_dturbo_switch(ic,
ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO);
/*
* Try to reassociate before scanning for a new ap.
*/
ieee80211_new_state(ic, IEEE80211_S_ASSOC, 1);
} else {
/*
* Somebody else is controlling state changes (e.g.
* a user-mode app) don't do anything that would
* confuse them; just drop into scan mode so they'll
* notified of the state change and given control.
*/
ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
}
}
/*
@ -901,6 +1056,34 @@ sta_deauth(void *arg, struct ieee80211_node *ni)
IEEE80211_REASON_ASSOC_LEAVE);
}
/*
* Handle deauth with reason. We retry only for
* the cases where we might succeed. Otherwise
* we downgrade the ap and scan.
*/
static void
sta_authretry(struct ieee80211com *ic, struct ieee80211_node *ni, int reason)
{
switch (reason) {
case IEEE80211_STATUS_TIMEOUT:
case IEEE80211_REASON_ASSOC_EXPIRE:
case IEEE80211_REASON_NOT_AUTHED:
case IEEE80211_REASON_NOT_ASSOCED:
case IEEE80211_REASON_ASSOC_LEAVE:
case IEEE80211_REASON_ASSOC_NOT_AUTHED:
IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 1);
break;
default:
ieee80211_scan_assoc_fail(ic, ic->ic_bss->ni_macaddr, reason);
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
ieee80211_check_scan(ic,
IEEE80211_SCAN_ACTIVE,
IEEE80211_SCAN_FOREVER,
ic->ic_des_nssid, ic->ic_des_ssid);
break;
}
}
static int
ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
@ -912,6 +1095,9 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__,
ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
ic->ic_state = nstate; /* state transition */
callout_stop(&ic->ic_mgtsend); /* XXX callout_drain */
if (ostate != IEEE80211_S_SCAN)
ieee80211_cancel_scan(ic); /* background scan */
ni = ic->ic_bss; /* NB: no reference held */
if (ic->ic_flags_ext & IEEE80211_FEXT_SWBMISS)
callout_stop(&ic->ic_swbmiss);
@ -959,9 +1145,9 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
}
if (ostate != IEEE80211_S_INIT) {
/* NB: optimize INIT -> INIT case */
ic->ic_mgt_timer = 0;
ieee80211_drain_ifq(&ic->ic_mgtq);
ieee80211_reset_bss(ic);
ieee80211_scan_flush(ic);
}
if (ic->ic_auth->ia_detach != NULL)
ic->ic_auth->ia_detach(ic);
@ -969,50 +1155,71 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
case IEEE80211_S_SCAN:
switch (ostate) {
case IEEE80211_S_INIT:
createibss:
if ((ic->ic_opmode == IEEE80211_M_HOSTAP ||
ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_AHDEMO) &&
ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
/*
* AP operation and we already have a channel;
* bypass the scan and startup immediately.
* Already have a channel; bypass the
* scan and startup immediately. Because
* of this explicitly sync the scanner state.
*/
ieee80211_scan_update(ic);
ieee80211_create_ibss(ic, ic->ic_des_chan);
} else {
ieee80211_begin_scan(ic, arg);
ieee80211_check_scan(ic,
IEEE80211_SCAN_ACTIVE |
IEEE80211_SCAN_FLUSH,
IEEE80211_SCAN_FOREVER,
ic->ic_des_nssid, ic->ic_des_ssid);
}
break;
case IEEE80211_S_SCAN:
/*
* Scan next. If doing an active scan probe
* for the requested ap (if any).
*/
if (ic->ic_flags & IEEE80211_F_ASCAN)
ieee80211_probe_curchan(ic, 0);
break;
case IEEE80211_S_RUN:
/* beacon miss */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE,
"no recent beacons from %s; rescanning\n",
ether_sprintf(ic->ic_bss->ni_bssid));
ieee80211_sta_leave(ic, ni);
ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */
/* FALLTHRU */
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
/* timeout restart scan */
ni = ieee80211_find_node(&ic->ic_scan,
ic->ic_bss->ni_macaddr);
if (ni != NULL) {
ni->ni_fails++;
ieee80211_unref_node(&ni);
}
/*
* These can happen either because of a timeout
* on an assoc/auth response or because of a
* change in state that requires a reset. For
* the former we're called with a non-zero arg
* that is the cause for the failure; pass this
* to the scan code so it can update state.
* Otherwise trigger a new scan unless we're in
* manual roaming mode in which case an application
* must issue an explicit scan request.
*/
if (arg != 0)
ieee80211_scan_assoc_fail(ic,
ic->ic_bss->ni_macaddr, arg);
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
ieee80211_begin_scan(ic, arg);
ieee80211_check_scan(ic,
IEEE80211_SCAN_ACTIVE,
IEEE80211_SCAN_FOREVER,
ic->ic_des_nssid, ic->ic_des_ssid);
break;
case IEEE80211_S_RUN: /* beacon miss */
if (ic->ic_opmode == IEEE80211_M_STA) {
ieee80211_sta_leave(ic, ni);
ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
ieee80211_check_scan(ic,
IEEE80211_SCAN_ACTIVE,
IEEE80211_SCAN_FOREVER,
ic->ic_des_nssid,
ic->ic_des_ssid);
} else {
ieee80211_iterate_nodes(&ic->ic_sta,
sta_disassoc, ic);
goto createibss;
}
break;
}
break;
case IEEE80211_S_AUTH:
KASSERT(ic->ic_opmode == IEEE80211_M_STA,
("switch to %s state when operating in mode %u",
ieee80211_state_name[nstate], ic->ic_opmode));
switch (ostate) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
@ -1021,19 +1228,19 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
break;
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
switch (arg) {
switch (arg & 0xff) {
case IEEE80211_FC0_SUBTYPE_AUTH:
/* ??? */
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH, 2);
break;
case IEEE80211_FC0_SUBTYPE_DEAUTH:
/* ignore and retry scan on timeout */
sta_authretry(ic, ni, arg>>8);
break;
}
break;
case IEEE80211_S_RUN:
switch (arg) {
switch (arg & 0xff) {
case IEEE80211_FC0_SUBTYPE_AUTH:
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_AUTH, 2);
@ -1052,22 +1259,26 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
}
break;
case IEEE80211_S_ASSOC:
KASSERT(ic->ic_opmode == IEEE80211_M_STA,
("switch to %s state when operating in mode %u",
ieee80211_state_name[nstate], ic->ic_opmode));
switch (ostate) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
case IEEE80211_S_ASSOC:
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
"%s: invalid transition\n", __func__);
break;
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
break;
case IEEE80211_S_RUN:
ieee80211_sta_leave(ic, ni);
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
IEEE80211_SEND_MGMT(ic, ni,
IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
IEEE80211_SEND_MGMT(ic, ni, arg ?
IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
}
break;
}
@ -1078,8 +1289,18 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
}
switch (ostate) {
case IEEE80211_S_INIT:
if (ic->ic_opmode == IEEE80211_M_MONITOR)
if (ic->ic_opmode == IEEE80211_M_MONITOR ||
ic->ic_opmode == IEEE80211_M_WDS ||
ic->ic_opmode == IEEE80211_M_HOSTAP) {
/*
* Already have a channel; bypass the
* scan and startup immediately. Because
* of this explicitly sync the scanner state.
*/
ieee80211_scan_update(ic);
ieee80211_create_ibss(ic, ic->ic_curchan);
break;
}
/* fall thru... */
case IEEE80211_S_AUTH:
IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
@ -1107,10 +1328,12 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate]));
}
#endif
ic->ic_mgt_timer = 0;
if (ic->ic_opmode == IEEE80211_M_STA)
if (ic->ic_opmode == IEEE80211_M_STA) {
ieee80211_scan_assoc_success(ic,
ni->ni_macaddr);
ieee80211_notify_node_join(ic, ni,
arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
}
if_start(ifp); /* XXX not authorized yet */
break;
}
@ -1150,8 +1373,8 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
* Enable inactivity processing.
* XXX
*/
ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT;
ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT;
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
ieee80211_node_timeout, ic);
break;
}
return 0;

View File

@ -52,32 +52,36 @@ void ieee80211_proto_detach(struct ieee80211com *);
struct ieee80211_node;
int ieee80211_input(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, u_int32_t);
struct ieee80211_node *, int, int, uint32_t);
void ieee80211_deliver_data(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
struct mbuf *ieee80211_decap1(struct mbuf *, int *);
int ieee80211_setup_rates(struct ieee80211_node *ni,
const u_int8_t *rates, const u_int8_t *xrates, int flags);
void ieee80211_saveie(u_int8_t **, const u_int8_t *);
const uint8_t *rates, const uint8_t *xrates, int flags);
void ieee80211_saveie(uint8_t **, const uint8_t *);
void ieee80211_saveath(struct ieee80211_node *, uint8_t *);
void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, int, int, u_int32_t);
struct ieee80211_node *, int, int, int, uint32_t);
int ieee80211_mgmt_output(struct ieee80211com *, struct ieee80211_node *,
struct mbuf *, int type);
struct ieee80211_bpf_params;
int ieee80211_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
int ieee80211_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_send_probereq(struct ieee80211_node *ni,
const u_int8_t sa[IEEE80211_ADDR_LEN],
const u_int8_t da[IEEE80211_ADDR_LEN],
const u_int8_t bssid[IEEE80211_ADDR_LEN],
const u_int8_t *ssid, size_t ssidlen,
const void *optie, size_t optielen);
int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
int, int);
int ieee80211_send_probereq(struct ieee80211_node *ni,
const uint8_t sa[IEEE80211_ADDR_LEN],
const uint8_t da[IEEE80211_ADDR_LEN],
const uint8_t bssid[IEEE80211_ADDR_LEN],
const uint8_t *ssid, size_t ssidlen,
const void *optie, size_t optielen);
int ieee80211_classify(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
struct mbuf *ieee80211_encap(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
void ieee80211_pwrsave(struct ieee80211com *, struct ieee80211_node *,
struct mbuf *);
void ieee80211_reset_erp(struct ieee80211com *);
void ieee80211_set_shortslottime(struct ieee80211com *, int onoff);
@ -101,12 +105,12 @@ ieee80211_hdrsize(const void *data)
if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
size += IEEE80211_ADDR_LEN;
if (IEEE80211_QOS_HAS_SEQ(wh))
size += sizeof(u_int16_t);
size += sizeof(uint16_t);
return size;
}
/*
* Return the size of the 802.11 header; handles any type of frame.
* Like ieee80211_hdrsize, but handles any type of frame.
*/
static __inline int
ieee80211_anyhdrsize(const void *data)
@ -118,6 +122,8 @@ ieee80211_anyhdrsize(const void *data)
case IEEE80211_FC0_SUBTYPE_CTS:
case IEEE80211_FC0_SUBTYPE_ACK:
return sizeof(struct ieee80211_frame_ack);
case IEEE80211_FC0_SUBTYPE_BAR:
return sizeof(struct ieee80211_frame_bar);
}
return sizeof(struct ieee80211_frame_min);
} else
@ -154,11 +160,11 @@ struct ieee80211_aclator {
int (*iac_attach)(struct ieee80211com *);
void (*iac_detach)(struct ieee80211com *);
int (*iac_check)(struct ieee80211com *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
const uint8_t mac[IEEE80211_ADDR_LEN]);
int (*iac_add)(struct ieee80211com *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
const uint8_t mac[IEEE80211_ADDR_LEN]);
int (*iac_remove)(struct ieee80211com *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
const uint8_t mac[IEEE80211_ADDR_LEN]);
int (*iac_flush)(struct ieee80211com *);
int (*iac_setpolicy)(struct ieee80211com *, int);
int (*iac_getpolicy)(struct ieee80211com *);
@ -174,7 +180,8 @@ const struct ieee80211_aclator *ieee80211_aclator_get(const char *name);
#define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */
#define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */
#define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */
#define IEEE80211_F_JOIN 0x00000010 /* sta joining our bss */
#define IEEE80211_F_DOBRS 0x00000010 /* check basic rate set */
#define IEEE80211_F_JOIN 0x00000020 /* sta joining our bss */
int ieee80211_fix_rate(struct ieee80211_node *,
struct ieee80211_rateset *, int);
@ -182,18 +189,18 @@ int ieee80211_fix_rate(struct ieee80211_node *,
* WME/WMM support.
*/
struct wmeParams {
u_int8_t wmep_acm;
u_int8_t wmep_aifsn;
u_int8_t wmep_logcwmin; /* log2(cwmin) */
u_int8_t wmep_logcwmax; /* log2(cwmax) */
u_int8_t wmep_txopLimit;
u_int8_t wmep_noackPolicy; /* 0 (ack), 1 (no ack) */
uint8_t wmep_acm;
uint8_t wmep_aifsn;
uint8_t wmep_logcwmin; /* log2(cwmin) */
uint8_t wmep_logcwmax; /* log2(cwmax) */
uint8_t wmep_txopLimit;
uint8_t wmep_noackPolicy; /* 0 (ack), 1 (no ack) */
};
#define IEEE80211_TXOP_TO_US(_txop) ((_txop)<<5)
#define IEEE80211_US_TO_TXOP(_us) ((_us)>>5)
struct chanAccParams {
u_int8_t cap_info; /* version of the current set */
uint8_t cap_info; /* version of the current set */
struct wmeParams cap_wmeParams[WME_NUM_AC];
};
@ -219,9 +226,12 @@ void ieee80211_wme_updateparams_locked(struct ieee80211com *);
#define ieee80211_new_state(_ic, _nstate, _arg) \
(((_ic)->ic_newstate)((_ic), (_nstate), (_arg)))
int ieee80211_init(struct ieee80211com *, int forcescan);
void ieee80211_dturbo_switch(struct ieee80211com *, int newflags);
void ieee80211_beacon_miss(struct ieee80211com *);
void ieee80211_print_essid(const u_int8_t *, int);
void ieee80211_dump_pkt(const u_int8_t *, int, int, int);
void ieee80211_print_essid(const uint8_t *, int);
void ieee80211_dump_pkt(struct ieee80211com *,
const uint8_t *, int, int, int);
extern const char *ieee80211_opmode_name[];
extern const char *ieee80211_state_name[IEEE80211_S_MAX];
@ -233,13 +243,14 @@ extern const char *ieee80211_wme_acnames[];
* can update the frame later w/ minimal overhead.
*/
struct ieee80211_beacon_offsets {
u_int16_t *bo_caps; /* capabilities */
u_int8_t *bo_tim; /* start of atim/dtim */
u_int8_t *bo_wme; /* start of WME parameters */
u_int8_t *bo_trailer; /* start of fixed-size trailer */
u_int16_t bo_tim_len; /* atim/dtim length in bytes */
u_int16_t bo_trailer_len; /* trailer length in bytes */
u_int8_t *bo_erp; /* start of ERP element */
uint16_t *bo_caps; /* capabilities */
uint8_t *bo_tim; /* start of atim/dtim */
uint8_t *bo_wme; /* start of WME parameters */
uint8_t *bo_trailer; /* start of fixed-size trailer */
uint16_t bo_tim_len; /* atim/dtim length in bytes */
uint16_t bo_trailer_len; /* trailer length in bytes */
uint8_t *bo_erp; /* start of ERP element */
uint8_t *bo_htinfo; /* start of HT info element */
};
struct mbuf *ieee80211_beacon_alloc(struct ieee80211com *,
struct ieee80211_node *, struct ieee80211_beacon_offsets *);

View File

@ -60,18 +60,18 @@
* Note well: all radiotap fields are little-endian.
*/
struct ieee80211_radiotap_header {
u_int8_t it_version; /* Version 0. Only increases
uint8_t it_version; /* Version 0. Only increases
* for drastic changes,
* introduction of compatible
* new fields does not count.
*/
u_int8_t it_pad;
u_int16_t it_len; /* length of the whole
uint8_t it_pad;
uint16_t it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
u_int32_t it_present; /* A bitmap telling which
uint32_t it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
@ -84,24 +84,25 @@ struct ieee80211_radiotap_header {
* Name Data type Units
* ---- --------- -----
*
* IEEE80211_RADIOTAP_TSFT u_int64_t microseconds
* IEEE80211_RADIOTAP_TSFT uint64_t microseconds
*
* Value in microseconds of the MAC's 64-bit 802.11 Time
* Synchronization Function timer when the first bit of the
* MPDU arrived at the MAC. For received frames, only.
*
* IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap
* IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
*
* Tx/Rx frequency in MHz, followed by flags (see below).
*
* IEEE80211_RADIOTAP_FHSS u_int16_t see below
* IEEE80211_RADIOTAP_FHSS uint16_t see below
*
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
* IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s
* IEEE80211_RADIOTAP_RATE uint8_t 500kb/s or index
*
* Tx/Rx data rate
* Tx/Rx data rate. If bit 0x80 is set then it represents an
* an MCS index and not an IEEE rate.
*
* IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from
* one milliwatt (dBm)
@ -115,30 +116,30 @@ struct ieee80211_radiotap_header {
* RF noise power at the antenna, decibel difference from one
* milliwatt.
*
* IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB)
* IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
*
* RF signal power at the antenna, decibel difference from an
* arbitrary, fixed reference.
*
* IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB)
* IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
*
* RF noise power at the antenna, decibel difference from an
* arbitrary, fixed reference point.
*
* IEEE80211_RADIOTAP_LOCK_QUALITY u_int16_t unitless
* IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
*
* Quality of Barker code lock. Unitless. Monotonically
* nondecreasing with "better" lock strength. Called "Signal
* Quality" in datasheets. (Is there a standard way to measure
* this?)
*
* IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless
* IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
*
* Transmit power expressed as unitless distance from max
* power set at factory calibration. 0 is max power.
* Monotonically nondecreasing with lower power levels.
*
* IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB)
* IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
*
* Transmit power expressed as decibel distance from max power
* set at factory calibration. 0 is max power. Monotonically
@ -151,15 +152,26 @@ struct ieee80211_radiotap_header {
* reference). This is the absolute power level measured at
* the antenna port.
*
* IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap
* IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
*
* Properties of transmitted and received frames. See flags
* defined below.
*
* IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index
* IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
*
* Unitless indication of the Rx/Tx antenna for this packet.
* The first antenna is antenna 0.
*
* IEEE80211_RADIOTAP_XCHANNEL uint32_t bitmap
* uint16_t MHz
* uint8_t channel number
* int8_t .5 dBm
*
* Extended channel specification: flags (see below) followed by
* frequency in MHz, the corresponding IEEE channel number, and
* finally the maximum regulatory transmit power cap in .5 dBm
* units. This property supersedes IEEE80211_RADIOTAP_CHANNEL
* and only one of the two should be present.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
@ -176,19 +188,27 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
IEEE80211_RADIOTAP_XCHANNEL = 14,
IEEE80211_RADIOTAP_EXT = 31,
};
#ifndef _KERNEL
/* Channel flags. */
#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
#define IEEE80211_CHAN_TURBO 0x00010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x00020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x00040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x00080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x00100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x00200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x00400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x00800 /* GFSK channel (FHSS PHY) */
#define IEEE80211_CHAN_GSM 0x01000 /* 900 MHz spectrum channel */
#define IEEE80211_CHAN_STURBO 0x02000 /* 11a static turbo channel only */
#define IEEE80211_CHAN_HALF 0x04000 /* Half rate channel */
#define IEEE80211_CHAN_QUARTER 0x08000 /* Quarter rate channel */
#define IEEE80211_CHAN_HT20 0x10000 /* HT 20 channel */
#define IEEE80211_CHAN_HT40U 0x20000 /* HT 40 channel w/ ext above */
#define IEEE80211_CHAN_HT40D 0x40000 /* HT 40 channel w/ ext below */
#endif /* !_KERNEL */
/* For IEEE80211_RADIOTAP_FLAGS */
@ -211,5 +231,6 @@ enum ieee80211_radiotap_type {
* (to 32-bit boundary)
*/
#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */
#define IEEE80211_RADIOTAP_F_SHORTGI 0x80 /* HT short GI */
#endif /* !_NET80211_IEEE80211_RADIOTAP_H_ */

View File

@ -0,0 +1,337 @@
/*-
* Copyright (c) 2005-2007 Sam Leffler, Errno Consulting
* 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>
__FBSDID("$FreeBSD$");
/*
* IEEE 802.11 regdomain support.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_regdomain.h>
void
ieee80211_regdomain_attach(struct ieee80211com *ic)
{
ic->ic_regdomain = 0; /* XXX */
ic->ic_countrycode = CTRY_UNITED_STATES;/* XXX */
ic->ic_location = 1+2; /* both */
}
void
ieee80211_regdomain_detach(struct ieee80211com *ic)
{
}
static void
addchan(struct ieee80211com *ic, int ieee, int flags)
{
struct ieee80211_channel *c;
c = &ic->ic_channels[ic->ic_nchans++];
c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
c->ic_ieee = ieee;
c->ic_flags = flags;
}
/*
* Setup the channel list for the specified regulatory domain,
* country code, and operating modes. This interface is used
* when a driver does not obtain the channel list from another
* source (such as firmware).
*/
void
ieee80211_init_channels(struct ieee80211com *ic,
int rd, enum ISOCountryCode cc, int bands, int outdoor, int ecm)
{
int i;
/* XXX just do something for now */
ic->ic_nchans = 0;
if (isset(&bands, IEEE80211_MODE_11B) ||
isset(&bands, IEEE80211_MODE_11G)) {
for (i = 1; i <= (ecm ? 14 : 11); i++) {
if (isset(&bands, IEEE80211_MODE_11B))
addchan(ic, i, IEEE80211_CHAN_B);
if (isset(&bands, IEEE80211_MODE_11G))
addchan(ic, i, IEEE80211_CHAN_G);
}
}
if (isset(&bands, IEEE80211_MODE_11A)) {
for (i = 36; i <= 64; i += 4)
addchan(ic, i, IEEE80211_CHAN_A);
for (i = 100; i <= 140; i += 4)
addchan(ic, i, IEEE80211_CHAN_A);
for (i = 149; i <= 161; i += 4)
addchan(ic, i, IEEE80211_CHAN_A);
}
ic->ic_regdomain = rd;
ic->ic_countrycode = cc;
ic->ic_location = outdoor;
}
/*
* Add Country Information IE.
*/
uint8_t *
ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic,
enum ISOCountryCode cc, int location)
{
#define CHAN_UNINTERESTING \
(IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO | \
IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)
/* XXX what about auto? */
/* flag set of channels to be excluded */
static const int skipflags[IEEE80211_MODE_MAX] = {
CHAN_UNINTERESTING, /* MODE_AUTO */
CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11A */
CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11B */
CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11G */
CHAN_UNINTERESTING | IEEE80211_CHAN_OFDM | /* MODE_FH */
IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN,
CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_TURBO_A */
CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_TURBO_G */
CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_STURBO_A */
CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11NA */
CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11NG */
};
struct ieee80211_country_ie *ie = (struct ieee80211_country_ie *)frm;
const char *iso_name;
uint8_t nextchan, chans[IEEE80211_CHAN_BYTES];
int i, skip;
ie->ie = IEEE80211_ELEMID_COUNTRY;
iso_name = ieee80211_cctoiso(cc);
if (iso_name == NULL) {
if_printf(ic->ic_ifp, "bad country code %d ignored\n", cc);
iso_name = " ";
}
ie->cc[0] = iso_name[0];
ie->cc[1] = iso_name[1];
/*
* Indoor/Outdoor portion of country string.
* NB: this is not quite right, since we should have one of:
* 'I' indoor only
* 'O' outdoor only
* ' ' all enviroments
*/
ie->cc[2] = ((location & 3) == 3 ? ' ' : location & 1 ? 'I' : 'O');
/*
* Run-length encoded channel+max tx power info.
*/
frm = (uint8_t *)&ie->band[0];
nextchan = 0; /* NB: impossible channel # */
memset(chans, 0, sizeof(chans));
skip = skipflags[ic->ic_curmode];
for (i = 0; i < ic->ic_nchans; i++) {
const struct ieee80211_channel *c = &ic->ic_channels[i];
if (isset(chans, c->ic_ieee)) /* suppress dup's */
continue;
if ((c->ic_flags & skip) == 0) /* skip band, etc. */
continue;
setbit(chans, c->ic_ieee);
if (c->ic_ieee != nextchan ||
c->ic_maxregpower != frm[-1]) { /* new run */
/* XXX max of 83 runs */
frm[0] = c->ic_ieee; /* starting channel # */
frm[1] = 1; /* # channels in run */
frm[2] = c->ic_maxregpower; /* tx power cap */
frm += 3;
nextchan = c->ic_ieee + 1; /* overflow? */
} else { /* extend run */
frm[-2]++;
nextchan++;
}
}
ie->len = frm - ie->cc;
if (ie->len & 1) /* pad to multiple of 2 */
ie->len++;
return frm;
#undef CHAN_UNINTERESTING
}
/*
* Country Code Table for code-to-string conversion.
*/
static const struct {
enum ISOCountryCode iso_code;
const char* iso_name;
} country_strings[] = {
{ CTRY_DEBUG, "DB" }, /* NB: nonstandard */
{ CTRY_DEFAULT, "NA" }, /* NB: nonstandard */
{ CTRY_ALBANIA, "AL" },
{ CTRY_ALGERIA, "DZ" },
{ CTRY_ARGENTINA, "AR" },
{ CTRY_ARMENIA, "AM" },
{ CTRY_AUSTRALIA, "AU" },
{ CTRY_AUSTRIA, "AT" },
{ CTRY_AZERBAIJAN, "AZ" },
{ CTRY_BAHRAIN, "BH" },
{ CTRY_BELARUS, "BY" },
{ CTRY_BELGIUM, "BE" },
{ CTRY_BELIZE, "BZ" },
{ CTRY_BOLIVIA, "BO" },
{ CTRY_BRAZIL, "BR" },
{ CTRY_BRUNEI_DARUSSALAM, "BN" },
{ CTRY_BULGARIA, "BG" },
{ CTRY_CANADA, "CA" },
{ CTRY_CHILE, "CL" },
{ CTRY_CHINA, "CN" },
{ CTRY_COLOMBIA, "CO" },
{ CTRY_COSTA_RICA, "CR" },
{ CTRY_CROATIA, "HR" },
{ CTRY_CYPRUS, "CY" },
{ CTRY_CZECH, "CZ" },
{ CTRY_DENMARK, "DK" },
{ CTRY_DOMINICAN_REPUBLIC, "DO" },
{ CTRY_ECUADOR, "EC" },
{ CTRY_EGYPT, "EG" },
{ CTRY_EL_SALVADOR, "SV" },
{ CTRY_ESTONIA, "EE" },
{ CTRY_FINLAND, "FI" },
{ CTRY_FRANCE, "FR" },
{ CTRY_FRANCE2, "F2" },
{ CTRY_GEORGIA, "GE" },
{ CTRY_GERMANY, "DE" },
{ CTRY_GREECE, "GR" },
{ CTRY_GUATEMALA, "GT" },
{ CTRY_HONDURAS, "HN" },
{ CTRY_HONG_KONG, "HK" },
{ CTRY_HUNGARY, "HU" },
{ CTRY_ICELAND, "IS" },
{ CTRY_INDIA, "IN" },
{ CTRY_INDONESIA, "ID" },
{ CTRY_IRAN, "IR" },
{ CTRY_IRELAND, "IE" },
{ CTRY_ISRAEL, "IL" },
{ CTRY_ITALY, "IT" },
{ CTRY_JAMAICA, "JM" },
{ CTRY_JAPAN, "JP" },
{ CTRY_JAPAN1, "J1" },
{ CTRY_JAPAN2, "J2" },
{ CTRY_JAPAN3, "J3" },
{ CTRY_JAPAN4, "J4" },
{ CTRY_JAPAN5, "J5" },
{ CTRY_JORDAN, "JO" },
{ CTRY_KAZAKHSTAN, "KZ" },
{ CTRY_KOREA_NORTH, "KP" },
{ CTRY_KOREA_ROC, "KR" },
{ CTRY_KOREA_ROC2, "K2" },
{ CTRY_KUWAIT, "KW" },
{ CTRY_LATVIA, "LV" },
{ CTRY_LEBANON, "LB" },
{ CTRY_LIECHTENSTEIN, "LI" },
{ CTRY_LITHUANIA, "LT" },
{ CTRY_LUXEMBOURG, "LU" },
{ CTRY_MACAU, "MO" },
{ CTRY_MACEDONIA, "MK" },
{ CTRY_MALAYSIA, "MY" },
{ CTRY_MEXICO, "MX" },
{ CTRY_MONACO, "MC" },
{ CTRY_MOROCCO, "MA" },
{ CTRY_NETHERLANDS, "NL" },
{ CTRY_NEW_ZEALAND, "NZ" },
{ CTRY_NORWAY, "NO" },
{ CTRY_OMAN, "OM" },
{ CTRY_PAKISTAN, "PK" },
{ CTRY_PANAMA, "PA" },
{ CTRY_PERU, "PE" },
{ CTRY_PHILIPPINES, "PH" },
{ CTRY_POLAND, "PL" },
{ CTRY_PORTUGAL, "PT" },
{ CTRY_PUERTO_RICO, "PR" },
{ CTRY_QATAR, "QA" },
{ CTRY_ROMANIA, "RO" },
{ CTRY_RUSSIA, "RU" },
{ CTRY_SAUDI_ARABIA, "SA" },
{ CTRY_SINGAPORE, "SG" },
{ CTRY_SLOVAKIA, "SK" },
{ CTRY_SLOVENIA, "SI" },
{ CTRY_SOUTH_AFRICA, "ZA" },
{ CTRY_SPAIN, "ES" },
{ CTRY_SWEDEN, "SE" },
{ CTRY_SWITZERLAND, "CH" },
{ CTRY_SYRIA, "SY" },
{ CTRY_TAIWAN, "TW" },
{ CTRY_THAILAND, "TH" },
{ CTRY_TRINIDAD_Y_TOBAGO, "TT" },
{ CTRY_TUNISIA, "TN" },
{ CTRY_TURKEY, "TR" },
{ CTRY_UKRAINE, "UA" },
{ CTRY_UAE, "AE" },
{ CTRY_UNITED_KINGDOM, "GB" },
{ CTRY_UNITED_STATES, "US" },
{ CTRY_URUGUAY, "UY" },
{ CTRY_UZBEKISTAN, "UZ" },
{ CTRY_VENEZUELA, "VE" },
{ CTRY_VIET_NAM, "VN" },
{ CTRY_YEMEN, "YE" },
{ CTRY_ZIMBABWE, "ZW" }
};
const char *
ieee80211_cctoiso(enum ISOCountryCode cc)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(country_strings); i++) {
if (country_strings[i].iso_code == cc)
return country_strings[i].iso_name;
}
return NULL;
#undef N
}
int
ieee80211_isotocc(const char iso[2])
{
#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
for (i = 0; i < N(country_strings); i++) {
if (country_strings[i].iso_name[0] == iso[0] &&
country_strings[i].iso_name[1] == iso[1])
return country_strings[i].iso_code;
}
return -1;
#undef N
}

View File

@ -0,0 +1,175 @@
/*-
* Copyright (c) 2005-2007 Sam Leffler, Errno Consulting
* 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_REGDOMAIN_H_
#define _NET80211_IEEE80211_REGDOMAIN_H_
/*
* 802.11 regulatory domain definitions.
*/
/*
* ISO 3166 Country/Region Codes
* http://ftp.ics.uci.edu/pub/ietf/http/related/iso3166.txt
*/
enum ISOCountryCode {
CTRY_AFGHANISTAN = 4,
CTRY_ALBANIA = 8, /* Albania */
CTRY_ALGERIA = 12, /* Algeria */
CTRY_AMERICAN_SAMOA = 16,
CTRY_ANDORRA = 20,
CTRY_ANGOLA = 24,
CTRY_ANGUILLA = 660,
/* XXX correct remainder */
CTRY_ARGENTINA = 32, /* Argentina */
CTRY_ARMENIA = 51, /* Armenia */
CTRY_AUSTRALIA = 36, /* Australia */
CTRY_AUSTRIA = 40, /* Austria */
CTRY_AZERBAIJAN = 31, /* Azerbaijan */
CTRY_BAHRAIN = 48, /* Bahrain */
CTRY_BELARUS = 112, /* Belarus */
CTRY_BELGIUM = 56, /* Belgium */
CTRY_BELIZE = 84, /* Belize */
CTRY_BOLIVIA = 68, /* Bolivia */
CTRY_BRAZIL = 76, /* Brazil */
CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */
CTRY_BULGARIA = 100, /* Bulgaria */
CTRY_CANADA = 124, /* Canada */
CTRY_CHILE = 152, /* Chile */
CTRY_CHINA = 156, /* People's Republic of China */
CTRY_COLOMBIA = 170, /* Colombia */
CTRY_COSTA_RICA = 188, /* Costa Rica */
CTRY_CROATIA = 191, /* Croatia */
CTRY_CYPRUS = 196, /* Cyprus */
CTRY_CZECH = 203, /* Czech Republic */
CTRY_DENMARK = 208, /* Denmark */
CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */
CTRY_ECUADOR = 218, /* Ecuador */
CTRY_EGYPT = 818, /* Egypt */
CTRY_EL_SALVADOR = 222, /* El Salvador */
CTRY_ESTONIA = 233, /* Estonia */
CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */
CTRY_FINLAND = 246, /* Finland */
CTRY_FRANCE = 250, /* France */
CTRY_FRANCE2 = 255, /* France2 */
CTRY_GEORGIA = 268, /* Georgia */
CTRY_GERMANY = 276, /* Germany */
CTRY_GREECE = 300, /* Greece */
CTRY_GUATEMALA = 320, /* Guatemala */
CTRY_HONDURAS = 340, /* Honduras */
CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */
CTRY_HUNGARY = 348, /* Hungary */
CTRY_ICELAND = 352, /* Iceland */
CTRY_INDIA = 356, /* India */
CTRY_INDONESIA = 360, /* Indonesia */
CTRY_IRAN = 364, /* Iran */
CTRY_IRAQ = 368, /* Iraq */
CTRY_IRELAND = 372, /* Ireland */
CTRY_ISRAEL = 376, /* Israel */
CTRY_ITALY = 380, /* Italy */
CTRY_JAMAICA = 388, /* Jamaica */
CTRY_JAPAN = 392, /* Japan */
CTRY_JAPAN1 = 393, /* Japan (JP1) */
CTRY_JAPAN2 = 394, /* Japan (JP0) */
CTRY_JAPAN3 = 395, /* Japan (JP1-1) */
CTRY_JAPAN4 = 396, /* Japan (JE1) */
CTRY_JAPAN5 = 397, /* Japan (JE2) */
CTRY_JORDAN = 400, /* Jordan */
CTRY_KAZAKHSTAN = 398, /* Kazakhstan */
CTRY_KENYA = 404, /* Kenya */
CTRY_KOREA_NORTH = 408, /* North Korea */
CTRY_KOREA_ROC = 410, /* South Korea */
CTRY_KOREA_ROC2 = 411, /* South Korea */
CTRY_KUWAIT = 414, /* Kuwait */
CTRY_LATVIA = 428, /* Latvia */
CTRY_LEBANON = 422, /* Lebanon */
CTRY_LIBYA = 434, /* Libya */
CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */
CTRY_LITHUANIA = 440, /* Lithuania */
CTRY_LUXEMBOURG = 442, /* Luxembourg */
CTRY_MACAU = 446, /* Macau */
CTRY_MACEDONIA = 807, /* the Former Yugoslav Republic of Macedonia */
CTRY_MALAYSIA = 458, /* Malaysia */
CTRY_MEXICO = 484, /* Mexico */
CTRY_MONACO = 492, /* Principality of Monaco */
CTRY_MOROCCO = 504, /* Morocco */
CTRY_NETHERLANDS = 528, /* Netherlands */
CTRY_NEW_ZEALAND = 554, /* New Zealand */
CTRY_NICARAGUA = 558, /* Nicaragua */
CTRY_NORWAY = 578, /* Norway */
CTRY_OMAN = 512, /* Oman */
CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */
CTRY_PANAMA = 591, /* Panama */
CTRY_PARAGUAY = 600, /* Paraguay */
CTRY_PERU = 604, /* Peru */
CTRY_PHILIPPINES = 608, /* Republic of the Philippines */
CTRY_POLAND = 616, /* Poland */
CTRY_PORTUGAL = 620, /* Portugal */
CTRY_PUERTO_RICO = 630, /* Puerto Rico */
CTRY_QATAR = 634, /* Qatar */
CTRY_ROMANIA = 642, /* Romania */
CTRY_RUSSIA = 643, /* Russia */
CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */
CTRY_SINGAPORE = 702, /* Singapore */
CTRY_SLOVAKIA = 703, /* Slovak Republic */
CTRY_SLOVENIA = 705, /* Slovenia */
CTRY_SOUTH_AFRICA = 710, /* South Africa */
CTRY_SPAIN = 724, /* Spain */
CTRY_SWEDEN = 752, /* Sweden */
CTRY_SWITZERLAND = 756, /* Switzerland */
CTRY_SYRIA = 760, /* Syria */
CTRY_TAIWAN = 158, /* Taiwan */
CTRY_THAILAND = 764, /* Thailand */
CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */
CTRY_TUNISIA = 788, /* Tunisia */
CTRY_TURKEY = 792, /* Turkey */
CTRY_UAE = 784, /* U.A.E. */
CTRY_UKRAINE = 804, /* Ukraine */
CTRY_UNITED_KINGDOM = 826, /* United Kingdom */
CTRY_UNITED_STATES = 840, /* United States */
CTRY_URUGUAY = 858, /* Uruguay */
CTRY_UZBEKISTAN = 860, /* Uzbekistan */
CTRY_VENEZUELA = 862, /* Venezuela */
CTRY_VIET_NAM = 704, /* Viet Nam */
CTRY_YEMEN = 887, /* Yemen */
CTRY_ZIMBABWE = 716, /* Zimbabwe */
};
#if defined(__KERNEL__) || defined(_KERNEL)
#define CTRY_DEBUG 0x1ff /* debug */
#define CTRY_DEFAULT 0 /* default */
void ieee80211_regdomain_attach(struct ieee80211com *);
void ieee80211_regdomain_detach(struct ieee80211com *);
void ieee80211_init_channels(struct ieee80211com *ic,
int rd, enum ISOCountryCode cc, int bands, int outdoor, int ecm);
uint8_t *ieee80211_add_countryie(uint8_t *, struct ieee80211com *,
enum ISOCountryCode cc, int location);
const char *ieee80211_cctoiso(enum ISOCountryCode);
int ieee80211_isotocc(const char iso[2]);
#endif /* defined(__KERNEL__) || defined(_KERNEL) */
#endif /* _NET80211_IEEE80211_REGDOMAIN_H_ */

View File

@ -0,0 +1,990 @@
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* 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>
__FBSDID("$FreeBSD$");
/*
* IEEE 802.11 scanning support.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
#include <net/bpf.h>
struct scan_state {
struct ieee80211_scan_state base; /* public state */
u_int ss_iflags; /* flags used internally */
#define ISCAN_MINDWELL 0x0001 /* min dwell time reached */
#define ISCAN_DISCARD 0x0002 /* discard rx'd frames */
#define ISCAN_CANCEL 0x0004 /* cancel current scan */
#define ISCAN_START 0x0008 /* 1st time through next_scan */
unsigned long ss_chanmindwell; /* min dwell on curchan */
unsigned long ss_scanend; /* time scan must stop */
u_int ss_duration; /* duration for next scan */
struct callout ss_scan_timer; /* scan timer */
};
#define SCAN_PRIVATE(ss) ((struct scan_state *) ss)
/*
* Amount of time to go off-channel during a background
* scan. This value should be large enough to catch most
* ap's but short enough that we can return on-channel
* before our listen interval expires.
*
* XXX tunable
* XXX check against configured listen interval
*/
#define IEEE80211_SCAN_OFFCHANNEL msecs_to_ticks(150)
/*
* Roaming-related defaults. RSSI thresholds are as returned by the
* driver (dBm). Transmit rate thresholds are IEEE rate codes (i.e
* .5M units).
*/
#define ROAM_RSSI_11A_DEFAULT 14 /* rssi threshold for 11a bss */
#define ROAM_RSSI_11B_DEFAULT 14 /* rssi threshold for 11b bss */
#define ROAM_RSSI_11BONLY_DEFAULT 14 /* rssi threshold for 11b-only bss */
#define ROAM_RATE_11A_DEFAULT 2*12 /* tx rate thresh for 11a bss */
#define ROAM_RATE_11B_DEFAULT 2*5 /* tx rate thresh for 11b bss */
#define ROAM_RATE_11BONLY_DEFAULT 2*1 /* tx rate thresh for 11b-only bss */
static void scan_restart_pwrsav(void *);
static void scan_curchan(struct ieee80211com *, unsigned long);
static void scan_mindwell(struct ieee80211com *);
static void scan_next(void *);
MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
void
ieee80211_scan_attach(struct ieee80211com *ic)
{
struct scan_state *ss;
ic->ic_roaming = IEEE80211_ROAMING_AUTO;
MALLOC(ss, struct scan_state *, sizeof(struct scan_state),
M_80211_SCAN, M_NOWAIT | M_ZERO);
if (ss == NULL) {
ic->ic_scan = NULL;
return;
}
callout_init(&ss->ss_scan_timer, CALLOUT_MPSAFE);
ic->ic_scan = &ss->base;
ic->ic_scan_curchan = scan_curchan;
ic->ic_scan_mindwell = scan_mindwell;
ic->ic_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz;
ic->ic_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz;
ic->ic_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz;
ic->ic_roam.rssi11a = ROAM_RSSI_11A_DEFAULT;
ic->ic_roam.rssi11b = ROAM_RSSI_11B_DEFAULT;
ic->ic_roam.rssi11bOnly = ROAM_RSSI_11BONLY_DEFAULT;
ic->ic_roam.rate11a = ROAM_RATE_11A_DEFAULT;
ic->ic_roam.rate11b = ROAM_RATE_11B_DEFAULT;
ic->ic_roam.rate11bOnly = ROAM_RATE_11BONLY_DEFAULT;
}
void
ieee80211_scan_detach(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss != NULL) {
callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
if (ss->ss_ops != NULL) {
ss->ss_ops->scan_detach(ss);
ss->ss_ops = NULL;
}
ic->ic_flags &= ~IEEE80211_F_SCAN;
ic->ic_scan = NULL;
FREE(SCAN_PRIVATE(ss), M_80211_SCAN);
}
}
/*
* Simple-minded scanner module support.
*/
#define IEEE80211_SCANNER_MAX (IEEE80211_M_MONITOR+1)
static const char *scan_modnames[IEEE80211_SCANNER_MAX] = {
"wlan_scan_sta", /* IEEE80211_M_IBSS */
"wlan_scan_sta", /* IEEE80211_M_STA */
"wlan_scan_wds", /* IEEE80211_M_WDS */
"wlan_scan_sta", /* IEEE80211_M_AHDEMO */
"wlan_scan_4", /* n/a */
"wlan_scan_5", /* n/a */
"wlan_scan_ap", /* IEEE80211_M_HOSTAP */
"wlan_scan_7", /* n/a */
"wlan_scan_monitor", /* IEEE80211_M_MONITOR */
};
static const struct ieee80211_scanner *scanners[IEEE80211_SCANNER_MAX];
const struct ieee80211_scanner *
ieee80211_scanner_get(enum ieee80211_opmode mode)
{
if (mode >= IEEE80211_SCANNER_MAX)
return NULL;
if (scanners[mode] == NULL)
ieee80211_load_module(scan_modnames[mode]);
return scanners[mode];
}
void
ieee80211_scanner_register(enum ieee80211_opmode mode,
const struct ieee80211_scanner *scan)
{
if (mode >= IEEE80211_SCANNER_MAX)
return;
scanners[mode] = scan;
}
void
ieee80211_scanner_unregister(enum ieee80211_opmode mode,
const struct ieee80211_scanner *scan)
{
if (mode >= IEEE80211_SCANNER_MAX)
return;
if (scanners[mode] == scan)
scanners[mode] = NULL;
}
void
ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan)
{
int m;
for (m = 0; m < IEEE80211_SCANNER_MAX; m++)
if (scanners[m] == scan)
scanners[m] = NULL;
}
/*
* Update common scanner state to reflect the current
* operating mode. This is called when the state machine
* is transitioned to RUN state w/o scanning--e.g. when
* operating in monitor mode. The purpose of this is to
* ensure later callbacks find ss_ops set to properly
* reflect current operating mode.
*/
int
ieee80211_scan_update(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
const struct ieee80211_scanner *scan;
scan = ieee80211_scanner_get(ic->ic_opmode);
IEEE80211_LOCK(ic);
if (scan == NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: no scanner support for mode %u\n",
__func__, ic->ic_opmode);
/* XXX stat */
}
ss->ss_ic = ic;
if (ss->ss_ops != scan) {
/* switch scanners; detach old, attach new */
if (ss->ss_ops != NULL)
ss->ss_ops->scan_detach(ss);
if (scan != NULL && !scan->scan_attach(ss)) {
/* XXX attach failure */
/* XXX stat+msg */
ss->ss_ops = NULL;
} else
ss->ss_ops = scan;
}
IEEE80211_UNLOCK(ic);
return (scan != NULL);
}
static void
change_channel(struct ieee80211com *ic,
struct ieee80211_channel *chan)
{
ic->ic_curchan = chan;
ic->ic_set_channel(ic);
}
static char
channel_type(const struct ieee80211_channel *c)
{
if (IEEE80211_IS_CHAN_ST(c))
return 'S';
if (IEEE80211_IS_CHAN_108A(c))
return 'T';
if (IEEE80211_IS_CHAN_108G(c))
return 'G';
if (IEEE80211_IS_CHAN_HT(c))
return 'n';
if (IEEE80211_IS_CHAN_A(c))
return 'a';
if (IEEE80211_IS_CHAN_ANYG(c))
return 'g';
if (IEEE80211_IS_CHAN_B(c))
return 'b';
return 'f';
}
void
ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
{
struct ieee80211com *ic = ss->ss_ic;
const char *sep;
int i;
sep = "";
for (i = ss->ss_next; i < ss->ss_last; i++) {
const struct ieee80211_channel *c = ss->ss_chans[i];
printf("%s%u%c", sep, ieee80211_chan2ieee(ic, c),
channel_type(c));
sep = ", ";
}
}
/*
* Enable station power save mode and start/restart the scanning thread.
*/
static void
scan_restart_pwrsav(void *arg)
{
struct scan_state *ss = (struct scan_state *) arg;
struct ieee80211com *ic = ss->base.ss_ic;
int delay;
ieee80211_sta_pwrsave(ic, 1);
/*
* Use an initial 1ms delay to insure the null
* data frame has a chance to go out.
* XXX 1ms is a lot, better to trigger scan
* on tx complete.
*/
delay = hz/1000;
if (delay < 1)
delay = 1;
ic->ic_scan_start(ic); /* notify driver */
ss->ss_scanend = ticks + delay + ss->ss_duration;
ss->ss_iflags |= ISCAN_START;
callout_reset(&ss->ss_scan_timer, delay, scan_next, ss);
}
/*
* Start/restart scanning. If we're operating in station mode
* and associated notify the ap we're going into power save mode
* and schedule a callback to initiate the work (where there's a
* better context for doing the work). Otherwise, start the scan
* directly.
*/
static int
scan_restart(struct scan_state *ss, u_int duration)
{
struct ieee80211com *ic = ss->base.ss_ic;
int defer = 0;
if (ss->base.ss_next == ss->base.ss_last) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: no channels to scan\n", __func__);
return 0;
}
if (ic->ic_opmode == IEEE80211_M_STA &&
ic->ic_state == IEEE80211_S_RUN) {
if ((ic->ic_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
/*
* Initiate power save before going off-channel.
* Note that we cannot do this directly because
* of locking issues; instead we defer it to a
* tasklet.
*/
ss->ss_duration = duration;
defer = 1;
}
}
if (!defer) {
ic->ic_scan_start(ic); /* notify driver */
ss->ss_scanend = ticks + duration;
ss->ss_iflags |= ISCAN_START;
callout_reset(&ss->ss_scan_timer, 0, scan_next, ss);
} else
scan_restart_pwrsav(ss);
return 1;
}
static void
copy_ssid(struct ieee80211com *ic, struct ieee80211_scan_state *ss,
int nssid, const struct ieee80211_scan_ssid ssids[])
{
if (nssid > IEEE80211_SCAN_MAX_SSID) {
/* XXX printf */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: too many ssid %d, ignoring all of them\n",
__func__, nssid);
return;
}
memcpy(ss->ss_ssid, ssids, nssid * sizeof(ssids[0]));
ss->ss_nssid = nssid;
}
/*
* Start a scan unless one is already going.
*/
int
ieee80211_start_scan(struct ieee80211com *ic, int flags, u_int duration,
u_int nssid, const struct ieee80211_scan_ssid ssids[])
{
const struct ieee80211_scanner *scan;
struct ieee80211_scan_state *ss = ic->ic_scan;
scan = ieee80211_scanner_get(ic->ic_opmode);
if (scan == NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: no scanner support for mode %u\n",
__func__, ic->ic_opmode);
/* XXX stat */
return 0;
}
IEEE80211_LOCK(ic);
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s scan, duration %u, desired mode %s, %s%s%s%s\n"
, __func__
, flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
, duration
, ieee80211_phymode_name[ic->ic_des_mode]
, flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
, flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
, flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
, flags & IEEE80211_SCAN_ONCE ? ", once" : ""
);
ss->ss_ic = ic;
if (ss->ss_ops != scan) {
/* switch scanners; detach old, attach new */
if (ss->ss_ops != NULL)
ss->ss_ops->scan_detach(ss);
if (!scan->scan_attach(ss)) {
/* XXX attach failure */
/* XXX stat+msg */
ss->ss_ops = NULL;
} else
ss->ss_ops = scan;
}
if (ss->ss_ops != NULL) {
if ((flags & IEEE80211_SCAN_NOSSID) == 0)
copy_ssid(ic, ss, nssid, ssids);
/* NB: top 4 bits for internal use */
ss->ss_flags = flags & 0xfff;
if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
ic->ic_stats.is_scan_active++;
else
ic->ic_stats.is_scan_passive++;
if (flags & IEEE80211_SCAN_FLUSH)
ss->ss_ops->scan_flush(ss);
/* NB: flush frames rx'd before 1st channel change */
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
ss->ss_ops->scan_start(ss, ic);
if (scan_restart(SCAN_PRIVATE(ss), duration))
ic->ic_flags |= IEEE80211_F_SCAN;
}
} else {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s scan already in progress\n", __func__,
ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
}
IEEE80211_UNLOCK(ic);
/* NB: racey, does it matter? */
return (ic->ic_flags & IEEE80211_F_SCAN);
}
/*
* Check the scan cache for an ap/channel to use; if that
* fails then kick off a new scan.
*/
int
ieee80211_check_scan(struct ieee80211com *ic, int flags, u_int duration,
u_int nssid, const struct ieee80211_scan_ssid ssids[])
{
struct ieee80211_scan_state *ss = ic->ic_scan;
int checkscanlist = 0;
/*
* Check if there's a list of scan candidates already.
* XXX want more than the ap we're currently associated with
*/
IEEE80211_LOCK(ic);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s scan, duration %u, desired mode %s, %s%s%s%s\n"
, __func__
, flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
, duration
, ieee80211_phymode_name[ic->ic_des_mode]
, flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
, flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
, flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
, flags & IEEE80211_SCAN_ONCE ? ", once" : ""
);
if (ss->ss_ops != NULL) {
/* XXX verify ss_ops matches ic->ic_opmode */
if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
/*
* Update the ssid list and mark flags so if
* we call start_scan it doesn't duplicate work.
*/
copy_ssid(ic, ss, nssid, ssids);
flags |= IEEE80211_SCAN_NOSSID;
}
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
time_before(ticks, ic->ic_lastscan + ic->ic_scanvalid)) {
/*
* We're not currently scanning and the cache is
* deemed hot enough to consult. Lock out others
* by marking IEEE80211_F_SCAN while we decide if
* something is already in the scan cache we can
* use. Also discard any frames that might come
* in while temporarily marked as scanning.
*/
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
ic->ic_flags |= IEEE80211_F_SCAN;
checkscanlist = 1;
}
}
IEEE80211_UNLOCK(ic);
if (checkscanlist) {
const struct ieee80211_scanner *scan;
scan = ieee80211_scanner_get(ic->ic_opmode);
if (scan == NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: no scanner support for mode %u\n",
__func__, ic->ic_opmode);
/* XXX stat */
return 0;
}
if (scan == ss->ss_ops && ss->ss_ops->scan_end(ss, ic)) {
/* found an ap, just clear the flag */
ic->ic_flags &= ~IEEE80211_F_SCAN;
return 1;
}
/* no ap, clear the flag before starting a scan */
ic->ic_flags &= ~IEEE80211_F_SCAN;
}
return ieee80211_start_scan(ic, flags, duration, nssid, ssids);
}
/*
* Restart a previous scan. If the previous scan completed
* then we start again using the existing channel list.
*/
int
ieee80211_bg_scan(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
IEEE80211_LOCK(ic);
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
u_int duration;
/*
* Go off-channel for a fixed interval that is large
* enough to catch most ap's but short enough that
* we can return on-channel before our listen interval
* expires.
*/
duration = IEEE80211_SCAN_OFFCHANNEL;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s scan, ticks %u duration %lu\n", __func__,
ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
ticks, duration);
if (ss->ss_ops != NULL) {
ss->ss_ic = ic;
/*
* A background scan does not select a new sta; it
* just refreshes the scan cache. Also, indicate
* the scan logic should follow the beacon schedule:
* we go off-channel and scan for a while, then
* return to the bss channel to receive a beacon,
* then go off-channel again. All during this time
* we notify the ap we're in power save mode. When
* the scan is complete we leave power save mode.
* If any beacon indicates there are frames pending
* for us then we drop out of power save mode
* (and background scan) automatically by way of the
* usual sta power save logic.
*/
ss->ss_flags |= IEEE80211_SCAN_NOPICK
| IEEE80211_SCAN_BGSCAN;
/* if previous scan completed, restart */
if (ss->ss_next >= ss->ss_last) {
ss->ss_next = 0;
if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
ic->ic_stats.is_scan_active++;
else
ic->ic_stats.is_scan_passive++;
ss->ss_ops->scan_restart(ss, ic);
}
/* NB: flush frames rx'd before 1st channel change */
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
ss->ss_maxdwell = duration;
if (scan_restart(SCAN_PRIVATE(ss), duration)) {
ic->ic_flags |= IEEE80211_F_SCAN;
ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
}
} else {
/* XXX msg+stat */
}
} else {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s scan already in progress\n", __func__,
ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
}
IEEE80211_UNLOCK(ic);
/* NB: racey, does it matter? */
return (ic->ic_flags & IEEE80211_F_SCAN);
}
/*
* Cancel any scan currently going on.
*/
void
ieee80211_cancel_scan(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
IEEE80211_LOCK(ic);
if ((ic->ic_flags & IEEE80211_F_SCAN) &&
(SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: cancel %s scan\n", __func__,
ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
"active" : "passive");
/* clear bg scan NOPICK and mark cancel request */
ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
/* force it to fire asap */
callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
0, scan_next, ss);
}
IEEE80211_UNLOCK(ic);
}
/*
* Public access to scan_next for drivers that manage
* scanning themselves (e.g. for firmware-based devices).
*/
void
ieee80211_scan_next(struct ieee80211com *ic)
{
/*
* XXX: We might need/want to decouple context here by either:
* callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
* or using a taskqueue. Let's see what kind of problems direct
* dispatch has for now.
*/
scan_next(ic->ic_scan);
}
/*
* Scan curchan. If this is an active scan and the channel
* is not marked passive then send probe request frame(s).
* Arrange for the channel change after maxdwell ticks.
*/
static void
scan_curchan(struct ieee80211com *ic, unsigned long maxdwell)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if ((ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
(ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) {
struct ifnet *ifp = ic->ic_ifp;
int i;
/*
* Send a broadcast probe request followed by
* any specified directed probe requests.
* XXX suppress broadcast probe req?
* XXX remove dependence on ic/ic->ic_bss
* XXX move to policy code?
*/
ieee80211_send_probereq(ic->ic_bss,
ic->ic_myaddr, ifp->if_broadcastaddr,
ifp->if_broadcastaddr,
"", 0,
ic->ic_opt_ie, ic->ic_opt_ie_len);
for (i = 0; i < ss->ss_nssid; i++)
ieee80211_send_probereq(ic->ic_bss,
ic->ic_myaddr, ifp->if_broadcastaddr,
ifp->if_broadcastaddr,
ss->ss_ssid[i].ssid,
ss->ss_ssid[i].len,
ic->ic_opt_ie, ic->ic_opt_ie_len);
}
callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
maxdwell, scan_next, ss);
}
/*
* Handle mindwell requirements completed; initiate a channel
* change to the next channel asap.
*/
static void
scan_mindwell(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
}
/*
* Switch to the next channel marked for scanning.
*/
static void
scan_next(void *arg)
{
#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_START | ISCAN_DISCARD)
struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
struct ieee80211com *ic = ss->ss_ic;
struct ieee80211_channel *chan;
unsigned long maxdwell, scanend;
int scanning, scandone;
IEEE80211_LOCK(ic);
scanning = (ic->ic_flags & IEEE80211_F_SCAN) != 0;
IEEE80211_UNLOCK(ic);
if (!scanning) /* canceled */
return;
again:
scandone = (ss->ss_next >= ss->ss_last) ||
(SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
scanend = SCAN_PRIVATE(ss)->ss_scanend;
if (!scandone &&
(ss->ss_flags & IEEE80211_SCAN_GOTPICK) == 0 &&
((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_START) ||
time_before(ticks + ss->ss_mindwell, scanend))) {
chan = ss->ss_chans[ss->ss_next++];
/*
* Watch for truncation due to the scan end time.
*/
if (time_after(ticks + ss->ss_maxdwell, scanend))
maxdwell = scanend - ticks;
else
maxdwell = ss->ss_maxdwell;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: chan %3d%c -> %3d%c [%s, dwell min %lu max %lu]\n",
__func__,
ieee80211_chan2ieee(ic, ic->ic_curchan),
channel_type(ic->ic_curchan),
ieee80211_chan2ieee(ic, chan), channel_type(chan),
(ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
(chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ?
"active" : "passive",
ss->ss_mindwell, maxdwell);
/*
* Potentially change channel and phy mode.
*/
change_channel(ic, chan);
/*
* Scan curchan. Drivers for "intelligent hardware"
* override ic_scan_curchan to tell the device to do
* the work. Otherwise we manage the work outselves;
* sending a probe request (as needed), and arming the
* timeout to switch channels after maxdwell ticks.
*/
ic->ic_scan_curchan(ic, maxdwell);
SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
/* clear mindwell lock and initial channel change flush */
SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
} else {
ic->ic_scan_end(ic); /* notify driver */
/*
* Record scan complete time. Note that we also do
* this when canceled so any background scan will
* not be restarted for a while.
*/
if (scandone)
ic->ic_lastscan = ticks;
/* return to the bss channel */
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
ic->ic_curchan != ic->ic_bsschan)
change_channel(ic, ic->ic_bsschan);
/* clear internal flags and any indication of a pick */
SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
/*
* If not canceled and scan completed, do post-processing.
* If the callback function returns 0, then it wants to
* continue/restart scanning. Unfortunately we needed to
* notify the driver to end the scan above to avoid having
* rx frames alter the scan candidate list.
*/
if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 &&
!ss->ss_ops->scan_end(ss, ic) &&
(ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
time_before(ticks + ss->ss_mindwell, scanend)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: done, restart "
"[ticks %u, dwell min %lu scanend %lu]\n",
__func__,
ticks, ss->ss_mindwell, scanend);
ss->ss_next = 0; /* reset to begining */
if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
ic->ic_stats.is_scan_active++;
else
ic->ic_stats.is_scan_passive++;
ic->ic_scan_start(ic); /* notify driver */
goto again;
} else {
/* past here, scandone is ``true'' if not in bg mode */
if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
scandone = 1;
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: %s, "
"[ticks %u, dwell min %lu scanend %lu]\n",
__func__, scandone ? "done" : "stopped",
ticks, ss->ss_mindwell, scanend);
/*
* Clear the SCAN bit first in case frames are
* pending on the station power save queue. If
* we defer this then the dispatch of the frames
* may generate a request to cancel scanning.
*/
ic->ic_flags &= ~IEEE80211_F_SCAN;
/*
* Drop out of power save mode when a scan has
* completed. If this scan was prematurely terminated
* because it is a background scan then don't notify
* the ap; we'll either return to scanning after we
* receive the beacon frame or we'll drop out of power
* save mode because the beacon indicates we have frames
* waiting for us.
*/
if (scandone) {
ieee80211_sta_pwrsave(ic, 0);
if (ss->ss_next >= ss->ss_last) {
ieee80211_notify_scan_done(ic);
ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
}
}
SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
ss->ss_flags &=
~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
}
}
#undef ISCAN_REP
}
#ifdef IEEE80211_DEBUG
static void
dump_probe_beacon(uint8_t subtype, int isnew,
const uint8_t mac[IEEE80211_ADDR_LEN],
const struct ieee80211_scanparams *sp)
{
printf("[%s] %s%s on chan %u (bss chan %u) ",
ether_sprintf(mac), isnew ? "new " : "",
ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
sp->chan, sp->bchan);
ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]);
printf("\n");
if (isnew) {
printf("[%s] caps 0x%x bintval %u erp 0x%x",
ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp);
if (sp->country != NULL) {
#ifdef __FreeBSD__
printf(" country info %*D",
sp->country[1], sp->country+2, " ");
#else
int i;
printf(" country info");
for (i = 0; i < sp->country[1]; i++)
printf(" %02x", sp->country[i+2]);
#endif
}
printf("\n");
}
}
#endif /* IEEE80211_DEBUG */
/*
* Process a beacon or probe response frame.
*/
void
ieee80211_add_scan(struct ieee80211com *ic,
const struct ieee80211_scanparams *sp,
const struct ieee80211_frame *wh,
int subtype, int rssi, int noise, int rstamp)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
/*
* Frames received during startup are discarded to avoid
* using scan state setup on the initial entry to the timer
* callback. This can occur because the device may enable
* rx prior to our doing the initial channel change in the
* timer routine (we defer the channel change to the timer
* code to simplify locking on linux).
*/
if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD)
return;
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN))
dump_probe_beacon(subtype, 1, wh->i_addr2, sp);
#endif
if (ss->ss_ops != NULL &&
ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise, rstamp)) {
/*
* If we've reached the min dwell time terminate
* the timer so we'll switch to the next channel.
*/
if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 &&
time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: chan %3d%c min dwell met (%u > %lu)\n",
__func__,
ieee80211_chan2ieee(ic, ic->ic_curchan),
channel_type(ic->ic_curchan),
ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
/*
* XXX
* We want to just kick the timer and still
* process frames until it fires but linux
* will livelock unless we discard frames.
*/
#if 0
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL;
#else
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
#endif
/*
* NB: trigger at next clock tick or wait for the
* hardware
*/
ic->ic_scan_mindwell(ic);
}
}
}
/*
* Timeout/age scan cache entries; called from sta timeout
* timer (XXX should be self-contained).
*/
void
ieee80211_scan_timeout(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss->ss_ops != NULL)
ss->ss_ops->scan_age(ss);
}
/*
* Mark a scan cache entry after a successful associate.
*/
void
ieee80211_scan_assoc_success(struct ieee80211com *ic, const uint8_t mac[])
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss->ss_ops != NULL) {
IEEE80211_NOTE_MAC(ic, IEEE80211_MSG_SCAN,
mac, "%s", __func__);
ss->ss_ops->scan_assoc_success(ss, mac);
}
}
/*
* Demerit a scan cache entry after failing to associate.
*/
void
ieee80211_scan_assoc_fail(struct ieee80211com *ic,
const uint8_t mac[], int reason)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss->ss_ops != NULL) {
IEEE80211_NOTE_MAC(ic, IEEE80211_MSG_SCAN, mac,
"%s: reason %u", __func__, reason);
ss->ss_ops->scan_assoc_fail(ss, mac, reason);
}
}
/*
* Iterate over the contents of the scan cache.
*/
void
ieee80211_scan_iterate(struct ieee80211com *ic,
ieee80211_scan_iter_func *f, void *arg)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss->ss_ops != NULL)
ss->ss_ops->scan_iterate(ss, f, arg);
}
/*
* Flush the contents of the scan cache.
*/
void
ieee80211_scan_flush(struct ieee80211com *ic)
{
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss->ss_ops != NULL) {
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s\n", __func__);
ss->ss_ops->scan_flush(ss);
}
}

View File

@ -0,0 +1,218 @@
/*-
* Copyright (c) 2005-2007 Sam Leffler, Errno Consulting
* 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_SCAN_H_
#define _NET80211_IEEE80211_SCAN_H_
#define IEEE80211_SCAN_MAX IEEE80211_CHAN_MAX
struct ieee80211_scanner;
struct ieee80211_scan_ssid {
int len; /* length in bytes */
uint8_t ssid[IEEE80211_NWID_LEN]; /* ssid contents */
};
#define IEEE80211_SCAN_MAX_SSID 1
struct ieee80211_scan_state {
struct ieee80211com *ss_ic;
const struct ieee80211_scanner *ss_ops; /* policy hookup, see below */
void *ss_priv; /* scanner private state */
uint16_t ss_flags;
#define IEEE80211_SCAN_NOPICK 0x0001 /* scan only, no selection */
#define IEEE80211_SCAN_ACTIVE 0x0002 /* active scan (probe req) */
#define IEEE80211_SCAN_PICK1ST 0x0004 /* ``hey sailor'' mode */
#define IEEE80211_SCAN_BGSCAN 0x0008 /* bg scan, exit ps at end */
#define IEEE80211_SCAN_ONCE 0x0010 /* do one complete pass */
#define IEEE80211_SCAN_GOTPICK 0x1000 /* got candidate, can stop */
uint8_t ss_nssid; /* # ssid's to probe/match */
struct ieee80211_scan_ssid ss_ssid[IEEE80211_SCAN_MAX_SSID];
/* ssid's to probe/match */
/* ordered channel set */
struct ieee80211_channel *ss_chans[IEEE80211_SCAN_MAX];
uint16_t ss_next; /* ix of next chan to scan */
uint16_t ss_last; /* ix+1 of last chan to scan */
unsigned long ss_mindwell; /* min dwell on channel */
unsigned long ss_maxdwell; /* max dwell on channel */
};
/*
* The upper 16 bits of the flags word is used to communicate
* information to the scanning code that is NOT recorded in
* ss_flags. It might be better to split this stuff out into
* a separate variable to avoid confusion.
*/
#define IEEE80211_SCAN_FLUSH 0x10000 /* flush candidate table */
#define IEEE80211_SCAN_NOSSID 0x20000 /* don't update ssid list */
struct ieee80211com;
void ieee80211_scan_attach(struct ieee80211com *);
void ieee80211_scan_detach(struct ieee80211com *);
void ieee80211_scan_dump_channels(const struct ieee80211_scan_state *);
int ieee80211_scan_update(struct ieee80211com *);
#define IEEE80211_SCAN_FOREVER 0x7fffffff
int ieee80211_start_scan(struct ieee80211com *, int flags, u_int duration,
u_int nssid, const struct ieee80211_scan_ssid ssids[]);
int ieee80211_check_scan(struct ieee80211com *, int flags, u_int duration,
u_int nssid, const struct ieee80211_scan_ssid ssids[]);
int ieee80211_bg_scan(struct ieee80211com *);
void ieee80211_cancel_scan(struct ieee80211com *);
void ieee80211_scan_next(struct ieee80211com *);
struct ieee80211_scanparams;
void ieee80211_add_scan(struct ieee80211com *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
int subtype, int rssi, int noise, int rstamp);
void ieee80211_scan_timeout(struct ieee80211com *);
void ieee80211_scan_assoc_success(struct ieee80211com *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
enum {
IEEE80211_SCAN_FAIL_TIMEOUT = 1, /* no response to mgmt frame */
IEEE80211_SCAN_FAIL_STATUS = 2 /* negative response to " " */
};
void ieee80211_scan_assoc_fail(struct ieee80211com *,
const uint8_t mac[IEEE80211_ADDR_LEN], int reason);
void ieee80211_scan_flush(struct ieee80211com *);
struct ieee80211_scan_entry;
typedef void ieee80211_scan_iter_func(void *,
const struct ieee80211_scan_entry *);
void ieee80211_scan_iterate(struct ieee80211com *,
ieee80211_scan_iter_func, void *);
/*
* Parameters supplied when adding/updating an entry in a
* scan cache. Pointer variables should be set to NULL
* if no data is available. Pointer references can be to
* local data; any information that is saved will be copied.
* All multi-byte values must be in host byte order.
*/
struct ieee80211_scanparams {
uint16_t capinfo; /* 802.11 capabilities */
uint16_t fhdwell; /* FHSS dwell interval */
uint8_t chan; /* */
uint8_t bchan;
uint8_t fhindex;
uint8_t erp;
uint16_t bintval;
uint8_t timoff;
uint8_t *tim;
uint8_t *tstamp;
uint8_t *country;
uint8_t *ssid;
uint8_t *rates;
uint8_t *xrates;
uint8_t *doth;
uint8_t *wpa;
uint8_t *rsn;
uint8_t *wme;
uint8_t *htcap;
uint8_t *htinfo;
uint8_t *ath;
};
/*
* Scan cache entry format used when exporting data from a policy
* module; this data may be represented some other way internally.
*/
struct ieee80211_scan_entry {
uint8_t se_macaddr[IEEE80211_ADDR_LEN];
uint8_t se_bssid[IEEE80211_ADDR_LEN];
uint8_t se_ssid[2+IEEE80211_NWID_LEN];
uint8_t se_rates[2+IEEE80211_RATE_MAXSIZE];
uint8_t se_xrates[2+IEEE80211_RATE_MAXSIZE];
uint32_t se_rstamp; /* recv timestamp */
union {
uint8_t data[8];
uint64_t tsf;
} se_tstamp; /* from last rcv'd beacon */
uint16_t se_intval; /* beacon interval (host byte order) */
uint16_t se_capinfo; /* capabilities (host byte order) */
struct ieee80211_channel *se_chan;/* channel where sta found */
uint16_t se_timoff; /* byte offset to TIM ie */
uint16_t se_fhdwell; /* FH only (host byte order) */
uint8_t se_fhindex; /* FH only */
uint8_t se_erp; /* ERP from beacon/probe resp */
int8_t se_rssi; /* avg'd recv ssi */
int8_t se_noise; /* noise floor */
uint8_t se_dtimperiod; /* DTIM period */
uint8_t *se_wpa_ie; /* captured WPA ie */
uint8_t *se_rsn_ie; /* captured RSN ie */
uint8_t *se_wme_ie; /* captured WME ie */
uint8_t *se_htcap_ie; /* captured HTP cap ie */
uint8_t *se_htinfo_ie; /* captured HTP info ie */
uint8_t *se_ath_ie; /* captured Atheros ie */
u_int se_age; /* age of entry (0 on create) */
};
MALLOC_DECLARE(M_80211_SCAN);
/*
* Template for an in-kernel scan policy module.
* Modules register with the scanning code and are
* typically loaded as needed.
*/
struct ieee80211_scanner {
const char *scan_name; /* printable name */
int (*scan_attach)(struct ieee80211_scan_state *);
int (*scan_detach)(struct ieee80211_scan_state *);
int (*scan_start)(struct ieee80211_scan_state *,
struct ieee80211com *);
int (*scan_restart)(struct ieee80211_scan_state *,
struct ieee80211com *);
int (*scan_cancel)(struct ieee80211_scan_state *,
struct ieee80211com *);
int (*scan_end)(struct ieee80211_scan_state *,
struct ieee80211com *);
int (*scan_flush)(struct ieee80211_scan_state *);
/* add an entry to the cache */
int (*scan_add)(struct ieee80211_scan_state *,
const struct ieee80211_scanparams *,
const struct ieee80211_frame *,
int subtype, int rssi, int noise, int rstamp);
/* age and/or purge entries in the cache */
void (*scan_age)(struct ieee80211_scan_state *);
/* note that association failed for an entry */
void (*scan_assoc_fail)(struct ieee80211_scan_state *,
const uint8_t macaddr[IEEE80211_ADDR_LEN],
int reason);
/* note that association succeed for an entry */
void (*scan_assoc_success)(struct ieee80211_scan_state *,
const uint8_t macaddr[IEEE80211_ADDR_LEN]);
/* iterate over entries in the scan cache */
void (*scan_iterate)(struct ieee80211_scan_state *,
ieee80211_scan_iter_func *, void *);
};
void ieee80211_scanner_register(enum ieee80211_opmode,
const struct ieee80211_scanner *);
void ieee80211_scanner_unregister(enum ieee80211_opmode,
const struct ieee80211_scanner *);
void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode);
#endif /* _NET80211_IEEE80211_SCAN_H_ */

View File

@ -0,0 +1,407 @@
/*-
* Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
* 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>
__FBSDID("$FreeBSD$");
/*
* IEEE 802.11 ap scanning support.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/ethernet.h>
#include <net80211/ieee80211_var.h>
#include <net/bpf.h>
struct ap_state {
int as_maxrssi[IEEE80211_CHAN_MAX];
};
static int ap_flush(struct ieee80211_scan_state *);
/* number of references from net80211 layer */
static int nrefs = 0;
/*
* Attach prior to any scanning work.
*/
static int
ap_attach(struct ieee80211_scan_state *ss)
{
struct ap_state *as;
MALLOC(as, struct ap_state *, sizeof(struct ap_state),
M_80211_SCAN, M_NOWAIT);
ss->ss_priv = as;
ap_flush(ss);
nrefs++; /* NB: we assume caller locking */
return 1;
}
/*
* Cleanup any private state.
*/
static int
ap_detach(struct ieee80211_scan_state *ss)
{
struct ap_state *as = ss->ss_priv;
if (as != NULL) {
KASSERT(nrefs > 0, ("imbalanced attach/detach"));
nrefs--; /* NB: we assume caller locking */
FREE(as, M_80211_SCAN);
}
return 1;
}
/*
* Flush all per-scan state.
*/
static int
ap_flush(struct ieee80211_scan_state *ss)
{
struct ap_state *as = ss->ss_priv;
memset(as->as_maxrssi, 0, sizeof(as->as_maxrssi));
ss->ss_last = 0; /* insure no channel will be picked */
return 0;
}
static int
find11gchannel(struct ieee80211com *ic, int i, int freq)
{
const struct ieee80211_channel *c;
int j;
/*
* The normal ordering in the channel list is b channel
* immediately followed by g so optimize the search for
* this. We'll still do a full search just in case.
*/
for (j = i+1; j < ic->ic_nchans; j++) {
c = &ic->ic_channels[j];
if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
return 1;
}
for (j = 0; j < i; j++) {
c = &ic->ic_channels[j];
if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
return 1;
}
return 0;
}
/*
* Start an ap scan by populating the channel list.
*/
static int
ap_start(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
{
struct ieee80211_channel *c;
int i;
ss->ss_last = 0;
if (ic->ic_des_mode == IEEE80211_MODE_AUTO) {
for (i = 0; i < ic->ic_nchans; i++) {
c = &ic->ic_channels[i];
if (IEEE80211_IS_CHAN_TURBO(c)) {
#ifdef IEEE80211_F_XR
/* XR is not supported on turbo channels */
if (ic->ic_flags & IEEE80211_F_XR)
continue;
#endif
/* dynamic channels are scanned in base mode */
if (!IEEE80211_IS_CHAN_ST(c))
continue;
} else if (IEEE80211_IS_CHAN_HT(c)) {
/* HT channels are scanned in legacy */
continue;
} else {
/*
* Use any 11g channel instead of 11b one.
*/
if (IEEE80211_IS_CHAN_B(c) &&
find11gchannel(ic, i, c->ic_freq))
continue;
}
if (ss->ss_last >= IEEE80211_SCAN_MAX)
break;
ss->ss_chans[ss->ss_last++] = c;
}
} else {
static const u_int chanflags[IEEE80211_MODE_MAX] = {
0, /* IEEE80211_MODE_AUTO */
IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
IEEE80211_CHAN_G, /* IEEE80211_MODE_11G */
IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
IEEE80211_CHAN_108A, /* IEEE80211_MODE_TURBO_A */
IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */
IEEE80211_CHAN_ST, /* IEEE80211_MODE_STURBO_A */
IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA */
IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG */
};
u_int modeflags;
modeflags = chanflags[ic->ic_des_mode];
if ((ic->ic_flags & IEEE80211_F_TURBOP) &&
modeflags != IEEE80211_CHAN_ST) {
if (ic->ic_des_mode == IEEE80211_MODE_11G)
modeflags = IEEE80211_CHAN_108G;
else
modeflags = IEEE80211_CHAN_108A;
}
for (i = 0; i < ic->ic_nchans; i++) {
c = &ic->ic_channels[i];
if ((c->ic_flags & modeflags) != modeflags)
continue;
#ifdef IEEE80211_F_XR
/* XR is not supported on turbo channels */
if (IEEE80211_IS_CHAN_TURBO(c) &&
(ic->ic_flags & IEEE80211_F_XR))
continue;
#endif
if (ss->ss_last >= IEEE80211_SCAN_MAX)
break;
/*
* Do not select static turbo channels if
* the mode is not static turbo.
*/
if (IEEE80211_IS_CHAN_STURBO(c) &&
ic->ic_des_mode != IEEE80211_MODE_STURBO_A)
continue;
ss->ss_chans[ss->ss_last++] = c;
}
}
ss->ss_next = 0;
/* XXX tunables */
ss->ss_mindwell = msecs_to_ticks(200); /* 200ms */
ss->ss_maxdwell = msecs_to_ticks(300); /* 300ms */
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(ic)) {
if_printf(ic->ic_ifp, "scan set ");
ieee80211_scan_dump_channels(ss);
printf(" dwell min %ld max %ld\n",
ss->ss_mindwell, ss->ss_maxdwell);
}
#endif /* IEEE80211_DEBUG */
return 0;
}
/*
* Restart a bg scan.
*/
static int
ap_restart(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
{
return 0;
}
/*
* Cancel an ongoing scan.
*/
static int
ap_cancel(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
{
return 0;
}
/*
* Record max rssi on channel.
*/
static int
ap_add(struct ieee80211_scan_state *ss,
const struct ieee80211_scanparams *sp,
const struct ieee80211_frame *wh,
int subtype, int rssi, int noise, int rstamp)
{
struct ap_state *as = ss->ss_priv;
struct ieee80211com *ic = ss->ss_ic;
int chan;
chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
/* XXX better quantification of channel use? */
/* XXX count bss's? */
if (rssi > as->as_maxrssi[chan])
as->as_maxrssi[chan] = rssi;
/* XXX interference, turbo requirements */
return 1;
}
/*
* Pick a quiet channel to use for ap operation.
*/
static int
ap_end(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
{
struct ap_state *as = ss->ss_priv;
int i, chan, bestchan, bestchanix;
KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
("wrong opmode %u", ic->ic_opmode));
/* XXX select channel more intelligently, e.g. channel spread, power */
bestchan = -1;
bestchanix = 0; /* NB: silence compiler */
/* NB: use scan list order to preserve channel preference */
for (i = 0; i < ss->ss_last; i++) {
/*
* If the channel is unoccupied the max rssi
* should be zero; just take it. Otherwise
* track the channel with the lowest rssi and
* use that when all channels appear occupied.
*/
/* XXX channel have interference? */
chan = ieee80211_chan2ieee(ic, ss->ss_chans[i]);
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: channel %u rssi %d bestchan %d bestchan rssi %d\n",
__func__, chan, as->as_maxrssi[chan],
bestchan, bestchan != -1 ? as->as_maxrssi[bestchan] : 0);
if (as->as_maxrssi[chan] == 0) {
bestchan = chan;
bestchanix = i;
/* XXX use other considerations */
break;
}
if (bestchan == -1 ||
as->as_maxrssi[chan] < as->as_maxrssi[bestchan])
bestchan = chan;
}
if (bestchan == -1) {
/* no suitable channel, should not happen */
IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
"%s: no suitable channel! (should not happen)\n", __func__);
/* XXX print something? */
return 0; /* restart scan */
} else {
struct ieee80211_channel *c;
/* XXX notify all vap's? */
/*
* If this is a dynamic turbo frequency,
* start with normal mode first.
*/
c = ss->ss_chans[bestchanix];
if (IEEE80211_IS_CHAN_TURBO(c) &&
!IEEE80211_IS_CHAN_STURBO(c)) {
c = ieee80211_find_channel(ic, c->ic_freq,
c->ic_flags & ~IEEE80211_CHAN_TURBO);
if (c == NULL) {
/* should never happen ?? */
return 0;
}
}
ieee80211_create_ibss(ic, c);
return 1;
}
}
static void
ap_age(struct ieee80211_scan_state *ss)
{
/* XXX is there anything meaningful to do? */
}
static void
ap_iterate(struct ieee80211_scan_state *ss,
ieee80211_scan_iter_func *f, void *arg)
{
/* NB: nothing meaningful we can do */
}
static void
ap_assoc_success(struct ieee80211_scan_state *ss,
const uint8_t macaddr[IEEE80211_ADDR_LEN])
{
/* should not be called */
}
static void
ap_assoc_fail(struct ieee80211_scan_state *ss,
const uint8_t macaddr[IEEE80211_ADDR_LEN], int reason)
{
/* should not be called */
}
static const struct ieee80211_scanner ap_default = {
.scan_name = "default",
.scan_attach = ap_attach,
.scan_detach = ap_detach,
.scan_start = ap_start,
.scan_restart = ap_restart,
.scan_cancel = ap_cancel,
.scan_end = ap_end,
.scan_flush = ap_flush,
.scan_add = ap_add,
.scan_age = ap_age,
.scan_iterate = ap_iterate,
.scan_assoc_success = ap_assoc_success,
.scan_assoc_fail = ap_assoc_fail,
};
/*
* Module glue.
*/
static int
wlan_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
ieee80211_scanner_register(IEEE80211_M_HOSTAP, &ap_default);
return 0;
case MOD_UNLOAD:
case MOD_QUIESCE:
if (nrefs) {
printf("wlan_scan_ap: still in use (%u dynamic refs)\n",
nrefs);
return EBUSY;
}
if (type == MOD_UNLOAD)
ieee80211_scanner_unregister_all(&ap_default);
return 0;
}
return EINVAL;
}
static moduledata_t wlan_mod = {
"wlan_scan_ap",
wlan_modevent,
0
};
DECLARE_MODULE(wlan_scan_ap, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(wlan_scan_ap, 1);
MODULE_DEPEND(wlan_scan_ap, wlan, 1, 1, 1);

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,9 @@
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h> /* for ieee80211_stats */
#include <net80211/ieee80211_node.h>
#include <net80211/ieee80211_power.h>
#include <net80211/ieee80211_proto.h>
#include <net80211/ieee80211_scan.h>
#define IEEE80211_TXPOWER_MAX 100 /* .5 dbM (XXX units?) */
#define IEEE80211_TXPOWER_MIN 0 /* kill radio */
@ -61,6 +63,15 @@
#define IEEE80211_BMISS_MAX 2 /* maximum consecutive bmiss allowed */
#define IEEE80211_HWBMISS_DEFAULT 7 /* h/w bmiss threshold (beacons) */
#define IEEE80211_BGSCAN_INTVAL_MIN 15 /* min bg scan intvl (secs) */
#define IEEE80211_BGSCAN_INTVAL_DEFAULT (5*60) /* default bg scan intvl */
#define IEEE80211_BGSCAN_IDLE_MIN 100 /* min idle time (ms) */
#define IEEE80211_BGSCAN_IDLE_DEFAULT 250 /* default idle time (ms) */
#define IEEE80211_SCAN_VALID_MIN 10 /* min scan valid time (secs) */
#define IEEE80211_SCAN_VALID_DEFAULT 60 /* default scan valid time */
#define IEEE80211_PS_SLEEP 0x1 /* STA is in power saving mode */
#define IEEE80211_PS_MAX_QUEUE 50 /* maximum saved packets */
@ -80,110 +91,132 @@ struct sysctl_ctx_list;
struct ieee80211com {
SLIST_ENTRY(ieee80211com) ic_next;
struct ifnet *ic_ifp; /* associated device */
ieee80211_com_lock_t ic_comlock; /* state update lock */
ieee80211_beacon_lock_t ic_beaconlock; /* beacon update lock */
struct ieee80211_stats ic_stats; /* statistics */
struct sysctl_ctx_list *ic_sysctl; /* dynamic sysctl context */
u_int32_t ic_debug; /* debug msg flags */
uint32_t ic_debug; /* debug msg flags */
int ic_vap; /* virtual AP index */
ieee80211_beacon_lock_t ic_beaconlock; /* beacon update lock */
int (*ic_reset)(struct ifnet *);
void (*ic_recv_mgmt)(struct ieee80211com *,
struct mbuf *, struct ieee80211_node *,
int, int, u_int32_t);
int (*ic_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);
int (*ic_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*ic_newassoc)(struct ieee80211_node *, int);
void (*ic_updateslot)(struct ifnet *);
void (*ic_set_tim)(struct ieee80211_node *, int);
int (*ic_raw_xmit)(struct ieee80211_node *,
struct mbuf *,
const struct ieee80211_bpf_params *);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
u_int8_t ic_chan_avail[IEEE80211_CHAN_BYTES];
u_int8_t ic_chan_active[IEEE80211_CHAN_BYTES];
u_int8_t ic_chan_scan[IEEE80211_CHAN_BYTES];
struct ieee80211_node_table ic_scan; /* scan candidates */
struct ifqueue ic_mgtq;
u_int32_t ic_flags; /* state flags */
u_int32_t ic_flags_ext; /* extended state flags */
u_int32_t ic_caps; /* capabilities */
u_int8_t ic_modecaps[2]; /* set of mode capabilities */
u_int16_t ic_curmode; /* current mode */
int ic_headroom; /* driver tx headroom needs */
enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */
enum ieee80211_opmode ic_opmode; /* operation mode */
enum ieee80211_state ic_state; /* 802.11 state */
enum ieee80211_protmode ic_protmode; /* 802.11g protection mode */
enum ieee80211_roamingmode ic_roaming; /* roaming mode */
struct ieee80211_node_table ic_sta; /* stations/neighbors */
u_int32_t *ic_aid_bitmap; /* association id map */
u_int16_t ic_max_aid;
u_int16_t ic_sta_assoc; /* stations associated */
u_int16_t ic_ps_sta; /* stations in power save */
u_int16_t ic_ps_pending; /* ps sta's w/ pending frames */
u_int8_t *ic_tim_bitmap; /* power-save stations w/ data*/
u_int16_t ic_tim_len; /* ic_tim_bitmap size (bytes) */
u_int8_t ic_dtim_period; /* DTIM period */
u_int8_t ic_dtim_count; /* DTIM count for last bcn */
struct ifmedia ic_media; /* interface media config */
uint8_t ic_myaddr[IEEE80211_ADDR_LEN];
uint32_t ic_flags; /* state flags */
uint32_t ic_flags_ext; /* extended state flags */
uint32_t ic_caps; /* capabilities */
uint8_t ic_modecaps[2]; /* set of mode capabilities */
uint16_t ic_curmode; /* current mode */
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
uint16_t ic_bintval; /* beacon interval */
uint16_t ic_lintval; /* listen interval */
uint16_t ic_holdover; /* PM hold over duration */
uint16_t ic_txpowlimit; /* global tx power limit */
uint32_t ic_htcaps; /* HT capabilities */
int ic_ampdu_rxmax; /* A-MPDU rx limit (bytes) */
int ic_ampdu_density;/* A-MPDU density */
int ic_ampdu_limit; /* A-MPDU tx limit (bytes) */
int ic_amsdu_limit; /* A-MSDU tx limit (bytes) */
/*
* Channel state:
*
* ic_channels is the set of available channels for the device;
* it is setup by the driver
* ic_nchans is the number of valid entries in ic_channels
* ic_chan_avail is a bit vector of these channels used to check
* whether a channel is available w/o searching the channel table.
* ic_chan_active is a (potentially) constrained subset of
* ic_chan_avail that reflects any mode setting or user-specified
* limit on the set of channels to use/scan
* ic_curchan is the current channel the device is set to; it may
* be different from ic_bsschan when we are off-channel scanning
* or otherwise doing background work
* ic_bsschan is the channel selected for operation; it may
* be undefined (IEEE80211_CHAN_ANYC)
* ic_prevchan is a cached ``previous channel'' used to optimize
* lookups when switching back+forth between two channels
* (e.g. for dynamic turbo)
*/
int ic_nchans; /* # entries in ic_channels */
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
uint8_t ic_chan_avail[IEEE80211_CHAN_BYTES];
uint8_t ic_chan_active[IEEE80211_CHAN_BYTES];
uint8_t ic_chan_scan[IEEE80211_CHAN_BYTES];
struct ieee80211_channel *ic_curchan; /* current channel */
struct ieee80211_channel *ic_bsschan; /* bss channel */
struct ieee80211_channel *ic_prevchan; /* previous channel */
int ic_countrycode; /* ISO country code */
uint16_t ic_regdomain; /* regulatory domain */
uint8_t ic_location; /* unknown, indoor, outdoor */
struct ieee80211_scan_state *ic_scan; /* scan state */
enum ieee80211_roamingmode ic_roaming; /* roaming mode */
int ic_lastdata; /* time of last data frame */
int ic_lastscan; /* time last scan completed */
int ic_des_nssid; /* # desired ssids */
struct ieee80211_scan_ssid ic_des_ssid[1];/* desired ssid table */
uint8_t ic_des_bssid[IEEE80211_ADDR_LEN];
struct ieee80211_channel *ic_des_chan; /* desired channel */
int ic_des_mode; /* desired phymode */
u_int ic_bgscanidle; /* bg scan idle threshold */
u_int ic_bgscanintvl; /* bg scan min interval */
u_int ic_scanvalid; /* scan cache valid threshold */
struct ieee80211_roam ic_roam; /* sta-mode roaming state */
struct ieee80211_node_table ic_sta; /* stations/neighbors */
struct ieee80211_wme_state ic_wme; /* WME/WMM state */
const struct ieee80211_aclator *ic_acl; /* aclator glue */
void *ic_as; /* private aclator state */
enum ieee80211_protmode ic_protmode; /* 802.11g protection mode */
uint16_t ic_nonerpsta; /* # non-ERP stations */
uint16_t ic_longslotsta; /* # long slot time stations */
uint16_t ic_sta_assoc; /* stations associated */
struct ifqueue ic_mgtq;
enum ieee80211_state ic_state; /* 802.11 state */
struct callout ic_mgtsend; /* mgmt frame response timer */
uint32_t *ic_aid_bitmap; /* association id map */
uint16_t ic_max_aid;
uint16_t ic_ps_sta; /* stations in power save */
uint16_t ic_ps_pending; /* ps sta's w/ pending frames */
uint8_t *ic_tim_bitmap; /* power-save stations w/ data*/
uint16_t ic_tim_len; /* ic_tim_bitmap size (bytes) */
uint8_t ic_dtim_period; /* DTIM period */
uint8_t ic_dtim_count; /* DTIM count for last bcn */
struct bpf_if *ic_rawbpf; /* packet filter structure */
struct ieee80211_node *ic_bss; /* information for this node */
struct ieee80211_channel *ic_ibss_chan;
struct ieee80211_channel *ic_curchan; /* current channel */
int ic_fixed_rate; /* index to ic_sup_rates[] */
int ic_fixed_rate; /* 802.11 rate or -1 */
int ic_mcast_rate; /* rate for mcast frames */
u_int16_t ic_rtsthreshold;
u_int16_t ic_fragthreshold;
u_int8_t ic_bmissthreshold;
u_int8_t ic_bmiss_count; /* current beacon miss count */
uint16_t ic_rtsthreshold;
uint16_t ic_fragthreshold;
uint8_t ic_bmissthreshold;
uint8_t ic_bmiss_count; /* current beacon miss count */
int ic_bmiss_max; /* max bmiss before scan */
u_int16_t ic_swbmiss_count;/* beacons in last period */
u_int16_t ic_swbmiss_period;/* s/w bmiss period */
uint16_t ic_swbmiss_count;/* beacons in last period */
uint16_t ic_swbmiss_period;/* s/w bmiss period */
struct callout ic_swbmiss; /* s/w beacon miss timer */
struct ieee80211_node *(*ic_node_alloc)(struct ieee80211_node_table*);
void (*ic_node_free)(struct ieee80211_node *);
void (*ic_node_cleanup)(struct ieee80211_node *);
u_int8_t (*ic_node_getrssi)(const struct ieee80211_node*);
u_int16_t ic_lintval; /* listen interval */
u_int16_t ic_bintval; /* beacon interval */
u_int16_t ic_holdover; /* PM hold over duration */
u_int16_t ic_txmin; /* min tx retry count */
u_int16_t ic_txmax; /* max tx retry count */
u_int16_t ic_txlifetime; /* tx lifetime */
u_int16_t ic_txpowlimit; /* global tx power limit */
u_int16_t ic_nonerpsta; /* # non-ERP stations */
u_int16_t ic_longslotsta; /* # long slot time stations */
int ic_mgt_timer; /* mgmt timeout */
int ic_inact_timer; /* inactivity timer wait */
int ic_des_esslen;
u_int8_t ic_des_essid[IEEE80211_NWID_LEN];
struct ieee80211_channel *ic_des_chan; /* desired channel */
u_int8_t ic_des_bssid[IEEE80211_ADDR_LEN];
uint16_t ic_txmin; /* min tx retry count */
uint16_t ic_txmax; /* max tx retry count */
uint16_t ic_txlifetime; /* tx lifetime */
struct callout ic_inact; /* inactivity timer wait */
void *ic_opt_ie; /* user-specified IE's */
u_int16_t ic_opt_ie_len; /* length of ni_opt_ie */
/*
* Inactivity timer settings for nodes.
*/
uint16_t ic_opt_ie_len; /* length of ni_opt_ie */
int ic_inact_init; /* initial setting */
int ic_inact_auth; /* auth but not assoc setting */
int ic_inact_run; /* authorized setting */
int ic_inact_probe; /* inactive probe time */
/*
* WME/WMM state.
*/
struct ieee80211_wme_state ic_wme;
/*
* Cipher state/configuration.
*/
struct ieee80211_crypto_state ic_crypto;
#define ic_nw_keys ic_crypto.cs_nw_keys /* XXX compatibility */
#define ic_def_txkey ic_crypto.cs_def_txkey /* XXX compatibility */
/*
* 802.1x glue. When an authenticator attaches it
* fills in this section. We assume that when ic_ec
@ -192,13 +225,64 @@ struct ieee80211com {
const struct ieee80211_authenticator *ic_auth;
struct eapolcom *ic_ec;
/* send/recv 802.11 management frame */
int (*ic_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);
void (*ic_recv_mgmt)(struct ieee80211com *,
struct mbuf *, struct ieee80211_node *,
int, int, int, uint32_t);
/* send raw 802.11 frame */
int (*ic_raw_xmit)(struct ieee80211_node *,
struct mbuf *,
const struct ieee80211_bpf_params *);
/* reset device state after 802.11 parameter/state change */
int (*ic_reset)(struct ifnet *);
/* update device state for 802.11 slot time change */
void (*ic_updateslot)(struct ifnet *);
/* new station association callback/notification */
void (*ic_newassoc)(struct ieee80211_node *, int);
/* node state management */
struct ieee80211_node *(*ic_node_alloc)(struct ieee80211_node_table*);
void (*ic_node_free)(struct ieee80211_node *);
void (*ic_node_cleanup)(struct ieee80211_node *);
int8_t (*ic_node_getrssi)(const struct ieee80211_node*);
void (*ic_node_getsignal)(const struct ieee80211_node*,
int8_t *, int8_t *);
/* scanning support */
void (*ic_scan_start)(struct ieee80211com *);
void (*ic_scan_end)(struct ieee80211com *);
void (*ic_set_channel)(struct ieee80211com *);
void (*ic_scan_curchan)(struct ieee80211com *,
unsigned long);
void (*ic_scan_mindwell)(struct ieee80211com *);
/* per-vap eventually... */
int (*ic_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*ic_set_tim)(struct ieee80211_node *, int);
/*
* Access control glue. When a control agent attaches
* it fills in this section. We assume that when ic_ac
* is setup that the methods are safe to call.
* 802.11n ADDBA support. A simple/generic implementation
* of A-MPDU tx aggregation is provided; the driver may
* override these methods to provide their own support.
* A-MPDU rx re-ordering happens automatically if the
* driver passes out-of-order frames to ieee80211_input
* from an assocated HT station.
*/
const struct ieee80211_aclator *ic_acl;
void *ic_as;
void (*ic_recv_action)(struct ieee80211_node *,
const uint8_t *frm, const uint8_t *efrm);
int (*ic_send_action)(struct ieee80211_node *,
int category, int action,
uint16_t args[4]);
/* start/stop doing A-MPDU tx aggregation for a station */
int (*ic_addba_request)(struct ieee80211_node *,
struct ieee80211_tx_ampdu *,
int dialogtoken, int baparamset,
int batimeout);
int (*ic_addba_response)(struct ieee80211_node *,
struct ieee80211_tx_ampdu *,
int status, int baparamset, int batimeout);
void (*ic_addba_stop)(struct ieee80211_node *,
struct ieee80211_tx_ampdu *);
};
#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0)
@ -206,9 +290,10 @@ struct ieee80211com {
/* ic_flags */
/* NB: bits 0x4c available */
#define IEEE80211_F_FF 0x00000001 /* CONF: ATH FF enabled */
#define IEEE80211_F_TURBOP 0x00000002 /* CONF: ATH Turbo enabled*/
#define IEEE80211_F_BURST 0x00000004 /* CONF: bursting enabled */
#define IEEE80211_F_TURBOP 0x00000001 /* CONF: ATH Turbo enabled*/
#define IEEE80211_F_COMP 0x00000002 /* CONF: ATH comp enabled */
#define IEEE80211_F_FF 0x00000004 /* CONF: ATH FF enabled */
#define IEEE80211_F_BURST 0x00000008 /* CONF: bursting enabled */
/* NB: this is intentionally setup to be IEEE80211_CAPINFO_PRIVACY */
#define IEEE80211_F_PRIVACY 0x00000010 /* CONF: privacy enabled */
#define IEEE80211_F_PUREG 0x00000020 /* CONF: 11g w/o 11b sta's */
@ -237,14 +322,32 @@ struct ieee80211com {
#define IEEE80211_F_HIDESSID 0x08000000 /* CONF: hide SSID in beacon */
#define IEEE80211_F_NOBRIDGE 0x10000000 /* CONF: dis. internal bridge */
#define IEEE80211_F_WMEUPDATE 0x20000000 /* STATUS: update beacon wme */
#define IEEE80211_F_DOTH 0x40000000 /* CONF: 11h enabled */
/* Atheros protocol-specific flags */
#define IEEE80211_F_ATHEROS \
(IEEE80211_F_FF | IEEE80211_F_COMP | IEEE80211_F_TURBOP)
/* Check if an Atheros capability was negotiated for use */
#define IEEE80211_ATH_CAP(ic, ni, bit) \
((ic)->ic_flags & (ni)->ni_ath_flags & (bit))
/* ic_flags_ext */
#define IEEE80211_FEXT_WDS 0x00000001 /* CONF: 4 addr allowed */
#define IEEE80211_FEXT_WDS 0x00000001 /* CONF: 4 addr allowed */
/* 0x00000006 reserved */
#define IEEE80211_FEXT_BGSCAN 0x00000008 /* STATUS: enable full bgscan completion */
#define IEEE80211_FEXT_BGSCAN 0x00000008 /* STATUS: complete bgscan */
#define IEEE80211_FEXT_ERPUPDATE 0x00000200 /* STATUS: update ERP element */
#define IEEE80211_FEXT_SWBMISS 0x00000400 /* CONF: do bmiss in s/w */
#define IEEE80211_FEXT_SWBMISS 0x00000400 /* CONF: do bmiss in s/w */
#define IEEE80211_FEXT_PROBECHAN 0x00020000 /* CONF: probe passive channel*/
#define IEEE80211_FEXT_HT 0x00080000 /* CONF: HT supported */
#define IEEE80211_FEXT_AMPDU_TX 0x00100000 /* CONF: A-MPDU tx supported */
#define IEEE80211_FEXT_AMPDU_RX 0x00200000 /* CONF: A-MPDU tx supported */
#define IEEE80211_FEXT_AMSDU_TX 0x00400000 /* CONF: A-MSDU tx supported */
#define IEEE80211_FEXT_AMSDU_RX 0x00800000 /* CONF: A-MSDU tx supported */
#define IEEE80211_FEXT_USEHT40 0x01000000 /* CONF: 20/40 use enabled */
#define IEEE80211_FEXT_PUREN 0x02000000 /* CONF: 11n w/o legacy sta's */
#define IEEE80211_FEXT_SHORTGI20 0x04000000 /* CONF: short GI in HT20 */
#define IEEE80211_FEXT_SHORTGI40 0x08000000 /* CONF: short GI in HT40 */
#define IEEE80211_FEXT_HTCOMPAT 0x10000000 /* CONF: HT vendor OUI's */
/* ic_caps */
#define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */
@ -277,29 +380,40 @@ struct ieee80211com {
#define IEEE80211_C_CRYPTO 0x0000002f /* CAPABILITY: crypto alg's */
/*
* ic_htcaps: HT-specific device/driver capabilities
*
* NB: the low 16-bits are the 802.11 definitions, the upper
* 16-bits are used to define s/w/driver capabilities.
*/
#define IEEE80211_HTC_AMPDU 0x00010000 /* CAPABILITY: A-MPDU tx */
#define IEEE80211_HTC_AMSDU 0x00020000 /* CAPABILITY: A-MSDU tx */
void ieee80211_ifattach(struct ieee80211com *);
void ieee80211_ifdetach(struct ieee80211com *);
const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *,
const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic,
const struct ieee80211_channel *);
void ieee80211_announce(struct ieee80211com *);
void ieee80211_announce_channels(struct ieee80211com *);
void ieee80211_media_init(struct ieee80211com *,
ifm_change_cb_t, ifm_stat_cb_t);
struct ieee80211com *ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN]);
struct ieee80211com *ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN]);
int ieee80211_media_change(struct ifnet *);
void ieee80211_media_status(struct ifnet *, struct ifmediareq *);
int ieee80211_ioctl(struct ieee80211com *, u_long, caddr_t);
int ieee80211_cfgget(struct ieee80211com *, u_long, caddr_t);
int ieee80211_cfgset(struct ieee80211com *, u_long, caddr_t);
void ieee80211_watchdog(struct ieee80211com *);
int ieee80211_rate2media(struct ieee80211com *, int,
enum ieee80211_phymode);
int ieee80211_media2rate(int);
int ieee80211_mhz2ieee(u_int, u_int);
int ieee80211_chan2ieee(struct ieee80211com *, const struct ieee80211_channel *);
u_int ieee80211_ieee2mhz(u_int, u_int);
int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *,
int ieee80211_chan2ieee(struct ieee80211com *,
const struct ieee80211_channel *);
u_int ieee80211_ieee2mhz(u_int, u_int);
struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
int freq, int flags);
int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
/*
* Key update synchronization methods. XXX should not be visible.
@ -329,7 +443,7 @@ ieee80211_hdrspace(struct ieee80211com *ic, const void *data)
{
int size = ieee80211_hdrsize(data);
if (ic->ic_flags & IEEE80211_F_DATAPAD)
size = roundup(size, sizeof(u_int32_t));
size = roundup(size, sizeof(uint32_t));
return size;
}
@ -341,10 +455,11 @@ ieee80211_anyhdrspace(struct ieee80211com *ic, const void *data)
{
int size = ieee80211_anyhdrsize(data);
if (ic->ic_flags & IEEE80211_F_DATAPAD)
size = roundup(size, sizeof(u_int32_t));
size = roundup(size, sizeof(uint32_t));
return size;
}
#define IEEE80211_MSG_11N 0x80000000 /* 11n mode debug */
#define IEEE80211_MSG_DEBUG 0x40000000 /* IFF_DEBUG equivalent */
#define IEEE80211_MSG_DUMPPKTS 0x20000000 /* IFF_LINK2 equivalant */
#define IEEE80211_MSG_CRYPTO 0x10000000 /* crypto work */
@ -371,6 +486,7 @@ ieee80211_anyhdrspace(struct ieee80211com *ic, const void *data)
#define IEEE80211_MSG_INACT 0x00000080 /* inactivity handling */
#define IEEE80211_MSG_ROAM 0x00000040 /* sta-mode roaming */
#define IEEE80211_MSG_RATECTL 0x00000020 /* tx rate control */
#define IEEE80211_MSG_ACTION 0x00000010 /* action frame handling */
#define IEEE80211_MSG_ANY 0xffffffff /* anything */
@ -394,7 +510,7 @@ ieee80211_anyhdrspace(struct ieee80211com *ic, const void *data)
} while (0)
void ieee80211_note(struct ieee80211com *ic, const char *fmt, ...);
void ieee80211_note_mac(struct ieee80211com *ic,
const u_int8_t mac[IEEE80211_ADDR_LEN], const char *fmt, ...);
const uint8_t mac[IEEE80211_ADDR_LEN], const char *fmt, ...);
void ieee80211_note_frame(struct ieee80211com *ic,
const struct ieee80211_frame *wh, const char *fmt, ...);
#define ieee80211_msg_debug(_ic) \
@ -438,10 +554,11 @@ void ieee80211_discard_frame(struct ieee80211com *,
void ieee80211_discard_ie(struct ieee80211com *,
const struct ieee80211_frame *, const char *type, const char *fmt, ...);
void ieee80211_discard_mac(struct ieee80211com *,
const u_int8_t mac[IEEE80211_ADDR_LEN], const char *type,
const uint8_t mac[IEEE80211_ADDR_LEN], const char *type,
const char *fmt, ...);
#else
#define IEEE80211_DPRINTF(_ic, _m, _fmt, ...)
#define IEEE80211_NOTE(_ic, _m, _ni, _fmt, ...)
#define IEEE80211_NOTE_FRAME(_ic, _m, _wh, _fmt, ...)
#define IEEE80211_NOTE_MAC(_ic, _m, _mac, _fmt, ...)
#define ieee80211_msg_dumppkts(_ic) 0

View File

@ -57,7 +57,7 @@
* is created, otherwise 1.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 700045 /* Master, propagated to newvers */
#define __FreeBSD_version 700046 /* Master, propagated to newvers */
#ifndef LOCORE
#include <sys/types.h>