Author: adrian Date: Wed Mar 2 17:19:54 2011 New Revision: 219185 URL: http://svn.freebsd.org/changeset/base/219185
Log: Break the keycache management functions out into if_ath_keycache.c . Added: head/sys/dev/ath/if_ath_keycache.c (contents, props changed) head/sys/dev/ath/if_ath_keycache.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/ath/if_ath.c head/sys/modules/ath/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Wed Mar 2 17:13:07 2011 (r219184) +++ head/sys/conf/files Wed Mar 2 17:19:54 2011 (r219185) @@ -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 \ Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Wed Mar 2 17:13:07 2011 (r219184) +++ head/sys/dev/ath/if_ath.c Wed Mar 2 17:19:54 2011 (r219185) @@ -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_l 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 Added: head/sys/dev/ath/if_ath_keycache.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_keycache.c Wed Mar 2 17:19:54 2011 (r219185) @@ -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); +} Added: head/sys/dev/ath/if_ath_keycache.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/ath/if_ath_keycache.h Wed Mar 2 17:19:54 2011 (r219185) @@ -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 *, *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"