summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath/if_ath.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/if_ath.c')
-rw-r--r--sys/dev/ath/if_ath.c2175
1 files changed, 1309 insertions, 866 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index fd02770..0d5ef91 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
+ * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,6 +84,22 @@ __FBSDID("$FreeBSD$");
#include <dev/ath/ath_tx99/ath_tx99.h>
#endif
+/*
+ * ATH_BCBUF determines the number of vap's that can transmit
+ * beacons and also (currently) the number of vap's that can
+ * have unique mac addresses/bssid. When staggering beacons
+ * 4 is probably a good max as otherwise the beacons become
+ * very closely spaced and there is limited time for cab q traffic
+ * to go out. You can burst beacons instead but that is not good
+ * for stations in power save and at some point you really want
+ * another radio (and channel).
+ *
+ * The limit on the number of mac addresses is tied to our use of
+ * the U/L bit and tracking addresses in a byte; it would be
+ * worthwhile to allow more for applications like proxy sta.
+ */
+CTASSERT(ATH_BCBUF <= 8);
+
/* unaligned little endian access */
#define LE_READ_2(p) \
((u_int16_t) \
@@ -99,49 +115,59 @@ enum {
ATH_LED_POLL,
};
+static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
+ const char name[IFNAMSIZ], int unit, int opmode,
+ int flags, const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void ath_vap_delete(struct ieee80211vap *);
static void ath_init(void *);
static void ath_stop_locked(struct ifnet *);
static void ath_stop(struct ifnet *);
static void ath_start(struct ifnet *);
static int ath_reset(struct ifnet *);
+static int ath_reset_vap(struct ieee80211vap *, u_long);
static int ath_media_change(struct ifnet *);
static void ath_watchdog(struct ifnet *);
static int ath_ioctl(struct ifnet *, u_long, caddr_t);
static void ath_fatal_proc(void *, int);
static void ath_rxorn_proc(void *, int);
+static void ath_bmiss_vap(struct ieee80211vap *);
static void ath_bmiss_proc(void *, int);
-static int ath_key_alloc(struct ieee80211com *,
+static int ath_key_alloc(struct ieee80211vap *,
const struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
-static int ath_key_delete(struct ieee80211com *,
+static int ath_key_delete(struct ieee80211vap *,
const struct ieee80211_key *);
-static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *,
+static int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *,
const u_int8_t mac[IEEE80211_ADDR_LEN]);
-static void ath_key_update_begin(struct ieee80211com *);
-static void ath_key_update_end(struct ieee80211com *);
+static void ath_key_update_begin(struct ieee80211vap *);
+static void ath_key_update_end(struct ieee80211vap *);
+static void ath_update_mcast(struct ifnet *);
+static void ath_update_promisc(struct ifnet *);
static void ath_mode_init(struct ath_softc *);
static void ath_setslottime(struct ath_softc *);
static void ath_updateslot(struct ifnet *);
static int ath_beaconq_setup(struct ath_hal *);
static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
-static void ath_beacon_update(struct ieee80211com *, int item);
+static void ath_beacon_update(struct ieee80211vap *, int item);
static void ath_beacon_setup(struct ath_softc *, struct ath_buf *);
static void ath_beacon_proc(void *, int);
+static struct ath_buf *ath_beacon_generate(struct ath_softc *,
+ struct ieee80211vap *);
static void ath_bstuck_proc(void *, int);
+static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
static void ath_beacon_free(struct ath_softc *);
-static void ath_beacon_config(struct ath_softc *);
+static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
static void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *, ath_bufhead *);
static int ath_desc_alloc(struct ath_softc *);
static void ath_desc_free(struct ath_softc *);
static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
static void ath_node_free(struct ieee80211_node *);
-static int8_t ath_node_getrssi(const struct ieee80211_node *);
static void ath_node_getsignal(const struct ieee80211_node *,
int8_t *, int8_t *);
static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
-static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni,
+static void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int noise, u_int32_t rstamp);
static void ath_setdefantenna(struct ath_softc *, u_int);
static void ath_rx_proc(void *, int);
@@ -157,6 +183,7 @@ static int ath_tx_start(struct ath_softc *, struct ieee80211_node *,
static void ath_tx_proc_q0(void *, int);
static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
+static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
static void ath_draintxq(struct ath_softc *);
static void ath_stoprecv(struct ath_softc *);
@@ -166,13 +193,16 @@ static void ath_scan_start(struct ieee80211com *);
static void ath_scan_end(struct ieee80211com *);
static void ath_set_channel(struct ieee80211com *);
static void ath_calibrate(void *);
-static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
static void ath_newassoc(struct ieee80211_node *, int);
-static int ath_getchannels(struct ath_softc *,
- HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL);
+static int ath_setregdomain(struct ieee80211com *,
+ struct ieee80211_regdomain *, int,
+ struct ieee80211_channel []);
+static void ath_getradiocaps(struct ieee80211com *, int *,
+ struct ieee80211_channel []);
+static int ath_getchannels(struct ath_softc *);
static void ath_led_event(struct ath_softc *, int);
-static void ath_update_txpow(struct ath_softc *);
static int ath_rate_setup(struct ath_softc *, u_int mode);
static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
@@ -189,21 +219,6 @@ SYSCTL_DECL(_hw_ath);
static int ath_calinterval = 30; /* calibrate every 30 secs */
SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval,
0, "chip calibration interval (secs)");
-static int ath_outdoor = AH_TRUE; /* outdoor operation */
-SYSCTL_INT(_hw_ath, OID_AUTO, outdoor, CTLFLAG_RW, &ath_outdoor,
- 0, "outdoor operation");
-TUNABLE_INT("hw.ath.outdoor", &ath_outdoor);
-static int ath_xchanmode = AH_TRUE; /* extended channel use */
-SYSCTL_INT(_hw_ath, OID_AUTO, xchanmode, CTLFLAG_RW, &ath_xchanmode,
- 0, "extended channel mode");
-TUNABLE_INT("hw.ath.xchanmode", &ath_xchanmode);
-static int ath_countrycode = CTRY_DEFAULT; /* country code */
-SYSCTL_INT(_hw_ath, OID_AUTO, countrycode, CTLFLAG_RW, &ath_countrycode,
- 0, "country code");
-TUNABLE_INT("hw.ath.countrycode", &ath_countrycode);
-static int ath_regdomain = 0; /* regulatory domain */
-SYSCTL_INT(_hw_ath, OID_AUTO, regdomain, CTLFLAG_RD, &ath_regdomain,
- 0, "regulatory domain");
static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */
SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &ath_rxbuf,
@@ -273,19 +288,20 @@ int
ath_attach(u_int16_t devid, struct ath_softc *sc)
{
struct ifnet *ifp;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic;
struct ath_hal *ah = NULL;
HAL_STATUS status;
int error = 0, i;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
- ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
+ ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
if (ifp == NULL) {
device_printf(sc->sc_dev, "can not if_alloc()\n");
error = ENOSPC;
goto bad;
}
+ ic = ifp->if_l2com;
/* set these up early for if_printf use */
if_initname(ifp, device_get_name(sc->sc_dev),
@@ -342,13 +358,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ath_hal_keyreset(ah, i);
/*
- * Collect the channel list using the default country
- * code and including outdoor channels. The 802.11 layer
- * is resposible for filtering this list based on settings
- * like the phy mode.
+ * Collect the default channel list.
*/
- error = ath_getchannels(sc, ath_regdomain, ath_countrycode,
- ath_outdoor != 0, ath_xchanmode != 0);
+ error = ath_getchannels(sc);
if (error != 0)
goto bad;
@@ -378,7 +390,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
goto bad;
}
callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE);
- callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE);
ATH_TXBUF_LOCK_INIT(sc);
@@ -412,8 +423,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
error = EIO;
goto bad2;
}
- /* NB: s/w q, qnum used only by WITNESS */
- ath_txq_init(sc, &sc->sc_mcastq, HAL_NUM_TX_QUEUES+1);
/* NB: insure BK queue is the lowest priority h/w queue */
if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) {
if_printf(ifp, "unable to setup xmit queue for %s traffic!\n",
@@ -497,10 +506,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
IFQ_SET_READY(&ifp->if_snd);
ic->ic_ifp = ifp;
- ic->ic_reset = ath_reset;
- ic->ic_newassoc = ath_newassoc;
- ic->ic_updateslot = ath_updateslot;
- ic->ic_wme.wme_update = ath_wme_update;
/* XXX not right but it's not used anywhere important */
ic->ic_phytype = IEEE80211_T_OFDM;
ic->ic_opmode = IEEE80211_M_STA;
@@ -509,6 +514,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
| IEEE80211_C_HOSTAP /* hostap mode */
| IEEE80211_C_MONITOR /* monitor mode */
| IEEE80211_C_AHDEMO /* adhoc demo mode */
+ | IEEE80211_C_WDS /* 4-address traffic works */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
@@ -519,22 +525,22 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
* Query the hal to figure out h/w crypto support.
*/
if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP))
- ic->ic_caps |= IEEE80211_C_WEP;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_WEP;
if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB))
- ic->ic_caps |= IEEE80211_C_AES;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_AES_OCB;
if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM))
- ic->ic_caps |= IEEE80211_C_AES_CCM;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_AES_CCM;
if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP))
- ic->ic_caps |= IEEE80211_C_CKIP;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_CKIP;
if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) {
- ic->ic_caps |= IEEE80211_C_TKIP;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIP;
/*
* Check if h/w does the MIC and/or whether the
* separate key cache entries are required to
* handle both tx+rx MIC keys.
*/
if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC))
- ic->ic_caps |= IEEE80211_C_TKIPMIC;
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIPMIC;
/*
* If the h/w supports storing tx+rx MIC keys
* in one cache slot automatically enable use.
@@ -542,6 +548,13 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if (ath_hal_hastkipsplit(ah) ||
!ath_hal_settkipsplit(ah, AH_FALSE))
sc->sc_splitmic = 1;
+ /*
+ * If the h/w can do TKIP MIC together with WME then
+ * we use it; otherwise we force the MIC to be done
+ * in software by the net80211 layer.
+ */
+ if (ath_hal_haswmetkipmic(ah))
+ sc->sc_wmetkipmic = 1;
}
sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR);
sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah);
@@ -578,9 +591,11 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
*/
if (ath_hal_hasbursting(ah))
ic->ic_caps |= IEEE80211_C_BURST;
+ sc->sc_hasbmask = ath_hal_hasbssidmask(ah);
+ sc->sc_hastsfadd = ath_hal_hastsfadjust(ah);
if (ath_hal_hasfastframes(ah))
ic->ic_caps |= IEEE80211_C_FF;
- if (ath_hal_getwirelessmodes(ah, ath_countrycode) & (HAL_MODE_108G|HAL_MODE_TURBO))
+ if (ath_hal_getwirelessmodes(ah, ic->ic_regdomain.country) & (HAL_MODE_108G|HAL_MODE_TURBO))
ic->ic_caps |= IEEE80211_C_TURBOP;
/*
@@ -602,33 +617,33 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
/* get mac address from hardware */
ath_hal_getmac(ah, ic->ic_myaddr);
+ if (sc->sc_hasbmask)
+ ath_hal_getbssidmask(ah, sc->sc_hwbssidmask);
+ /* NB: used to size node table key mapping array */
+ ic->ic_max_keyix = sc->sc_keymax;
/* call MI attach routine. */
ieee80211_ifattach(ic);
- sc->sc_opmode = ic->ic_opmode;
+ ic->ic_setregdomain = ath_setregdomain;
+ ic->ic_getradiocaps = ath_getradiocaps;
+ sc->sc_opmode = HAL_M_STA;
+
/* override default methods */
+ ic->ic_newassoc = ath_newassoc;
+ ic->ic_updateslot = ath_updateslot;
+ ic->ic_wme.wme_update = ath_wme_update;
+ ic->ic_vap_create = ath_vap_create;
+ ic->ic_vap_delete = ath_vap_delete;
+ ic->ic_raw_xmit = ath_raw_xmit;
+ ic->ic_update_mcast = ath_update_mcast;
+ ic->ic_update_promisc = ath_update_promisc;
ic->ic_node_alloc = ath_node_alloc;
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = ath_node_free;
- ic->ic_node_getrssi = ath_node_getrssi;
ic->ic_node_getsignal = ath_node_getsignal;
- sc->sc_recv_mgmt = ic->ic_recv_mgmt;
- ic->ic_recv_mgmt = ath_recv_mgmt;
- sc->sc_newstate = ic->ic_newstate;
- ic->ic_newstate = ath_newstate;
ic->ic_scan_start = ath_scan_start;
ic->ic_scan_end = ath_scan_end;
ic->ic_set_channel = ath_set_channel;
- ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
- ic->ic_crypto.cs_key_alloc = ath_key_alloc;
- ic->ic_crypto.cs_key_delete = ath_key_delete;
- ic->ic_crypto.cs_key_set = ath_key_set;
- ic->ic_crypto.cs_key_update_begin = ath_key_update_begin;
- ic->ic_crypto.cs_key_update_end = ath_key_update_end;
- ic->ic_raw_xmit = ath_raw_xmit;
- ic->ic_update_beacon = ath_beacon_update;
- /* complete initialization */
- ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
ath_bpfattach(sc);
/*
@@ -675,7 +690,7 @@ ath_detach(struct ath_softc *sc)
* it last
* Other than that, it's straightforward...
*/
- ieee80211_ifdetach(&sc->sc_ic);
+ ieee80211_ifdetach(ifp->if_l2com);
#ifdef ATH_TX99_DIAG
if (sc->sc_tx99 != NULL)
sc->sc_tx99->detach(sc->sc_tx99);
@@ -690,6 +705,343 @@ ath_detach(struct ath_softc *sc)
return 0;
}
+/*
+ * MAC address handling for multiple BSS on the same radio.
+ * The first vap uses the MAC address from the EEPROM. For
+ * subsequent vap's we set the U/L bit (bit 1) in the MAC
+ * address and use the next six bits as an index.
+ */
+static void
+assign_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN], int clone)
+{
+ int i;
+
+ if (clone && sc->sc_hasbmask) {
+ /* NB: we only do this if h/w supports multiple bssid */
+ for (i = 0; i < 8; i++)
+ if ((sc->sc_bssidmask & (1<<i)) == 0)
+ break;
+ if (i != 0)
+ mac[0] |= (i << 2)|0x2;
+ } else
+ i = 0;
+ sc->sc_bssidmask |= 1<<i;
+ sc->sc_hwbssidmask[0] &= ~mac[0];
+ if (i == 0)
+ sc->sc_nbssid0++;
+}
+
+static void
+reclaim_address(struct ath_softc *sc, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ int i = mac[0] >> 2;
+ uint8_t mask;
+
+ if (i != 0 || --sc->sc_nbssid0 == 0) {
+ sc->sc_bssidmask &= ~(1<<i);
+ /* recalculate bssid mask from remaining addresses */
+ mask = 0xff;
+ for (i = 1; i < 8; i++)
+ if (sc->sc_bssidmask & (1<<i))
+ mask &= ~((i<<2)|0x2);
+ sc->sc_hwbssidmask[0] |= mask;
+ }
+}
+
+/*
+ * Assign a beacon xmit slot. We try to space out
+ * assignments so when beacons are staggered the
+ * traffic coming out of the cab q has maximal time
+ * to go out before the next beacon is scheduled.
+ */
+static int
+assign_bslot(struct ath_softc *sc)
+{
+ u_int slot, free;
+
+ free = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++)
+ if (sc->sc_bslot[slot] == NULL) {
+ if (sc->sc_bslot[(slot+1)%ATH_BCBUF] == NULL &&
+ sc->sc_bslot[(slot-1)%ATH_BCBUF] == NULL)
+ return slot;
+ free = slot;
+ /* NB: keep looking for a double slot */
+ }
+ return free;
+}
+
+static struct ieee80211vap *
+ath_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac0[IEEE80211_ADDR_LEN])
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_vap *avp;
+ struct ieee80211vap *vap;
+ uint8_t mac[IEEE80211_ADDR_LEN];
+ int ic_opmode, needbeacon, error;
+
+ avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
+ M_80211_VAP, M_WAITOK | M_ZERO);
+ needbeacon = 0;
+ IEEE80211_ADDR_COPY(mac, mac0);
+
+ ATH_LOCK(sc);
+ switch (opmode) {
+ case IEEE80211_M_STA:
+ if (sc->sc_nstavaps != 0) { /* XXX only 1 sta for now */
+ device_printf(sc->sc_dev, "only 1 sta vap supported\n");
+ goto bad;
+ }
+ if (sc->sc_nvaps) {
+ /*
+ * When there are multiple vaps we must fall
+ * back to s/w beacon miss handling.
+ */
+ flags |= IEEE80211_CLONE_NOBEACONS;
+ }
+ if (flags & IEEE80211_CLONE_NOBEACONS) {
+ sc->sc_swbmiss = 1;
+ ic_opmode = IEEE80211_M_HOSTAP;
+ } else
+ ic_opmode = opmode;
+ break;
+ case IEEE80211_M_IBSS:
+ if (sc->sc_nvaps != 0) { /* XXX only 1 for now */
+ device_printf(sc->sc_dev,
+ "only 1 ibss vap supported\n");
+ goto bad;
+ }
+ ic_opmode = opmode;
+ needbeacon = 1;
+ break;
+ case IEEE80211_M_AHDEMO:
+ /* fall thru... */
+ case IEEE80211_M_MONITOR:
+ if (sc->sc_nvaps != 0 && ic->ic_opmode != opmode) {
+ /* XXX not right for monitor mode */
+ ic_opmode = ic->ic_opmode;
+ } else
+ ic_opmode = opmode;
+ break;
+ case IEEE80211_M_HOSTAP:
+ needbeacon = 1;
+ /* fall thru... */
+ case IEEE80211_M_WDS:
+ if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA) {
+ device_printf(sc->sc_dev,
+ "wds not supported in sta mode\n");
+ goto bad;
+ }
+ if (opmode == IEEE80211_M_WDS) {
+ /*
+ * Silently remove any request for a unique
+ * bssid; WDS vap's always share the local
+ * mac address.
+ */
+ flags &= ~IEEE80211_CLONE_BSSID;
+ }
+ ic_opmode = IEEE80211_M_HOSTAP;
+ break;
+ default:
+ device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
+ goto bad;
+ }
+ /*
+ * Check that a beacon buffer is available; the code below assumes it.
+ */
+ if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) {
+ device_printf(sc->sc_dev, "no beacon buffer available\n");
+ goto bad;
+ }
+
+ /* STA, AHDEMO? */
+ if (opmode == IEEE80211_M_HOSTAP) {
+ assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
+ ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask);
+ }
+
+ vap = &avp->av_vap;
+ /* XXX can't hold mutex across if_alloc */
+ ATH_UNLOCK(sc);
+ error = ieee80211_vap_setup(ic, vap, name, unit, opmode, flags,
+ bssid, mac);
+ ATH_LOCK(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "%s: error %d creating vap\n",
+ __func__, error);
+ goto bad2;
+ }
+
+ /* h/w crypto support */
+ vap->iv_key_alloc = ath_key_alloc;
+ vap->iv_key_delete = ath_key_delete;
+ vap->iv_key_set = ath_key_set;
+ vap->iv_key_update_begin = ath_key_update_begin;
+ vap->iv_key_update_end = ath_key_update_end;
+
+ /* override various methods */
+ avp->av_recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = ath_recv_mgmt;
+ vap->iv_reset = ath_reset_vap;
+ vap->iv_update_beacon = ath_beacon_update;
+ avp->av_newstate = vap->iv_newstate;
+ vap->iv_newstate = ath_newstate;
+ avp->av_bmiss = vap->iv_bmiss;
+ vap->iv_bmiss = ath_bmiss_vap;
+
+ avp->av_bslot = -1;
+ if (needbeacon) {
+ /*
+ * Allocate beacon state and setup the q for buffered
+ * multicast frames. We know a beacon buffer is
+ * available because we checked above.
+ */
+ avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf);
+ STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list);
+ if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) {
+ /*
+ * Assign the vap to a beacon xmit slot. As above
+ * this cannot fail to find a free one.
+ */
+ avp->av_bslot = assign_bslot(sc);
+ KASSERT(sc->sc_bslot[avp->av_bslot] == NULL,
+ ("beacon slot %u not empty", avp->av_bslot));
+ sc->sc_bslot[avp->av_bslot] = vap;
+ sc->sc_nbcnvaps++;
+ }
+ if (sc->sc_hastsfadd && sc->sc_nbcnvaps > 0) {
+ /*
+ * Multple vaps are to transmit beacons and we
+ * have h/w support for TSF adjusting; enable
+ * use of staggered beacons.
+ */
+ sc->sc_stagbeacons = 1;
+ }
+ ath_txq_init(sc, &avp->av_mcastq, ATH_TXQ_SWQ);
+ }
+
+ ic->ic_opmode = ic_opmode;
+ if (opmode != IEEE80211_M_WDS) {
+ sc->sc_nvaps++;
+ if (opmode == IEEE80211_M_STA)
+ sc->sc_nstavaps++;
+ }
+ switch (ic_opmode) {
+ case IEEE80211_M_IBSS:
+ sc->sc_opmode = HAL_M_IBSS;
+ break;
+ case IEEE80211_M_STA:
+ sc->sc_opmode = HAL_M_STA;
+ break;
+ case IEEE80211_M_AHDEMO:
+ case IEEE80211_M_HOSTAP:
+ sc->sc_opmode = HAL_M_HOSTAP;
+ break;
+ case IEEE80211_M_MONITOR:
+ sc->sc_opmode = HAL_M_MONITOR;
+ break;
+ default:
+ /* XXX should not happen */
+ break;
+ }
+ if (sc->sc_hastsfadd) {
+ /*
+ * Configure whether or not TSF adjust should be done.
+ */
+ ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons);
+ }
+ ATH_UNLOCK(sc);
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
+ return vap;
+bad2:
+ reclaim_address(sc, mac);
+ ath_hal_setbssidmask(sc->sc_ah, sc->sc_hwbssidmask);
+bad:
+ free(avp, M_80211_VAP);
+ ATH_UNLOCK(sc);
+ return NULL;
+}
+
+static void
+ath_vap_delete(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_vap *avp = ATH_VAP(vap);
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ /*
+ * Quiesce the hardware while we remove the vap. In
+ * particular we need to reclaim all references to
+ * the vap state by any frames pending on the tx queues.
+ */
+ ath_hal_intrset(ah, 0); /* disable interrupts */
+ ath_draintxq(sc); /* stop xmit side */
+ ath_stoprecv(sc); /* stop recv side */
+ }
+
+ ieee80211_vap_detach(vap);
+ ATH_LOCK(sc);
+ /*
+ * Reclaim beacon state. Note this must be done before
+ * the vap instance is reclaimed as we may have a reference
+ * to it in the buffer for the beacon frame.
+ */
+ if (avp->av_bcbuf != NULL) {
+ if (avp->av_bslot != -1) {
+ sc->sc_bslot[avp->av_bslot] = NULL;
+ sc->sc_nbcnvaps--;
+ }
+ ath_beacon_return(sc, avp->av_bcbuf);
+ avp->av_bcbuf = NULL;
+ if (sc->sc_nbcnvaps == 0) {
+ sc->sc_stagbeacons = 0;
+ if (sc->sc_hastsfadd)
+ ath_hal_settsfadjust(sc->sc_ah, 0);
+ }
+ /*
+ * Reclaim any pending mcast frames for the vap.
+ */
+ ath_tx_draintxq(sc, &avp->av_mcastq);
+ ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
+ }
+ /*
+ * Update bookkeeping.
+ */
+ if (vap->iv_opmode == IEEE80211_M_STA) {
+ sc->sc_nstavaps--;
+ if (sc->sc_nstavaps == 0 && sc->sc_swbmiss)
+ sc->sc_swbmiss = 0;
+ } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ reclaim_address(sc, vap->iv_myaddr);
+ ath_hal_setbssidmask(ah, sc->sc_hwbssidmask);
+ }
+ if (vap->iv_opmode != IEEE80211_M_WDS)
+ sc->sc_nvaps--;
+ ATH_UNLOCK(sc);
+ free(avp, M_80211_VAP);
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ /*
+ * Restart rx+tx machines if still running (RUNNING will
+ * be reset if we just destroyed the last vap).
+ */
+ if (ath_startrecv(sc) != 0)
+ if_printf(ifp, "%s: unable to restart recv logic\n",
+ __func__);
+ if (sc->sc_beacons)
+ ath_beacon_config(sc, NULL);
+ ath_hal_intrset(ah, sc->sc_imask);
+ }
+}
+
void
ath_suspend(struct ath_softc *sc)
{
@@ -864,37 +1216,40 @@ ath_rxorn_proc(void *arg, int pending)
}
static void
+ath_bmiss_vap(struct ieee80211vap *vap)
+{
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+ u_int64_t lastrx = sc->sc_lastrx;
+ u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
+ u_int bmisstimeout =
+ vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024;
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
+ __func__, (unsigned long long) tsf,
+ (unsigned long long)(tsf - lastrx),
+ (unsigned long long) lastrx, bmisstimeout);
+ /*
+ * Workaround phantom bmiss interrupts by sanity-checking
+ * the time of our last rx'd frame. If it is within the
+ * beacon miss interval then ignore the interrupt. If it's
+ * truly a bmiss we'll get another interrupt soon and that'll
+ * be dispatched up for processing.
+ */
+ if (tsf - lastrx > bmisstimeout)
+ ATH_VAP(vap)->av_bmiss(vap);
+ else
+ sc->sc_stats.ast_bmiss_phantom++;
+}
+
+static void
ath_bmiss_proc(void *arg, int pending)
{
struct ath_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
- KASSERT(ic->ic_opmode == IEEE80211_M_STA,
- ("unexpect operating mode %u", ic->ic_opmode));
- if (ic->ic_state == IEEE80211_S_RUN) {
- u_int64_t lastrx = sc->sc_lastrx;
- u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
- u_int bmisstimeout =
- ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024;
-
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
- __func__, (unsigned long long) tsf,
- (unsigned long long)(tsf - lastrx),
- (unsigned long long) lastrx, bmisstimeout);
- /*
- * Workaround phantom bmiss interrupts by sanity-checking
- * the time of our last rx'd frame. If it is within the
- * beacon miss interval then ignore the interrupt. If it's
- * truly a bmiss we'll get another interrupt soon and that'll
- * be dispatched up for processing.
- */
- if (tsf - lastrx > bmisstimeout)
- ieee80211_beacon_miss(ic);
- else
- sc->sc_stats.ast_bmiss_phantom++;
- }
+ ieee80211_beacon_miss(ifp->if_l2com);
}
/*
@@ -939,12 +1294,35 @@ ath_mapchan(HAL_CHANNEL *hc, const struct ieee80211_channel *chan)
#undef N
}
+/*
+ * Handle TKIP MIC setup to deal hardware that doesn't do MIC
+ * calcs together with WME. If necessary disable the crypto
+ * hardware and mark the 802.11 state so keys will be setup
+ * with the MIC work done in software.
+ */
+static void
+ath_settkipmic(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if ((ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIP) && !sc->sc_wmetkipmic) {
+ if (ic->ic_flags & IEEE80211_F_WME) {
+ ath_hal_settkipmic(sc->sc_ah, AH_FALSE);
+ ic->ic_cryptocaps &= ~IEEE80211_CRYPTO_TKIPMIC;
+ } else {
+ ath_hal_settkipmic(sc->sc_ah, AH_TRUE);
+ ic->ic_cryptocaps |= IEEE80211_CRYPTO_TKIPMIC;
+ }
+ }
+}
+
static void
ath_init(void *arg)
{
struct ath_softc *sc = (struct ath_softc *) arg;
- struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
HAL_STATUS status;
@@ -966,18 +1344,16 @@ ath_init(void *arg)
* and then setup of the interrupt mask.
*/
ath_mapchan(&sc->sc_curchan, ic->ic_curchan);
+ ath_settkipmic(sc);
if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
if_printf(ifp, "unable to reset hardware; hal status %u\n",
status);
- goto done;
+ ATH_UNLOCK(sc);
+ return;
}
+ ath_chan_change(sc, ic->ic_curchan);
/*
- * This is needed only to setup initial state
- * but it's best done after a reset.
- */
- ath_update_txpow(sc);
- /*
* Likewise this is set during reset so update
* state cached in the driver.
*/
@@ -994,7 +1370,8 @@ ath_init(void *arg)
*/
if (ath_startrecv(sc) != 0) {
if_printf(ifp, "unable to start recv logic\n");
- goto done;
+ ATH_UNLOCK(sc);
+ return;
}
/*
@@ -1009,36 +1386,24 @@ ath_init(void *arg)
*/
if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
sc->sc_imask |= HAL_INT_MIB;
- ath_hal_intrset(ah, sc->sc_imask);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- ic->ic_state = IEEE80211_S_INIT;
+ ath_hal_intrset(ah, sc->sc_imask);
+
+ ATH_UNLOCK(sc);
- /*
- * The hardware should be ready to go now so it's safe
- * to kick the 802.11 state machine as it's likely to
- * immediately call back to us to send mgmt frames.
- */
- ath_chan_change(sc, ic->ic_curchan);
#ifdef ATH_TX99_DIAG
if (sc->sc_tx99 != NULL)
sc->sc_tx99->start(sc->sc_tx99);
else
#endif
- if (ic->ic_opmode != IEEE80211_M_MONITOR) {
- if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- } else
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
-done:
- ATH_UNLOCK(sc);
+ ieee80211_start_all(ic); /* start all vap's */
}
static void
ath_stop_locked(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
struct ath_hal *ah = sc->sc_ah;
DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n",
@@ -1065,7 +1430,6 @@ ath_stop_locked(struct ifnet *ifp)
if (sc->sc_tx99 != NULL)
sc->sc_tx99->stop(sc->sc_tx99);
#endif
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
ifp->if_timer = 0;
if (!sc->sc_invalid) {
@@ -1083,8 +1447,7 @@ ath_stop_locked(struct ifnet *ifp)
ath_hal_phydisable(ah);
} else
sc->sc_rxlink = NULL;
- IFQ_DRV_PURGE(&ifp->if_snd);
- ath_beacon_free(sc);
+ ath_beacon_free(sc); /* XXX not needed */
}
}
@@ -1121,7 +1484,7 @@ static int
ath_reset(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
HAL_STATUS status;
@@ -1134,11 +1497,11 @@ ath_reset(struct ifnet *ifp)
ath_hal_intrset(ah, 0); /* disable interrupts */
ath_draintxq(sc); /* stop xmit side */
ath_stoprecv(sc); /* stop recv side */
+ ath_settkipmic(sc); /* configure TKIP MIC handling */
/* NB: indicate channel change so we do a full reset */
if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status))
if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
__func__, status);
- ath_update_txpow(sc); /* update tx power state */
sc->sc_diversity = ath_hal_getdiversity(ah);
sc->sc_calinterval = 1;
sc->sc_caltries = 0;
@@ -1150,14 +1513,20 @@ ath_reset(struct ifnet *ifp)
* might change as a result.
*/
ath_chan_change(sc, ic->ic_curchan);
- if (ic->ic_state == IEEE80211_S_RUN)
- ath_beacon_config(sc); /* restart beacons */
+ if (sc->sc_beacons)
+ ath_beacon_config(sc, NULL); /* restart beacons */
ath_hal_intrset(ah, sc->sc_imask);
ath_start(ifp); /* restart xmit */
return 0;
}
+static int
+ath_reset_vap(struct ieee80211vap *vap, u_long cmd)
+{
+ return ath_reset(vap->iv_ic->ic_ifp);
+}
+
static int
ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
{
@@ -1210,7 +1579,7 @@ ath_ff_stageq_flush(struct ath_softc *sc, struct ath_txq *txq,
sc->sc_stats.ast_ff_flush++;
/* encap and xmit */
- bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni);
+ bf->bf_m = ieee80211_encap(ni, bf->bf_m);
if (bf->bf_m == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
"%s: discard, encapsulation failure\n",
@@ -1243,6 +1612,7 @@ ath_ff_stageq_flush(struct ath_softc *sc, struct ath_txq *txq,
static __inline u_int32_t
ath_ff_approx_txtime(struct ath_softc *sc, struct ath_node *an, struct mbuf *m)
{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
u_int32_t framelen;
struct ath_buf *bf;
@@ -1256,7 +1626,7 @@ ath_ff_approx_txtime(struct ath_softc *sc, struct ath_node *an, struct mbuf *m)
* - 14: 1 802.3 FF tunnel header (skb already accounts for 2nd)
*/
framelen = m->m_pkthdr.len + 32 + 4 + 6 + 16 + 14;
- if (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY)
+ if (ic->ic_flags & IEEE80211_F_PRIVACY)
framelen += 24;
bf = an->an_ff_buf[M_WME_GETAC(m)];
if (bf != NULL)
@@ -1280,7 +1650,7 @@ static __inline int
ath_ff_can_aggregate(struct ath_softc *sc,
struct ath_node *an, struct mbuf *m, int *flushq)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct ath_txq *txq;
u_int32_t txoplimit;
u_int pri;
@@ -1330,7 +1700,6 @@ static struct mbuf *
ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
{
- struct ieee80211com *ic = ni->ni_ic;
struct ath_node *an = ATH_NODE(ni);
struct ath_buf *bfstaged;
int ff_flush, pri;
@@ -1423,7 +1792,7 @@ ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
ether_sprintf(an->an_node.ni_macaddr));
/* encap and xmit */
- bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni);
+ bfstaged->bf_m = ieee80211_encap(ni, bfstaged->bf_m);
if (bfstaged->bf_m == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
"%s: discard, encap failure\n", __func__);
@@ -1525,13 +1894,10 @@ static void
ath_start(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ath_hal *ah = sc->sc_ah;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211_node *ni;
struct ath_buf *bf;
struct mbuf *m, *next;
- struct ieee80211_frame *wh;
- struct ether_header *eh;
struct ath_txq *txq;
ath_bufhead frags;
int pri;
@@ -1554,154 +1920,63 @@ ath_start(struct ifnet *ifp)
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
break;
}
- /*
- * Poll the management queue for frames; they
- * have priority over normal data frames.
- */
- IF_DEQUEUE(&ic->ic_mgtq, m);
- if (m == NULL) {
- /*
- * No data frames go out unless we're associated.
- */
- if (ic->ic_state != IEEE80211_S_RUN) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: discard data packet, state %s\n",
- __func__,
- ieee80211_state_name[ic->ic_state]);
- sc->sc_stats.ast_tx_discard++;
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- break;
- }
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */
- if (m == NULL) {
- ATH_TXBUF_LOCK(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
- ATH_TXBUF_UNLOCK(sc);
- break;
- }
- /*
- * Cancel any background scan.
- */
- if (ic->ic_flags & IEEE80211_F_SCAN)
- ieee80211_cancel_scan(ic);
- STAILQ_INIT(&frags);
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ break;
+ }
+ STAILQ_INIT(&frags);
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ pri = M_WME_GETAC(m);
+ txq = sc->sc_ac2q[pri];
+ if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
/*
- * Find the node for the destination so we can do
- * things like power save and fast frames aggregation.
+ * Check queue length; if too deep drop this
+ * frame (tail drop considered good).
*/
- if (m->m_len < sizeof(struct ether_header) &&
- (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
- ic->ic_stats.is_tx_nobuf++; /* XXX */
- ni = NULL;
- goto bad;
- }
- eh = mtod(m, struct ether_header *);
- ni = ieee80211_find_txnode(ic, eh->ether_dhost);
- if (ni == NULL) {
- /* NB: ieee80211_find_txnode does stat+msg */
+ if (txq->axq_depth >= sc->sc_fftxqmax) {
+ DPRINTF(sc, ATH_DEBUG_FF,
+ "[%s] tail drop on q %u depth %u\n",
+ ether_sprintf(ni->ni_macaddr),
+ txq->axq_qnum, txq->axq_depth);
+ sc->sc_stats.ast_tx_qfull++;
m_freem(m);
- goto bad;
- }
- if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
- (m->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, m);
goto reclaim;
}
- /* calculate priority so we can find the tx queue */
- if (ieee80211_classify(ic, m, ni)) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: discard, classification failure\n",
- __func__);
- m_freem(m);
- goto bad;
- }
- pri = M_WME_GETAC(m);
- txq = sc->sc_ac2q[pri];
- if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
- /*
- * Check queue length; if too deep drop this
- * frame (tail drop considered good).
- */
- if (txq->axq_depth >= sc->sc_fftxqmax) {
- DPRINTF(sc, ATH_DEBUG_FF,
- "[%s] tail drop on q %u depth %u\n",
- ether_sprintf(ni->ni_macaddr),
- txq->axq_qnum, txq->axq_depth);
- sc->sc_stats.ast_tx_qfull++;
- m_freem(m);
- goto reclaim;
- }
- m = ath_ff_check(sc, txq, bf, m, ni);
- if (m == NULL) {
- /* NB: ni ref & bf held on stageq */
- continue;
- }
- }
- ifp->if_opackets++;
- BPF_MTAP(ifp, m);
- /*
- * Encapsulate the packet in prep for transmission.
- */
- m = ieee80211_encap(ic, m, ni);
+ m = ath_ff_check(sc, txq, bf, m, ni);
if (m == NULL) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: encapsulation failure\n",
- __func__);
- sc->sc_stats.ast_tx_encap++;
- goto bad;
+ /* NB: ni ref & bf held on stageq */
+ continue;
}
- /*
- * Check for fragmentation. If this frame
- * has been broken up verify we have enough
- * buffers to send all the fragments so all
- * go out or none...
- */
- if ((m->m_flags & M_FRAG) &&
- !ath_txfrag_setup(sc, &frags, m, ni)) {
- DPRINTF(sc, ATH_DEBUG_XMIT,
- "%s: out of txfrag buffers\n", __func__);
- ic->ic_stats.is_tx_nobuf++; /* XXX */
- ath_freetx(m);
- goto bad;
- }
- } else {
- /*
- * Hack! The referenced node pointer is in the
- * rcvif field of the packet header. This is
- * placed there by ieee80211_mgmt_output because
- * we need to hold the reference with the frame
- * and there's no other way (other than packet
- * tags which we consider too expensive to use)
- * to pass it along.
- */
- ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
- m->m_pkthdr.rcvif = NULL;
-
- wh = mtod(m, struct ieee80211_frame *);
- if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
- IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
- /* fill time stamp */
- u_int64_t tsf;
- u_int32_t *tstamp;
-
- tsf = ath_hal_gettsf64(ah);
- /* XXX: adjust 100us delay to xmit */
- tsf += 100;
- tstamp = (u_int32_t *)&wh[1];
- tstamp[0] = htole32(tsf & 0xffffffff);
- tstamp[1] = htole32(tsf >> 32);
- }
- sc->sc_stats.ast_tx_mgmt++;
}
-
+ ifp->if_opackets++;
+ /*
+ * Encapsulate the packet in prep for transmission.
+ */
+ m = ieee80211_encap(ni, m);
+ if (m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: encapsulation failure\n", __func__);
+ sc->sc_stats.ast_tx_encap++;
+ goto bad;
+ }
+ /*
+ * Check for fragmentation. If this frame
+ * has been broken up verify we have enough
+ * buffers to send all the fragments so all
+ * go out or none...
+ */
+ if ((m->m_flags & M_FRAG) &&
+ !ath_txfrag_setup(sc, &frags, m, ni)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: out of txfrag buffers\n", __func__);
+ ic->ic_stats.is_tx_nobuf++; /* XXX */
+ ath_freetx(m);
+ goto bad;
+ }
nextfrag:
/*
* Pass the frame to the h/w for transmission.
@@ -1735,11 +2010,11 @@ ath_start(struct ifnet *ifp)
* Beware of state changing between frags.
* XXX check sta power-save state?
*/
- if (ic->ic_state != IEEE80211_S_RUN) {
+ if (ni->ni_vap->iv_state != IEEE80211_S_RUN) {
DPRINTF(sc, ATH_DEBUG_XMIT,
"%s: flush fragmented packet, state %s\n",
__func__,
- ieee80211_state_name[ic->ic_state]);
+ ieee80211_state_name[ni->ni_vap->iv_state]);
ath_freetx(next);
goto reclaim;
}
@@ -1751,7 +2026,6 @@ ath_start(struct ifnet *ifp)
}
ifp->if_timer = 5;
- ic->ic_lastdata = ticks;
#if 0
/*
* Flush stale frames from the fast-frame staging queue.
@@ -1765,30 +2039,9 @@ ath_start(struct ifnet *ifp)
static int
ath_media_change(struct ifnet *ifp)
{
-#define IS_UP(ifp) \
- ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
- int error;
-
- error = ieee80211_media_change(ifp);
- if (error == ENETRESET) {
- struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
- /*
- * Adhoc demo mode is just ibss mode w/o beacons
- * (mostly). The hal knows nothing about it;
- * tell it we're operating in ibss mode.
- */
- sc->sc_opmode = HAL_M_IBSS;
- } else
- sc->sc_opmode = ic->ic_opmode;
- if (IS_UP(ifp))
- ath_init(sc); /* XXX lose error */
- error = 0;
- }
- return error;
-#undef IS_UP
+ int error = ieee80211_media_change(ifp);
+ /* NB: only the fixed rate can change and that doesn't need a reset */
+ return (error == ENETRESET ? 0 : error);
}
#ifdef ATH_DEBUG
@@ -1860,7 +2113,7 @@ ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
/*
* Room for both TX+RX MIC keys in one key cache
* slot, just set key at the first index; the hal
- * will handle the reset.
+ * will handle the rest.
*/
memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
#if HAL_ABI_VERSION > 0x06052200
@@ -1869,13 +2122,16 @@ ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
KEYPRINTF(sc, k->wk_keyix, hk, mac);
return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
}
- } else if (k->wk_flags & IEEE80211_KEY_XR) {
- /*
- * TX/RX key goes at first index.
- * The hal handles the MIC keys are index+64.
- */
- memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
- k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic));
+ } else if (k->wk_flags & IEEE80211_KEY_XMIT) {
+#if HAL_ABI_VERSION > 0x06052200
+ memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
+#else
+ memcpy(hk->kv_mic, k->wk_mic, sizeof(hk->kv_mic));
+#endif
+ KEYPRINTF(sc, k->wk_keyix, hk, mac);
+ return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
+ } else if (k->wk_flags & IEEE80211_KEY_RECV) {
+ memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
KEYPRINTF(sc, k->wk_keyix, hk, mac);
return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
}
@@ -2091,10 +2347,10 @@ key_alloc_single(struct ath_softc *sc,
* 64 entries.
*/
static int
-ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
/*
* Group key allocation must be handled specially for
@@ -2108,8 +2364,8 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
* multi-station operation.
*/
if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
- if (!(&ic->ic_nw_keys[0] <= k &&
- k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+ if (!(&vap->iv_nw_keys[0] <= k &&
+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
/* should not happen */
DPRINTF(sc, ATH_DEBUG_KEYCACHE,
"%s: bogus group key\n", __func__);
@@ -2119,7 +2375,7 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
* XXX we pre-allocate the global keys so
* have no way to check if they've already been allocated.
*/
- *keyix = *rxkeyix = k - ic->ic_nw_keys;
+ *keyix = *rxkeyix = k - vap->iv_nw_keys;
return 1;
}
@@ -2148,9 +2404,9 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
* Delete an entry in the key cache allocated by ath_key_alloc.
*/
static int
-ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
struct ath_hal *ah = sc->sc_ah;
const struct ieee80211_cipher *cip = k->wk_cipher;
u_int keyix = k->wk_keyix;
@@ -2188,12 +2444,12 @@ ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
* slot(s) must already have been allocated by ath_key_alloc.
*/
static int
-ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
const u_int8_t mac[IEEE80211_ADDR_LEN])
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
- return ath_keyset(sc, k, mac, ic->ic_bss);
+ return ath_keyset(sc, k, mac, vap->iv_bss);
}
/*
@@ -2203,29 +2459,25 @@ ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
* uses that originate in the driver.
*/
static void
-ath_key_update_begin(struct ieee80211com *ic)
+ath_key_update_begin(struct ieee80211vap *vap)
{
- struct ifnet *ifp = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
-#if 0
- tasklet_disable(&sc->sc_rxtq);
-#endif
+ taskqueue_block(sc->sc_tq);
IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */
}
static void
-ath_key_update_end(struct ieee80211com *ic)
+ath_key_update_end(struct ieee80211vap *vap)
{
- struct ifnet *ifp = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ic->ic_ifp;
struct ath_softc *sc = ifp->if_softc;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
IF_UNLOCK(&ifp->if_snd);
-#if 0
- tasklet_enable(&sc->sc_rxtq);
-#endif
+ taskqueue_unblock(sc->sc_tq);
}
/*
@@ -2233,80 +2485,101 @@ ath_key_update_end(struct ieee80211com *ic)
* operating mode and state:
*
* o always accept unicast, broadcast, and multicast traffic
- * o maintain current state of phy error reception (the hal
- * may enable phy error frames for noise immunity work)
+ * o accept PHY error frames when hardware doesn't have MIB support
+ * to count and we need them for ANI (sta mode only at the moment)
+ * and we are not scanning (ANI is disabled)
+ * NB: only with recent hal's; older hal's add rx filter bits out
+ * of sight and we need to blindly preserve them
* o probe request frames are accepted only when operating in
* hostap, adhoc, or monitor modes
- * o enable promiscuous mode according to the interface state
+ * o enable promiscuous mode
+ * - when in monitor mode
+ * - if interface marked PROMISC (assumes bridge setting is filtered)
* o accept beacons:
- * - when operating in adhoc mode so the 802.11 layer creates
- * node table entries for peers,
* - when operating in station mode for collecting rssi data when
* the station is otherwise quiet, or
+ * - when operating in adhoc mode so the 802.11 layer creates
+ * node table entries for peers,
* - when scanning
+ * - when doing s/w beacon miss (e.g. for ap+sta)
+ * - when operating in ap mode in 11g to detect overlapping bss that
+ * require protection
* o accept control frames:
* - when in monitor mode
+ * XXX BAR frames for 11n
+ * XXX HT protection for 11n
*/
static u_int32_t
ath_calcrxfilter(struct ath_softc *sc)
{
-#define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)
- struct ieee80211com *ic = &sc->sc_ic;
- struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
u_int32_t rfilt;
- rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE)
+#if HAL_ABI_VERSION < 0x08011600
+ rfilt = (ath_hal_getrxfilter(sc->sc_ah) &
+ (HAL_RX_FILTER_PHYRADAR | HAL_RX_FILTER_PHYERR))
| HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+#else
+ rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ !sc->sc_needmib && !sc->sc_scanning)
+ rfilt |= HAL_RX_FILTER_PHYERR;
+#endif
if (ic->ic_opmode != IEEE80211_M_STA)
rfilt |= HAL_RX_FILTER_PROBEREQ;
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- (ifp->if_flags & IFF_PROMISC))
+ if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC))
rfilt |= HAL_RX_FILTER_PROM;
if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_opmode == IEEE80211_M_IBSS ||
- sc->sc_scanning)
+ sc->sc_opmode == HAL_M_IBSS ||
+ sc->sc_swbmiss || sc->sc_scanning)
+ rfilt |= HAL_RX_FILTER_BEACON;
+ /*
+ * NB: We don't recalculate the rx filter when
+ * ic_protmode changes; otherwise we could do
+ * this only when ic_protmode != NONE.
+ */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
rfilt |= HAL_RX_FILTER_BEACON;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
+ DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, %s if_flags 0x%x\n",
+ __func__, rfilt, ieee80211_opmode_name[ic->ic_opmode], ifp->if_flags);
return rfilt;
-#undef RX_FILTER_PRESERVE
}
static void
-ath_mode_init(struct ath_softc *sc)
+ath_update_promisc(struct ifnet *ifp)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ath_hal *ah = sc->sc_ah;
- struct ifnet *ifp = sc->sc_ifp;
- u_int32_t rfilt, mfilt[2], val;
- u_int8_t pos;
- struct ifmultiaddr *ifma;
+ struct ath_softc *sc = ifp->if_softc;
+ u_int32_t rfilt;
/* configure rx filter */
rfilt = ath_calcrxfilter(sc);
- ath_hal_setrxfilter(ah, rfilt);
+ ath_hal_setrxfilter(sc->sc_ah, rfilt);
- /* configure operational mode */
- ath_hal_setopmode(ah);
+ DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt);
+}
- /*
- * Handle any link-level address change. Note that we only
- * need to force ic_myaddr; any other addresses are handled
- * as a byproduct of the ifnet code marking the interface
- * down then up.
- *
- * XXX should get from lladdr instead of arpcom but that's more work
- */
- IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
- ath_hal_setmac(ah, ic->ic_myaddr);
+static void
+ath_update_mcast(struct ifnet *ifp)
+{
+ struct ath_softc *sc = ifp->if_softc;
+ u_int32_t mfilt[2];
/* calculate and install multicast filter */
if ((ifp->if_flags & IFF_ALLMULTI) == 0) {
+ struct ifmultiaddr *ifma;
+ /*
+ * Merge multicast addresses to form the hardware filter.
+ */
mfilt[0] = mfilt[1] = 0;
- IF_ADDR_LOCK(ifp);
+ IF_ADDR_LOCK(ifp); /* XXX need some fiddling to remove? */
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
caddr_t dl;
+ u_int32_t val;
+ u_int8_t pos;
/* calculate XOR of eight 6bit values */
dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
@@ -2318,12 +2591,41 @@ ath_mode_init(struct ath_softc *sc)
mfilt[pos / 32] |= (1 << (pos % 32));
}
IF_ADDR_UNLOCK(ifp);
- } else {
+ } else
mfilt[0] = mfilt[1] = ~0;
- }
- ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]);
- DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x, MC filter %08x:%08x\n",
- __func__, rfilt, mfilt[0], mfilt[1]);
+ ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]);
+ DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n",
+ __func__, mfilt[0], mfilt[1]);
+}
+
+static void
+ath_mode_init(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t rfilt;
+
+ /* configure rx filter */
+ rfilt = ath_calcrxfilter(sc);
+ ath_hal_setrxfilter(ah, rfilt);
+
+ /* configure operational mode */
+ ath_hal_setopmode(ah);
+
+ /*
+ * Handle any link-level address change. Note that we only
+ * need to force ic_myaddr; any other addresses are handled
+ * as a byproduct of the ifnet code marking the interface
+ * down then up.
+ *
+ * XXX should get from lladdr instead of arpcom but that's more work
+ */
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+ ath_hal_setmac(ah, ic->ic_myaddr);
+
+ /* calculate and install multicast filter */
+ ath_update_mcast(ifp);
}
/*
@@ -2332,7 +2634,7 @@ ath_mode_init(struct ath_softc *sc)
static void
ath_setslottime(struct ath_softc *sc)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
u_int usec;
@@ -2367,7 +2669,7 @@ static void
ath_updateslot(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = ifp->if_l2com;
/*
* When not coordinating the BSS, change the hardware
@@ -2404,7 +2706,7 @@ static int
ath_beaconq_config(struct ath_softc *sc)
{
#define ATH_EXPONENT_TO_VALUE(v) ((1<<(v))-1)
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
HAL_TXQ_INFO qi;
@@ -2444,38 +2746,81 @@ ath_beaconq_config(struct ath_softc *sc)
static int
ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni)
{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_vap *avp = ATH_VAP(vap);
struct ath_buf *bf;
struct mbuf *m;
int error;
- bf = STAILQ_FIRST(&sc->sc_bbuf);
- if (bf == NULL) {
- DPRINTF(sc, ATH_DEBUG_BEACON, "%s: no dma buffers\n", __func__);
- sc->sc_stats.ast_be_nombuf++; /* XXX */
- return ENOMEM; /* XXX */
+ bf = avp->av_bcbuf;
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
}
+
/*
* NB: the beacon data buffer must be 32-bit aligned;
* we assume the mbuf routines will return us something
* with this alignment (perhaps should assert).
*/
- m = ieee80211_beacon_alloc(ni, &sc->sc_boff);
+ m = ieee80211_beacon_alloc(ni, &avp->av_boff);
if (m == NULL) {
- DPRINTF(sc, ATH_DEBUG_BEACON, "%s: cannot get mbuf\n",
- __func__);
+ device_printf(sc->sc_dev, "%s: cannot get mbuf\n", __func__);
sc->sc_stats.ast_be_nombuf++;
return ENOMEM;
}
error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
bf->bf_segs, &bf->bf_nseg,
BUS_DMA_NOWAIT);
- if (error == 0) {
- bf->bf_m = m;
- bf->bf_node = ieee80211_ref_node(ni);
- } else {
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: cannot map mbuf, bus_dmamap_load_mbuf_sg returns %d\n",
+ __func__, error);
m_freem(m);
+ return error;
}
- return error;
+
+ /*
+ * Calculate a TSF adjustment factor required for staggered
+ * beacons. Note that we assume the format of the beacon
+ * frame leaves the tstamp field immediately following the
+ * header.
+ */
+ if (sc->sc_stagbeacons && avp->av_bslot > 0) {
+ uint64_t tsfadjust;
+ struct ieee80211_frame *wh;
+
+ /*
+ * The beacon interval is in TU's; the TSF is in usecs.
+ * We figure out how many TU's to add to align the timestamp
+ * then convert to TSF units and handle byte swapping before
+ * inserting it in the frame. The hardware will then add this
+ * each time a beacon frame is sent. Note that we align vap's
+ * 1..N and leave vap 0 untouched. This means vap 0 has a
+ * timestamp in one beacon interval while the others get a
+ * timstamp aligned to the next interval.
+ */
+ tsfadjust = ni->ni_intval *
+ (ATH_BCBUF - avp->av_bslot) / ATH_BCBUF;
+ tsfadjust = htole64(tsfadjust << 10); /* TU -> TSF */
+
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: %s beacons bslot %d intval %u tsfadjust %llu\n",
+ __func__, sc->sc_stagbeacons ? "stagger" : "burst",
+ avp->av_bslot, ni->ni_intval, le64toh(tsfadjust));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust));
+ }
+ bf->bf_m = m;
+ bf->bf_node = ieee80211_ref_node(ni);
+
+ return 0;
}
/*
@@ -2516,8 +2861,12 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
* Switch antenna every 4 beacons.
* XXX assumes two antenna
*/
- antenna = sc->sc_txantenna != 0 ? sc->sc_txantenna
- : (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1);
+ if (sc->sc_txantenna != 0)
+ antenna = sc->sc_txantenna;
+ else if (sc->sc_stagbeacons && sc->sc_nbcnvaps != 0)
+ antenna = ((sc->sc_stats.ast_be_xmit / sc->sc_nbcnvaps) & 4 ? 2 : 1);
+ else
+ antenna = (sc->sc_stats.ast_be_xmit & 4 ? 2 : 1);
}
KASSERT(bf->bf_nseg == 1,
@@ -2527,7 +2876,7 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
* Calculate rate code.
* XXX everything at min xmit rate
*/
- rix = sc->sc_minrateix;
+ rix = 0;
rt = sc->sc_currates;
rate = rt->info[rix].rateCode;
if (USE_SHPREAMBLE(ic))
@@ -2551,14 +2900,16 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf)
, AH_TRUE /* last segment */
, ds /* first descriptor */
);
+#if 0
+ ath_desc_swap(ds);
+#endif
#undef USE_SHPREAMBLE
}
static void
-ath_beacon_update(struct ieee80211com *ic, int item)
+ath_beacon_update(struct ieee80211vap *vap, int item)
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
- struct ieee80211_beacon_offsets *bo = &sc->sc_boff;
+ struct ieee80211_beacon_offsets *bo = &ATH_VAP(vap)->av_boff;
setbit(bo->bo_flags, item);
}
@@ -2586,24 +2937,14 @@ static void
ath_beacon_proc(void *arg, int pending)
{
struct ath_softc *sc = arg;
- struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf);
- struct ieee80211_node *ni = bf->bf_node;
- struct ieee80211com *ic = ni->ni_ic;
struct ath_hal *ah = sc->sc_ah;
- struct ath_txq *cabq = sc->sc_cabq;
- struct mbuf *m;
- int ncabq, nmcastq, error, otherant;
+ struct ieee80211vap *vap;
+ struct ath_buf *bf;
+ int slot, otherant;
+ uint32_t bfaddr;
DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: pending %u\n",
__func__, pending);
-
- if (ic->ic_opmode == IEEE80211_M_STA ||
- ic->ic_opmode == IEEE80211_M_MONITOR ||
- bf == NULL || bf->bf_m == NULL) {
- DPRINTF(sc, ATH_DEBUG_ANY, "%s: ic_flags=%x bf=%p bf_m=%p\n",
- __func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL);
- return;
- }
/*
* Check if the previous beacon has gone out. If
* not don't try to post another, skip this period
@@ -2627,39 +2968,34 @@ ath_beacon_proc(void *arg, int pending)
sc->sc_bmisscount = 0;
}
- /*
- * Update dynamic beacon contents. If this returns
- * non-zero then we need to remap the memory because
- * the beacon frame changed size (probably because
- * of the TIM bitmap).
- */
- m = bf->bf_m;
- nmcastq = sc->sc_mcastq.axq_depth;
- ncabq = ath_hal_numtxpending(ah, cabq->axq_qnum);
- if (ieee80211_beacon_update(bf->bf_node, &sc->sc_boff, m, ncabq+nmcastq)) {
- /* XXX too conservative? */
- bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
- bf->bf_segs, &bf->bf_nseg,
- BUS_DMA_NOWAIT);
- if (error != 0) {
- if_printf(ic->ic_ifp,
- "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
- __func__, error);
- return;
+ if (sc->sc_stagbeacons) { /* staggered beacons */
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t tsftu;
+
+ tsftu = ath_hal_gettsf32(ah) >> 10;
+ /* XXX lintval */
+ slot = ((tsftu % ic->ic_lintval) * ATH_BCBUF) / ic->ic_lintval;
+ vap = sc->sc_bslot[(slot+1) % ATH_BCBUF];
+ bfaddr = 0;
+ if (vap != NULL && vap->iv_state == IEEE80211_S_RUN) {
+ bf = ath_beacon_generate(sc, vap);
+ if (bf != NULL)
+ bfaddr = bf->bf_daddr;
}
- }
- if (ncabq && (sc->sc_boff.bo_tim[4] & 1)) {
- /*
- * CABQ traffic from the previous DTIM is still pending.
- * This is ok for now but when there are multiple vap's
- * and we are using staggered beacons we'll want to drain
- * the cabq before loading frames for the different vap.
- */
- DPRINTF(sc, ATH_DEBUG_BEACON,
- "%s: cabq did not drain, mcastq %u cabq %u/%u\n",
- __func__, nmcastq, ncabq, cabq->axq_depth);
- sc->sc_stats.ast_cabq_busy++;
+ } else { /* burst'd beacons */
+ uint32_t *bflink = &bfaddr;
+
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ vap = sc->sc_bslot[slot];
+ if (vap != NULL && vap->iv_state == IEEE80211_S_RUN) {
+ bf = ath_beacon_generate(sc, vap);
+ if (bf != NULL) {
+ *bflink = bf->bf_daddr;
+ bflink = &bf->bf_desc->ds_link;
+ }
+ }
+ }
+ *bflink = 0; /* terminate list */
}
/*
@@ -2670,9 +3006,10 @@ ath_beacon_proc(void *arg, int pending)
* beacon interval to note the state change.
*/
/* XXX locking */
- if (sc->sc_updateslot == UPDATE)
+ if (sc->sc_updateslot == UPDATE) {
sc->sc_updateslot = COMMIT; /* commit next beacon */
- else if (sc->sc_updateslot == COMMIT)
+ sc->sc_slotupdate = slot;
+ } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
ath_setslottime(sc); /* commit change to h/w */
/*
@@ -2681,64 +3018,159 @@ ath_beacon_proc(void *arg, int pending)
* on the non-default antenna.
* XXX assumes 2 anntenae
*/
- otherant = sc->sc_defant & 1 ? 2 : 1;
- if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
- ath_setdefantenna(sc, otherant);
- sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+ if (!sc->sc_diversity && (!sc->sc_stagbeacons || slot == 0)) {
+ otherant = sc->sc_defant & 1 ? 2 : 1;
+ if (sc->sc_ant_tx[otherant] > sc->sc_ant_tx[sc->sc_defant] + 2)
+ ath_setdefantenna(sc, otherant);
+ sc->sc_ant_tx[1] = sc->sc_ant_tx[2] = 0;
+ }
- /*
- * Construct tx descriptor.
- */
- ath_beacon_setup(sc, bf);
+ if (bfaddr != 0) {
+ /*
+ * Stop any current dma and put the new frame on the queue.
+ * This should never fail since we check above that no frames
+ * are still pending on the queue.
+ */
+ if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
+ DPRINTF(sc, ATH_DEBUG_ANY,
+ "%s: beacon queue %u did not stop?\n",
+ __func__, sc->sc_bhalq);
+ }
+ /* NB: cabq traffic should already be queued and primed */
+ ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr);
+ ath_hal_txstart(ah, sc->sc_bhalq);
+
+ sc->sc_stats.ast_be_xmit++;
+ }
+}
+
+static struct ath_buf *
+ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_vap *avp = ATH_VAP(vap);
+ struct ath_txq *cabq = sc->sc_cabq;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int nmcastq, error;
+
+ KASSERT(vap->iv_state == IEEE80211_S_RUN,
+ ("not running, state %d", vap->iv_state));
+ KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
/*
- * Stop any current dma and put the new frame on the queue.
- * This should never fail since we check above that no frames
- * are still pending on the queue.
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
*/
- if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
- DPRINTF(sc, ATH_DEBUG_ANY,
- "%s: beacon queue %u did not stop?\n",
- __func__, sc->sc_bhalq);
+ bf = avp->av_bcbuf;
+ m = bf->bf_m;
+ nmcastq = avp->av_mcastq.axq_depth;
+ if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, nmcastq)) {
+ /* XXX too conservative? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(vap->iv_ifp,
+ "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
+ __func__, error);
+ return NULL;
+ }
}
+ if ((avp->av_boff.bo_tim[4] & 1) && cabq->axq_depth) {
+ DPRINTF(sc, ATH_DEBUG_BEACON,
+ "%s: cabq did not drain, mcastq %u cabq %u\n",
+ __func__, nmcastq, cabq->axq_depth);
+ sc->sc_stats.ast_cabq_busy++;
+ if (sc->sc_nvaps > 1 && sc->sc_stagbeacons) {
+ /*
+ * CABQ traffic from a previous vap is still pending.
+ * We must drain the q before this beacon frame goes
+ * out as otherwise this vap's stations will get cab
+ * frames from a different vap.
+ * XXX could be slow causing us to miss DBA
+ */
+ ath_tx_draintxq(sc, cabq);
+ }
+ }
+ ath_beacon_setup(sc, bf);
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
/*
* Enable the CAB queue before the beacon queue to
* insure cab frames are triggered by this beacon.
*/
- if (sc->sc_boff.bo_tim_len && (sc->sc_boff.bo_tim[4] & 1)) {
+ if (avp->av_boff.bo_tim[4] & 1) {
+ struct ath_hal *ah = sc->sc_ah;
+
/* NB: only at DTIM */
ATH_TXQ_LOCK(cabq);
- ATH_TXQ_LOCK(&sc->sc_mcastq);
+ ATH_TXQ_LOCK(&avp->av_mcastq);
if (nmcastq) {
struct ath_buf *bfm;
/*
* Move frames from the s/w mcast q to the h/w cab q.
+ * XXX MORE_DATA bit
*/
- bfm = STAILQ_FIRST(&sc->sc_mcastq.axq_q);
+ bfm = STAILQ_FIRST(&avp->av_mcastq.axq_q);
if (cabq->axq_link != NULL) {
*cabq->axq_link = bfm->bf_daddr;
} else
ath_hal_puttxbuf(ah, cabq->axq_qnum,
bfm->bf_daddr);
- ath_txqmove(cabq, &sc->sc_mcastq);
+ ath_txqmove(cabq, &avp->av_mcastq);
sc->sc_stats.ast_cabq_xmit += nmcastq;
}
/* NB: gated by beacon so safe to start here */
ath_hal_txstart(ah, cabq->axq_qnum);
ATH_TXQ_UNLOCK(cabq);
- ATH_TXQ_UNLOCK(&sc->sc_mcastq);
+ ATH_TXQ_UNLOCK(&avp->av_mcastq);
}
+ return bf;
+}
+
+static void
+ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211vap *vap)
+{
+ struct ath_vap *avp = ATH_VAP(vap);
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ struct mbuf *m;
+ int error;
+
+ KASSERT(avp->av_bcbuf != NULL, ("no beacon buffer"));
+
+ /*
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
+ */
+ bf = avp->av_bcbuf;
+ m = bf->bf_m;
+ if (ieee80211_beacon_update(bf->bf_node, &avp->av_boff, m, 0)) {
+ /* XXX too conservative? */
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, bf->bf_dmamap, m,
+ bf->bf_segs, &bf->bf_nseg,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if_printf(vap->iv_ifp,
+ "%s: bus_dmamap_load_mbuf_sg failed, error %u\n",
+ __func__, error);
+ return;
+ }
+ }
+ ath_beacon_setup(sc, bf);
+ bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
+
+ /* NB: caller is known to have already stopped tx dma */
ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
ath_hal_txstart(ah, sc->sc_bhalq);
- DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
- "%s: TXDP[%u] = %p (%p)\n", __func__,
- sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc);
-
- sc->sc_stats.ast_be_xmit++;
}
/*
@@ -2756,6 +3188,25 @@ ath_bstuck_proc(void *arg, int pending)
}
/*
+ * Reclaim beacon resources and return buffer to the pool.
+ */
+static void
+ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf)
+{
+
+ if (bf->bf_m != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+ if (bf->bf_node != NULL) {
+ ieee80211_free_node(bf->bf_node);
+ bf->bf_node = NULL;
+ }
+ STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
+}
+
+/*
* Reclaim beacon resources.
*/
static void
@@ -2792,29 +3243,46 @@ ath_beacon_free(struct ath_softc *sc)
* we've associated with.
*/
static void
-ath_beacon_config(struct ath_softc *sc)
+ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap)
{
#define TSF_TO_TU(_h,_l) \
((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
#define FUDGE 2
struct ath_hal *ah = sc->sc_ah;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni = ic->ic_bss;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211_node *ni;
u_int32_t nexttbtt, intval, tsftu;
u_int64_t tsf;
+ if (vap == NULL)
+ vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */
+ ni = vap->iv_bss;
+
/* extract tstamp from last beacon and convert to TU */
nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4),
LE_READ_4(ni->ni_tstamp.data));
- /* NB: the beacon interval is kept internally in TU's */
- intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ /*
+ * For multi-bss ap support beacons are either staggered
+ * evenly over N slots or burst together. For the former
+ * arrange for the SWBA to be delivered for each slot.
+ * Slots that are not occupied will generate nothing.
+ */
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ if (sc->sc_stagbeacons)
+ intval /= ATH_BCBUF;
+ } else {
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = ni->ni_intval & HAL_BEACON_PERIOD;
+ }
if (nexttbtt == 0) /* e.g. for ap mode */
nexttbtt = intval;
else if (intval) /* NB: can be 0 for monitor mode */
nexttbtt = roundup(nexttbtt, intval);
DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
__func__, nexttbtt, intval, ni->ni_intval);
- if (ic->ic_opmode == IEEE80211_M_STA) {
+ if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) {
HAL_BEACON_STATE bs;
int dtimperiod, dtimcount;
int cfpperiod, cfpcount;
@@ -2870,7 +3338,7 @@ ath_beacon_config(struct ath_softc *sc)
* before taking a BMISS interrupt.
* Note that we clamp the result to at most 10 beacons.
*/
- bs.bs_bmissthreshold = ic->ic_bmissthreshold;
+ bs.bs_bmissthreshold = vap->iv_bmissthreshold;
if (bs.bs_bmissthreshold > 10)
bs.bs_bmissthreshold = 10;
else if (bs.bs_bmissthreshold <= 0)
@@ -2953,7 +3421,7 @@ ath_beacon_config(struct ath_softc *sc)
* ibss mode load it once here.
*/
if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol)
- ath_beacon_proc(sc, 0);
+ ath_beacon_start_adhoc(sc, vap);
}
sc->sc_syncbeacon = 0;
#undef FUDGE
@@ -3130,7 +3598,7 @@ ath_desc_alloc(struct ath_softc *sc)
}
error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
- "beacon", 1, 1);
+ "beacon", ATH_BCBUF, 1);
if (error != 0) {
ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
@@ -3164,7 +3632,6 @@ ath_node_alloc(struct ieee80211_node_table *nt)
/* XXX stat+msg */
return NULL;
}
- an->an_avgrssi = ATH_RSSI_DUMMY_MARKER;
ath_rate_node_init(sc, an);
DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an);
@@ -3183,26 +3650,6 @@ ath_node_free(struct ieee80211_node *ni)
sc->sc_node_free(ni);
}
-static int8_t
-ath_node_getrssi(const struct ieee80211_node *ni)
-{
-#define HAL_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
- u_int32_t avgrssi = ATH_NODE_CONST(ni)->an_avgrssi;
- int32_t rssi;
-
- /*
- * When only one frame is received there will be no state in
- * avgrssi so fallback on the value recorded by the 802.11 layer.
- */
- if (avgrssi != ATH_RSSI_DUMMY_MARKER)
- rssi = HAL_EP_RND(avgrssi, HAL_RSSI_EP_MULTIPLIER);
- else
- rssi = ni->ni_rssi;
- return rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
-#undef HAL_EP_RND
-}
-
static void
ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
{
@@ -3211,7 +3658,7 @@ ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
struct ath_hal *ah = sc->sc_ah;
HAL_CHANNEL hchan;
- *rssi = ath_node_getrssi(ni);
+ *rssi = ic->ic_node_getrssi(ni);
if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
ath_mapchan(&hchan, ni->ni_chan);
*noise = ath_hal_getchannoise(ah, &hchan);
@@ -3309,33 +3756,33 @@ ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf)
* and to do ibss merges.
*/
static void
-ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni,
+ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int noise, u_int32_t rstamp)
{
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
/*
* Call up first so subsequent work can use information
* potentially stored in the node (e.g. for ibss merge).
*/
- sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, noise, rstamp);
+ ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_BEACON:
/* update rssi statistics for use by the hal */
ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi);
if (sc->sc_syncbeacon &&
- ni == ic->ic_bss && ic->ic_state == IEEE80211_S_RUN) {
+ ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) {
/*
* Resync beacon timers using the tsf of the beacon
* frame we just received.
*/
- ath_beacon_config(sc);
+ ath_beacon_config(sc, vap);
}
/* fall thru... */
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
- if (ic->ic_opmode == IEEE80211_M_IBSS &&
- ic->ic_state == IEEE80211_S_RUN) {
+ if (vap->iv_opmode == IEEE80211_M_IBSS &&
+ vap->iv_state == IEEE80211_S_RUN) {
u_int64_t tsf = ath_extend_tsf(rstamp,
ath_hal_gettsf64(sc->sc_ah));
/*
@@ -3377,14 +3824,13 @@ ath_setdefantenna(struct ath_softc *sc, u_int antenna)
}
static int
-ath_rx_tap(struct ath_softc *sc, struct mbuf *m,
+ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
{
#define CHANNEL_HT (CHANNEL_HT20|CHANNEL_HT40PLUS|CHANNEL_HT40MINUS)
+ struct ath_softc *sc = ifp->if_softc;
u_int8_t rix;
- KASSERT(sc->sc_drvbpf != NULL, ("no tap"));
-
/*
* Discard anything shorter than an ack or cts.
*/
@@ -3425,13 +3871,28 @@ ath_rx_tap(struct ath_softc *sc, struct mbuf *m,
sc->sc_rx_th.wr_antnoise = nf;
sc->sc_rx_th.wr_antenna = rs->rs_antenna;
- bpf_mtap2(sc->sc_drvbpf, &sc->sc_rx_th, sc->sc_rx_th_len, m);
+ bpf_mtap2(ifp->if_bpf, &sc->sc_rx_th, sc->sc_rx_th_len, m);
return 1;
#undef CHANNEL_HT
}
static void
+ath_handle_micerror(struct ieee80211com *ic,
+ struct ieee80211_frame *wh, int keyix)
+{
+ struct ieee80211_node *ni;
+
+ /* XXX recheck MIC to deal w/ chips that lie */
+ /* XXX discard MIC errors on !data frames */
+ ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) wh);
+ if (ni != NULL) {
+ ieee80211_notify_michael_failure(ni->ni_vap, wh, keyix);
+ ieee80211_free_node(ni);
+ }
+}
+
+static void
ath_rx_proc(void *arg, int npending)
{
#define PA2DESC(_sc, _pa) \
@@ -3439,21 +3900,19 @@ ath_rx_proc(void *arg, int npending)
((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
struct ath_softc *sc = arg;
struct ath_buf *bf;
- struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds;
struct ath_rx_status *rs;
struct mbuf *m;
struct ieee80211_node *ni;
- struct ath_node *an;
int len, type, ngood;
u_int phyerr;
HAL_STATUS status;
int16_t nf;
u_int64_t tsf;
-
DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending);
ngood = 0;
nf = ath_hal_getchannoise(ah, &sc->sc_curchan);
@@ -3540,11 +3999,10 @@ ath_rx_proc(void *arg, int npending)
bus_dmamap_sync(sc->sc_dmat,
bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
- ieee80211_notify_michael_failure(ic,
+ ath_handle_micerror(ic,
mtod(m, struct ieee80211_frame *),
sc->sc_splitmic ?
- rs->rs_keyix-32 : rs->rs_keyix
- );
+ rs->rs_keyix-32 : rs->rs_keyix);
}
}
ifp->if_ierrors++;
@@ -3562,14 +4020,14 @@ rx_error:
* pass decrypt+mic errors but others may be
* interesting (e.g. crc).
*/
- if (bpf_peers_present(sc->sc_drvbpf) &&
+ if (bpf_peers_present(ifp->if_bpf) &&
(rs->rs_status & sc->sc_monpass)) {
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
BUS_DMASYNC_POSTREAD);
/* NB: bpf needs the mbuf length setup */
len = rs->rs_datalen;
m->m_pkthdr.len = m->m_len = len;
- (void) ath_rx_tap(sc, m, rs, tsf, nf);
+ (void) ath_rx_tap(ifp, m, rs, tsf, nf);
}
/* XXX pass MIC errors up for s/w reclaculation */
goto rx_next;
@@ -3624,10 +4082,11 @@ rx_accept:
m->m_pkthdr.len = len;
}
+ ifp->if_ipackets++;
sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
- if (bpf_peers_present(sc->sc_drvbpf) &&
- !ath_rx_tap(sc, m, rs, tsf, nf)) {
+ if (bpf_peers_present(ifp->if_bpf) &&
+ !ath_rx_tap(ifp, m, rs, tsf, nf)) {
m_freem(m); /* XXX reclaim */
goto rx_next;
}
@@ -3661,18 +4120,30 @@ rx_accept:
mtod(m, const struct ieee80211_frame_min *),
rs->rs_keyix == HAL_RXKEYIX_INVALID ?
IEEE80211_KEYIX_NONE : rs->rs_keyix);
+ if (ni != NULL) {
+ /*
+ * Sending station is known, dispatch directly.
+ */
+ type = ieee80211_input(ni, m,
+ rs->rs_rssi, nf, rs->rs_tstamp);
+ ieee80211_free_node(ni);
+ /*
+ * Arrange to update the last rx timestamp only for
+ * frames from our ap when operating in station mode.
+ * This assumes the rx key is always setup when
+ * associated.
+ */
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ rs->rs_keyix != HAL_RXKEYIX_INVALID)
+ ngood++;
+ } else {
+ type = ieee80211_input_all(ic, m,
+ rs->rs_rssi, nf, rs->rs_tstamp);
+ }
/*
* Track rx rssi and do any rx antenna management.
*/
- an = ATH_NODE(ni);
- ATH_RSSI_LPF(an->an_avgrssi, rs->rs_rssi);
ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi);
- /*
- * Send frame up for processing.
- */
- type = ieee80211_input(ic, m, ni,
- rs->rs_rssi, nf, rs->rs_tstamp);
- ieee80211_free_node(ni);
if (sc->sc_diversity) {
/*
* When using fast diversity, change the default rx
@@ -3698,14 +4169,6 @@ rx_accept:
} else if (ticks - sc->sc_ledevent >= sc->sc_ledidle)
ath_led_event(sc, ATH_LED_POLL);
}
- /*
- * Arrange to update the last rx timestamp only for
- * frames from our ap when operating in station mode.
- * This assumes the rx key is always setup when associated.
- */
- if (ic->ic_opmode == IEEE80211_M_STA &&
- rs->rs_keyix != HAL_RXKEYIX_INVALID)
- ngood++;
rx_next:
STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
} while (ath_rxbuf_init(sc, bf) == 0);
@@ -3715,7 +4178,6 @@ rx_next:
if (ngood)
sc->sc_lastrx = tsf;
- /* NB: may want to check mgtq too */
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 &&
!IFQ_IS_EMPTY(&ifp->if_snd))
ath_start(ifp);
@@ -3825,7 +4287,8 @@ ath_txq_update(struct ath_softc *sc, int ac)
{
#define ATH_EXPONENT_TO_VALUE(v) ((1<<v)-1)
#define ATH_TXOP_TO_US(v) (v<<5)
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_txq *txq = sc->sc_ac2q[ac];
struct wmeParams *wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[ac];
struct ath_hal *ah = sc->sc_ah;
@@ -3838,7 +4301,7 @@ ath_txq_update(struct ath_softc *sc, int ac)
qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit);
if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) {
- device_printf(sc->sc_dev, "unable to update hardware queue "
+ if_printf(ifp, "unable to update hardware queue "
"parameters for %s traffic!\n",
ieee80211_wme_acnames[ac]);
return 0;
@@ -3888,7 +4351,6 @@ ath_tx_cleanup(struct ath_softc *sc)
for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->sc_txq[i]);
- ATH_TXQ_LOCK_DESTROY(&sc->sc_mcastq);
}
/*
@@ -4016,8 +4478,8 @@ ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
* to avoid possible races.
*/
ATH_TXQ_LOCK(txq);
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- if (txq != &sc->sc_mcastq) {
+ if (txq->axq_qnum != ATH_TXQ_SWQ) {
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
if (txq->axq_link == NULL) {
ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
DPRINTF(sc, ATH_DEBUG_XMIT,
@@ -4034,8 +4496,20 @@ ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
ath_hal_txstart(ah, txq->axq_qnum);
} else {
- if (txq->axq_link != NULL)
+ if (txq->axq_link != NULL) {
+ struct ath_buf *last = ATH_TXQ_LAST(txq);
+ struct ieee80211_frame *wh;
+
+ /* mark previous frame */
+ wh = mtod(last->bf_m, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ bus_dmamap_sync(sc->sc_dmat, last->bf_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ /* link descriptor */
*txq->axq_link = bf->bf_daddr;
+ }
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
txq->axq_link = &bf->bf_desc[bf->bf_nseg - 1].ds_link;
}
ATH_TXQ_UNLOCK(txq);
@@ -4045,9 +4519,11 @@ static int
ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf,
struct mbuf *m0)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_vap *avp = ATH_VAP(vap);
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
int error, iswep, ismcast, isfrag, ismrr;
int keyix, hdrlen, pktlen, try0;
@@ -4083,7 +4559,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
* frame. The only reason this can fail is because of an
* unknown or unsupported cipher/key type.
*/
- k = ieee80211_crypto_encap(ic, ni, m0);
+ k = ieee80211_crypto_encap(ni, m0);
if (k == NULL) {
/*
* This can happen when the key is yanked after the
@@ -4156,6 +4632,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
an = ATH_NODE(ni);
flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */
ismrr = 0; /* default no multi-rate retry*/
+ pri = M_WME_GETAC(m0); /* honor classification */
/*
* Calculate Atheros packet type from IEEE80211 packet header,
* setup for rate calculations, and select h/w transmit queue.
@@ -4171,32 +4648,20 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
atype = HAL_PKT_TYPE_ATIM;
else
atype = HAL_PKT_TYPE_NORMAL; /* XXX */
- rix = sc->sc_minrateix;
+ rix = an->an_mgmtrix;
txrate = rt->info[rix].rateCode;
if (shortPreamble)
txrate |= rt->info[rix].shortPreamble;
try0 = ATH_TXMGTTRY;
- /* NB: force all management frames to highest queue */
- if (ni->ni_flags & IEEE80211_NODE_QOS) {
- /* NB: force all management frames to highest queue */
- pri = WME_AC_VO;
- } else
- pri = WME_AC_BE;
flags |= HAL_TXDESC_INTREQ; /* force interrupt */
break;
case IEEE80211_FC0_TYPE_CTL:
atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */
- rix = sc->sc_minrateix;
+ rix = an->an_mgmtrix;
txrate = rt->info[rix].rateCode;
if (shortPreamble)
txrate |= rt->info[rix].shortPreamble;
try0 = ATH_TXMGTTRY;
- /* NB: force all ctl frames to highest queue */
- if (ni->ni_flags & IEEE80211_NODE_QOS) {
- /* NB: force all ctl frames to highest queue */
- pri = WME_AC_VO;
- } else
- pri = WME_AC_BE;
flags |= HAL_TXDESC_INTREQ; /* force interrupt */
break;
case IEEE80211_FC0_TYPE_DATA:
@@ -4207,16 +4672,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
* rate to use.
*/
if (ismcast) {
- /*
- * Check mcast rate setting in case it's changed.
- * XXX move out of fastpath
- */
- if (ic->ic_mcast_rate != sc->sc_mcastrate) {
- sc->sc_mcastrix =
- ath_tx_findrix(rt, ic->ic_mcast_rate);
- sc->sc_mcastrate = ic->ic_mcast_rate;
- }
- rix = sc->sc_mcastrix;
+ rix = an->an_mcastrix;
txrate = rt->info[rix].rateCode;
if (shortPreamble)
txrate |= rt->info[rix].shortPreamble;
@@ -4229,7 +4685,6 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
if (try0 != ATH_TXMAXTRY)
ismrr = 1;
}
- pri = M_WME_GETAC(m0);
if (cap->cap_wmeParams[pri].wmep_noackPolicy)
flags |= HAL_TXDESC_NOACK;
break;
@@ -4248,17 +4703,15 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
* queue (to prevent out of order delivery) multicast
* frames must be buffered until after the beacon.
*/
- if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth)) {
- txq = &sc->sc_mcastq;
- /* XXX? more bit in 802.11 frame header */
- }
+ if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
+ txq = &avp->av_mcastq;
/*
* Calculate miscellaneous flags.
*/
if (ismcast) {
flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
- } else if (pktlen > ic->ic_rtsthreshold &&
+ } else if (pktlen > vap->iv_rtsthreshold &&
(ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) {
flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
cix = rt->info[rix].controlRate;
@@ -4386,9 +4839,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
sc->sc_hwmap[txrate].ieeerate, -1);
- if (bpf_peers_present(ic->ic_rawbpf))
- bpf_mtap(ic->ic_rawbpf, m0);
- if (bpf_peers_present(sc->sc_drvbpf)) {
+ if (bpf_peers_present(ifp->if_bpf)) {
u_int64_t tsf = ath_hal_gettsf64(ah);
sc->sc_tx_th.wt_tsf = htole64(tsf);
@@ -4401,8 +4852,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
sc->sc_tx_th.wt_txpower = ni->ni_txpower;
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
- bpf_mtap2(sc->sc_drvbpf,
- &sc->sc_tx_th, sc->sc_tx_th_len, m0);
+ bpf_mtap2(ifp->if_bpf, &sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
/*
@@ -4465,7 +4915,8 @@ static int
ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hal *ah = sc->sc_ah;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_buf *bf;
struct ath_desc *ds, *ds0;
struct ath_tx_status *ts;
@@ -4706,10 +5157,12 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
ATH_TXQ_UNLOCK(txq);
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RESET) {
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
ath_printtxbuf(bf, txq->axq_qnum, ix,
ath_hal_txprocdesc(ah, bf->bf_desc,
&bf->bf_status.ds_txstat) == HAL_OK);
- ieee80211_dump_pkt(&sc->sc_ic, mtod(bf->bf_m, caddr_t),
+ ieee80211_dump_pkt(ic, mtod(bf->bf_m, caddr_t),
bf->bf_m->m_len, 0, -1);
}
#endif /* ATH_DEBUG */
@@ -4770,7 +5223,6 @@ ath_draintxq(struct ath_softc *sc)
for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_draintxq(sc, &sc->sc_txq[i]);
- ath_tx_draintxq(sc, &sc->sc_mcastq);
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RESET) {
struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf);
@@ -4778,7 +5230,7 @@ ath_draintxq(struct ath_softc *sc)
ath_printtxbuf(bf, sc->sc_bhalq, 0,
ath_hal_txprocdesc(ah, bf->bf_desc,
&bf->bf_status.ds_txstat) == HAL_OK);
- ieee80211_dump_pkt(&sc->sc_ic, mtod(bf->bf_m, caddr_t),
+ ieee80211_dump_pkt(ifp->if_l2com, mtod(bf->bf_m, caddr_t),
bf->bf_m->m_len, 0, -1);
}
}
@@ -4890,42 +5342,6 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
}
/*
- * Poll for a channel clear indication; this is required
- * for channels requiring DFS and not previously visited
- * and/or with a recent radar detection.
- */
-static void
-ath_dfswait(void *arg)
-{
- struct ath_softc *sc = arg;
- struct ath_hal *ah = sc->sc_ah;
- HAL_CHANNEL hchan;
-
- ath_hal_radar_wait(ah, &hchan);
- DPRINTF(sc, ATH_DEBUG_DFS, "%s: radar_wait %u/%x/%x\n",
- __func__, hchan.channel, hchan.channelFlags, hchan.privFlags);
-
- if (hchan.privFlags & CHANNEL_INTERFERENCE) {
- if_printf(sc->sc_ifp,
- "channel %u/0x%x/0x%x has interference\n",
- hchan.channel, hchan.channelFlags, hchan.privFlags);
- return;
- }
- if ((hchan.privFlags & CHANNEL_DFS) == 0) {
- /* XXX should not happen */
- return;
- }
- if (hchan.privFlags & CHANNEL_DFS_CLEAR) {
- sc->sc_curchan.privFlags |= CHANNEL_DFS_CLEAR;
- sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- if_printf(sc->sc_ifp,
- "channel %u/0x%x/0x%x marked clear\n",
- hchan.channel, hchan.channelFlags, hchan.privFlags);
- } else
- callout_reset(&sc->sc_dfs_ch, 2 * hz, ath_dfswait, sc);
-}
-
-/*
* Set/change channels. If the channel is really being changed,
* it's done by reseting the chip. To accomplish this we must
* first cleanup any pending DMA, then restart stuff after a la
@@ -4934,8 +5350,9 @@ ath_dfswait(void *arg)
static int
ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
- struct ieee80211com *ic = &sc->sc_ic;
HAL_CHANNEL hchan;
/*
@@ -4967,7 +5384,7 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
ath_draintxq(sc); /* clear pending tx frames */
ath_stoprecv(sc); /* turn off frame recv */
if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)) {
- if_printf(ic->ic_ifp, "%s: unable to reset "
+ if_printf(ifp, "%s: unable to reset "
"channel %u (%u Mhz, flags 0x%x hal flags 0x%x), "
"hal status %u\n", __func__,
ieee80211_chan2ieee(ic, chan), chan->ic_freq,
@@ -4975,7 +5392,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
return EIO;
}
sc->sc_curchan = hchan;
- ath_update_txpow(sc); /* update tx power state */
sc->sc_diversity = ath_hal_getdiversity(ah);
sc->sc_calinterval = 1;
sc->sc_caltries = 0;
@@ -4984,8 +5400,8 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
* Re-enable rx framework.
*/
if (ath_startrecv(sc) != 0) {
- if_printf(ic->ic_ifp,
- "%s: unable to restart recv logic\n", __func__);
+ if_printf(ifp, "%s: unable to restart recv logic\n",
+ __func__);
return EIO;
}
@@ -4996,25 +5412,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
ath_chan_change(sc, chan);
/*
- * Handle DFS required waiting period to determine
- * if channel is clear of radar traffic.
- */
- if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
-#define DFS_AND_NOT_CLEAR(_c) \
- (((_c)->privFlags & (CHANNEL_DFS | CHANNEL_DFS_CLEAR)) == CHANNEL_DFS)
- if (DFS_AND_NOT_CLEAR(&sc->sc_curchan)) {
- if_printf(sc->sc_ifp,
- "wait for DFS clear channel signal\n");
- /* XXX stop sndq */
- sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- callout_reset(&sc->sc_dfs_ch,
- 2 * hz, ath_dfswait, sc);
- } else
- callout_stop(&sc->sc_dfs_ch);
-#undef DFS_NOT_CLEAR
- }
-
- /*
* Re-enable interrupts.
*/
ath_hal_intrset(ah, sc->sc_imask);
@@ -5138,13 +5535,32 @@ ath_set_channel(struct ieee80211com *ic)
sc->sc_syncbeacon = 1;
}
+/*
+ * Walk the vap list and check if there any vap's in RUN state.
+ */
static int
-ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+ath_isanyrunningvaps(struct ieee80211vap *this)
{
- struct ifnet *ifp = ic->ic_ifp;
- struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = this->iv_ic;
+ struct ieee80211vap *vap;
+
+ IEEE80211_LOCK_ASSERT(ic);
+
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+ if (vap != this && vap->iv_state == IEEE80211_S_RUN)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_vap *avp = ATH_VAP(vap);
struct ath_hal *ah = sc->sc_ah;
- struct ieee80211_node *ni;
+ struct ieee80211_node *ni = NULL;
int i, error, stamode;
u_int32_t rfilt;
static const HAL_LED_STATE leds[] = {
@@ -5159,75 +5575,70 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
};
DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__,
- ieee80211_state_name[ic->ic_state],
+ ieee80211_state_name[vap->iv_state],
ieee80211_state_name[nstate]);
callout_stop(&sc->sc_cal_ch);
- callout_stop(&sc->sc_dfs_ch);
ath_hal_setledstate(ah, leds[nstate]); /* set LED */
- if (nstate == IEEE80211_S_INIT) {
+ if (nstate == IEEE80211_S_SCAN) {
/*
- * Shutdown host/driver operation:
- * o disable interrupts so we don't rx frames
- * o clean any pending items on the task q
- * o notify the rate control algorithm
+ * Scanning: turn off beacon miss and don't beacon.
+ * Mark beacon state so when we reach RUN state we'll
+ * [re]setup beacons. Unblock the task q thread so
+ * deferred interrupt processing is done.
*/
+ ath_hal_intrset(ah,
+ sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
- ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL);
-#if 0
- /* XXX can't use taskqueue_drain 'cuz we're holding sc_mtx */
- taskqueue_drain(sc->sc_tq, &sc->sc_rxtask);
- taskqueue_drain(sc->sc_tq, &sc->sc_rxorntask);
- taskqueue_drain(sc->sc_tq, &sc->sc_bmisstask);
- taskqueue_drain(sc->sc_tq, &sc->sc_bstucktask);
-#endif
- ath_rate_newstate(sc, nstate);
- goto done;
+ sc->sc_beacons = 0;
+ taskqueue_unblock(sc->sc_tq);
}
- ni = ic->ic_bss;
+ ni = vap->iv_bss;
rfilt = ath_calcrxfilter(sc);
- stamode = (sc->sc_opmode == HAL_M_STA || sc->sc_opmode == HAL_M_IBSS);
+ stamode = (vap->iv_opmode == IEEE80211_M_STA ||
+ vap->iv_opmode == IEEE80211_M_IBSS);
if (stamode && nstate == IEEE80211_S_RUN) {
sc->sc_curaid = ni->ni_associd;
IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid);
- } else
- sc->sc_curaid = 0;
-
+ ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid);
+ }
DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n",
- __func__, rfilt, ether_sprintf(sc->sc_curbssid),
- sc->sc_curaid);
-
+ __func__, rfilt, ether_sprintf(sc->sc_curbssid), sc->sc_curaid);
ath_hal_setrxfilter(ah, rfilt);
- if (stamode)
- ath_hal_setassocid(ah, sc->sc_curbssid, ni->ni_associd);
- if (ic->ic_opmode != IEEE80211_M_STA &&
- (ic->ic_flags & IEEE80211_F_PRIVACY)) {
+ /* XXX is this to restore keycache on resume? */
+ if (vap->iv_opmode != IEEE80211_M_STA &&
+ (vap->iv_flags & IEEE80211_F_PRIVACY)) {
for (i = 0; i < IEEE80211_WEP_NKID; i++)
if (ath_hal_keyisvalid(ah, i))
ath_hal_keysetmac(ah, i, ni->ni_bssid);
}
-
/*
* Notify the rate control algorithm so rates
* are setup should ath_beacon_alloc be called.
*/
- ath_rate_newstate(sc, nstate);
+ ath_rate_newstate(vap, nstate);
+
+ /*
+ * Invoke the parent method to do net80211 work.
+ */
+ error = avp->av_newstate(vap, nstate, arg);
+ if (error != 0)
+ goto bad;
if (nstate == IEEE80211_S_RUN) {
+ /* NB: collect bss node again, it may have changed */
+ ni = vap->iv_bss;
+
DPRINTF(sc, ATH_DEBUG_STATE,
- "%s(RUN): ic_flags=0x%08x iv=%d bssid=%s "
- "capinfo=0x%04x chan=%d\n"
- , __func__
- , ic->ic_flags
- , ni->ni_intval
- , ether_sprintf(ni->ni_bssid)
- , ni->ni_capinfo
- , ieee80211_chan2ieee(ic, ic->ic_curchan));
-
- switch (ic->ic_opmode) {
+ "%s(RUN): iv_flags 0x%08x bintvl %d bssid %s "
+ "capinfo 0x%04x chan %d\n", __func__,
+ vap->iv_flags, ni->ni_intval, ether_sprintf(ni->ni_bssid),
+ ni->ni_capinfo, ieee80211_chan2ieee(ic, ic->ic_curchan));
+
+ switch (vap->iv_opmode) {
case IEEE80211_M_HOSTAP:
case IEEE80211_M_IBSS:
/*
@@ -5240,7 +5651,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
* be called with beacon transmission active.
*/
ath_hal_stoptxdma(ah, sc->sc_bhalq);
- ath_beacon_free(sc);
+
error = ath_beacon_alloc(sc, ni);
if (error != 0)
goto bad;
@@ -5248,22 +5659,23 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
* If joining an adhoc network defer beacon timer
* configuration to the next beacon frame so we
* have a current TSF to use. Otherwise we're
- * starting an ibss/bss so there's no need to delay.
+ * starting an ibss/bss so there's no need to delay;
+ * if this is the first vap moving to RUN state, then
+ * beacon state needs to be [re]configured.
*/
- if (ic->ic_opmode == IEEE80211_M_IBSS &&
- ic->ic_bss->ni_tstamp.tsf != 0)
+ if (vap->iv_opmode == IEEE80211_M_IBSS &&
+ ni->ni_tstamp.tsf != 0) {
sc->sc_syncbeacon = 1;
- else
- ath_beacon_config(sc);
+ } else if (!sc->sc_beacons) {
+ ath_beacon_config(sc, vap);
+ sc->sc_beacons = 1;
+ }
break;
case IEEE80211_M_STA:
/*
- * Allocate a key cache slot to the station.
+ * Fakeup since we're not called by net80211.
*/
- if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0 &&
- sc->sc_hasclrkey &&
- ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE)
- ath_setup_stationkey(ni);
+ ath_newassoc(ni, 1);
/*
* Defer beacon timer configuration to the next
* beacon frame so we have a current TSF to use
@@ -5271,6 +5683,16 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
*/
sc->sc_syncbeacon = 1;
break;
+ case IEEE80211_M_MONITOR:
+ /*
+ * Monitor mode vaps have only INIT->RUN and RUN->RUN
+ * transitions so we must re-enable interrupts here to
+ * handle the case of a single monitor mode vap.
+ */
+ ath_hal_intrset(ah, sc->sc_imask);
+ break;
+ case IEEE80211_M_WDS:
+ break;
default:
break;
}
@@ -5285,23 +5707,31 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
- } else {
- ath_hal_intrset(ah,
- sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
- sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
- }
-done:
- /*
- * Invoke the parent method to complete the work.
- */
- error = sc->sc_newstate(ic, nstate, arg);
- /*
- * Finally, start any timers.
- */
- if (nstate == IEEE80211_S_RUN) {
- /* start periodic recalibration timer */
- callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
- ath_calibrate, sc);
+ /*
+ * Finally, start any timers and the task q thread
+ * (in case we didn't go through SCAN state).
+ */
+ if (sc->sc_calinterval != 0) {
+ /* start periodic recalibration timer */
+ callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
+ ath_calibrate, sc);
+ }
+ taskqueue_unblock(sc->sc_tq);
+ } else if (nstate == IEEE80211_S_INIT) {
+ /*
+ * If there are no vaps left in RUN state then
+ * shutdown host/driver operation:
+ * o disable interrupts
+ * o disable the task queue thread
+ * o mark beacon processing as stopped
+ */
+ if (!ath_isanyrunningvaps(vap)) {
+ sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
+ /* disable interrupts */
+ ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL);
+ taskqueue_block(sc->sc_tq);
+ sc->sc_beacons = 0;
+ }
}
bad:
return error;
@@ -5318,11 +5748,11 @@ bad:
static void
ath_setup_stationkey(struct ieee80211_node *ni)
{
- struct ieee80211com *ic = ni->ni_ic;
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
ieee80211_keyix keyix, rxkeyix;
- if (!ath_key_alloc(ic, &ni->ni_ucastkey, &keyix, &rxkeyix)) {
+ if (!ath_key_alloc(vap, &ni->ni_ucastkey, &keyix, &rxkeyix)) {
/*
* Key cache is full; we'll fall back to doing
* the more expensive lookup in software. Note
@@ -5334,7 +5764,7 @@ ath_setup_stationkey(struct ieee80211_node *ni)
ni->ni_ucastkey.wk_keyix = keyix;
ni->ni_ucastkey.wk_rxkeyix = rxkeyix;
/* NB: this will create a pass-thru key entry */
- ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, ic->ic_bss);
+ ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, vap->iv_bss);
}
}
@@ -5346,58 +5776,78 @@ ath_setup_stationkey(struct ieee80211_node *ni)
static void
ath_newassoc(struct ieee80211_node *ni, int isnew)
{
- struct ieee80211com *ic = ni->ni_ic;
- struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+ const struct ieee80211_txparam *tp;
+ enum ieee80211_phymode mode;
- ath_rate_newassoc(sc, ATH_NODE(ni), isnew);
- if (isnew &&
- (ic->ic_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey) {
- KASSERT(ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE,
- ("new assoc with a unicast key already setup (keyix %u)",
- ni->ni_ucastkey.wk_keyix));
+ /*
+ * Deduce netband of station to simplify setting up xmit
+ * parameters. Note this allows us to assign different
+ * parameters to each station in a mixed bss (b/g, n/[abg]).
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
+ mode = IEEE80211_MODE_11NA;
+ else
+ mode = IEEE80211_MODE_11NG;
+ } else if (IEEE80211_IS_CHAN_A(ni->ni_chan))
+ mode = IEEE80211_MODE_11A;
+ else if (ni->ni_flags & IEEE80211_NODE_ERP)
+ mode = IEEE80211_MODE_11G;
+ else
+ mode = IEEE80211_MODE_11B;
+ tp = &vap->iv_txparms[mode];
+ an->an_tp = tp;
+ an->an_mcastrix = ath_tx_findrix(sc->sc_rates[mode], tp->mcastrate);
+ an->an_mgmtrix = ath_tx_findrix(sc->sc_rates[mode], tp->mgmtrate);
+
+ ath_rate_newassoc(sc, an, isnew);
+ if (isnew &&
+ (vap->iv_flags & IEEE80211_F_PRIVACY) == 0 && sc->sc_hasclrkey &&
+ ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE)
ath_setup_stationkey(ni);
- }
}
static int
-ath_getchannels(struct ath_softc *sc,
- HAL_REG_DOMAIN rd, HAL_CTRY_CODE cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
+getchannels(struct ath_softc *sc, int *nchans, struct ieee80211_channel chans[],
+ int cc, int ecm, int outdoor)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = sc->sc_ifp;
struct ath_hal *ah = sc->sc_ah;
- HAL_CHANNEL *chans;
- int i, nchan;
- u_int32_t regdomain;
-
- chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
- M_TEMP, M_NOWAIT);
- if (chans == NULL) {
- if_printf(ifp, "unable to allocate channel table\n");
+ HAL_CHANNEL *halchans;
+ int i, nhalchans, error;
+
+ halchans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
+ M_TEMP, M_NOWAIT | M_ZERO);
+ if (halchans == NULL) {
+ device_printf(sc->sc_dev,
+ "%s: unable to allocate channel table\n", __func__);
return ENOMEM;
}
- if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
- NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) {
- (void) ath_hal_getregdomain(ah, &regdomain);
- if_printf(ifp, "unable to collect channel list from hal; "
- "regdomain likely %u country code %u\n", regdomain, cc);
- free(chans, M_TEMP);
- return EINVAL;
+ error = 0;
+ if (!ath_hal_init_channels(ah, halchans, IEEE80211_CHAN_MAX, &nhalchans,
+ NULL, 0, NULL, CTRY_DEFAULT, HAL_MODE_ALL, AH_FALSE, AH_TRUE)) {
+ error = EINVAL;
+ goto done;
}
+ if (nchans == NULL) /* no table requested */
+ goto done;
/*
* Convert HAL channels to ieee80211 ones.
*/
- memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
- for (i = 0; i < nchan; i++) {
- HAL_CHANNEL *c = &chans[i];
- struct ieee80211_channel *ichan = &ic->ic_channels[i];
+ for (i = 0; i < nhalchans; i++) {
+ HAL_CHANNEL *c = &halchans[i];
+ struct ieee80211_channel *ichan = &chans[i];
ichan->ic_ieee = ath_hal_mhz2ieee(ah, c->channel,
c->channelFlags);
if (bootverbose)
- if_printf(ifp, "hal channel %u/%x -> %u\n",
- c->channel, c->channelFlags, ichan->ic_ieee);
+ device_printf(sc->sc_dev, "hal channel %u/%x -> %u "
+ "maxpow %d minpow %d maxreg %d\n",
+ c->channel, c->channelFlags, ichan->ic_ieee,
+ c->maxTxPower, c->minTxPower, c->maxRegTxPower);
ichan->ic_freq = c->channel;
if ((c->channelFlags & CHANNEL_PUREG) == CHANNEL_PUREG) {
@@ -5419,15 +5869,98 @@ ath_getchannels(struct ath_softc *sc,
ichan->ic_flags);
}
ichan->ic_maxregpower = c->maxRegTxPower; /* dBm */
- ichan->ic_maxpower = c->maxTxPower; /* 1/2 dBm */
+ /* XXX: old hal's don't provide maxTxPower for some parts */
+ ichan->ic_maxpower = (c->maxTxPower != 0) ?
+ c->maxTxPower : 2*c->maxRegTxPower; /* 1/2 dBm */
ichan->ic_minpower = c->minTxPower; /* 1/2 dBm */
}
- ic->ic_nchans = nchan;
- free(chans, M_TEMP);
- (void) ath_hal_getregdomain(ah, &sc->sc_regdomain);
- ath_hal_getcountrycode(ah, &sc->sc_countrycode);
- sc->sc_xchanmode = xchanmode;
- sc->sc_outdoor = outdoor;
+ *nchans = nhalchans;
+done:
+ free(halchans, M_TEMP);
+ return error;
+}
+
+static int
+ath_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd,
+ int nchans, struct ieee80211_channel chans[])
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t ord;
+ int error;
+
+ (void) ath_hal_getregdomain(ah, &ord);
+ /* XXX map sku->rd */
+ ath_hal_setregdomain(ah, rd->regdomain);
+ error = getchannels(sc, &nchans, chans, rd->country,
+ rd->ecm ? AH_TRUE : AH_FALSE,
+ rd->location == 'O' ? AH_TRUE : AH_FALSE);
+ if (error != 0) {
+ /*
+ * Restore previous state.
+ */
+ ath_hal_setregdomain(ah, ord);
+ (void) getchannels(sc, NULL, NULL, ic->ic_regdomain.country,
+ ic->ic_regdomain.ecm ? AH_TRUE : AH_FALSE,
+ ic->ic_regdomain.location == 'O' ? AH_TRUE : AH_FALSE);
+ return error;
+ }
+ return 0;
+}
+
+static void
+ath_getradiocaps(struct ieee80211com *ic,
+ int *nchans, struct ieee80211_channel chans[])
+{
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t ord;
+
+ (void) ath_hal_getregdomain(ah, &ord);
+ ath_hal_setregdomain(ah, 0);
+ /* XXX not quite right but close enough for now */
+ getchannels(sc, nchans, chans, CTRY_DEBUG, AH_TRUE, AH_FALSE);
+ ath_hal_setregdomain(ah, ord);
+}
+
+static int
+ath_mapregdomain(struct ath_softc *sc, u_int32_t rd)
+{
+ /* map Atheros rd's to SKU's */
+ return rd;
+}
+
+static int
+ath_getchannels(struct ath_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t rd, cc;
+ int error;
+
+ /*
+ * Convert HAL channels to ieee80211 ones.
+ */
+ error = getchannels(sc, &ic->ic_nchans, ic->ic_channels,
+ CTRY_DEFAULT, AH_TRUE, AH_FALSE);
+ (void) ath_hal_getregdomain(ah, &rd);
+ ath_hal_getcountrycode(ah, &cc); /* NB: cannot fail */
+ if (error) {
+ if_printf(ifp, "%s: unable to collect channel list from hal, "
+ "error %d\n", __func__, error);
+ if (error == EINVAL) {
+ if_printf(ifp, "%s: regdomain likely %u country code %u\n",
+ __func__, rd, cc);
+ }
+ return error;
+ }
+ ic->ic_regdomain.regdomain = ath_mapregdomain(sc, rd);
+ ic->ic_regdomain.country = cc;
+ ic->ic_regdomain.ecm = 1;
+ ic->ic_regdomain.location = 'I';
+ ic->ic_regdomain.isocc[0] = ' '; /* XXX don't know */
+ ic->ic_regdomain.isocc[1] = ' ';
return 0;
}
@@ -5488,26 +6021,6 @@ ath_led_event(struct ath_softc *sc, int event)
}
}
-static void
-ath_update_txpow(struct ath_softc *sc)
-{
- struct ieee80211com *ic = &sc->sc_ic;
- struct ath_hal *ah = sc->sc_ah;
- u_int32_t txpow;
-
- if (sc->sc_curtxpow != ic->ic_txpowlimit) {
- ath_hal_settxpowlimit(ah, ic->ic_txpowlimit);
- /* read back in case value is clamped */
- if (ath_hal_gettxpowlimit(ah, &txpow))
- ic->ic_txpowlimit = sc->sc_curtxpow = txpow;
- }
- /*
- * Fetch max tx power level for status requests.
- */
- if (ath_hal_getmaxtxpow(sc->sc_ah, &txpow))
- ic->ic_bss->ni_txpower = txpow;
-}
-
static int
ath_rate_setup(struct ath_softc *sc, u_int mode)
{
@@ -5630,14 +6143,6 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
sc->sc_protrix = ath_tx_findrix(rt, 2*2);
else
sc->sc_protrix = ath_tx_findrix(rt, 2*1);
- /* rate index used to send management frames */
- sc->sc_minrateix = 0;
- /*
- * Setup multicast rate state.
- */
- /* XXX layering violation */
- sc->sc_mcastrix = ath_tx_findrix(rt, sc->sc_ic.ic_mcast_rate);
- sc->sc_mcastrate = sc->sc_ic.ic_mcast_rate;
/* NB: caller is responsible for reseting rate control state */
#undef N
}
@@ -5763,7 +6268,7 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
#define IS_RUNNING(ifp) \
((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ifreq *ifr = (struct ifreq *)data;
int error = 0;
@@ -5787,7 +6292,7 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
* torn down much of our state. There's
* probably a better way to deal with this.
*/
- if (!sc->sc_invalid && ic->ic_bss != NULL)
+ if (!sc->sc_invalid)
ath_init(sc); /* XXX lose error */
} else
ath_stop_locked(ifp);
@@ -5802,12 +6307,18 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
ath_mode_init(sc);
break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
+ break;
case SIOCGATHSTATS:
/* NB: embed these numbers to get a consistent view */
sc->sc_stats.ast_tx_packets = ifp->if_opackets;
sc->sc_stats.ast_rx_packets = ifp->if_ipackets;
+#if 0
ieee80211_getsignal(ic, &sc->sc_stats.ast_rx_rssi,
&sc->sc_stats.ast_rx_noise);
+#endif
sc->sc_stats.ast_tx_rate = sc->sc_hwmap[sc->sc_txrate].ieeerate;
ATH_UNLOCK(sc);
/*
@@ -5826,15 +6337,7 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
#endif
default:
- error = ieee80211_ioctl(ic, cmd, data);
- if (error == ENETRESET) {
- if (IS_RUNNING(ifp) &&
- ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
- ath_init(sc); /* XXX lose error */
- error = 0;
- }
- if (error == ERESTART)
- error = IS_RUNNING(ifp) ? ath_reset(ifp) : 0;
+ error = ether_ioctl(ifp, cmd, data);
break;
}
ATH_UNLOCK(sc);
@@ -6059,48 +6562,6 @@ ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS)
}
static int
-ath_sysctl_countrycode(SYSCTL_HANDLER_ARGS)
-{
- struct ath_softc *sc = arg1;
- u_int32_t cc = sc->sc_countrycode;
- struct ieee80211com *ic = &sc->sc_ic;
- int error;
-
- error = sysctl_handle_int(oidp, &cc, 0, req);
- if (error || !req->newptr)
- return error;
- error = ath_getchannels(sc, sc->sc_regdomain, cc,
- sc->sc_outdoor != 0, sc->sc_xchanmode != 0);
- if (error != 0)
- return error;
- ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
- /* setcurmode? */
- return 0;
-}
-
-static int
-ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS)
-{
- struct ath_softc *sc = arg1;
- u_int32_t rd = sc->sc_regdomain;
- struct ieee80211com *ic = &sc->sc_ic;
- int error;
-
- error = sysctl_handle_int(oidp, &rd, 0, req);
- if (error || !req->newptr)
- return error;
- if (!ath_hal_setregdomain(sc->sc_ah, rd))
- return EINVAL;
- error = ath_getchannels(sc, rd, sc->sc_countrycode,
- sc->sc_outdoor != 0, sc->sc_xchanmode != 0);
- if (error != 0)
- return error;
- ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
- /* setcurmode? */
- return 0;
-}
-
-static int
ath_sysctl_tpack(SYSCTL_HANDLER_ARGS)
{
struct ath_softc *sc = arg1;
@@ -6135,12 +6596,6 @@ ath_sysctlattach(struct ath_softc *sc)
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
struct ath_hal *ah = sc->sc_ah;
- SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
- "countrycode", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- ath_sysctl_countrycode, "I", "country code");
- SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
- "regdomain", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
- ath_sysctl_regdomain, "I", "EEPROM regdomain code");
#ifdef ATH_DEBUG
sc->sc_debug = ath_debug;
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
@@ -6228,9 +6683,8 @@ ath_bpfattach(struct ath_softc *sc)
{
struct ifnet *ifp = sc->sc_ifp;
- bpfattach2(ifp, DLT_IEEE802_11_RADIO,
- sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th),
- &sc->sc_drvbpf);
+ bpfattach(ifp, DLT_IEEE802_11_RADIO,
+ sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th));
/*
* Initialize constant fields.
* XXX make header lengths a multiple of 32-bits so subsequent
@@ -6254,12 +6708,12 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
struct ath_buf *bf, struct mbuf *m0,
const struct ieee80211_bpf_params *params)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ath_hal *ah = sc->sc_ah;
int error, ismcast, ismrr;
int hdrlen, pktlen, try0, txantenna;
u_int8_t rix, cix, txrate, ctsrate, rate1, rate2, rate3;
- struct ath_txq *txq;
struct ieee80211_frame *wh;
u_int flags, ctsduration;
HAL_PKT_TYPE atype;
@@ -6340,9 +6794,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
sc->sc_hwmap[txrate].ieeerate, -1);
- if (bpf_peers_present(ic->ic_rawbpf))
- bpf_mtap(ic->ic_rawbpf, m0);
- if (bpf_peers_present(sc->sc_drvbpf)) {
+ if (bpf_peers_present(ifp->if_bpf)) {
u_int64_t tsf = ath_hal_gettsf64(ah);
sc->sc_tx_th.wt_tsf = htole64(tsf);
@@ -6353,8 +6805,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
sc->sc_tx_th.wt_txpower = ni->ni_txpower;
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
- bpf_mtap2(sc->sc_drvbpf,
- &sc->sc_tx_th, sc->sc_tx_th_len, m0);
+ bpf_mtap2(ifp->if_bpf, &sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
/*
@@ -6402,16 +6853,8 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
);
}
- /*
- * When servicing one or more stations in power-save mode
- * (or) if there is some mcast data waiting on the mcast
- * queue (to prevent out of order delivery) multicast
- * frames must be buffered until after the beacon.
- */
- txq = sc->sc_ac2q[pri];
- if (ismcast && (ic->ic_ps_sta || sc->sc_mcastq.axq_depth))
- txq = &sc->sc_mcastq;
- ath_tx_handoff(sc, txq, bf);
+ /* NB: no buffered multicast in power save support */
+ ath_tx_handoff(sc, sc->sc_ac2q[pri], bf);
return 0;
}
OpenPOWER on IntegriCloud