diff options
author | adrian <adrian@FreeBSD.org> | 2011-03-02 17:19:54 +0000 |
---|---|---|
committer | adrian <adrian@FreeBSD.org> | 2011-03-02 17:19:54 +0000 |
commit | dad2200ab2ea4ee7a23fdb24cf98f477bf31e70c (patch) | |
tree | 8d935a7e40f8e8a60e212d2b74950c3fa0d08e85 | |
parent | 9791856c179074baee547d95afd0c7b32ea1d064 (diff) | |
download | FreeBSD-src-dad2200ab2ea4ee7a23fdb24cf98f477bf31e70c.zip FreeBSD-src-dad2200ab2ea4ee7a23fdb24cf98f477bf31e70c.tar.gz |
Break the keycache management functions out into if_ath_keycache.c .
-rw-r--r-- | sys/conf/files | 2 | ||||
-rw-r--r-- | sys/dev/ath/if_ath.c | 428 | ||||
-rw-r--r-- | sys/dev/ath/if_ath_keycache.c | 497 | ||||
-rw-r--r-- | sys/dev/ath/if_ath_keycache.h | 43 | ||||
-rw-r--r-- | sys/modules/ath/Makefile | 3 |
5 files changed, 545 insertions, 428 deletions
diff --git a/sys/conf/files b/sys/conf/files index f61a753..5a5e68f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -574,6 +574,8 @@ dev/ath/if_ath.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_debug.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" +dev/ath/if_ath_keycache.c optional ath \ + compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_tx.c optional ath \ compile-with "${NORMAL_C} -I$S/dev/ath" dev/ath/if_ath_tx_ht.c optional ath \ diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index cdd0ba3..97b5b6b 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ath/if_ath_misc.h> #include <dev/ath/if_ath_tx.h> #include <dev/ath/if_ath_sysctl.h> +#include <dev/ath/if_ath_keycache.h> #ifdef ATH_TX99_DIAG #include <dev/ath/ath_tx99/ath_tx99.h> @@ -130,15 +131,6 @@ static int ath_ioctl(struct ifnet *, u_long, caddr_t); static void ath_fatal_proc(void *, int); static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); -static int ath_keyset(struct ath_softc *, const struct ieee80211_key *, - struct ieee80211_node *); -static int ath_key_alloc(struct ieee80211vap *, - struct ieee80211_key *, - ieee80211_keyix *, ieee80211_keyix *); -static int ath_key_delete(struct ieee80211vap *, - 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 ieee80211vap *); static void ath_key_update_end(struct ieee80211vap *); static void ath_update_mcast(struct ifnet *); @@ -1851,424 +1843,6 @@ ath_media_change(struct ifnet *ifp) return (error == ENETRESET ? 0 : error); } -#ifdef ATH_DEBUG -static void -ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix, - const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) -{ - static const char *ciphers[] = { - "WEP", - "AES-OCB", - "AES-CCM", - "CKIP", - "TKIP", - "CLR", - }; - int i, n; - - printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]); - for (i = 0, n = hk->kv_len; i < n; i++) - printf("%02x", hk->kv_val[i]); - printf(" mac %s", ether_sprintf(mac)); - if (hk->kv_type == HAL_CIPHER_TKIP) { - printf(" %s ", sc->sc_splitmic ? "mic" : "rxmic"); - for (i = 0; i < sizeof(hk->kv_mic); i++) - printf("%02x", hk->kv_mic[i]); - if (!sc->sc_splitmic) { - printf(" txmic "); - for (i = 0; i < sizeof(hk->kv_txmic); i++) - printf("%02x", hk->kv_txmic[i]); - } - } - printf("\n"); -} -#endif - -/* - * Set a TKIP key into the hardware. This handles the - * potential distribution of key state to multiple key - * cache slots for TKIP. - */ -static int -ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k, - HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) -{ -#define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) - static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; - struct ath_hal *ah = sc->sc_ah; - - KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP, - ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher)); - if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { - if (sc->sc_splitmic) { - /* - * TX key goes at first index, RX key at the rx index. - * The hal handles the MIC keys at index+64. - */ - memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); - KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); - if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid)) - return 0; - - memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); - KEYPRINTF(sc, k->wk_keyix+32, hk, mac); - /* XXX delete tx key on failure? */ - return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac); - } else { - /* - * Room for both TX+RX MIC keys in one key cache - * slot, just set key at the first index; the hal - * will handle the rest. - */ - memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic)); - KEYPRINTF(sc, k->wk_keyix, hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, hk, mac); - } - } 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, 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 -} - -/* - * Set a net80211 key into the hardware. This handles the - * potential distribution of key state to multiple key - * cache slots for TKIP with hardware MIC support. - */ -static int -ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, - struct ieee80211_node *bss) -{ -#define N(a) (sizeof(a)/sizeof(a[0])) - static const u_int8_t ciphermap[] = { - HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ - HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ - HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ - HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ - (u_int8_t) -1, /* 4 is not allocated */ - HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ - HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ - }; - struct ath_hal *ah = sc->sc_ah; - const struct ieee80211_cipher *cip = k->wk_cipher; - u_int8_t gmac[IEEE80211_ADDR_LEN]; - const u_int8_t *mac; - HAL_KEYVAL hk; - - memset(&hk, 0, sizeof(hk)); - /* - * Software crypto uses a "clear key" so non-crypto - * state kept in the key cache are maintained and - * so that rx frames have an entry to match. - */ - if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { - KASSERT(cip->ic_cipher < N(ciphermap), - ("invalid cipher type %u", cip->ic_cipher)); - hk.kv_type = ciphermap[cip->ic_cipher]; - hk.kv_len = k->wk_keylen; - memcpy(hk.kv_val, k->wk_key, k->wk_keylen); - } else - hk.kv_type = HAL_CIPHER_CLR; - - if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) { - /* - * Group keys on hardware that supports multicast frame - * key search use a MAC that is the sender's address with - * the multicast bit set instead of the app-specified address. - */ - IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr); - gmac[0] |= 0x01; - mac = gmac; - } else - mac = k->wk_macaddr; - - if (hk.kv_type == HAL_CIPHER_TKIP && - (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { - return ath_keyset_tkip(sc, k, &hk, mac); - } else { - KEYPRINTF(sc, k->wk_keyix, &hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); - } -#undef N -} - -/* - * 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 u_int16_t -key_alloc_2pair(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++) { - u_int8_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; - } - /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ - if (isset(sc->sc_keymap, keyix+32) || - isset(sc->sc_keymap, keyix+64) || - isset(sc->sc_keymap, keyix+32+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); - setbit(sc->sc_keymap, keyix+32); - setbit(sc->sc_keymap, keyix+32+64); - DPRINTF(sc, ATH_DEBUG_KEYCACHE, - "%s: key pair %u,%u %u,%u\n", - __func__, keyix, keyix+64, - keyix+32, keyix+32+64); - *txkeyix = keyix; - *rxkeyix = keyix+32; - return 1; - } - } - DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); - return 0; -#undef N -} - -/* - * 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 u_int16_t -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++) { - u_int8_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 -key_alloc_single(struct ath_softc *sc, - ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) -{ -#define N(a) (sizeof(a)/sizeof(a[0])) - u_int i, keyix; - - /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ - for (i = 0; i < N(sc->sc_keymap); i++) { - u_int8_t b = sc->sc_keymap[i]; - if (b != 0xff) { - /* - * One or more slots are free. - */ - keyix = i*NBBY; - while (b & 1) - keyix++, b >>= 1; - setbit(sc->sc_keymap, keyix); - DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n", - __func__, keyix); - *txkeyix = *rxkeyix = keyix; - return 1; - } - } - DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__); - return 0; -#undef N -} - -/* - * Allocate one or more key cache slots for a uniacst key. The - * key itself is needed only to identify the cipher. For hardware - * TKIP with split cipher+MIC keys we allocate two key cache slot - * pairs so that we can setup separate TX and RX MIC keys. Note - * that the MIC key for a TKIP key at slot i is assumed by the - * hardware to be at slot i+64. This limits TKIP keys to the first - * 64 entries. - */ -static int -ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, - ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) -{ - struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; - - /* - * Group key allocation must be handled specially for - * parts that do not support multicast key cache search - * functionality. For those parts the key id must match - * the h/w key index so lookups find the right key. On - * parts w/ the key search facility we install the sender's - * mac address (with the high bit set) and let the hardware - * find the key w/o using the key id. This is preferred as - * it permits us to support multiple users for adhoc and/or - * multi-station operation. - */ - if (k->wk_keyix != IEEE80211_KEYIX_NONE) { - /* - * Only global keys should have key index assigned. - */ - 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__); - return 0; - } - if (vap->iv_opmode != IEEE80211_M_HOSTAP || - !(k->wk_flags & IEEE80211_KEY_GROUP) || - !sc->sc_mcastkey) { - /* - * XXX we pre-allocate the global keys so - * have no way to check if they've already - * been allocated. - */ - *keyix = *rxkeyix = k - vap->iv_nw_keys; - return 1; - } - /* - * Group key and device supports multicast key search. - */ - k->wk_keyix = IEEE80211_KEYIX_NONE; - } - - /* - * We allocate two pair for TKIP when using the h/w to do - * the MIC. For everything else, including software crypto, - * we allocate a single entry. Note that s/w crypto requires - * a pass-through slot on the 5211 and 5212. The 5210 does - * not support pass-through cache entries and we map all - * those requests to slot 0. - */ - 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) { - 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); - } -} - -/* - * Delete an entry in the key cache allocated by ath_key_alloc. - */ -static int -ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) -{ - 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; - - DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); - - ath_hal_keyreset(ah, keyix); - /* - * Handle split tx/rx keying required for TKIP with h/w MIC. - */ - if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && - (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) - ath_hal_keyreset(ah, keyix+32); /* RX key */ - if (keyix >= IEEE80211_WEP_NKID) { - /* - * Don't touch keymap entries for global keys so - * they are never considered for dynamic allocation. - */ - clrbit(sc->sc_keymap, keyix); - if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && - (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { - clrbit(sc->sc_keymap, keyix+64); /* TX 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; -} - -/* - * Set the key cache contents for the specified key. Key cache - * slot(s) must already have been allocated by ath_key_alloc. - */ -static int -ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, - const u_int8_t mac[IEEE80211_ADDR_LEN]) -{ - struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; - - return ath_keyset(sc, k, vap->iv_bss); -} - /* * Block/unblock tx+rx processing while a key change is done. * We assume the caller serializes key management operations diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c new file mode 100644 index 0000000..842f766 --- /dev/null +++ b/sys/dev/ath/if_ath_keycache.c @@ -0,0 +1,497 @@ +/*- + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Atheros Wireless LAN controller. + * + * This software is derived from work of Atsushi Onoe; his contribution + * is greatly appreciated. + */ + +#include "opt_inet.h" +#include "opt_ath.h" +#include "opt_wlan.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> +#include <sys/callout.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/priv.h> + +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_llc.h> + +#include <net80211/ieee80211_var.h> + +#include <net/bpf.h> + +#include <dev/ath/if_athvar.h> + +#include <dev/ath/if_ath_debug.h> +#include <dev/ath/if_ath_keycache.h> + +#ifdef ATH_DEBUG +static void +ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix, + const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) +{ + static const char *ciphers[] = { + "WEP", + "AES-OCB", + "AES-CCM", + "CKIP", + "TKIP", + "CLR", + }; + int i, n; + + printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]); + for (i = 0, n = hk->kv_len; i < n; i++) + printf("%02x", hk->kv_val[i]); + printf(" mac %s", ether_sprintf(mac)); + if (hk->kv_type == HAL_CIPHER_TKIP) { + printf(" %s ", sc->sc_splitmic ? "mic" : "rxmic"); + for (i = 0; i < sizeof(hk->kv_mic); i++) + printf("%02x", hk->kv_mic[i]); + if (!sc->sc_splitmic) { + printf(" txmic "); + for (i = 0; i < sizeof(hk->kv_txmic); i++) + printf("%02x", hk->kv_txmic[i]); + } + } + printf("\n"); +} +#endif + +/* + * Set a TKIP key into the hardware. This handles the + * potential distribution of key state to multiple key + * cache slots for TKIP. + */ +static int +ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k, + HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN]) +{ +#define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) + static const u_int8_t zerobssid[IEEE80211_ADDR_LEN]; + struct ath_hal *ah = sc->sc_ah; + + KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP, + ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher)); + if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { + if (sc->sc_splitmic) { + /* + * TX key goes at first index, RX key at the rx index. + * The hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic)); + KEYPRINTF(sc, k->wk_keyix, hk, zerobssid); + if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid)) + return 0; + + memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); + KEYPRINTF(sc, k->wk_keyix+32, hk, mac); + /* XXX delete tx key on failure? */ + return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac); + } else { + /* + * Room for both TX+RX MIC keys in one key cache + * slot, just set key at the first index; the hal + * will handle the rest. + */ + memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic)); + KEYPRINTF(sc, k->wk_keyix, hk, mac); + return ath_hal_keyset(ah, k->wk_keyix, hk, mac); + } + } 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, 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 +} + +/* + * Set a net80211 key into the hardware. This handles the + * potential distribution of key state to multiple key + * cache slots for TKIP with hardware MIC support. + */ +int +ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, + struct ieee80211_node *bss) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + static const u_int8_t ciphermap[] = { + HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ + HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ + HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ + HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ + (u_int8_t) -1, /* 4 is not allocated */ + HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ + HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ + }; + struct ath_hal *ah = sc->sc_ah; + const struct ieee80211_cipher *cip = k->wk_cipher; + u_int8_t gmac[IEEE80211_ADDR_LEN]; + const u_int8_t *mac; + HAL_KEYVAL hk; + + memset(&hk, 0, sizeof(hk)); + /* + * Software crypto uses a "clear key" so non-crypto + * state kept in the key cache are maintained and + * so that rx frames have an entry to match. + */ + if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { + KASSERT(cip->ic_cipher < N(ciphermap), + ("invalid cipher type %u", cip->ic_cipher)); + hk.kv_type = ciphermap[cip->ic_cipher]; + hk.kv_len = k->wk_keylen; + memcpy(hk.kv_val, k->wk_key, k->wk_keylen); + } else + hk.kv_type = HAL_CIPHER_CLR; + + if ((k->wk_flags & IEEE80211_KEY_GROUP) && sc->sc_mcastkey) { + /* + * Group keys on hardware that supports multicast frame + * key search use a MAC that is the sender's address with + * the multicast bit set instead of the app-specified address. + */ + IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr); + gmac[0] |= 0x01; + mac = gmac; + } else + mac = k->wk_macaddr; + + if (hk.kv_type == HAL_CIPHER_TKIP && + (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { + return ath_keyset_tkip(sc, k, &hk, mac); + } else { + KEYPRINTF(sc, k->wk_keyix, &hk, mac); + return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); + } +#undef N +} + +/* + * 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 u_int16_t +key_alloc_2pair(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++) { + u_int8_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; + } + /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ + if (isset(sc->sc_keymap, keyix+32) || + isset(sc->sc_keymap, keyix+64) || + isset(sc->sc_keymap, keyix+32+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); + setbit(sc->sc_keymap, keyix+32); + setbit(sc->sc_keymap, keyix+32+64); + DPRINTF(sc, ATH_DEBUG_KEYCACHE, + "%s: key pair %u,%u %u,%u\n", + __func__, keyix, keyix+64, + keyix+32, keyix+32+64); + *txkeyix = keyix; + *rxkeyix = keyix+32; + return 1; + } + } + DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__); + return 0; +#undef N +} + +/* + * 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 u_int16_t +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++) { + u_int8_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 +key_alloc_single(struct ath_softc *sc, + ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + u_int i, keyix; + + /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ + for (i = 0; i < N(sc->sc_keymap); i++) { + u_int8_t b = sc->sc_keymap[i]; + if (b != 0xff) { + /* + * One or more slots are free. + */ + keyix = i*NBBY; + while (b & 1) + keyix++, b >>= 1; + setbit(sc->sc_keymap, keyix); + DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n", + __func__, keyix); + *txkeyix = *rxkeyix = keyix; + return 1; + } + } + DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__); + return 0; +#undef N +} + +/* + * Allocate one or more key cache slots for a uniacst key. The + * key itself is needed only to identify the cipher. For hardware + * TKIP with split cipher+MIC keys we allocate two key cache slot + * pairs so that we can setup separate TX and RX MIC keys. Note + * that the MIC key for a TKIP key at slot i is assumed by the + * hardware to be at slot i+64. This limits TKIP keys to the first + * 64 entries. + */ +int +ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + + /* + * Group key allocation must be handled specially for + * parts that do not support multicast key cache search + * functionality. For those parts the key id must match + * the h/w key index so lookups find the right key. On + * parts w/ the key search facility we install the sender's + * mac address (with the high bit set) and let the hardware + * find the key w/o using the key id. This is preferred as + * it permits us to support multiple users for adhoc and/or + * multi-station operation. + */ + if (k->wk_keyix != IEEE80211_KEYIX_NONE) { + /* + * Only global keys should have key index assigned. + */ + 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__); + return 0; + } + if (vap->iv_opmode != IEEE80211_M_HOSTAP || + !(k->wk_flags & IEEE80211_KEY_GROUP) || + !sc->sc_mcastkey) { + /* + * XXX we pre-allocate the global keys so + * have no way to check if they've already + * been allocated. + */ + *keyix = *rxkeyix = k - vap->iv_nw_keys; + return 1; + } + /* + * Group key and device supports multicast key search. + */ + k->wk_keyix = IEEE80211_KEYIX_NONE; + } + + /* + * We allocate two pair for TKIP when using the h/w to do + * the MIC. For everything else, including software crypto, + * we allocate a single entry. Note that s/w crypto requires + * a pass-through slot on the 5211 and 5212. The 5210 does + * not support pass-through cache entries and we map all + * those requests to slot 0. + */ + 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) { + 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); + } +} + +/* + * Delete an entry in the key cache allocated by ath_key_alloc. + */ +int +ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + 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; + + DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); + + ath_hal_keyreset(ah, keyix); + /* + * Handle split tx/rx keying required for TKIP with h/w MIC. + */ + if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && + (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) + ath_hal_keyreset(ah, keyix+32); /* RX key */ + if (keyix >= IEEE80211_WEP_NKID) { + /* + * Don't touch keymap entries for global keys so + * they are never considered for dynamic allocation. + */ + clrbit(sc->sc_keymap, keyix); + if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && + (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { + clrbit(sc->sc_keymap, keyix+64); /* TX 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; +} + +/* + * Set the key cache contents for the specified key. Key cache + * slot(s) must already have been allocated by ath_key_alloc. + */ +int +ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, + const u_int8_t mac[IEEE80211_ADDR_LEN]) +{ + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + + return ath_keyset(sc, k, vap->iv_bss); +} diff --git a/sys/dev/ath/if_ath_keycache.h b/sys/dev/ath/if_ath_keycache.h new file mode 100644 index 0000000..f1696cb --- /dev/null +++ b/sys/dev/ath/if_ath_keycache.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2011 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef __IF_ATH_CRYPTO_H__ +#define __IF_ATH_CRYPTO_H__ + +extern int ath_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); +extern int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *); +extern int ath_key_set(struct ieee80211vap *, const struct ieee80211_key *, + const u_int8_t mac[IEEE80211_ADDR_LEN]); +extern int ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k, + struct ieee80211_node *bss); + +#endif diff --git a/sys/modules/ath/Makefile b/sys/modules/ath/Makefile index 4f5d65d..991c027 100644 --- a/sys/modules/ath/Makefile +++ b/sys/modules/ath/Makefile @@ -35,7 +35,8 @@ ATH_RATE?= sample # tx rate control algorithm .PATH: ${.CURDIR}/../../dev/ath/ath_hal KMOD= if_ath -SRCS= if_ath.c if_ath_pci.c if_ath_debug.c if_ath_sysctl.c if_ath_tx.c if_ath_tx_ht.c +SRCS= if_ath.c if_ath_pci.c if_ath_debug.c if_ath_keycache.c if_ath_sysctl.c +SRCS+= if_ath_tx.c if_ath_tx_ht.c # NB: v3 eeprom support used by both AR5211 and AR5212; just include it SRCS+= ah_osdep.c ah.c ah_regdomain.c ah_eeprom_v3.c SRCS+= device_if.h bus_if.h pci_if.h opt_inet.h opt_ath.h opt_ah.h opt_wlan.h |