summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjmcneill <jmcneill@NetBSD.org>2009-08-02 13:26:33 +0000
committerjmcneill <jmcneill@NetBSD.org>2009-08-02 13:26:33 +0000
commit783afeb19c1e2ed6991aba442f7c3a6ef34de92b (patch)
tree46f68e077e374163137f4602083a2087e825d353 /sys/dev
parent9337b12fa8130dac15517cd1bf5793461d3f64d5 (diff)
- fix TKIP, changes adapted from FreeBSD
- reduce diffs between FreeBSD and NetBSD athvar.h
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/ath.c162
-rw-r--r--sys/dev/ic/athvar.h40
2 files changed, 141 insertions, 61 deletions
diff --git a/sys/dev/ic/ath.c b/sys/dev/ic/ath.c
index 99a18101df2..bd4817e3bb1 100644
--- a/sys/dev/ic/ath.c
+++ b/sys/dev/ic/ath.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ath.c,v 1.105 2008/12/11 06:04:01 alc Exp $ */
+/* $NetBSD: ath.c,v 1.106 2009/08/02 13:26:33 jmcneill Exp $ */
/*-
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -41,7 +41,7 @@
__FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.104 2005/09/16 10:09:23 ru Exp $");
#endif
#ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.105 2008/12/11 06:04:01 alc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.106 2009/08/02 13:26:33 jmcneill Exp $");
#endif
/*
@@ -520,28 +520,40 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
* separate key cache entries are required to
* handle both tx+rx MIC keys.
*/
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) {
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC))
ic->ic_caps |= IEEE80211_C_TKIPMIC;
- /*
- * Check if h/w does MIC correctly when
- * WMM is turned on.
- */
- if (ath_hal_wmetkipmic(ah))
- ic->ic_caps |= IEEE80211_C_WME_TKIPMIC;
- }
/*
* If the h/w supports storing tx+rx MIC keys
* in one cache slot automatically enable use.
*/
- if (ath_hal_tkipsplit(ah) ||
+ 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))
+ ic->ic_caps |= IEEE80211_C_WME_TKIPMIC;
}
sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR);
-#if 0
sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah);
-#endif
+ /*
+ * Mark key cache slots associated with global keys
+ * as in use. If we knew TKIP was not to be used we
+ * could leave the +32, +64, and +32+64 slots free.
+ */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ setbit(sc->sc_keymap, i);
+ setbit(sc->sc_keymap, i+64);
+ if (sc->sc_splitmic) {
+ setbit(sc->sc_keymap, i+32);
+ setbit(sc->sc_keymap, i+32+64);
+ }
+ }
/*
* TPC support can be done either with a global cap or
* per-packet support. The latter is not available on
@@ -948,6 +960,24 @@ ath_ifinit(struct ifnet *ifp)
return ath_init(sc);
}
+static void
+ath_settkipmic(struct ath_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_hal *ah = sc->sc_ah;
+
+ if ((ic->ic_caps & IEEE80211_C_TKIP) &&
+ !(ic->ic_caps & IEEE80211_C_WME_TKIPMIC)) {
+ if (ic->ic_flags & IEEE80211_F_WME) {
+ (void)ath_hal_settkipmic(ah, AH_FALSE);
+ ic->ic_caps &= ~IEEE80211_C_TKIPMIC;
+ } else {
+ (void)ath_hal_settkipmic(ah, AH_TRUE);
+ ic->ic_caps |= IEEE80211_C_TKIPMIC;
+ }
+ }
+}
+
static int
ath_init(struct ath_softc *sc)
{
@@ -973,17 +1003,6 @@ ath_init(struct ath_softc *sc)
*/
ath_stop_locked(ifp, 0);
- int dummy; /* XXX: gcc */
- /* Whether we should enable h/w TKIP MIC */
- if ((ic->ic_caps & IEEE80211_C_WME) &&
- ((ic->ic_caps & IEEE80211_C_WME_TKIPMIC) ||
- !(ic->ic_flags & IEEE80211_F_WME))) {
- dummy = ath_hal_settkipmic(ah, AH_TRUE);
- } else {
- dummy = ath_hal_settkipmic(ah, AH_FALSE);
- }
-
-
/*
* The basic interface to setting the hardware in a good
* state is ``reset''. On return the hardware is known to
@@ -991,6 +1010,7 @@ ath_init(struct ath_softc *sc)
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
+ ath_settkipmic(sc);
sc->sc_curchan.channel = ic->ic_curchan->ic_freq;
sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan);
if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
@@ -1170,6 +1190,7 @@ 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, ic->ic_opmode, &sc->sc_curchan, AH_TRUE, &status))
if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
@@ -1512,21 +1533,25 @@ ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
* will handle the reset.
*/
memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
-#if HAL_ABI_VERSION > 0x06052200
memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
-#endif
KEYPRINTF(sc, k->wk_keyix, hk, mac);
return ath_hal_keyset(ah, ATH_KEY(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 (sc->sc_splitmic) {
+ /*
+ * NB: must pass MIC key in expected location when
+ * the keycache only holds one MIC key per entry.
+ */
+ memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_txmic));
+ } else
+ memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
KEYPRINTF(sc, k->wk_keyix, hk, mac);
return ath_hal_keyset(ah, ATH_KEY(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);
}
return 0;
#undef IEEE80211_KEY_XR
@@ -1586,7 +1611,7 @@ ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
mac = mac0;
if ((hk.kv_type == HAL_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) && sc->sc_splitmic) {
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0)) {
return ath_keyset_tkip(sc, k, &hk, mac);
} else {
KEYPRINTF(sc, k->wk_keyix, &hk, mac);
@@ -1651,6 +1676,54 @@ key_alloc_2pair(struct ath_softc *sc,
}
/*
+ * Allocate tx/rx key slots for TKIP. We allocate two slots for
+ * each key, one for decrypt/encrypt and the other for the MIC.
+ */
+static int
+key_alloc_pair(struct ath_softc *sc, ieee80211_keyix *txkeyix,
+ ieee80211_keyix *rxkeyix)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ u_int i, keyix;
+
+ KASSERT(!sc->sc_splitmic, ("key cache split"));
+ /* XXX could optimize */
+ for (i = 0; i < N(sc->sc_keymap)/4; i++) {
+ uint8_t b = sc->sc_keymap[i];
+ if (b != 0xff) {
+ /*
+ * One or more slots in this byte are free.
+ */
+ keyix = i*NBBY;
+ while (b & 1) {
+ again:
+ keyix++;
+ b >>= 1;
+ }
+ if (isset(sc->sc_keymap, keyix+64)) {
+ /* full pair unavailable */
+ /* XXX statistic */
+ if (keyix == (i+1)*NBBY) {
+ /* no slots were appropriate, advance */
+ continue;
+ }
+ goto again;
+ }
+ setbit(sc->sc_keymap, keyix);
+ setbit(sc->sc_keymap, keyix+64);
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE,
+ "%s: key pair %u,%u\n",
+ __func__, keyix, keyix+64);
+ *txkeyix = *rxkeyix = keyix;
+ return 1;
+ }
+ }
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
+ return 0;
+#undef N
+}
+
+/*
* Allocate a single key cache slot.
*/
static int
@@ -1735,8 +1808,11 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
return key_alloc_single(sc, keyix, rxkeyix);
} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) {
- return key_alloc_2pair(sc, keyix, rxkeyix);
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
+ if (sc->sc_splitmic)
+ return key_alloc_2pair(sc, keyix, rxkeyix);
+ else
+ return key_alloc_pair(sc, keyix, rxkeyix);
} else {
return key_alloc_single(sc, keyix, rxkeyix);
}
@@ -1774,11 +1850,13 @@ ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
*/
clrbit(sc->sc_keymap, keyix);
if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
- sc->sc_splitmic) {
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
clrbit(sc->sc_keymap, keyix+64); /* TX key MIC */
- clrbit(sc->sc_keymap, keyix+32); /* RX key */
- clrbit(sc->sc_keymap, keyix+32+64); /* RX key MIC */
+ if (sc->sc_splitmic) {
+ /* +32 for RX key, +32+64 for RX key MIC */
+ clrbit(sc->sc_keymap, keyix+32);
+ clrbit(sc->sc_keymap, keyix+32+64);
+ }
}
}
return 1;
@@ -2982,7 +3060,7 @@ ath_rx_proc(void *arg, int npending)
*/
status = ath_hal_rxprocdesc(ah, ds,
bf->bf_daddr, PA2DESC(sc, ds->ds_link),
- tsf, &ds->ds_rxstat);
+ &ds->ds_rxstat);
#ifdef AR_DEBUG
if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
ath_printrxbuf(bf, status == HAL_OK);
@@ -4301,7 +4379,7 @@ ath_stoprecv(struct ath_softc *sc)
tsf = ath_hal_gettsf64(sc->sc_ah);
HAL_STATUS status = ath_hal_rxprocdesc(ah, ds,
bf->bf_daddr, PA2DESC(sc, ds->ds_link),
- tsf, &ds->ds_rxstat);
+ &ds->ds_rxstat);
if (status == HAL_OK || (sc->sc_debug & ATH_DEBUG_FATAL))
ath_printrxbuf(bf, status == HAL_OK);
}
diff --git a/sys/dev/ic/athvar.h b/sys/dev/ic/athvar.h
index 359223c412d..0a9c6b83d5e 100644
--- a/sys/dev/ic/athvar.h
+++ b/sys/dev/ic/athvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: athvar.h,v 1.27 2009/05/12 14:25:17 cegger Exp $ */
+/* $NetBSD: athvar.h,v 1.28 2009/08/02 13:26:33 jmcneill Exp $ */
/*-
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -58,7 +58,7 @@
#define ATH_RXBUF 40 /* number of RX buffers */
#endif
#ifndef ATH_TXBUF
-#define ATH_TXBUF 100 /* number of TX buffers */
+#define ATH_TXBUF 200 /* number of TX buffers */
#endif
#define ATH_TXDESC 10 /* number of descriptors per buffer */
#define ATH_TXMAXTRY 11 /* max number of transmit attempts */
@@ -128,7 +128,7 @@ struct ath_descdma {
const char* dd_name;
struct ath_desc *dd_desc; /* descriptors */
bus_addr_t dd_desc_paddr; /* physical addr of dd_desc */
- bus_addr_t dd_desc_len; /* size of dd_desc */
+ bus_size_t dd_desc_len; /* size of dd_desc */
bus_dma_segment_t dd_dseg;
int dd_dnseg; /* number of segments */
bus_dma_tag_t dd_dmat; /* bus DMA tag */
@@ -457,16 +457,20 @@ extern int ath_txbuf;
#define ath_hal_getregdomain(_ah, _prd) \
(ath_hal_getcapability(_ah, HAL_CAP_REG_DMN, 0, (_prd)) == HAL_OK)
#define ath_hal_setregdomain(_ah, _rd) \
- ((*(_ah)->ah_setRegulatoryDomain)((_ah), (_rd), NULL))
+ ath_hal_setcapability(_ah, HAL_CAP_REG_DMN, 0, _rd, NULL)
#define ath_hal_getcountrycode(_ah, _pcc) \
(*(_pcc) = (_ah)->ah_countryCode)
-#define ath_hal_tkipsplit(_ah) \
+#define ath_hal_gettkipmic(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TKIP_MIC, 1, NULL) == HAL_OK)
+#define ath_hal_settkipmic(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_TKIP_MIC, 1, _v, NULL)
+#define ath_hal_hastkipsplit(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_TKIP_SPLIT, 0, NULL) == HAL_OK)
-#define ath_hal_settkipmic(_ah, _v) \
- (ath_hal_setcapability(_ah, HAL_CAP_TKIP_MIC, 1, _v, NULL) == HAL_OK)
-#define ath_hal_settkipsplit(_ah, _v) \
- (ath_hal_setcapability(_ah, HAL_CAP_TKIP_SPLIT, 1, _v, NULL) == HAL_OK)
-#define ath_hal_wmetkipmic(_ah) \
+#define ath_hal_gettkipsplit(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_TKIP_SPLIT, 1, NULL) == HAL_OK)
+#define ath_hal_settkipsplit(_ah, _v) \
+ ath_hal_setcapability(_ah, HAL_CAP_TKIP_SPLIT, 1, _v, NULL)
+#define ath_hal_haswmetkipmic(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_WME_TKIPMIC, 0, NULL) == HAL_OK)
#define ath_hal_hwphycounters(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_PHYCOUNTERS, 0, NULL) == HAL_OK)
@@ -530,20 +534,18 @@ extern int ath_txbuf;
(ath_hal_getcapability(_ah, HAL_CAP_TPC_CTS, 0, _ptpcts) == HAL_OK)
#define ath_hal_settpcts(_ah, _tpcts) \
ath_hal_setcapability(_ah, HAL_CAP_TPC_CTS, 0, _tpcts, NULL)
-#if HAL_ABI_VERSION < 0x05120700
-#define ath_hal_process_noisefloor(_ah)
-#define ath_hal_getchannoise(_ah, _c) (-96)
-#define HAL_CAP_TPC_ACK 99
-#define HAL_CAP_TPC_CTS 100
-#else
#define ath_hal_getchannoise(_ah, _c) \
((*(_ah)->ah_getChanNoise)((_ah), (_c)))
-#endif
#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
+#if 0
#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext, tsf, a5) \
((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext), (tsf), (a5)))
+#else
+#define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext, _rs) \
+ ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext), 0, (_rs)))
+#endif
#define ath_hal_setuptxdesc(_ah, _ds, _plen, _hlen, _atype, _txpow, \
_txr0, _txtr0, _keyix, _ant, _flags, \
_rtsrate, _rtsdura) \
@@ -556,8 +558,8 @@ extern int ath_txbuf;
(_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3)))
#define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last, _ds0) \
((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0)))
-#define ath_hal_txprocdesc(_ah, _ds, _a2) \
- ((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_a2)))
+#define ath_hal_txprocdesc(_ah, _ds, _ts) \
+ ((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_ts)))
#define ath_hal_gettxintrtxqs(_ah, _txqs) \
((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs)))