Project : madwifi
Revision : 1838
Author : dwhedon (David Kimdon)
Date : 2006-12-07 01:37:02 +0100 (Thu, 07 Dec 2006)
Log Message :
ticket:986
Add hardware encryption support.
* README.dadwifi : Note that the feature related to sc_mcastkey
* ath/if_ath.h : Add prototypes for ath_key_alloc, ath_key_delete,
ath_keyset, these functions are now exported from if_ath.c.
* ath/if_athvar.h : Pull in some constants from net80211.
(struct ath_key) : New structure, add an array of them to struct ath_softc.
* ath/if_ath_d80211.c (ath_d80211_set_key) : New function.
* ath/if_ath.c (ath_attach) : Do not pre-allocate global keys. We need to
know if keys are set in case a default key is used. unifdef section where
we figure out hardware's crypto support.
(ath_tx_startraw) : Set key index based on struct ieee80211_tx_control and
adjust pktlen based on data hardware will add.
(ath_keyprint) : unifdef
(ath_keyset_tkip) : Take struct ieee80211_key_conf rather
than struct ieee80211_key as key argument. For station mode,
only set rx key.
(ath_keyset) : Take struct ieee80211_key_conf rather than struct
ieee80211_key as key argument. Remove explicit group key handling,
that is all taken care of by key allocation.
(key_alloc_2pair, key_alloc_single) : Never alloc a default key or
any of the index needed for TKIP split MIC.
(ath_key_alloc) : Pass address to this function so we can tell if this is
a default key. If this is a default key mark the bitmap appropriately. Take
struct ieee80211_key_conf rather than struct ieee80211_key as key argument.
(ath_key_delete) : Take struct ieee80211_key_conf rather than struct
ieee80211_key as key argument. This function now clears global keys as
well.
(ath_key_set) : Remove this function, this is only needed to interface with
net80211.
(ath_rx_hw_decrypted) : New function.
(ath_rx_tasklet) : Fix setting of RX_FLAG_DECRYPTED.
(ATH_SYSCTL_DECL) : Enable toggle of TKIP MIC hwaccell.
Affected Files:
* branches/dadwifi/README.dadwifi updated
* branches/dadwifi/ath/if_ath.c updated
* branches/dadwifi/ath/if_ath.h updated
* branches/dadwifi/ath/if_ath_d80211.c updated
* branches/dadwifi/ath/if_athvar.h updated
Modified: branches/dadwifi/README.dadwifi
===================================================================
--- branches/dadwifi/README.dadwifi 2006-12-06 18:04:39 UTC (rev 1837)
+++ branches/dadwifi/README.dadwifi 2006-12-07 00:37:02 UTC (rev 1838)
@@ -91,6 +91,11 @@
- tx power control : tx power control handling needs to be looked at. I
don't
know what the unit is for the power argument to ath_hal_setuptxdesc().
+Here is a list of features which are currently on hold:
+
+ - multicast frame key search: See sc->sc_mcastkey, etc. I disabled this
+ for now since I am unsure what to do about it.
+
Here is a list of features which we do not plan on working on:
- Super G, super G fast frames, super G compression, dynamic turbo and XR :
Modified: branches/dadwifi/ath/if_ath.c
===================================================================
--- branches/dadwifi/ath/if_ath.c 2006-12-06 18:04:39 UTC (rev 1837)
+++ branches/dadwifi/ath/if_ath.c 2006-12-07 00:37:02 UTC (rev 1838)
@@ -124,11 +124,6 @@
#if 0
static void ath_initkeytable(struct ath_softc *);
#endif
-static int ath_key_alloc(struct ieee80211vap *, const struct ieee80211_key *);
-static int ath_key_delete(struct ieee80211vap *, const struct ieee80211_key *,
- struct ieee80211_node *);
-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 *);
#endif
@@ -368,6 +363,7 @@
int
ath_attach(u_int16_t devid, struct ath_softc *sc)
{
+ struct ieee80211_hw *hw = sc->sc_hw;
struct ath_hal *ah;
HAL_STATUS status;
int error = 0, i;
@@ -457,20 +453,6 @@
*/
for (i = 0; i < sc->sc_keymax; i++)
ath_hal_keyreset(ah, i);
-#if 0
- /*
- * Mark key cache slots associated with global keys
- * as in use. If we knew TKIP was not to be used we
- * could leave the +32, +64, and +32+64 slots free.
- * XXX only for splitmic.
- */
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- setbit(sc->sc_keymap, i);
- setbit(sc->sc_keymap, i+32);
- setbit(sc->sc_keymap, i+64);
- setbit(sc->sc_keymap, i+32+64);
- }
-#endif
/*
* Collect the channel list using the default country
@@ -744,37 +726,36 @@
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
| IEEE80211_C_BGSCAN /* capable of bg scanning */
;
+#endif
/*
* Query the hal to figure out h/w crypto support.
*/
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_WEP))
- ic->ic_caps |= IEEE80211_C_WEP;
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_OCB))
- ic->ic_caps |= IEEE80211_C_AES;
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM))
- ic->ic_caps |= IEEE80211_C_AES_CCM;
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_CKIP))
- ic->ic_caps |= IEEE80211_C_CKIP;
if (ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) {
- ic->ic_caps |= IEEE80211_C_TKIP;
/*
* Check if h/w does the MIC and/or whether the
* separate key cache entries are required to
* handle both tx+rx MIC keys.
*/
- if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC)) {
- ic->ic_caps |= IEEE80211_C_TKIPMIC;
+ if (ath_hal_ciphersupported(ah, HAL_CIPHER_MIC) &&
+ ath_hal_hastkipmic(ah)) {
+
/*
* Check if h/w does MIC correctly when
* WMM is turned on.
*/
- if (ath_hal_wmetkipmic(ah))
- ic->ic_caps |= IEEE80211_C_WME_TKIPMIC;
+ if (!ath_hal_wmetkipmic(ah))
+ /* FIXME: add a flag to d80211 so we can
+ support hardware TKIP and software MIC
+ for WME? */
+ hw->flags |= IEEE80211_HW_NO_TKIP_WMM_HWACCEL;
+ } else {
+ hw->flags |= IEEE80211_HW_TKIP_INCLUDE_MMIC;
}
if (ath_hal_tkipsplit(ah))
sc->sc_splitmic = 1;
}
+#if 0
sc->sc_hasclrkey = ath_hal_ciphersupported(ah, HAL_CIPHER_CLR);
#if 0
sc->sc_mcastkey = ath_hal_getmcastkeysearch(ah);
@@ -1025,9 +1006,6 @@
vap = &avp->av_vap;
avp->av_newstate = vap->iv_newstate;
vap->iv_newstate = ath_newstate;
- vap->iv_key_alloc = ath_key_alloc;
- vap->iv_key_delete = ath_key_delete;
- vap->iv_key_set = ath_key_set;
vap->iv_key_update_begin = ath_key_update_begin;
vap->iv_key_update_end = ath_key_update_end;
#ifdef ATH_SUPERG_COMP
@@ -2256,7 +2234,31 @@
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
pktlen = skb->len - header_pad + FCS_LEN;
- keyix = HAL_TXKEYIX_INVALID;
+ if (control->key_idx == HW_KEY_IDX_INVALID)
+ keyix = HAL_TXKEYIX_INVALID;
+ else {
+ keyix = control->key_idx;
+
+ if (sc->sc_ath_keys[keyix].ak_alg == ALG_TKIP) {
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ u16 sc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+ sc = le16_to_cpu(hdr->seq_ctrl);
+
+ if (likely(!(fc & IEEE80211_FCTL_MOREFRAGS) &&
+ (sc & IEEE80211_SCTL_FRAG) == 0)) {
+
+ /* hwaccel adds Michael MIC to the end of the
+ * payload of unfragmented frames. */
+ pktlen += 8;
+ }
+ }
+
+ pktlen += control->icv_len;
+ }
flags = HAL_TXDESC_INTREQ | HAL_TXDESC_CLRDMASK; /* XXX needed for
crypto errs */
bf->bf_skbaddr = bus_map_single(sc->sc_bdev,
@@ -2864,6 +2866,7 @@
skb = NULL;
return error;
}
+#endif
#ifdef AR_DEBUG
static void
@@ -2883,7 +2886,7 @@
printk("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]);
for (i = 0, n = hk->kv_len; i < n; i++)
printk("%02x", hk->kv_val[i]);
- printk(" mac %s", ether_sprintf(mac));
+ printk(" mac " MAC_FMT, MAC_ARG(mac));
if (hk->kv_type == HAL_CIPHER_TKIP) {
printk(" mic ");
for (i = 0; i < sizeof(hk->kv_mic); i++)
@@ -2899,68 +2902,63 @@
* 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])
+ath_keyset_tkip(struct ath_softc *sc, struct ieee80211_key_conf *key,
+ 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));
+ KASSERT(hk->kv_type == HAL_CIPHER_TKIP,
+ ("got a non-TKIP key, cipher %u", hk->kv_type));
KASSERT(sc->sc_splitmic, ("key cache !split"));
- if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
+ if (!(sc->sc_opmode == HAL_M_STA && key->hw_key_idx <
IEEE80211_WEP_NKID)) {
/*
* TX key goes at first index, RX key at +32.
* 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))
+ memcpy(hk->kv_mic, key->key + 16 /*
ALG_TKIP_TEMP_AUTH_TX_MIC_KEY */,
+ 8 /* FIXME: define a constant */);
+ KEYPRINTF(sc, key->hw_key_idx, hk, zerobssid);
+ if (!ath_hal_keyset(ah, key->hw_key_idx, hk, zerobssid))
return 0;
- memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
- KEYPRINTF(sc, k->wk_keyix + 32, hk, mac);
+ memcpy(hk->kv_mic, key->key + 24 /*
ALG_TKIP_TEMP_AUTH_RX_MIC_KEY */,
+ 8 /* FIXME: define a constant */);
+ KEYPRINTF(sc, key->hw_key_idx + 32, hk, mac);
/* XXX delete tx key on failure? */
- return ath_hal_keyset(ah, k->wk_keyix + 32, hk, mac);
- } else if (k->wk_flags & IEEE80211_KEY_XR) {
+ return ath_hal_keyset(ah, key->hw_key_idx + 32, hk, mac);
+ } else {
/*
- * TX/RX key goes at first index.
+ * RX key goes at first index.
* The hal handles the MIC keys are index+64.
*/
- memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
- k->wk_txmic : k->wk_rxmic, sizeof(hk->kv_mic));
- KEYPRINTF(sc, k->wk_keyix, hk, mac);
- return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
+ memcpy(hk->kv_mic, key->key + 24 /*
ALG_TKIP_TEMP_AUTH_RX_MIC_KEY */,
+ 8 /* FIXME: define a constant */);
+ KEYPRINTF(sc, key->hw_key_idx, hk, mac);
+ return ath_hal_keyset(ah, key->hw_key_idx, hk, mac);
}
return 0;
-#undef IEEE80211_KEY_XR
}
/*
- * Set a net80211 key into the hardware. This handles the
+ * Set a 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,
- const u_int8_t mac0[IEEE80211_ADDR_LEN],
- struct ieee80211_node *bss)
+int
+ath_keyset(struct ath_softc *sc, struct ieee80211_key_conf *key,
+ const u_int8_t mac[IEEE80211_ADDR_LEN])
{
#define N(a) ((int)(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 */
+ HAL_CIPHER_CLR, /* ALG_NONE */
+ HAL_CIPHER_WEP, /* ALG_WEP */
+ HAL_CIPHER_TKIP, /* ALG_TKIP */
+ HAL_CIPHER_AES_CCM, /* ALG_CCMP */
+ HAL_CIPHER_CLR, /* ALG_NULL */
};
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;
+ struct ieee80211_hw *hw = sc->sc_hw;
HAL_KEYVAL hk;
memset(&hk, 0, sizeof(hk));
@@ -2969,34 +2967,28 @@
* 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);
+ if (key->alg != ALG_NULL) {
+ if (key->alg >= N(ciphermap)) {
+ DPRINTF(sc, ATH_DEBUG_KEYCACHE,
+ "%s: invalid cipher type %u\n", __func__,
key->alg);
+ return 0;
+ }
+ hk.kv_type = ciphermap[key->alg];
+ if (key->alg == ALG_TKIP)
+ hk.kv_len = 16; /* FIXME: define a constant */
+ else
+ hk.kv_len = key->keylen;
+ memcpy(hk.kv_val, key->key, hk.kv_len);
} 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 high bit set instead of the app-specified address.
- */
- IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
- gmac[0] |= 0x80;
- mac = gmac;
- } else
- mac = mac0;
-
if (hk.kv_type == HAL_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
+ (hw->flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) == 0 &&
sc->sc_splitmic) {
- return ath_keyset_tkip(sc, k, &hk, mac);
+ return ath_keyset_tkip(sc, key, &hk, mac);
} else {
- KEYPRINTF(sc, k->wk_keyix, &hk, mac);
- return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
+ KEYPRINTF(sc, key->hw_key_idx, &hk, mac);
+ return ath_hal_keyset(ah, key->hw_key_idx, &hk, mac);
}
#undef N
}
@@ -3028,8 +3020,9 @@
/* 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 */
+ isset(sc->sc_keymap, keyix + 32 + 64) ||
+ keyix < IEEE80211_WEP_NKID) {
+ /* index unavailable */
/* XXX statistic */
if (keyix == (i + 1) * NBBY) {
/* no slots were appropriate, advance */
@@ -3070,8 +3063,23 @@
* One or more slots are free.
*/
keyix = i * NBBY;
- while (b & 1)
+ while (b & 1) {
+ again:
keyix++, b >>= 1;
+ }
+ if (keyix < IEEE80211_WEP_NKID ||
+ (keyix >= 32 && keyix < (32 + IEEE80211_WEP_NKID))
||
+ (keyix >= 64 && keyix < (64 + IEEE80211_WEP_NKID))
||
+ (keyix >= (32 + 64) &&
+ keyix < (32 + 64 + IEEE80211_WEP_NKID))) {
+ /* never alloc a default key or default TKIP
+ key pair */
+ if (keyix == (i + 1) * NBBY) {
+ /* no slots were appropriate, advance */
+ continue;
+ }
+ goto again;
+ }
setbit(sc->sc_keymap, keyix);
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
__func__, keyix);
@@ -3092,38 +3100,26 @@
* hardware to be at slot i+64. This limits TKIP keys to the first
* 64 entries.
*/
-static int
-ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k)
+int
+ath_key_alloc(struct ath_softc *sc, struct ieee80211_key_conf *key,
+ const u_int8_t addr[IEEE80211_ADDR_LEN])
{
- struct net_device *dev = vap->iv_ic->ic_dev;
- struct ath_softc *sc = dev->priv;
+ struct ieee80211_hw *hw = sc->sc_hw;
+ u_int keyix;
- /*
- * 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_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
- u_int keyix;
+ if ((key->flags & IEEE80211_KEY_DEFAULT_WEP_ONLY) &&
+ (addr == NULL ||
+ memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)) {
+ keyix = key->keyidx;
- 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 IEEE80211_KEYIX_NONE;
- }
- keyix = k - vap->iv_nw_keys;
- /*
- * XXX we pre-allocate the global keys so
- * have no way to check if they've already been allocated.
- */
+ if (key->alg == ALG_TKIP) {
+ setbit(sc->sc_keymap, keyix);
+ setbit(sc->sc_keymap, keyix + 64);
+ setbit(sc->sc_keymap, keyix + 32);
+ setbit(sc->sc_keymap, keyix + 32 + 64);
+ } else
+ setbit(sc->sc_keymap, keyix);
+
return keyix;
}
/*
@@ -3137,10 +3133,9 @@
* Allocate 1 pair of keys for WEP case. Make sure the key
* is not a shared-key.
*/
- if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
- return key_alloc_single(sc);
- else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) {
+ if (key->alg == ALG_TKIP &&
+ (hw->flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) == 0 &&
+ sc->sc_splitmic) {
return key_alloc_2pair(sc);
} else
return key_alloc_single(sc);
@@ -3149,91 +3144,42 @@
/*
* 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 ieee80211_node *ninfo)
+int
+ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
{
- struct net_device *dev = vap->iv_ic->ic_dev;
- struct ath_softc *sc = dev->priv;
struct ath_hal *ah = sc->sc_ah;
- const struct ieee80211_cipher *cip = k->wk_cipher;
- struct ieee80211_node *ni;
- u_int keyix = k->wk_keyix;
- int rxkeyoff = 0;
+ struct ieee80211_hw *hw = sc->sc_hw;
+ u_int keyix = key->hw_key_idx;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
+ keyix = key->hw_key_idx;
+
ath_hal_keyreset(ah, keyix);
/*
- * Check the key->node map and flush any ref.
- */
- ni = sc->sc_keyixmap[keyix];
- if (ni != NULL) {
- ieee80211_free_node(ni);
- sc->sc_keyixmap[keyix] = NULL;
- }
- /*
* 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) {
+ if (key->alg == ALG_TKIP &&
+ (hw->flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) == 0 &&
+ sc->sc_splitmic) {
ath_hal_keyreset(ah, keyix + 32); /* RX key */
- ni = sc->sc_keyixmap[keyix+32];
- if (ni != NULL) { /* as above... */
- ieee80211_free_node(ni);
- sc->sc_keyixmap[keyix+32] = NULL;
- }
}
- /* Remove receive key entry if one exists for static WEP case */
- if (ninfo != NULL) {
- rxkeyoff = ninfo->ni_rxkeyoff;
- if (rxkeyoff != 0) {
- ninfo->ni_rxkeyoff = 0;
- ath_hal_keyreset(ah, keyix + rxkeyoff);
- ni = sc->sc_keyixmap[keyix+rxkeyoff];
- if (ni != NULL) { /* as above... */
- ieee80211_free_node(ni);
- sc->sc_keyixmap[keyix+rxkeyoff] = NULL;
- }
- }
- }
-
- if (keyix >= IEEE80211_WEP_NKID) {
- /*
- * Don't touch keymap entries for global keys so
- * they are never considered for dynamic allocation.
- */
+ if (1) {
clrbit(sc->sc_keymap, keyix);
- if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
- (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
+ if (key->alg == ALG_TKIP &&
+ (hw->flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) == 0 &&
sc->sc_splitmic) {
clrbit(sc->sc_keymap, keyix + 64); /* TX key MIC */
clrbit(sc->sc_keymap, keyix + 32); /* RX key */
clrbit(sc->sc_keymap, keyix + 32 + 64); /* RX key MIC */
}
-
- if (rxkeyoff != 0)
- clrbit(sc->sc_keymap, keyix + rxkeyoff);/*RX Key */
}
return 1;
}
+#if 0
/*
- * 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 net_device *dev = vap->iv_ic->ic_dev;
- struct ath_softc *sc = dev->priv;
-
- return ath_keyset(sc, k, mac, vap->iv_bss);
-}
-
-/*
* Block/unblock tx+rx processing while a key change is done.
* We assume the caller serializes key management operations
* so we only need to worry about synchronization with other
@@ -5434,6 +5380,42 @@
sc->sc_rxotherant = 0;
}
+/**
+ * ath_rx_hw_decrypted - determine if this frame was decrypted by hardware
+ *
+ * Returns non-zero if the frame was decrypted by the device.
+ */
+static int
+ath_rx_hw_decrypted(struct ath_softc *sc, struct ath_desc *ds,
+ struct sk_buff *skb, int header_len)
+{
+ u16 fc;
+ struct ieee80211_hdr *hdr;
+ int keyix;
+
+ if (!(ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) &&
+ (ds->ds_rxstat.rs_keyix != HAL_RXKEYIX_INVALID))
+ return 1;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ /* Apparently when a default key is used to decrypt the packet
+ the hal does not set the index used to decrypt. In such cases
+ get the index from the packet. */
+ if (!(ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) &&
+ fc & IEEE80211_FCTL_PROTECTED &&
+ skb->len >= header_len + 4) {
+ keyix = skb->data[header_len + 3] >> 6;
+
+ if (isset(sc->sc_keymap, keyix)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static void
ath_rx_tasklet(TQUEUE_ARG data)
{
@@ -5717,10 +5699,6 @@
status.ssi = ds->ds_rxstat.rs_rssi;
status.antenna = ds->ds_rxstat.rs_antenna;
status.rate = ds->ds_rxstat.rs_rate;
-
- if (!(ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) &&
- (ds->ds_rxstat.rs_keyix != HAL_RXKEYIX_INVALID))
- status.flag |= RX_FLAG_DECRYPTED;
/* The device will pad 802.11 header to a multiple of 4 bytes.
Remove the padding before passing the skb to the stack. */
@@ -5732,6 +5710,9 @@
skb_pull(skb, header_pad);
}
+ if (ath_rx_hw_decrypted(sc, ds, skb, header_len))
+ status.flag |= RX_FLAG_DECRYPTED;
+
__ieee80211_rx(sc->sc_hw, skb, &status);
#endif
if (sc->sc_diversity) {
@@ -9258,6 +9239,7 @@
ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
{
struct ath_softc *sc = ctl->extra1;
+ struct ieee80211_hw *hw = sc->sc_hw;
struct ath_hal *ah = sc->sc_ah;
u_int val;
int ret;
@@ -9348,20 +9330,18 @@
/* XXX valiate? */
sc->sc_fftxqmin = val;
break;
-#ifdef CONFIG_NET80211
case ATH_TKIPMIC: {
- struct ieee80211com *ic = &sc->sc_ic;
-
if (!ath_hal_hastkipmic(ah))
return -EINVAL;
ath_hal_settkipmic(ah, val);
if (val)
- ic->ic_caps |= IEEE80211_C_TKIPMIC;
+ hw->flags &=
~IEEE80211_HW_TKIP_INCLUDE_MMIC;
else
- ic->ic_caps &= ~IEEE80211_C_TKIPMIC;
+ hw->flags |=
IEEE80211_HW_TKIP_INCLUDE_MMIC;
+
+ ieee80211_update_hw(hw);
break;
}
-#endif
#ifdef ATH_SUPERG_XR
case ATH_XR_POLL_PERIOD:
if (val > XR_MAX_POLL_INTERVAL)
Modified: branches/dadwifi/ath/if_ath.h
===================================================================
--- branches/dadwifi/ath/if_ath.h 2006-12-06 18:04:39 UTC (rev 1837)
+++ branches/dadwifi/ath/if_ath.h 2006-12-07 00:37:02 UTC (rev 1838)
@@ -50,6 +50,12 @@
void ath_descdma_cleanup(struct ath_softc *, struct ath_descdma *,
ath_bufhead *, int);
+int ath_key_alloc(struct ath_softc *sc, struct ieee80211_key_conf *key,
+ const u_int8_t addr[IEEE80211_ADDR_LEN]);
+int ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key);
+int ath_keyset(struct ath_softc *sc, struct ieee80211_key_conf *key,
+ const u_int8_t mac0[IEEE80211_ADDR_LEN]);
+
#define AR_DEBUG
extern int ath_debug;
Modified: branches/dadwifi/ath/if_ath_d80211.c
===================================================================
--- branches/dadwifi/ath/if_ath_d80211.c 2006-12-06 18:04:39 UTC (rev
1837)
+++ branches/dadwifi/ath/if_ath_d80211.c 2006-12-07 00:37:02 UTC (rev
1838)
@@ -46,6 +46,7 @@
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
#include "if_athvar.h"
#include "if_ath_d80211.h"
@@ -522,7 +523,103 @@
return ath_reset(sc);
}
+static int
+ath_d80211_set_key(struct ieee80211_hw *hw, set_key_cmd cmd, u8 *addr,
+ struct ieee80211_key_conf *key, int aid)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+ int ret = 0;
+ u_int keyix;
+ int i;
+ DPRINTF(sc, ATH_DEBUG_D80211,
+ "%s %s%s%s hw %d %s%s%s%s%s " MAC_FMT " WEP %x, %s%s\n",
+ __func__,
+ cmd == SET_KEY ? "SET_KEY" : "",
+ cmd == DISABLE_KEY ? "DISABLE_KEY" : "",
+ cmd == REMOVE_ALL_KEYS ? "REMOVE_ALL_KEYS" : "",
+ key->hw_key_idx,
+ key->alg == ALG_NONE ? "ALG_NONE" : "",
+ key->alg == ALG_WEP ? "ALG_WEP" : "",
+ key->alg == ALG_TKIP ? "ALG_TKIP" : "",
+ key->alg == ALG_CCMP ? "ALG_CCMP" : "",
+ key->alg == ALG_NULL ? "ALG_NULL" : "",
+ MAC_ARG(addr),
+ key->keyidx,
+ key->flags & IEEE80211_KEY_DEFAULT_TX_KEY ?
+ " DEFAULT_TX_KEY" : "",
+ key->flags & IEEE80211_KEY_DEFAULT_WEP_ONLY ?
+ " DEFAULT_WEP_ONLY" : "");
+ ATH_LOCK(sc);
+
+ switch (cmd) {
+ case SET_KEY:
+ switch (key->alg) {
+ case ALG_WEP:
+ if (!ath_hal_ciphersupported(ah, HAL_CIPHER_WEP)) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ case ALG_TKIP:
+ if (!ath_hal_ciphersupported(ah, HAL_CIPHER_TKIP)) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ case ALG_CCMP:
+ if (!ath_hal_ciphersupported(ah, HAL_CIPHER_AES_CCM)) {
+ ret = -1;
+ goto done;
+ }
+ break;
+ case ALG_NONE:
+ case ALG_NULL:
+ break;
+ }
+
+ keyix = ath_key_alloc(sc, key, addr);
+
+ if (keyix == IEEE80211_KEYIX_NONE) {
+ ret = -1;
+ goto done;
+ }
+
+ key->hw_key_idx = keyix;
+
+ if (!ath_keyset(sc, key, addr)) {
+
+ ath_key_delete(sc, key);
+
+ ret = -1;
+ goto done;
+ }
+
+ key->flags &= ~IEEE80211_KEY_FORCE_SW_ENCRYPT;
+ sc->sc_ath_keys[keyix].ak_alg = key->alg;
+ break;
+
+ case DISABLE_KEY:
+ ath_key_delete(sc, key);
+ break;
+ case REMOVE_ALL_KEYS:
+ for (i = 0; i < sc->sc_keymax; i++) {
+ ath_hal_keyreset(ah, i);
+ clrbit(sc->sc_keymap, i);
+ }
+ memset(sc->sc_ath_keys, 0, sizeof(sc->sc_ath_keys));
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+done:
+ ATH_UNLOCK(sc);
+ return ret;
+}
+
+
static u64
ath_d80211_get_tsf(struct ieee80211_hw *hw)
{
@@ -556,6 +653,7 @@
.remove_interface = ath_d80211_remove_interface,
.config = ath_d80211_config,
.config_interface = ath_d80211_config_interface,
+ .set_key = ath_d80211_set_key,
.get_tsf = ath_d80211_get_tsf,
.reset_tsf = ath_d80211_reset_tsf,
};
Modified: branches/dadwifi/ath/if_athvar.h
===================================================================
--- branches/dadwifi/ath/if_athvar.h 2006-12-06 18:04:39 UTC (rev 1837)
+++ branches/dadwifi/ath/if_athvar.h 2006-12-07 00:37:02 UTC (rev 1838)
@@ -64,6 +64,8 @@
#define WME_AC_VO 3 /* voice */
#define IEEE80211_MAX_LEN 2500
#define ATHDESC_HEADER_SIZE 32
+#define IEEE80211_KEYIX_NONE ((u_int16_t) - 1)
+#define IEEE80211_WEP_NKID 4 /* number of key ids */
/* WME stream classes */
#define WME_AC_BE 0 /* best effort */
@@ -299,13 +301,17 @@
/*
* The key cache is used for h/w cipher state and also for
* tracking station state such as the current tx antenna.
- * We also setup a mapping table between key cache slot indices
- * and station state to short-circuit node lookups on rx.
* Different parts have different size key caches. We handle
* up to ATH_KEYMAX entries (could dynamically allocate state).
*/
#define ATH_KEYMAX 128 /* max key cache size we handle
*/
#define ATH_KEYBYTES (ATH_KEYMAX / NBBY) /* storage space in
bytes */
+
+/* used to keep track of hardware cipher state */
+struct ath_key {
+ u8 ak_alg;
+};
+
#define ATH_MIN_FF_RATE 12000 /* min rate fof ff
aggragattion.in Kbps */
#define ATH_MIN_FF_RATE 12000 /* min rate fof ff
aggragattion.in Kbps */
struct ath_buf;
@@ -594,6 +600,7 @@
u_int sc_fftxqmin; /* aggregation threshold */
HAL_INT sc_imask; /* interrupt mask copy */
u_int sc_keymax; /* size of key cache */
+ struct ath_key sc_ath_keys[ATH_KEYMAX]; /* cached key table */
u_int8_t sc_keymap[ATH_KEYBYTES]; /* key use bit map */
struct ieee80211_node *sc_keyixmap[ATH_KEYMAX];/* key ix->node map */
u_int8_t sc_bssidmask[IEEE80211_ADDR_LEN];
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
|