1572ff6f6SMatthew Dillon /*-
2572ff6f6SMatthew Dillon * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3572ff6f6SMatthew Dillon * All rights reserved.
4572ff6f6SMatthew Dillon *
5572ff6f6SMatthew Dillon * Redistribution and use in source and binary forms, with or without
6572ff6f6SMatthew Dillon * modification, are permitted provided that the following conditions
7572ff6f6SMatthew Dillon * are met:
8572ff6f6SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
9572ff6f6SMatthew Dillon * notice, this list of conditions and the following disclaimer,
10572ff6f6SMatthew Dillon * without modification.
11572ff6f6SMatthew Dillon * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12572ff6f6SMatthew Dillon * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13572ff6f6SMatthew Dillon * redistribution must be conditioned upon including a substantially
14572ff6f6SMatthew Dillon * similar Disclaimer requirement for further binary redistribution.
15572ff6f6SMatthew Dillon *
16572ff6f6SMatthew Dillon * NO WARRANTY
17572ff6f6SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18572ff6f6SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19df052c2aSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY
20572ff6f6SMatthew Dillon * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21572ff6f6SMatthew Dillon * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22572ff6f6SMatthew Dillon * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23572ff6f6SMatthew Dillon * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24572ff6f6SMatthew Dillon * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25572ff6f6SMatthew Dillon * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26572ff6f6SMatthew Dillon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27572ff6f6SMatthew Dillon * THE POSSIBILITY OF SUCH DAMAGES.
28572ff6f6SMatthew Dillon */
29572ff6f6SMatthew Dillon
30572ff6f6SMatthew Dillon #include <sys/cdefs.h>
31848b370cSMatthew Dillon __FBSDID("$FreeBSD$");
32572ff6f6SMatthew Dillon
33572ff6f6SMatthew Dillon /*
34572ff6f6SMatthew Dillon * Driver for the Atheros Wireless LAN controller.
35572ff6f6SMatthew Dillon *
36572ff6f6SMatthew Dillon * This software is derived from work of Atsushi Onoe; his contribution
37572ff6f6SMatthew Dillon * is greatly appreciated.
38572ff6f6SMatthew Dillon */
39572ff6f6SMatthew Dillon
40572ff6f6SMatthew Dillon #include "opt_inet.h"
41572ff6f6SMatthew Dillon #include "opt_ath.h"
42572ff6f6SMatthew Dillon #include "opt_wlan.h"
43572ff6f6SMatthew Dillon
44572ff6f6SMatthew Dillon #include <sys/param.h>
45572ff6f6SMatthew Dillon #include <sys/systm.h>
46572ff6f6SMatthew Dillon #include <sys/sysctl.h>
47572ff6f6SMatthew Dillon #include <sys/mbuf.h>
48572ff6f6SMatthew Dillon #include <sys/malloc.h>
49572ff6f6SMatthew Dillon #include <sys/lock.h>
50572ff6f6SMatthew Dillon #include <sys/kernel.h>
51572ff6f6SMatthew Dillon #include <sys/socket.h>
52572ff6f6SMatthew Dillon #include <sys/sockio.h>
53572ff6f6SMatthew Dillon #include <sys/errno.h>
54572ff6f6SMatthew Dillon #include <sys/callout.h>
55572ff6f6SMatthew Dillon #include <sys/bus.h>
56572ff6f6SMatthew Dillon #include <sys/endian.h>
57572ff6f6SMatthew Dillon #include <sys/kthread.h>
58572ff6f6SMatthew Dillon #include <sys/taskqueue.h>
59*2b3f93eaSMatthew Dillon #include <sys/caps.h>
60572ff6f6SMatthew Dillon
61dc249793SMatthew Dillon #if defined(__DragonFly__)
62dc249793SMatthew Dillon /* empty */
63dc249793SMatthew Dillon #else
64b14ca477SMatthew Dillon #include <machine/bus.h>
65dc249793SMatthew Dillon #endif
66b14ca477SMatthew Dillon
67572ff6f6SMatthew Dillon #include <net/if.h>
68572ff6f6SMatthew Dillon #include <net/if_var.h>
69572ff6f6SMatthew Dillon #include <net/if_dl.h>
70572ff6f6SMatthew Dillon #include <net/if_media.h>
71572ff6f6SMatthew Dillon #include <net/if_types.h>
72572ff6f6SMatthew Dillon #include <net/if_arp.h>
73572ff6f6SMatthew Dillon #include <net/ethernet.h>
74572ff6f6SMatthew Dillon #include <net/if_llc.h>
75572ff6f6SMatthew Dillon
76dc249793SMatthew Dillon #include <netproto/802_11/ieee80211_var.h>
77572ff6f6SMatthew Dillon
78572ff6f6SMatthew Dillon #include <net/bpf.h>
79572ff6f6SMatthew Dillon
80dc249793SMatthew Dillon #include <dev/netif/ath/ath/if_athvar.h>
81572ff6f6SMatthew Dillon
82dc249793SMatthew Dillon #include <dev/netif/ath/ath/if_ath_debug.h>
83dc249793SMatthew Dillon #include <dev/netif/ath/ath/if_ath_keycache.h>
84dc249793SMatthew Dillon #include <dev/netif/ath/ath/if_ath_misc.h>
85572ff6f6SMatthew Dillon
86572ff6f6SMatthew Dillon #ifdef ATH_DEBUG
87572ff6f6SMatthew Dillon 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])88572ff6f6SMatthew Dillon ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix,
89572ff6f6SMatthew Dillon const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
90572ff6f6SMatthew Dillon {
91572ff6f6SMatthew Dillon static const char *ciphers[] = {
92572ff6f6SMatthew Dillon "WEP",
93572ff6f6SMatthew Dillon "AES-OCB",
94572ff6f6SMatthew Dillon "AES-CCM",
95572ff6f6SMatthew Dillon "CKIP",
96572ff6f6SMatthew Dillon "TKIP",
97572ff6f6SMatthew Dillon "CLR",
98572ff6f6SMatthew Dillon };
99572ff6f6SMatthew Dillon int i, n;
100572ff6f6SMatthew Dillon
101dc249793SMatthew Dillon kprintf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]);
102572ff6f6SMatthew Dillon for (i = 0, n = hk->kv_len; i < n; i++)
103dc249793SMatthew Dillon kprintf("%02x", hk->kv_val[i]);
104dc249793SMatthew Dillon kprintf(" mac %s", ether_sprintf(mac));
105572ff6f6SMatthew Dillon if (hk->kv_type == HAL_CIPHER_TKIP) {
106dc249793SMatthew Dillon kprintf(" %s ", sc->sc_splitmic ? "mic" : "rxmic");
107572ff6f6SMatthew Dillon for (i = 0; i < sizeof(hk->kv_mic); i++)
108dc249793SMatthew Dillon kprintf("%02x", hk->kv_mic[i]);
109572ff6f6SMatthew Dillon if (!sc->sc_splitmic) {
110dc249793SMatthew Dillon kprintf(" txmic ");
111572ff6f6SMatthew Dillon for (i = 0; i < sizeof(hk->kv_txmic); i++)
112dc249793SMatthew Dillon kprintf("%02x", hk->kv_txmic[i]);
113572ff6f6SMatthew Dillon }
114572ff6f6SMatthew Dillon }
115dc249793SMatthew Dillon kprintf("\n");
116572ff6f6SMatthew Dillon }
117572ff6f6SMatthew Dillon #endif
118572ff6f6SMatthew Dillon
119572ff6f6SMatthew Dillon /*
120572ff6f6SMatthew Dillon * Set a TKIP key into the hardware. This handles the
121572ff6f6SMatthew Dillon * potential distribution of key state to multiple key
122572ff6f6SMatthew Dillon * cache slots for TKIP.
123572ff6f6SMatthew Dillon */
124572ff6f6SMatthew Dillon 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])125572ff6f6SMatthew Dillon ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
126572ff6f6SMatthew Dillon HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
127572ff6f6SMatthew Dillon {
128572ff6f6SMatthew Dillon #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
129572ff6f6SMatthew Dillon static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
130572ff6f6SMatthew Dillon struct ath_hal *ah = sc->sc_ah;
131572ff6f6SMatthew Dillon
132572ff6f6SMatthew Dillon KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP,
133572ff6f6SMatthew Dillon ("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher));
134572ff6f6SMatthew Dillon if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
135572ff6f6SMatthew Dillon if (sc->sc_splitmic) {
136572ff6f6SMatthew Dillon /*
137572ff6f6SMatthew Dillon * TX key goes at first index, RX key at the rx index.
138572ff6f6SMatthew Dillon * The hal handles the MIC keys at index+64.
139572ff6f6SMatthew Dillon */
140572ff6f6SMatthew Dillon memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic));
141572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix, hk, zerobssid);
142572ff6f6SMatthew Dillon if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid))
143572ff6f6SMatthew Dillon return 0;
144572ff6f6SMatthew Dillon
145572ff6f6SMatthew Dillon memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
146572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix+32, hk, mac);
147572ff6f6SMatthew Dillon /* XXX delete tx key on failure? */
148572ff6f6SMatthew Dillon return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac);
149572ff6f6SMatthew Dillon } else {
150572ff6f6SMatthew Dillon /*
151572ff6f6SMatthew Dillon * Room for both TX+RX MIC keys in one key cache
152572ff6f6SMatthew Dillon * slot, just set key at the first index; the hal
153572ff6f6SMatthew Dillon * will handle the rest.
154572ff6f6SMatthew Dillon */
155572ff6f6SMatthew Dillon memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
156572ff6f6SMatthew Dillon memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
157572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix, hk, mac);
158572ff6f6SMatthew Dillon return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
159572ff6f6SMatthew Dillon }
160572ff6f6SMatthew Dillon } else if (k->wk_flags & IEEE80211_KEY_XMIT) {
161572ff6f6SMatthew Dillon if (sc->sc_splitmic) {
162572ff6f6SMatthew Dillon /*
163572ff6f6SMatthew Dillon * NB: must pass MIC key in expected location when
164572ff6f6SMatthew Dillon * the keycache only holds one MIC key per entry.
165572ff6f6SMatthew Dillon */
166572ff6f6SMatthew Dillon memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_txmic));
167572ff6f6SMatthew Dillon } else
168572ff6f6SMatthew Dillon memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
169572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix, hk, mac);
170572ff6f6SMatthew Dillon return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
171572ff6f6SMatthew Dillon } else if (k->wk_flags & IEEE80211_KEY_RECV) {
172572ff6f6SMatthew Dillon memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
173572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix, hk, mac);
174572ff6f6SMatthew Dillon return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
175572ff6f6SMatthew Dillon }
176572ff6f6SMatthew Dillon return 0;
177572ff6f6SMatthew Dillon #undef IEEE80211_KEY_XR
178572ff6f6SMatthew Dillon }
179572ff6f6SMatthew Dillon
180572ff6f6SMatthew Dillon /*
181572ff6f6SMatthew Dillon * Set a net80211 key into the hardware. This handles the
182572ff6f6SMatthew Dillon * potential distribution of key state to multiple key
183572ff6f6SMatthew Dillon * cache slots for TKIP with hardware MIC support.
184572ff6f6SMatthew Dillon */
185572ff6f6SMatthew Dillon int
ath_keyset(struct ath_softc * sc,struct ieee80211vap * vap,const struct ieee80211_key * k,struct ieee80211_node * bss)186572ff6f6SMatthew Dillon ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
187572ff6f6SMatthew Dillon const struct ieee80211_key *k,
188572ff6f6SMatthew Dillon struct ieee80211_node *bss)
189572ff6f6SMatthew Dillon {
190572ff6f6SMatthew Dillon static const u_int8_t ciphermap[] = {
191572ff6f6SMatthew Dillon HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */
192572ff6f6SMatthew Dillon HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */
193572ff6f6SMatthew Dillon HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */
194572ff6f6SMatthew Dillon HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */
195572ff6f6SMatthew Dillon (u_int8_t) -1, /* 4 is not allocated */
196572ff6f6SMatthew Dillon HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */
197572ff6f6SMatthew Dillon HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */
198572ff6f6SMatthew Dillon };
199572ff6f6SMatthew Dillon struct ath_hal *ah = sc->sc_ah;
200572ff6f6SMatthew Dillon const struct ieee80211_cipher *cip = k->wk_cipher;
201572ff6f6SMatthew Dillon u_int8_t gmac[IEEE80211_ADDR_LEN];
202572ff6f6SMatthew Dillon const u_int8_t *mac;
203572ff6f6SMatthew Dillon HAL_KEYVAL hk;
204d98a0bcfSMatthew Dillon int ret;
205572ff6f6SMatthew Dillon
206572ff6f6SMatthew Dillon memset(&hk, 0, sizeof(hk));
207572ff6f6SMatthew Dillon /*
208572ff6f6SMatthew Dillon * Software crypto uses a "clear key" so non-crypto
209572ff6f6SMatthew Dillon * state kept in the key cache are maintained and
210572ff6f6SMatthew Dillon * so that rx frames have an entry to match.
211572ff6f6SMatthew Dillon */
212572ff6f6SMatthew Dillon if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
213b14ca477SMatthew Dillon KASSERT(cip->ic_cipher < nitems(ciphermap),
214572ff6f6SMatthew Dillon ("invalid cipher type %u", cip->ic_cipher));
215572ff6f6SMatthew Dillon hk.kv_type = ciphermap[cip->ic_cipher];
216572ff6f6SMatthew Dillon hk.kv_len = k->wk_keylen;
217572ff6f6SMatthew Dillon memcpy(hk.kv_val, k->wk_key, k->wk_keylen);
218572ff6f6SMatthew Dillon } else
219572ff6f6SMatthew Dillon hk.kv_type = HAL_CIPHER_CLR;
220572ff6f6SMatthew Dillon
221572ff6f6SMatthew Dillon /*
222572ff6f6SMatthew Dillon * If we're installing a clear cipher key and
223572ff6f6SMatthew Dillon * the hardware doesn't support that, just succeed.
224572ff6f6SMatthew Dillon * Leave it up to the net80211 layer to figure it out.
225572ff6f6SMatthew Dillon */
226572ff6f6SMatthew Dillon if (hk.kv_type == HAL_CIPHER_CLR && sc->sc_hasclrkey == 0) {
227572ff6f6SMatthew Dillon return (1);
228572ff6f6SMatthew Dillon }
229572ff6f6SMatthew Dillon
230572ff6f6SMatthew Dillon /*
231572ff6f6SMatthew Dillon * XXX TODO: check this:
232572ff6f6SMatthew Dillon *
233572ff6f6SMatthew Dillon * Group keys on hardware that supports multicast frame
234572ff6f6SMatthew Dillon * key search should only be done in adhoc/hostap mode,
235572ff6f6SMatthew Dillon * not STA mode.
236572ff6f6SMatthew Dillon *
237572ff6f6SMatthew Dillon * XXX TODO: what about mesh, tdma?
238572ff6f6SMatthew Dillon */
239572ff6f6SMatthew Dillon #if 0
240572ff6f6SMatthew Dillon if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
241572ff6f6SMatthew Dillon vap->iv_opmode == IEEE80211_M_IBSS) &&
242572ff6f6SMatthew Dillon #else
243572ff6f6SMatthew Dillon if (
244572ff6f6SMatthew Dillon #endif
245572ff6f6SMatthew Dillon (k->wk_flags & IEEE80211_KEY_GROUP) &&
246572ff6f6SMatthew Dillon sc->sc_mcastkey) {
247572ff6f6SMatthew Dillon /*
248572ff6f6SMatthew Dillon * Group keys on hardware that supports multicast frame
249572ff6f6SMatthew Dillon * key search use a MAC that is the sender's address with
250572ff6f6SMatthew Dillon * the multicast bit set instead of the app-specified address.
251572ff6f6SMatthew Dillon */
252572ff6f6SMatthew Dillon IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
253572ff6f6SMatthew Dillon gmac[0] |= 0x01;
254572ff6f6SMatthew Dillon mac = gmac;
255572ff6f6SMatthew Dillon } else
256572ff6f6SMatthew Dillon mac = k->wk_macaddr;
257572ff6f6SMatthew Dillon
258848b370cSMatthew Dillon ATH_LOCK(sc);
259d98a0bcfSMatthew Dillon ath_power_set_power_state(sc, HAL_PM_AWAKE);
260572ff6f6SMatthew Dillon if (hk.kv_type == HAL_CIPHER_TKIP &&
261572ff6f6SMatthew Dillon (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
262d98a0bcfSMatthew Dillon ret = ath_keyset_tkip(sc, k, &hk, mac);
263572ff6f6SMatthew Dillon } else {
264572ff6f6SMatthew Dillon KEYPRINTF(sc, k->wk_keyix, &hk, mac);
265d98a0bcfSMatthew Dillon ret = ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
266572ff6f6SMatthew Dillon }
267d98a0bcfSMatthew Dillon ath_power_restore_power_state(sc);
268848b370cSMatthew Dillon ATH_UNLOCK(sc);
269d98a0bcfSMatthew Dillon
270d98a0bcfSMatthew Dillon return (ret);
271572ff6f6SMatthew Dillon }
272572ff6f6SMatthew Dillon
273572ff6f6SMatthew Dillon /*
274572ff6f6SMatthew Dillon * Allocate tx/rx key slots for TKIP. We allocate two slots for
275572ff6f6SMatthew Dillon * each key, one for decrypt/encrypt and the other for the MIC.
276572ff6f6SMatthew Dillon */
277572ff6f6SMatthew Dillon static u_int16_t
key_alloc_2pair(struct ath_softc * sc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)278572ff6f6SMatthew Dillon key_alloc_2pair(struct ath_softc *sc,
279572ff6f6SMatthew Dillon ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
280572ff6f6SMatthew Dillon {
281572ff6f6SMatthew Dillon u_int i, keyix;
282572ff6f6SMatthew Dillon
283572ff6f6SMatthew Dillon KASSERT(sc->sc_splitmic, ("key cache !split"));
284572ff6f6SMatthew Dillon /* XXX could optimize */
285b14ca477SMatthew Dillon for (i = 0; i < nitems(sc->sc_keymap)/4; i++) {
286572ff6f6SMatthew Dillon u_int8_t b = sc->sc_keymap[i];
287572ff6f6SMatthew Dillon if (b != 0xff) {
288572ff6f6SMatthew Dillon /*
289572ff6f6SMatthew Dillon * One or more slots in this byte are free.
290572ff6f6SMatthew Dillon */
291572ff6f6SMatthew Dillon keyix = i*NBBY;
292572ff6f6SMatthew Dillon while (b & 1) {
293572ff6f6SMatthew Dillon again:
294572ff6f6SMatthew Dillon keyix++;
295572ff6f6SMatthew Dillon b >>= 1;
296572ff6f6SMatthew Dillon }
297572ff6f6SMatthew Dillon /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
298572ff6f6SMatthew Dillon if (isset(sc->sc_keymap, keyix+32) ||
299572ff6f6SMatthew Dillon isset(sc->sc_keymap, keyix+64) ||
300572ff6f6SMatthew Dillon isset(sc->sc_keymap, keyix+32+64)) {
301572ff6f6SMatthew Dillon /* full pair unavailable */
302572ff6f6SMatthew Dillon /* XXX statistic */
303572ff6f6SMatthew Dillon if (keyix == (i+1)*NBBY) {
304572ff6f6SMatthew Dillon /* no slots were appropriate, advance */
305572ff6f6SMatthew Dillon continue;
306572ff6f6SMatthew Dillon }
307572ff6f6SMatthew Dillon goto again;
308572ff6f6SMatthew Dillon }
309572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix);
310572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix+64);
311572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix+32);
312572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix+32+64);
313572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE,
314572ff6f6SMatthew Dillon "%s: key pair %u,%u %u,%u\n",
315572ff6f6SMatthew Dillon __func__, keyix, keyix+64,
316572ff6f6SMatthew Dillon keyix+32, keyix+32+64);
317572ff6f6SMatthew Dillon *txkeyix = keyix;
318572ff6f6SMatthew Dillon *rxkeyix = keyix+32;
319572ff6f6SMatthew Dillon return 1;
320572ff6f6SMatthew Dillon }
321572ff6f6SMatthew Dillon }
322572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
323572ff6f6SMatthew Dillon return 0;
324572ff6f6SMatthew Dillon }
325572ff6f6SMatthew Dillon
326572ff6f6SMatthew Dillon /*
327572ff6f6SMatthew Dillon * Allocate tx/rx key slots for TKIP. We allocate two slots for
328572ff6f6SMatthew Dillon * each key, one for decrypt/encrypt and the other for the MIC.
329572ff6f6SMatthew Dillon */
330572ff6f6SMatthew Dillon static u_int16_t
key_alloc_pair(struct ath_softc * sc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)331572ff6f6SMatthew Dillon key_alloc_pair(struct ath_softc *sc,
332572ff6f6SMatthew Dillon ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
333572ff6f6SMatthew Dillon {
334572ff6f6SMatthew Dillon u_int i, keyix;
335572ff6f6SMatthew Dillon
336572ff6f6SMatthew Dillon KASSERT(!sc->sc_splitmic, ("key cache split"));
337572ff6f6SMatthew Dillon /* XXX could optimize */
338b14ca477SMatthew Dillon for (i = 0; i < nitems(sc->sc_keymap)/4; i++) {
339572ff6f6SMatthew Dillon u_int8_t b = sc->sc_keymap[i];
340572ff6f6SMatthew Dillon if (b != 0xff) {
341572ff6f6SMatthew Dillon /*
342572ff6f6SMatthew Dillon * One or more slots in this byte are free.
343572ff6f6SMatthew Dillon */
344572ff6f6SMatthew Dillon keyix = i*NBBY;
345572ff6f6SMatthew Dillon while (b & 1) {
346572ff6f6SMatthew Dillon again:
347572ff6f6SMatthew Dillon keyix++;
348572ff6f6SMatthew Dillon b >>= 1;
349572ff6f6SMatthew Dillon }
350572ff6f6SMatthew Dillon if (isset(sc->sc_keymap, keyix+64)) {
351572ff6f6SMatthew Dillon /* full pair unavailable */
352572ff6f6SMatthew Dillon /* XXX statistic */
353572ff6f6SMatthew Dillon if (keyix == (i+1)*NBBY) {
354572ff6f6SMatthew Dillon /* no slots were appropriate, advance */
355572ff6f6SMatthew Dillon continue;
356572ff6f6SMatthew Dillon }
357572ff6f6SMatthew Dillon goto again;
358572ff6f6SMatthew Dillon }
359572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix);
360572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix+64);
361572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE,
362572ff6f6SMatthew Dillon "%s: key pair %u,%u\n",
363572ff6f6SMatthew Dillon __func__, keyix, keyix+64);
364572ff6f6SMatthew Dillon *txkeyix = *rxkeyix = keyix;
365572ff6f6SMatthew Dillon return 1;
366572ff6f6SMatthew Dillon }
367572ff6f6SMatthew Dillon }
368572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
369572ff6f6SMatthew Dillon return 0;
370572ff6f6SMatthew Dillon }
371572ff6f6SMatthew Dillon
372572ff6f6SMatthew Dillon /*
373572ff6f6SMatthew Dillon * Allocate a single key cache slot.
374572ff6f6SMatthew Dillon */
375572ff6f6SMatthew Dillon static int
key_alloc_single(struct ath_softc * sc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)376572ff6f6SMatthew Dillon key_alloc_single(struct ath_softc *sc,
377572ff6f6SMatthew Dillon ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
378572ff6f6SMatthew Dillon {
379572ff6f6SMatthew Dillon u_int i, keyix;
380572ff6f6SMatthew Dillon
381572ff6f6SMatthew Dillon if (sc->sc_hasclrkey == 0) {
382572ff6f6SMatthew Dillon /*
383572ff6f6SMatthew Dillon * Map to slot 0 for the AR5210.
384572ff6f6SMatthew Dillon */
385572ff6f6SMatthew Dillon *txkeyix = *rxkeyix = 0;
386572ff6f6SMatthew Dillon return (1);
387572ff6f6SMatthew Dillon }
388572ff6f6SMatthew Dillon
389572ff6f6SMatthew Dillon /* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
390b14ca477SMatthew Dillon for (i = 0; i < nitems(sc->sc_keymap); i++) {
391572ff6f6SMatthew Dillon u_int8_t b = sc->sc_keymap[i];
392572ff6f6SMatthew Dillon if (b != 0xff) {
393572ff6f6SMatthew Dillon /*
394572ff6f6SMatthew Dillon * One or more slots are free.
395572ff6f6SMatthew Dillon */
396572ff6f6SMatthew Dillon keyix = i*NBBY;
397572ff6f6SMatthew Dillon while (b & 1)
398572ff6f6SMatthew Dillon keyix++, b >>= 1;
399572ff6f6SMatthew Dillon setbit(sc->sc_keymap, keyix);
400572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
401572ff6f6SMatthew Dillon __func__, keyix);
402572ff6f6SMatthew Dillon *txkeyix = *rxkeyix = keyix;
403572ff6f6SMatthew Dillon return 1;
404572ff6f6SMatthew Dillon }
405572ff6f6SMatthew Dillon }
406572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__);
407572ff6f6SMatthew Dillon return 0;
408572ff6f6SMatthew Dillon }
409572ff6f6SMatthew Dillon
410572ff6f6SMatthew Dillon /*
411572ff6f6SMatthew Dillon * Allocate one or more key cache slots for a uniacst key. The
412572ff6f6SMatthew Dillon * key itself is needed only to identify the cipher. For hardware
413572ff6f6SMatthew Dillon * TKIP with split cipher+MIC keys we allocate two key cache slot
414572ff6f6SMatthew Dillon * pairs so that we can setup separate TX and RX MIC keys. Note
415572ff6f6SMatthew Dillon * that the MIC key for a TKIP key at slot i is assumed by the
416572ff6f6SMatthew Dillon * hardware to be at slot i+64. This limits TKIP keys to the first
417572ff6f6SMatthew Dillon * 64 entries.
418572ff6f6SMatthew Dillon */
419572ff6f6SMatthew Dillon int
ath_key_alloc(struct ieee80211vap * vap,struct ieee80211_key * k,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)420572ff6f6SMatthew Dillon ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
421572ff6f6SMatthew Dillon ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
422572ff6f6SMatthew Dillon {
4234f1aaf2fSImre Vadász struct ath_softc *sc = vap->iv_ic->ic_softc;
424572ff6f6SMatthew Dillon
425572ff6f6SMatthew Dillon /*
426572ff6f6SMatthew Dillon * Group key allocation must be handled specially for
427572ff6f6SMatthew Dillon * parts that do not support multicast key cache search
428572ff6f6SMatthew Dillon * functionality. For those parts the key id must match
429572ff6f6SMatthew Dillon * the h/w key index so lookups find the right key. On
430572ff6f6SMatthew Dillon * parts w/ the key search facility we install the sender's
431572ff6f6SMatthew Dillon * mac address (with the high bit set) and let the hardware
432572ff6f6SMatthew Dillon * find the key w/o using the key id. This is preferred as
433572ff6f6SMatthew Dillon * it permits us to support multiple users for adhoc and/or
434572ff6f6SMatthew Dillon * multi-station operation.
435572ff6f6SMatthew Dillon */
436572ff6f6SMatthew Dillon if (k->wk_keyix != IEEE80211_KEYIX_NONE) {
437572ff6f6SMatthew Dillon /*
438572ff6f6SMatthew Dillon * Only global keys should have key index assigned.
439572ff6f6SMatthew Dillon */
440572ff6f6SMatthew Dillon if (!(&vap->iv_nw_keys[0] <= k &&
441572ff6f6SMatthew Dillon k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
442572ff6f6SMatthew Dillon /* should not happen */
443572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE,
444572ff6f6SMatthew Dillon "%s: bogus group key\n", __func__);
445572ff6f6SMatthew Dillon return 0;
446572ff6f6SMatthew Dillon }
447572ff6f6SMatthew Dillon if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
448572ff6f6SMatthew Dillon !(k->wk_flags & IEEE80211_KEY_GROUP) ||
449572ff6f6SMatthew Dillon !sc->sc_mcastkey) {
450572ff6f6SMatthew Dillon /*
451572ff6f6SMatthew Dillon * XXX we pre-allocate the global keys so
452572ff6f6SMatthew Dillon * have no way to check if they've already
453572ff6f6SMatthew Dillon * been allocated.
454572ff6f6SMatthew Dillon */
455572ff6f6SMatthew Dillon *keyix = *rxkeyix = k - vap->iv_nw_keys;
456572ff6f6SMatthew Dillon return 1;
457572ff6f6SMatthew Dillon }
458572ff6f6SMatthew Dillon /*
459572ff6f6SMatthew Dillon * Group key and device supports multicast key search.
460572ff6f6SMatthew Dillon */
461572ff6f6SMatthew Dillon k->wk_keyix = IEEE80211_KEYIX_NONE;
462572ff6f6SMatthew Dillon }
463572ff6f6SMatthew Dillon
464572ff6f6SMatthew Dillon /*
465572ff6f6SMatthew Dillon * We allocate two pair for TKIP when using the h/w to do
466572ff6f6SMatthew Dillon * the MIC. For everything else, including software crypto,
467572ff6f6SMatthew Dillon * we allocate a single entry. Note that s/w crypto requires
468572ff6f6SMatthew Dillon * a pass-through slot on the 5211 and 5212. The 5210 does
469572ff6f6SMatthew Dillon * not support pass-through cache entries and we map all
470572ff6f6SMatthew Dillon * those requests to slot 0.
471572ff6f6SMatthew Dillon */
472572ff6f6SMatthew Dillon if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
473572ff6f6SMatthew Dillon return key_alloc_single(sc, keyix, rxkeyix);
474572ff6f6SMatthew Dillon } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
475572ff6f6SMatthew Dillon (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
476572ff6f6SMatthew Dillon if (sc->sc_splitmic)
477572ff6f6SMatthew Dillon return key_alloc_2pair(sc, keyix, rxkeyix);
478572ff6f6SMatthew Dillon else
479572ff6f6SMatthew Dillon return key_alloc_pair(sc, keyix, rxkeyix);
480572ff6f6SMatthew Dillon } else {
481572ff6f6SMatthew Dillon return key_alloc_single(sc, keyix, rxkeyix);
482572ff6f6SMatthew Dillon }
483572ff6f6SMatthew Dillon }
484572ff6f6SMatthew Dillon
485572ff6f6SMatthew Dillon /*
486572ff6f6SMatthew Dillon * Delete an entry in the key cache allocated by ath_key_alloc.
487572ff6f6SMatthew Dillon */
488572ff6f6SMatthew Dillon int
ath_key_delete(struct ieee80211vap * vap,const struct ieee80211_key * k)489572ff6f6SMatthew Dillon ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
490572ff6f6SMatthew Dillon {
4914f1aaf2fSImre Vadász struct ath_softc *sc = vap->iv_ic->ic_softc;
492572ff6f6SMatthew Dillon struct ath_hal *ah = sc->sc_ah;
493572ff6f6SMatthew Dillon const struct ieee80211_cipher *cip = k->wk_cipher;
494572ff6f6SMatthew Dillon u_int keyix = k->wk_keyix;
495572ff6f6SMatthew Dillon
496572ff6f6SMatthew Dillon DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
497572ff6f6SMatthew Dillon
498848b370cSMatthew Dillon ATH_LOCK(sc);
499d98a0bcfSMatthew Dillon ath_power_set_power_state(sc, HAL_PM_AWAKE);
500572ff6f6SMatthew Dillon ath_hal_keyreset(ah, keyix);
501572ff6f6SMatthew Dillon /*
502572ff6f6SMatthew Dillon * Handle split tx/rx keying required for TKIP with h/w MIC.
503572ff6f6SMatthew Dillon */
504572ff6f6SMatthew Dillon if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
505572ff6f6SMatthew Dillon (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
506572ff6f6SMatthew Dillon ath_hal_keyreset(ah, keyix+32); /* RX key */
507572ff6f6SMatthew Dillon if (keyix >= IEEE80211_WEP_NKID) {
508572ff6f6SMatthew Dillon /*
509572ff6f6SMatthew Dillon * Don't touch keymap entries for global keys so
510572ff6f6SMatthew Dillon * they are never considered for dynamic allocation.
511572ff6f6SMatthew Dillon */
512572ff6f6SMatthew Dillon clrbit(sc->sc_keymap, keyix);
513572ff6f6SMatthew Dillon if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
514572ff6f6SMatthew Dillon (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
515572ff6f6SMatthew Dillon clrbit(sc->sc_keymap, keyix+64); /* TX key MIC */
516572ff6f6SMatthew Dillon if (sc->sc_splitmic) {
517572ff6f6SMatthew Dillon /* +32 for RX key, +32+64 for RX key MIC */
518572ff6f6SMatthew Dillon clrbit(sc->sc_keymap, keyix+32);
519572ff6f6SMatthew Dillon clrbit(sc->sc_keymap, keyix+32+64);
520572ff6f6SMatthew Dillon }
521572ff6f6SMatthew Dillon }
522572ff6f6SMatthew Dillon }
523d98a0bcfSMatthew Dillon ath_power_restore_power_state(sc);
524848b370cSMatthew Dillon ATH_UNLOCK(sc);
525572ff6f6SMatthew Dillon return 1;
526572ff6f6SMatthew Dillon }
527572ff6f6SMatthew Dillon
528572ff6f6SMatthew Dillon /*
529572ff6f6SMatthew Dillon * Set the key cache contents for the specified key. Key cache
530572ff6f6SMatthew Dillon * slot(s) must already have been allocated by ath_key_alloc.
531572ff6f6SMatthew Dillon */
532572ff6f6SMatthew Dillon int
ath_key_set(struct ieee80211vap * vap,const struct ieee80211_key * k)533b14ca477SMatthew Dillon ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
534572ff6f6SMatthew Dillon {
5354f1aaf2fSImre Vadász struct ath_softc *sc = vap->iv_ic->ic_softc;
536572ff6f6SMatthew Dillon
537572ff6f6SMatthew Dillon return ath_keyset(sc, vap, k, vap->iv_bss);
538572ff6f6SMatthew Dillon }
539