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"

Reply via email to