Module Name: src Committed By: jmcneill Date: Sun Aug 2 13:26:33 UTC 2009
Modified Files: src/sys/dev/ic: ath.c athvar.h Log Message: - fix TKIP, changes adapted from FreeBSD - reduce diffs between FreeBSD and NetBSD athvar.h To generate a diff of this commit: cvs rdiff -u -r1.105 -r1.106 src/sys/dev/ic/ath.c cvs rdiff -u -r1.27 -r1.28 src/sys/dev/ic/athvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/ath.c diff -u src/sys/dev/ic/ath.c:1.105 src/sys/dev/ic/ath.c:1.106 --- src/sys/dev/ic/ath.c:1.105 Thu Dec 11 06:04:01 2008 +++ src/sys/dev/ic/ath.c Sun Aug 2 13:26:33 2009 @@ -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 @@ * 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 @@ 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_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 @@ * 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_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 @@ * 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 @@ 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 @@ } /* + * 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 @@ 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 @@ */ 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 @@ */ 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 @@ 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); } Index: src/sys/dev/ic/athvar.h diff -u src/sys/dev/ic/athvar.h:1.27 src/sys/dev/ic/athvar.h:1.28 --- src/sys/dev/ic/athvar.h:1.27 Tue May 12 14:25:17 2009 +++ src/sys/dev/ic/athvar.h Sun Aug 2 13:26:33 2009 @@ -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 @@ 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 @@ #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 @@ (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 @@ (_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)))