xref: /dflybsd-src/sys/dev/netif/ath/ath/if_ath_keycache.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
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