xref: /freebsd/sys/dev/ath/if_ath_keycache.c (revision 55c7b877459e1b1ae5110dac46e5830b61d17101)
1d2d7a00aSAdrian Chadd /*-
2d2d7a00aSAdrian Chadd  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3d2d7a00aSAdrian Chadd  * All rights reserved.
4d2d7a00aSAdrian Chadd  *
5d2d7a00aSAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6d2d7a00aSAdrian Chadd  * modification, are permitted provided that the following conditions
7d2d7a00aSAdrian Chadd  * are met:
8d2d7a00aSAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9d2d7a00aSAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10d2d7a00aSAdrian Chadd  *    without modification.
11d2d7a00aSAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12d2d7a00aSAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13d2d7a00aSAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14d2d7a00aSAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15d2d7a00aSAdrian Chadd  *
16d2d7a00aSAdrian Chadd  * NO WARRANTY
17d2d7a00aSAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18d2d7a00aSAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19d2d7a00aSAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20d2d7a00aSAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21d2d7a00aSAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22d2d7a00aSAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23d2d7a00aSAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24d2d7a00aSAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25d2d7a00aSAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26d2d7a00aSAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27d2d7a00aSAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28d2d7a00aSAdrian Chadd  */
29d2d7a00aSAdrian Chadd 
30d2d7a00aSAdrian Chadd #include <sys/cdefs.h>
31d2d7a00aSAdrian Chadd __FBSDID("$FreeBSD$");
32d2d7a00aSAdrian Chadd 
33d2d7a00aSAdrian Chadd /*
34d2d7a00aSAdrian Chadd  * Driver for the Atheros Wireless LAN controller.
35d2d7a00aSAdrian Chadd  *
36d2d7a00aSAdrian Chadd  * This software is derived from work of Atsushi Onoe; his contribution
37d2d7a00aSAdrian Chadd  * is greatly appreciated.
38d2d7a00aSAdrian Chadd  */
39d2d7a00aSAdrian Chadd 
40d2d7a00aSAdrian Chadd #include "opt_inet.h"
41d2d7a00aSAdrian Chadd #include "opt_ath.h"
42d2d7a00aSAdrian Chadd #include "opt_wlan.h"
43d2d7a00aSAdrian Chadd 
44d2d7a00aSAdrian Chadd #include <sys/param.h>
45d2d7a00aSAdrian Chadd #include <sys/systm.h>
46d2d7a00aSAdrian Chadd #include <sys/sysctl.h>
47d2d7a00aSAdrian Chadd #include <sys/mbuf.h>
48d2d7a00aSAdrian Chadd #include <sys/malloc.h>
49d2d7a00aSAdrian Chadd #include <sys/lock.h>
50d2d7a00aSAdrian Chadd #include <sys/mutex.h>
51d2d7a00aSAdrian Chadd #include <sys/kernel.h>
52d2d7a00aSAdrian Chadd #include <sys/socket.h>
53d2d7a00aSAdrian Chadd #include <sys/sockio.h>
54d2d7a00aSAdrian Chadd #include <sys/errno.h>
55d2d7a00aSAdrian Chadd #include <sys/callout.h>
56d2d7a00aSAdrian Chadd #include <sys/bus.h>
57d2d7a00aSAdrian Chadd #include <sys/endian.h>
58d2d7a00aSAdrian Chadd #include <sys/kthread.h>
59d2d7a00aSAdrian Chadd #include <sys/taskqueue.h>
60d2d7a00aSAdrian Chadd #include <sys/priv.h>
61d2d7a00aSAdrian Chadd 
62d2d7a00aSAdrian Chadd #include <machine/bus.h>
63d2d7a00aSAdrian Chadd 
64d2d7a00aSAdrian Chadd #include <net/if.h>
65d2d7a00aSAdrian Chadd #include <net/if_dl.h>
66d2d7a00aSAdrian Chadd #include <net/if_media.h>
67d2d7a00aSAdrian Chadd #include <net/if_types.h>
68d2d7a00aSAdrian Chadd #include <net/if_arp.h>
69d2d7a00aSAdrian Chadd #include <net/ethernet.h>
70d2d7a00aSAdrian Chadd #include <net/if_llc.h>
71d2d7a00aSAdrian Chadd 
72d2d7a00aSAdrian Chadd #include <net80211/ieee80211_var.h>
73d2d7a00aSAdrian Chadd 
74d2d7a00aSAdrian Chadd #include <net/bpf.h>
75d2d7a00aSAdrian Chadd 
76d2d7a00aSAdrian Chadd #include <dev/ath/if_athvar.h>
77d2d7a00aSAdrian Chadd 
78d2d7a00aSAdrian Chadd #include <dev/ath/if_ath_debug.h>
79d2d7a00aSAdrian Chadd #include <dev/ath/if_ath_keycache.h>
80d2d7a00aSAdrian Chadd 
81d2d7a00aSAdrian Chadd #ifdef ATH_DEBUG
82d2d7a00aSAdrian Chadd static void
83d2d7a00aSAdrian Chadd ath_keyprint(struct ath_softc *sc, const char *tag, u_int ix,
84d2d7a00aSAdrian Chadd 	const HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
85d2d7a00aSAdrian Chadd {
86d2d7a00aSAdrian Chadd 	static const char *ciphers[] = {
87d2d7a00aSAdrian Chadd 		"WEP",
88d2d7a00aSAdrian Chadd 		"AES-OCB",
89d2d7a00aSAdrian Chadd 		"AES-CCM",
90d2d7a00aSAdrian Chadd 		"CKIP",
91d2d7a00aSAdrian Chadd 		"TKIP",
92d2d7a00aSAdrian Chadd 		"CLR",
93d2d7a00aSAdrian Chadd 	};
94d2d7a00aSAdrian Chadd 	int i, n;
95d2d7a00aSAdrian Chadd 
96d2d7a00aSAdrian Chadd 	printf("%s: [%02u] %-7s ", tag, ix, ciphers[hk->kv_type]);
97d2d7a00aSAdrian Chadd 	for (i = 0, n = hk->kv_len; i < n; i++)
98d2d7a00aSAdrian Chadd 		printf("%02x", hk->kv_val[i]);
99d2d7a00aSAdrian Chadd 	printf(" mac %s", ether_sprintf(mac));
100d2d7a00aSAdrian Chadd 	if (hk->kv_type == HAL_CIPHER_TKIP) {
101d2d7a00aSAdrian Chadd 		printf(" %s ", sc->sc_splitmic ? "mic" : "rxmic");
102d2d7a00aSAdrian Chadd 		for (i = 0; i < sizeof(hk->kv_mic); i++)
103d2d7a00aSAdrian Chadd 			printf("%02x", hk->kv_mic[i]);
104d2d7a00aSAdrian Chadd 		if (!sc->sc_splitmic) {
105d2d7a00aSAdrian Chadd 			printf(" txmic ");
106d2d7a00aSAdrian Chadd 			for (i = 0; i < sizeof(hk->kv_txmic); i++)
107d2d7a00aSAdrian Chadd 				printf("%02x", hk->kv_txmic[i]);
108d2d7a00aSAdrian Chadd 		}
109d2d7a00aSAdrian Chadd 	}
110d2d7a00aSAdrian Chadd 	printf("\n");
111d2d7a00aSAdrian Chadd }
112d2d7a00aSAdrian Chadd #endif
113d2d7a00aSAdrian Chadd 
114d2d7a00aSAdrian Chadd /*
115d2d7a00aSAdrian Chadd  * Set a TKIP key into the hardware.  This handles the
116d2d7a00aSAdrian Chadd  * potential distribution of key state to multiple key
117d2d7a00aSAdrian Chadd  * cache slots for TKIP.
118d2d7a00aSAdrian Chadd  */
119d2d7a00aSAdrian Chadd static int
120d2d7a00aSAdrian Chadd ath_keyset_tkip(struct ath_softc *sc, const struct ieee80211_key *k,
121d2d7a00aSAdrian Chadd 	HAL_KEYVAL *hk, const u_int8_t mac[IEEE80211_ADDR_LEN])
122d2d7a00aSAdrian Chadd {
123d2d7a00aSAdrian Chadd #define	IEEE80211_KEY_XR	(IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
124d2d7a00aSAdrian Chadd 	static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
125d2d7a00aSAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
126d2d7a00aSAdrian Chadd 
127d2d7a00aSAdrian Chadd 	KASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP,
128d2d7a00aSAdrian Chadd 		("got a non-TKIP key, cipher %u", k->wk_cipher->ic_cipher));
129d2d7a00aSAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
130d2d7a00aSAdrian Chadd 		if (sc->sc_splitmic) {
131d2d7a00aSAdrian Chadd 			/*
132d2d7a00aSAdrian Chadd 			 * TX key goes at first index, RX key at the rx index.
133d2d7a00aSAdrian Chadd 			 * The hal handles the MIC keys at index+64.
134d2d7a00aSAdrian Chadd 			 */
135d2d7a00aSAdrian Chadd 			memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_mic));
136d2d7a00aSAdrian Chadd 			KEYPRINTF(sc, k->wk_keyix, hk, zerobssid);
137d2d7a00aSAdrian Chadd 			if (!ath_hal_keyset(ah, k->wk_keyix, hk, zerobssid))
138d2d7a00aSAdrian Chadd 				return 0;
139d2d7a00aSAdrian Chadd 
140d2d7a00aSAdrian Chadd 			memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
141d2d7a00aSAdrian Chadd 			KEYPRINTF(sc, k->wk_keyix+32, hk, mac);
142d2d7a00aSAdrian Chadd 			/* XXX delete tx key on failure? */
143d2d7a00aSAdrian Chadd 			return ath_hal_keyset(ah, k->wk_keyix+32, hk, mac);
144d2d7a00aSAdrian Chadd 		} else {
145d2d7a00aSAdrian Chadd 			/*
146d2d7a00aSAdrian Chadd 			 * Room for both TX+RX MIC keys in one key cache
147d2d7a00aSAdrian Chadd 			 * slot, just set key at the first index; the hal
148d2d7a00aSAdrian Chadd 			 * will handle the rest.
149d2d7a00aSAdrian Chadd 			 */
150d2d7a00aSAdrian Chadd 			memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
151d2d7a00aSAdrian Chadd 			memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
152d2d7a00aSAdrian Chadd 			KEYPRINTF(sc, k->wk_keyix, hk, mac);
153d2d7a00aSAdrian Chadd 			return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
154d2d7a00aSAdrian Chadd 		}
155d2d7a00aSAdrian Chadd 	} else if (k->wk_flags & IEEE80211_KEY_XMIT) {
156d2d7a00aSAdrian Chadd 		if (sc->sc_splitmic) {
157d2d7a00aSAdrian Chadd 			/*
158d2d7a00aSAdrian Chadd 			 * NB: must pass MIC key in expected location when
159d2d7a00aSAdrian Chadd 			 * the keycache only holds one MIC key per entry.
160d2d7a00aSAdrian Chadd 			 */
161d2d7a00aSAdrian Chadd 			memcpy(hk->kv_mic, k->wk_txmic, sizeof(hk->kv_txmic));
162d2d7a00aSAdrian Chadd 		} else
163d2d7a00aSAdrian Chadd 			memcpy(hk->kv_txmic, k->wk_txmic, sizeof(hk->kv_txmic));
164d2d7a00aSAdrian Chadd 		KEYPRINTF(sc, k->wk_keyix, hk, mac);
165d2d7a00aSAdrian Chadd 		return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
166d2d7a00aSAdrian Chadd 	} else if (k->wk_flags & IEEE80211_KEY_RECV) {
167d2d7a00aSAdrian Chadd 		memcpy(hk->kv_mic, k->wk_rxmic, sizeof(hk->kv_mic));
168d2d7a00aSAdrian Chadd 		KEYPRINTF(sc, k->wk_keyix, hk, mac);
169d2d7a00aSAdrian Chadd 		return ath_hal_keyset(ah, k->wk_keyix, hk, mac);
170d2d7a00aSAdrian Chadd 	}
171d2d7a00aSAdrian Chadd 	return 0;
172d2d7a00aSAdrian Chadd #undef IEEE80211_KEY_XR
173d2d7a00aSAdrian Chadd }
174d2d7a00aSAdrian Chadd 
175d2d7a00aSAdrian Chadd /*
176d2d7a00aSAdrian Chadd  * Set a net80211 key into the hardware.  This handles the
177d2d7a00aSAdrian Chadd  * potential distribution of key state to multiple key
178d2d7a00aSAdrian Chadd  * cache slots for TKIP with hardware MIC support.
179d2d7a00aSAdrian Chadd  */
180d2d7a00aSAdrian Chadd int
181*55c7b877SAdrian Chadd ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
182*55c7b877SAdrian Chadd 	const struct ieee80211_key *k,
183d2d7a00aSAdrian Chadd 	struct ieee80211_node *bss)
184d2d7a00aSAdrian Chadd {
185d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
186d2d7a00aSAdrian Chadd 	static const u_int8_t ciphermap[] = {
187d2d7a00aSAdrian Chadd 		HAL_CIPHER_WEP,		/* IEEE80211_CIPHER_WEP */
188d2d7a00aSAdrian Chadd 		HAL_CIPHER_TKIP,	/* IEEE80211_CIPHER_TKIP */
189d2d7a00aSAdrian Chadd 		HAL_CIPHER_AES_OCB,	/* IEEE80211_CIPHER_AES_OCB */
190d2d7a00aSAdrian Chadd 		HAL_CIPHER_AES_CCM,	/* IEEE80211_CIPHER_AES_CCM */
191d2d7a00aSAdrian Chadd 		(u_int8_t) -1,		/* 4 is not allocated */
192d2d7a00aSAdrian Chadd 		HAL_CIPHER_CKIP,	/* IEEE80211_CIPHER_CKIP */
193d2d7a00aSAdrian Chadd 		HAL_CIPHER_CLR,		/* IEEE80211_CIPHER_NONE */
194d2d7a00aSAdrian Chadd 	};
195d2d7a00aSAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
196d2d7a00aSAdrian Chadd 	const struct ieee80211_cipher *cip = k->wk_cipher;
197d2d7a00aSAdrian Chadd 	u_int8_t gmac[IEEE80211_ADDR_LEN];
198d2d7a00aSAdrian Chadd 	const u_int8_t *mac;
199d2d7a00aSAdrian Chadd 	HAL_KEYVAL hk;
200d2d7a00aSAdrian Chadd 
201d2d7a00aSAdrian Chadd 	memset(&hk, 0, sizeof(hk));
202d2d7a00aSAdrian Chadd 	/*
203d2d7a00aSAdrian Chadd 	 * Software crypto uses a "clear key" so non-crypto
204d2d7a00aSAdrian Chadd 	 * state kept in the key cache are maintained and
205d2d7a00aSAdrian Chadd 	 * so that rx frames have an entry to match.
206d2d7a00aSAdrian Chadd 	 */
207d2d7a00aSAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
208d2d7a00aSAdrian Chadd 		KASSERT(cip->ic_cipher < N(ciphermap),
209d2d7a00aSAdrian Chadd 			("invalid cipher type %u", cip->ic_cipher));
210d2d7a00aSAdrian Chadd 		hk.kv_type = ciphermap[cip->ic_cipher];
211d2d7a00aSAdrian Chadd 		hk.kv_len = k->wk_keylen;
212d2d7a00aSAdrian Chadd 		memcpy(hk.kv_val, k->wk_key, k->wk_keylen);
213d2d7a00aSAdrian Chadd 	} else
214d2d7a00aSAdrian Chadd 		hk.kv_type = HAL_CIPHER_CLR;
215d2d7a00aSAdrian Chadd 
216*55c7b877SAdrian Chadd 	/*
217*55c7b877SAdrian Chadd 	 * XXX TODO: check this:
218*55c7b877SAdrian Chadd 	 *
219*55c7b877SAdrian Chadd 	 * Group keys on hardware that supports multicast frame
220*55c7b877SAdrian Chadd 	 * key search should only be done in adhoc/hostap mode,
221*55c7b877SAdrian Chadd 	 * not STA mode.
222*55c7b877SAdrian Chadd 	 *
223*55c7b877SAdrian Chadd 	 * XXX TODO: what about mesh, tdma?
224*55c7b877SAdrian Chadd 	 */
225*55c7b877SAdrian Chadd #if 0
226*55c7b877SAdrian Chadd 	if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
227*55c7b877SAdrian Chadd 	     vap->iv_opmode == IEEE80211_M_IBSS) &&
228*55c7b877SAdrian Chadd #else
229*55c7b877SAdrian Chadd 	if (
230*55c7b877SAdrian Chadd #endif
231*55c7b877SAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_GROUP) &&
232*55c7b877SAdrian Chadd 	    sc->sc_mcastkey) {
233d2d7a00aSAdrian Chadd 		/*
234d2d7a00aSAdrian Chadd 		 * Group keys on hardware that supports multicast frame
235d2d7a00aSAdrian Chadd 		 * key search use a MAC that is the sender's address with
236d2d7a00aSAdrian Chadd 		 * the multicast bit set instead of the app-specified address.
237d2d7a00aSAdrian Chadd 		 */
238d2d7a00aSAdrian Chadd 		IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
239d2d7a00aSAdrian Chadd 		gmac[0] |= 0x01;
240d2d7a00aSAdrian Chadd 		mac = gmac;
241d2d7a00aSAdrian Chadd 	} else
242d2d7a00aSAdrian Chadd 		mac = k->wk_macaddr;
243d2d7a00aSAdrian Chadd 
244d2d7a00aSAdrian Chadd 	if (hk.kv_type == HAL_CIPHER_TKIP &&
245d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
246d2d7a00aSAdrian Chadd 		return ath_keyset_tkip(sc, k, &hk, mac);
247d2d7a00aSAdrian Chadd 	} else {
248d2d7a00aSAdrian Chadd 		KEYPRINTF(sc, k->wk_keyix, &hk, mac);
249d2d7a00aSAdrian Chadd 		return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
250d2d7a00aSAdrian Chadd 	}
251d2d7a00aSAdrian Chadd #undef N
252d2d7a00aSAdrian Chadd }
253d2d7a00aSAdrian Chadd 
254d2d7a00aSAdrian Chadd /*
255d2d7a00aSAdrian Chadd  * Allocate tx/rx key slots for TKIP.  We allocate two slots for
256d2d7a00aSAdrian Chadd  * each key, one for decrypt/encrypt and the other for the MIC.
257d2d7a00aSAdrian Chadd  */
258d2d7a00aSAdrian Chadd static u_int16_t
259d2d7a00aSAdrian Chadd key_alloc_2pair(struct ath_softc *sc,
260d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
261d2d7a00aSAdrian Chadd {
262d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
263d2d7a00aSAdrian Chadd 	u_int i, keyix;
264d2d7a00aSAdrian Chadd 
265d2d7a00aSAdrian Chadd 	KASSERT(sc->sc_splitmic, ("key cache !split"));
266d2d7a00aSAdrian Chadd 	/* XXX could optimize */
267d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap)/4; i++) {
268d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
269d2d7a00aSAdrian Chadd 		if (b != 0xff) {
270d2d7a00aSAdrian Chadd 			/*
271d2d7a00aSAdrian Chadd 			 * One or more slots in this byte are free.
272d2d7a00aSAdrian Chadd 			 */
273d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
274d2d7a00aSAdrian Chadd 			while (b & 1) {
275d2d7a00aSAdrian Chadd 		again:
276d2d7a00aSAdrian Chadd 				keyix++;
277d2d7a00aSAdrian Chadd 				b >>= 1;
278d2d7a00aSAdrian Chadd 			}
279d2d7a00aSAdrian Chadd 			/* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
280d2d7a00aSAdrian Chadd 			if (isset(sc->sc_keymap, keyix+32) ||
281d2d7a00aSAdrian Chadd 			    isset(sc->sc_keymap, keyix+64) ||
282d2d7a00aSAdrian Chadd 			    isset(sc->sc_keymap, keyix+32+64)) {
283d2d7a00aSAdrian Chadd 				/* full pair unavailable */
284d2d7a00aSAdrian Chadd 				/* XXX statistic */
285d2d7a00aSAdrian Chadd 				if (keyix == (i+1)*NBBY) {
286d2d7a00aSAdrian Chadd 					/* no slots were appropriate, advance */
287d2d7a00aSAdrian Chadd 					continue;
288d2d7a00aSAdrian Chadd 				}
289d2d7a00aSAdrian Chadd 				goto again;
290d2d7a00aSAdrian Chadd 			}
291d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
292d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+64);
293d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+32);
294d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+32+64);
295d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
296d2d7a00aSAdrian Chadd 				"%s: key pair %u,%u %u,%u\n",
297d2d7a00aSAdrian Chadd 				__func__, keyix, keyix+64,
298d2d7a00aSAdrian Chadd 				keyix+32, keyix+32+64);
299d2d7a00aSAdrian Chadd 			*txkeyix = keyix;
300d2d7a00aSAdrian Chadd 			*rxkeyix = keyix+32;
301d2d7a00aSAdrian Chadd 			return 1;
302d2d7a00aSAdrian Chadd 		}
303d2d7a00aSAdrian Chadd 	}
304d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
305d2d7a00aSAdrian Chadd 	return 0;
306d2d7a00aSAdrian Chadd #undef N
307d2d7a00aSAdrian Chadd }
308d2d7a00aSAdrian Chadd 
309d2d7a00aSAdrian Chadd /*
310d2d7a00aSAdrian Chadd  * Allocate tx/rx key slots for TKIP.  We allocate two slots for
311d2d7a00aSAdrian Chadd  * each key, one for decrypt/encrypt and the other for the MIC.
312d2d7a00aSAdrian Chadd  */
313d2d7a00aSAdrian Chadd static u_int16_t
314d2d7a00aSAdrian Chadd key_alloc_pair(struct ath_softc *sc,
315d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
316d2d7a00aSAdrian Chadd {
317d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
318d2d7a00aSAdrian Chadd 	u_int i, keyix;
319d2d7a00aSAdrian Chadd 
320d2d7a00aSAdrian Chadd 	KASSERT(!sc->sc_splitmic, ("key cache split"));
321d2d7a00aSAdrian Chadd 	/* XXX could optimize */
322d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap)/4; i++) {
323d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
324d2d7a00aSAdrian Chadd 		if (b != 0xff) {
325d2d7a00aSAdrian Chadd 			/*
326d2d7a00aSAdrian Chadd 			 * One or more slots in this byte are free.
327d2d7a00aSAdrian Chadd 			 */
328d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
329d2d7a00aSAdrian Chadd 			while (b & 1) {
330d2d7a00aSAdrian Chadd 		again:
331d2d7a00aSAdrian Chadd 				keyix++;
332d2d7a00aSAdrian Chadd 				b >>= 1;
333d2d7a00aSAdrian Chadd 			}
334d2d7a00aSAdrian Chadd 			if (isset(sc->sc_keymap, keyix+64)) {
335d2d7a00aSAdrian Chadd 				/* full pair unavailable */
336d2d7a00aSAdrian Chadd 				/* XXX statistic */
337d2d7a00aSAdrian Chadd 				if (keyix == (i+1)*NBBY) {
338d2d7a00aSAdrian Chadd 					/* no slots were appropriate, advance */
339d2d7a00aSAdrian Chadd 					continue;
340d2d7a00aSAdrian Chadd 				}
341d2d7a00aSAdrian Chadd 				goto again;
342d2d7a00aSAdrian Chadd 			}
343d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
344d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+64);
345d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
346d2d7a00aSAdrian Chadd 				"%s: key pair %u,%u\n",
347d2d7a00aSAdrian Chadd 				__func__, keyix, keyix+64);
348d2d7a00aSAdrian Chadd 			*txkeyix = *rxkeyix = keyix;
349d2d7a00aSAdrian Chadd 			return 1;
350d2d7a00aSAdrian Chadd 		}
351d2d7a00aSAdrian Chadd 	}
352d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
353d2d7a00aSAdrian Chadd 	return 0;
354d2d7a00aSAdrian Chadd #undef N
355d2d7a00aSAdrian Chadd }
356d2d7a00aSAdrian Chadd 
357d2d7a00aSAdrian Chadd /*
358d2d7a00aSAdrian Chadd  * Allocate a single key cache slot.
359d2d7a00aSAdrian Chadd  */
360d2d7a00aSAdrian Chadd static int
361d2d7a00aSAdrian Chadd key_alloc_single(struct ath_softc *sc,
362d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
363d2d7a00aSAdrian Chadd {
364d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
365d2d7a00aSAdrian Chadd 	u_int i, keyix;
366d2d7a00aSAdrian Chadd 
367d2d7a00aSAdrian Chadd 	/* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
368d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap); i++) {
369d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
370d2d7a00aSAdrian Chadd 		if (b != 0xff) {
371d2d7a00aSAdrian Chadd 			/*
372d2d7a00aSAdrian Chadd 			 * One or more slots are free.
373d2d7a00aSAdrian Chadd 			 */
374d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
375d2d7a00aSAdrian Chadd 			while (b & 1)
376d2d7a00aSAdrian Chadd 				keyix++, b >>= 1;
377d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
378d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
379d2d7a00aSAdrian Chadd 				__func__, keyix);
380d2d7a00aSAdrian Chadd 			*txkeyix = *rxkeyix = keyix;
381d2d7a00aSAdrian Chadd 			return 1;
382d2d7a00aSAdrian Chadd 		}
383d2d7a00aSAdrian Chadd 	}
384d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__);
385d2d7a00aSAdrian Chadd 	return 0;
386d2d7a00aSAdrian Chadd #undef N
387d2d7a00aSAdrian Chadd }
388d2d7a00aSAdrian Chadd 
389d2d7a00aSAdrian Chadd /*
390d2d7a00aSAdrian Chadd  * Allocate one or more key cache slots for a uniacst key.  The
391d2d7a00aSAdrian Chadd  * key itself is needed only to identify the cipher.  For hardware
392d2d7a00aSAdrian Chadd  * TKIP with split cipher+MIC keys we allocate two key cache slot
393d2d7a00aSAdrian Chadd  * pairs so that we can setup separate TX and RX MIC keys.  Note
394d2d7a00aSAdrian Chadd  * that the MIC key for a TKIP key at slot i is assumed by the
395d2d7a00aSAdrian Chadd  * hardware to be at slot i+64.  This limits TKIP keys to the first
396d2d7a00aSAdrian Chadd  * 64 entries.
397d2d7a00aSAdrian Chadd  */
398d2d7a00aSAdrian Chadd int
399d2d7a00aSAdrian Chadd ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
400d2d7a00aSAdrian Chadd 	ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
401d2d7a00aSAdrian Chadd {
402d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
403d2d7a00aSAdrian Chadd 
404d2d7a00aSAdrian Chadd 	/*
405d2d7a00aSAdrian Chadd 	 * Group key allocation must be handled specially for
406d2d7a00aSAdrian Chadd 	 * parts that do not support multicast key cache search
407d2d7a00aSAdrian Chadd 	 * functionality.  For those parts the key id must match
408d2d7a00aSAdrian Chadd 	 * the h/w key index so lookups find the right key.  On
409d2d7a00aSAdrian Chadd 	 * parts w/ the key search facility we install the sender's
410d2d7a00aSAdrian Chadd 	 * mac address (with the high bit set) and let the hardware
411d2d7a00aSAdrian Chadd 	 * find the key w/o using the key id.  This is preferred as
412d2d7a00aSAdrian Chadd 	 * it permits us to support multiple users for adhoc and/or
413d2d7a00aSAdrian Chadd 	 * multi-station operation.
414d2d7a00aSAdrian Chadd 	 */
415d2d7a00aSAdrian Chadd 	if (k->wk_keyix != IEEE80211_KEYIX_NONE) {
416d2d7a00aSAdrian Chadd 		/*
417d2d7a00aSAdrian Chadd 		 * Only global keys should have key index assigned.
418d2d7a00aSAdrian Chadd 		 */
419d2d7a00aSAdrian Chadd 		if (!(&vap->iv_nw_keys[0] <= k &&
420d2d7a00aSAdrian Chadd 		      k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
421d2d7a00aSAdrian Chadd 			/* should not happen */
422d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
423d2d7a00aSAdrian Chadd 				"%s: bogus group key\n", __func__);
424d2d7a00aSAdrian Chadd 			return 0;
425d2d7a00aSAdrian Chadd 		}
426d2d7a00aSAdrian Chadd 		if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
427d2d7a00aSAdrian Chadd 		    !(k->wk_flags & IEEE80211_KEY_GROUP) ||
428d2d7a00aSAdrian Chadd 		    !sc->sc_mcastkey) {
429d2d7a00aSAdrian Chadd 			/*
430d2d7a00aSAdrian Chadd 			 * XXX we pre-allocate the global keys so
431d2d7a00aSAdrian Chadd 			 * have no way to check if they've already
432d2d7a00aSAdrian Chadd 			 * been allocated.
433d2d7a00aSAdrian Chadd 			 */
434d2d7a00aSAdrian Chadd 			*keyix = *rxkeyix = k - vap->iv_nw_keys;
435d2d7a00aSAdrian Chadd 			return 1;
436d2d7a00aSAdrian Chadd 		}
437d2d7a00aSAdrian Chadd 		/*
438d2d7a00aSAdrian Chadd 		 * Group key and device supports multicast key search.
439d2d7a00aSAdrian Chadd 		 */
440d2d7a00aSAdrian Chadd 		k->wk_keyix = IEEE80211_KEYIX_NONE;
441d2d7a00aSAdrian Chadd 	}
442d2d7a00aSAdrian Chadd 
443d2d7a00aSAdrian Chadd 	/*
444d2d7a00aSAdrian Chadd 	 * We allocate two pair for TKIP when using the h/w to do
445d2d7a00aSAdrian Chadd 	 * the MIC.  For everything else, including software crypto,
446d2d7a00aSAdrian Chadd 	 * we allocate a single entry.  Note that s/w crypto requires
447d2d7a00aSAdrian Chadd 	 * a pass-through slot on the 5211 and 5212.  The 5210 does
448d2d7a00aSAdrian Chadd 	 * not support pass-through cache entries and we map all
449d2d7a00aSAdrian Chadd 	 * those requests to slot 0.
450d2d7a00aSAdrian Chadd 	 */
451d2d7a00aSAdrian Chadd 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
452d2d7a00aSAdrian Chadd 		return key_alloc_single(sc, keyix, rxkeyix);
453d2d7a00aSAdrian Chadd 	} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
454d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
455d2d7a00aSAdrian Chadd 		if (sc->sc_splitmic)
456d2d7a00aSAdrian Chadd 			return key_alloc_2pair(sc, keyix, rxkeyix);
457d2d7a00aSAdrian Chadd 		else
458d2d7a00aSAdrian Chadd 			return key_alloc_pair(sc, keyix, rxkeyix);
459d2d7a00aSAdrian Chadd 	} else {
460d2d7a00aSAdrian Chadd 		return key_alloc_single(sc, keyix, rxkeyix);
461d2d7a00aSAdrian Chadd 	}
462d2d7a00aSAdrian Chadd }
463d2d7a00aSAdrian Chadd 
464d2d7a00aSAdrian Chadd /*
465d2d7a00aSAdrian Chadd  * Delete an entry in the key cache allocated by ath_key_alloc.
466d2d7a00aSAdrian Chadd  */
467d2d7a00aSAdrian Chadd int
468d2d7a00aSAdrian Chadd ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
469d2d7a00aSAdrian Chadd {
470d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
471d2d7a00aSAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
472d2d7a00aSAdrian Chadd 	const struct ieee80211_cipher *cip = k->wk_cipher;
473d2d7a00aSAdrian Chadd 	u_int keyix = k->wk_keyix;
474d2d7a00aSAdrian Chadd 
475d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
476d2d7a00aSAdrian Chadd 
477d2d7a00aSAdrian Chadd 	ath_hal_keyreset(ah, keyix);
478d2d7a00aSAdrian Chadd 	/*
479d2d7a00aSAdrian Chadd 	 * Handle split tx/rx keying required for TKIP with h/w MIC.
480d2d7a00aSAdrian Chadd 	 */
481d2d7a00aSAdrian Chadd 	if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
482d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
483d2d7a00aSAdrian Chadd 		ath_hal_keyreset(ah, keyix+32);		/* RX key */
484d2d7a00aSAdrian Chadd 	if (keyix >= IEEE80211_WEP_NKID) {
485d2d7a00aSAdrian Chadd 		/*
486d2d7a00aSAdrian Chadd 		 * Don't touch keymap entries for global keys so
487d2d7a00aSAdrian Chadd 		 * they are never considered for dynamic allocation.
488d2d7a00aSAdrian Chadd 		 */
489d2d7a00aSAdrian Chadd 		clrbit(sc->sc_keymap, keyix);
490d2d7a00aSAdrian Chadd 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
491d2d7a00aSAdrian Chadd 		    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
492d2d7a00aSAdrian Chadd 			clrbit(sc->sc_keymap, keyix+64);	/* TX key MIC */
493d2d7a00aSAdrian Chadd 			if (sc->sc_splitmic) {
494d2d7a00aSAdrian Chadd 				/* +32 for RX key, +32+64 for RX key MIC */
495d2d7a00aSAdrian Chadd 				clrbit(sc->sc_keymap, keyix+32);
496d2d7a00aSAdrian Chadd 				clrbit(sc->sc_keymap, keyix+32+64);
497d2d7a00aSAdrian Chadd 			}
498d2d7a00aSAdrian Chadd 		}
499d2d7a00aSAdrian Chadd 	}
500d2d7a00aSAdrian Chadd 	return 1;
501d2d7a00aSAdrian Chadd }
502d2d7a00aSAdrian Chadd 
503d2d7a00aSAdrian Chadd /*
504d2d7a00aSAdrian Chadd  * Set the key cache contents for the specified key.  Key cache
505d2d7a00aSAdrian Chadd  * slot(s) must already have been allocated by ath_key_alloc.
506d2d7a00aSAdrian Chadd  */
507d2d7a00aSAdrian Chadd int
508d2d7a00aSAdrian Chadd ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
509d2d7a00aSAdrian Chadd 	const u_int8_t mac[IEEE80211_ADDR_LEN])
510d2d7a00aSAdrian Chadd {
511d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
512d2d7a00aSAdrian Chadd 
513*55c7b877SAdrian Chadd 	return ath_keyset(sc, vap, k, vap->iv_bss);
514d2d7a00aSAdrian Chadd }
515