summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath/if_ath.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/if_ath.c')
-rw-r--r--sys/dev/ath/if_ath.c124
1 files changed, 44 insertions, 80 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 7e91f30..ac99401 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -112,7 +112,8 @@ static void ath_fatal_proc(void *, int);
static void ath_rxorn_proc(void *, int);
static void ath_bmiss_proc(void *, int);
static int ath_key_alloc(struct ieee80211com *,
- const struct ieee80211_key *);
+ const struct ieee80211_key *,
+ ieee80211_keyix *, ieee80211_keyix *);
static int ath_key_delete(struct ieee80211com *,
const struct ieee80211_key *);
static int ath_key_set(struct ieee80211com *, const struct ieee80211_key *,
@@ -568,6 +569,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ic->ic_recv_mgmt = ath_recv_mgmt;
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = ath_newstate;
+ ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
ic->ic_crypto.cs_key_alloc = ath_key_alloc;
ic->ic_crypto.cs_key_delete = ath_key_delete;
ic->ic_crypto.cs_key_set = ath_key_set;
@@ -1262,7 +1264,7 @@ ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
KASSERT(sc->sc_splitmic, ("key cache !split"));
if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
/*
- * TX key goes at first index, RX key at +32.
+ * 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));
@@ -1357,7 +1359,8 @@ ath_keyset(struct ath_softc *sc, const struct ieee80211_key *k,
* each key, one for decrypt/encrypt and the other for the MIC.
*/
static u_int16_t
-key_alloc_2pair(struct ath_softc *sc)
+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;
@@ -1396,19 +1399,22 @@ key_alloc_2pair(struct ath_softc *sc)
"%s: key pair %u,%u %u,%u\n",
__func__, keyix, keyix+64,
keyix+32, keyix+32+64);
- return keyix;
+ *txkeyix = keyix;
+ *rxkeyix = keyix+32;
+ return 1;
}
}
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
- return IEEE80211_KEYIX_NONE;
+ return 0;
#undef N
}
/*
* Allocate a single key cache slot.
*/
-static u_int16_t
-key_alloc_single(struct ath_softc *sc)
+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;
@@ -1426,11 +1432,12 @@ key_alloc_single(struct ath_softc *sc)
setbit(sc->sc_keymap, keyix);
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
__func__, keyix);
- return keyix;
+ *txkeyix = *rxkeyix = keyix;
+ return 1;
}
}
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__);
- return IEEE80211_KEYIX_NONE;
+ return 0;
#undef N
}
@@ -1444,7 +1451,8 @@ key_alloc_single(struct ath_softc *sc)
* 64 entries.
*/
static int
-ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
+ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
struct ath_softc *sc = ic->ic_ifp->if_softc;
@@ -1460,21 +1468,19 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
* multi-station operation.
*/
if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
- u_int keyix;
-
if (!(&ic->ic_nw_keys[0] <= k &&
k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
/* should not happen */
DPRINTF(sc, ATH_DEBUG_KEYCACHE,
"%s: bogus group key\n", __func__);
- return IEEE80211_KEYIX_NONE;
+ return 0;
}
- keyix = k - ic->ic_nw_keys;
/*
* XXX we pre-allocate the global keys so
* have no way to check if they've already been allocated.
*/
- return keyix;
+ *keyix = *rxkeyix = k - ic->ic_nw_keys;
+ return 1;
}
/*
@@ -1486,12 +1492,12 @@ ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
* those requests to slot 0.
*/
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
- return key_alloc_single(sc);
+ return key_alloc_single(sc, keyix, rxkeyix);
} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
(k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic) {
- return key_alloc_2pair(sc);
+ return key_alloc_2pair(sc, keyix, rxkeyix);
} else {
- return key_alloc_single(sc);
+ return key_alloc_single(sc, keyix, rxkeyix);
}
}
@@ -1504,32 +1510,17 @@ ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
struct ath_softc *sc = ic->ic_ifp->if_softc;
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;
DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
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) {
+ (k->wk_flags & IEEE80211_KEY_SWMIC) == 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;
- }
- }
if (keyix >= IEEE80211_WEP_NKID) {
/*
* Don't touch keymap entries for global keys so
@@ -2821,50 +2812,22 @@ rx_accept:
/*
* Locate the node for sender, track state, and then
* pass the (referenced) node up to the 802.11 layer
- * for its use. If the sender is unknown spam the
- * frame; it'll be dropped where it's not wanted.
+ * for its use.
*/
- if (ds->ds_rxstat.rs_keyix != HAL_RXKEYIX_INVALID &&
- (ni = sc->sc_keyixmap[ds->ds_rxstat.rs_keyix]) != NULL) {
- /*
- * Fast path: node is present in the key map;
- * grab a reference for processing the frame.
- */
- an = ATH_NODE(ieee80211_ref_node(ni));
- ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
- type = ieee80211_input(ic, m, ni,
- ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
- } else {
- /*
- * Locate the node for sender, track state, and then
- * pass the (referenced) node up to the 802.11 layer
- * for its use.
- */
- ni = ieee80211_find_rxnode(ic,
- mtod(m, const struct ieee80211_frame_min *));
- /*
- * Track rx rssi and do any rx antenna management.
- */
- an = ATH_NODE(ni);
- ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
- /*
- * Send frame up for processing.
- */
- type = ieee80211_input(ic, m, ni,
- ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
- if (ni != ic->ic_bss) {
- u_int16_t keyix;
- /*
- * If the station has a key cache slot assigned
- * update the key->node mapping table.
- */
- keyix = ni->ni_ucastkey.wk_keyix;
- if (keyix != IEEE80211_KEYIX_NONE &&
- sc->sc_keyixmap[keyix] == NULL)
- sc->sc_keyixmap[keyix] =
- ieee80211_ref_node(ni);
- }
- }
+ ni = ieee80211_find_rxnode_withkey(ic,
+ mtod(m, const struct ieee80211_frame_min *),
+ ds->ds_rxstat.rs_keyix == HAL_RXKEYIX_INVALID ?
+ IEEE80211_KEYIX_NONE : ds->ds_rxstat.rs_keyix);
+ /*
+ * Track rx rssi and do any rx antenna management.
+ */
+ an = ATH_NODE(ni);
+ ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi);
+ /*
+ * Send frame up for processing.
+ */
+ type = ieee80211_input(ic, m, ni,
+ ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
ieee80211_free_node(ni);
if (sc->sc_diversity) {
/*
@@ -4265,10 +4228,9 @@ ath_setup_stationkey(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct ath_softc *sc = ic->ic_ifp->if_softc;
- u_int16_t keyix;
+ ieee80211_keyix keyix, rxkeyix;
- keyix = ath_key_alloc(ic, &ni->ni_ucastkey);
- if (keyix == IEEE80211_KEYIX_NONE) {
+ if (!ath_key_alloc(ic, &ni->ni_ucastkey, &keyix, &rxkeyix)) {
/*
* Key cache is full; we'll fall back to doing
* the more expensive lookup in software. Note
@@ -4276,7 +4238,9 @@ ath_setup_stationkey(struct ieee80211_node *ni)
*/
/* XXX msg+statistic */
} else {
+ /* XXX locking? */
ni->ni_ucastkey.wk_keyix = keyix;
+ ni->ni_ucastkey.wk_rxkeyix = rxkeyix;
/* NB: this will create a pass-thru key entry */
ath_keyset(sc, &ni->ni_ucastkey, ni->ni_macaddr, ic->ic_bss);
}
OpenPOWER on IntegriCloud