xref: /freebsd/sys/dev/ath/if_ath_keycache.c (revision cc637103f69892f4a7f4ef82d4787e180e1692be)
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
18155c7b877SAdrian Chadd ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap,
18255c7b877SAdrian 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 
21655c7b877SAdrian Chadd 	/*
217*cc637103SAdrian Chadd 	 * If we're installing a clear cipher key and
218*cc637103SAdrian Chadd 	 * the hardware doesn't support that, just succeed.
219*cc637103SAdrian Chadd 	 * Leave it up to the net80211 layer to figure it out.
220*cc637103SAdrian Chadd 	 */
221*cc637103SAdrian Chadd 	if (hk.kv_type == HAL_CIPHER_CLR && sc->sc_hasclrkey == 0) {
222*cc637103SAdrian Chadd 		return (1);
223*cc637103SAdrian Chadd 	}
224*cc637103SAdrian Chadd 
225*cc637103SAdrian Chadd 	/*
22655c7b877SAdrian Chadd 	 * XXX TODO: check this:
22755c7b877SAdrian Chadd 	 *
22855c7b877SAdrian Chadd 	 * Group keys on hardware that supports multicast frame
22955c7b877SAdrian Chadd 	 * key search should only be done in adhoc/hostap mode,
23055c7b877SAdrian Chadd 	 * not STA mode.
23155c7b877SAdrian Chadd 	 *
23255c7b877SAdrian Chadd 	 * XXX TODO: what about mesh, tdma?
23355c7b877SAdrian Chadd 	 */
23455c7b877SAdrian Chadd #if 0
23555c7b877SAdrian Chadd 	if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
23655c7b877SAdrian Chadd 	     vap->iv_opmode == IEEE80211_M_IBSS) &&
23755c7b877SAdrian Chadd #else
23855c7b877SAdrian Chadd 	if (
23955c7b877SAdrian Chadd #endif
24055c7b877SAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_GROUP) &&
24155c7b877SAdrian Chadd 	    sc->sc_mcastkey) {
242d2d7a00aSAdrian Chadd 		/*
243d2d7a00aSAdrian Chadd 		 * Group keys on hardware that supports multicast frame
244d2d7a00aSAdrian Chadd 		 * key search use a MAC that is the sender's address with
245d2d7a00aSAdrian Chadd 		 * the multicast bit set instead of the app-specified address.
246d2d7a00aSAdrian Chadd 		 */
247d2d7a00aSAdrian Chadd 		IEEE80211_ADDR_COPY(gmac, bss->ni_macaddr);
248d2d7a00aSAdrian Chadd 		gmac[0] |= 0x01;
249d2d7a00aSAdrian Chadd 		mac = gmac;
250d2d7a00aSAdrian Chadd 	} else
251d2d7a00aSAdrian Chadd 		mac = k->wk_macaddr;
252d2d7a00aSAdrian Chadd 
253d2d7a00aSAdrian Chadd 	if (hk.kv_type == HAL_CIPHER_TKIP &&
254d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
255d2d7a00aSAdrian Chadd 		return ath_keyset_tkip(sc, k, &hk, mac);
256d2d7a00aSAdrian Chadd 	} else {
257d2d7a00aSAdrian Chadd 		KEYPRINTF(sc, k->wk_keyix, &hk, mac);
258d2d7a00aSAdrian Chadd 		return ath_hal_keyset(ah, k->wk_keyix, &hk, mac);
259d2d7a00aSAdrian Chadd 	}
260d2d7a00aSAdrian Chadd #undef N
261d2d7a00aSAdrian Chadd }
262d2d7a00aSAdrian Chadd 
263d2d7a00aSAdrian Chadd /*
264d2d7a00aSAdrian Chadd  * Allocate tx/rx key slots for TKIP.  We allocate two slots for
265d2d7a00aSAdrian Chadd  * each key, one for decrypt/encrypt and the other for the MIC.
266d2d7a00aSAdrian Chadd  */
267d2d7a00aSAdrian Chadd static u_int16_t
268d2d7a00aSAdrian Chadd key_alloc_2pair(struct ath_softc *sc,
269d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
270d2d7a00aSAdrian Chadd {
271d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
272d2d7a00aSAdrian Chadd 	u_int i, keyix;
273d2d7a00aSAdrian Chadd 
274d2d7a00aSAdrian Chadd 	KASSERT(sc->sc_splitmic, ("key cache !split"));
275d2d7a00aSAdrian Chadd 	/* XXX could optimize */
276d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap)/4; i++) {
277d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
278d2d7a00aSAdrian Chadd 		if (b != 0xff) {
279d2d7a00aSAdrian Chadd 			/*
280d2d7a00aSAdrian Chadd 			 * One or more slots in this byte are free.
281d2d7a00aSAdrian Chadd 			 */
282d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
283d2d7a00aSAdrian Chadd 			while (b & 1) {
284d2d7a00aSAdrian Chadd 		again:
285d2d7a00aSAdrian Chadd 				keyix++;
286d2d7a00aSAdrian Chadd 				b >>= 1;
287d2d7a00aSAdrian Chadd 			}
288d2d7a00aSAdrian Chadd 			/* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
289d2d7a00aSAdrian Chadd 			if (isset(sc->sc_keymap, keyix+32) ||
290d2d7a00aSAdrian Chadd 			    isset(sc->sc_keymap, keyix+64) ||
291d2d7a00aSAdrian Chadd 			    isset(sc->sc_keymap, keyix+32+64)) {
292d2d7a00aSAdrian Chadd 				/* full pair unavailable */
293d2d7a00aSAdrian Chadd 				/* XXX statistic */
294d2d7a00aSAdrian Chadd 				if (keyix == (i+1)*NBBY) {
295d2d7a00aSAdrian Chadd 					/* no slots were appropriate, advance */
296d2d7a00aSAdrian Chadd 					continue;
297d2d7a00aSAdrian Chadd 				}
298d2d7a00aSAdrian Chadd 				goto again;
299d2d7a00aSAdrian Chadd 			}
300d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
301d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+64);
302d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+32);
303d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+32+64);
304d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
305d2d7a00aSAdrian Chadd 				"%s: key pair %u,%u %u,%u\n",
306d2d7a00aSAdrian Chadd 				__func__, keyix, keyix+64,
307d2d7a00aSAdrian Chadd 				keyix+32, keyix+32+64);
308d2d7a00aSAdrian Chadd 			*txkeyix = keyix;
309d2d7a00aSAdrian Chadd 			*rxkeyix = keyix+32;
310d2d7a00aSAdrian Chadd 			return 1;
311d2d7a00aSAdrian Chadd 		}
312d2d7a00aSAdrian Chadd 	}
313d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
314d2d7a00aSAdrian Chadd 	return 0;
315d2d7a00aSAdrian Chadd #undef N
316d2d7a00aSAdrian Chadd }
317d2d7a00aSAdrian Chadd 
318d2d7a00aSAdrian Chadd /*
319d2d7a00aSAdrian Chadd  * Allocate tx/rx key slots for TKIP.  We allocate two slots for
320d2d7a00aSAdrian Chadd  * each key, one for decrypt/encrypt and the other for the MIC.
321d2d7a00aSAdrian Chadd  */
322d2d7a00aSAdrian Chadd static u_int16_t
323d2d7a00aSAdrian Chadd key_alloc_pair(struct ath_softc *sc,
324d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
325d2d7a00aSAdrian Chadd {
326d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
327d2d7a00aSAdrian Chadd 	u_int i, keyix;
328d2d7a00aSAdrian Chadd 
329d2d7a00aSAdrian Chadd 	KASSERT(!sc->sc_splitmic, ("key cache split"));
330d2d7a00aSAdrian Chadd 	/* XXX could optimize */
331d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap)/4; i++) {
332d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
333d2d7a00aSAdrian Chadd 		if (b != 0xff) {
334d2d7a00aSAdrian Chadd 			/*
335d2d7a00aSAdrian Chadd 			 * One or more slots in this byte are free.
336d2d7a00aSAdrian Chadd 			 */
337d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
338d2d7a00aSAdrian Chadd 			while (b & 1) {
339d2d7a00aSAdrian Chadd 		again:
340d2d7a00aSAdrian Chadd 				keyix++;
341d2d7a00aSAdrian Chadd 				b >>= 1;
342d2d7a00aSAdrian Chadd 			}
343d2d7a00aSAdrian Chadd 			if (isset(sc->sc_keymap, keyix+64)) {
344d2d7a00aSAdrian Chadd 				/* full pair unavailable */
345d2d7a00aSAdrian Chadd 				/* XXX statistic */
346d2d7a00aSAdrian Chadd 				if (keyix == (i+1)*NBBY) {
347d2d7a00aSAdrian Chadd 					/* no slots were appropriate, advance */
348d2d7a00aSAdrian Chadd 					continue;
349d2d7a00aSAdrian Chadd 				}
350d2d7a00aSAdrian Chadd 				goto again;
351d2d7a00aSAdrian Chadd 			}
352d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
353d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix+64);
354d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
355d2d7a00aSAdrian Chadd 				"%s: key pair %u,%u\n",
356d2d7a00aSAdrian Chadd 				__func__, keyix, keyix+64);
357d2d7a00aSAdrian Chadd 			*txkeyix = *rxkeyix = keyix;
358d2d7a00aSAdrian Chadd 			return 1;
359d2d7a00aSAdrian Chadd 		}
360d2d7a00aSAdrian Chadd 	}
361d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of pair space\n", __func__);
362d2d7a00aSAdrian Chadd 	return 0;
363d2d7a00aSAdrian Chadd #undef N
364d2d7a00aSAdrian Chadd }
365d2d7a00aSAdrian Chadd 
366d2d7a00aSAdrian Chadd /*
367d2d7a00aSAdrian Chadd  * Allocate a single key cache slot.
368d2d7a00aSAdrian Chadd  */
369d2d7a00aSAdrian Chadd static int
370d2d7a00aSAdrian Chadd key_alloc_single(struct ath_softc *sc,
371d2d7a00aSAdrian Chadd 	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
372d2d7a00aSAdrian Chadd {
373d2d7a00aSAdrian Chadd #define	N(a)	(sizeof(a)/sizeof(a[0]))
374d2d7a00aSAdrian Chadd 	u_int i, keyix;
375d2d7a00aSAdrian Chadd 
376*cc637103SAdrian Chadd 	if (sc->sc_hasclrkey == 0) {
377*cc637103SAdrian Chadd 		/*
378*cc637103SAdrian Chadd 		 * Map to slot 0 for the AR5210.
379*cc637103SAdrian Chadd 		 */
380*cc637103SAdrian Chadd 		*txkeyix = *rxkeyix = 0;
381*cc637103SAdrian Chadd 		return (1);
382*cc637103SAdrian Chadd 	}
383*cc637103SAdrian Chadd 
384d2d7a00aSAdrian Chadd 	/* XXX try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
385d2d7a00aSAdrian Chadd 	for (i = 0; i < N(sc->sc_keymap); i++) {
386d2d7a00aSAdrian Chadd 		u_int8_t b = sc->sc_keymap[i];
387d2d7a00aSAdrian Chadd 		if (b != 0xff) {
388d2d7a00aSAdrian Chadd 			/*
389d2d7a00aSAdrian Chadd 			 * One or more slots are free.
390d2d7a00aSAdrian Chadd 			 */
391d2d7a00aSAdrian Chadd 			keyix = i*NBBY;
392d2d7a00aSAdrian Chadd 			while (b & 1)
393d2d7a00aSAdrian Chadd 				keyix++, b >>= 1;
394d2d7a00aSAdrian Chadd 			setbit(sc->sc_keymap, keyix);
395d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: key %u\n",
396d2d7a00aSAdrian Chadd 				__func__, keyix);
397d2d7a00aSAdrian Chadd 			*txkeyix = *rxkeyix = keyix;
398d2d7a00aSAdrian Chadd 			return 1;
399d2d7a00aSAdrian Chadd 		}
400d2d7a00aSAdrian Chadd 	}
401d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: out of space\n", __func__);
402d2d7a00aSAdrian Chadd 	return 0;
403d2d7a00aSAdrian Chadd #undef N
404d2d7a00aSAdrian Chadd }
405d2d7a00aSAdrian Chadd 
406d2d7a00aSAdrian Chadd /*
407d2d7a00aSAdrian Chadd  * Allocate one or more key cache slots for a uniacst key.  The
408d2d7a00aSAdrian Chadd  * key itself is needed only to identify the cipher.  For hardware
409d2d7a00aSAdrian Chadd  * TKIP with split cipher+MIC keys we allocate two key cache slot
410d2d7a00aSAdrian Chadd  * pairs so that we can setup separate TX and RX MIC keys.  Note
411d2d7a00aSAdrian Chadd  * that the MIC key for a TKIP key at slot i is assumed by the
412d2d7a00aSAdrian Chadd  * hardware to be at slot i+64.  This limits TKIP keys to the first
413d2d7a00aSAdrian Chadd  * 64 entries.
414d2d7a00aSAdrian Chadd  */
415d2d7a00aSAdrian Chadd int
416d2d7a00aSAdrian Chadd ath_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
417d2d7a00aSAdrian Chadd 	ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
418d2d7a00aSAdrian Chadd {
419d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
420d2d7a00aSAdrian Chadd 
421d2d7a00aSAdrian Chadd 	/*
422d2d7a00aSAdrian Chadd 	 * Group key allocation must be handled specially for
423d2d7a00aSAdrian Chadd 	 * parts that do not support multicast key cache search
424d2d7a00aSAdrian Chadd 	 * functionality.  For those parts the key id must match
425d2d7a00aSAdrian Chadd 	 * the h/w key index so lookups find the right key.  On
426d2d7a00aSAdrian Chadd 	 * parts w/ the key search facility we install the sender's
427d2d7a00aSAdrian Chadd 	 * mac address (with the high bit set) and let the hardware
428d2d7a00aSAdrian Chadd 	 * find the key w/o using the key id.  This is preferred as
429d2d7a00aSAdrian Chadd 	 * it permits us to support multiple users for adhoc and/or
430d2d7a00aSAdrian Chadd 	 * multi-station operation.
431d2d7a00aSAdrian Chadd 	 */
432d2d7a00aSAdrian Chadd 	if (k->wk_keyix != IEEE80211_KEYIX_NONE) {
433d2d7a00aSAdrian Chadd 		/*
434d2d7a00aSAdrian Chadd 		 * Only global keys should have key index assigned.
435d2d7a00aSAdrian Chadd 		 */
436d2d7a00aSAdrian Chadd 		if (!(&vap->iv_nw_keys[0] <= k &&
437d2d7a00aSAdrian Chadd 		      k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
438d2d7a00aSAdrian Chadd 			/* should not happen */
439d2d7a00aSAdrian Chadd 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
440d2d7a00aSAdrian Chadd 				"%s: bogus group key\n", __func__);
441d2d7a00aSAdrian Chadd 			return 0;
442d2d7a00aSAdrian Chadd 		}
443d2d7a00aSAdrian Chadd 		if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
444d2d7a00aSAdrian Chadd 		    !(k->wk_flags & IEEE80211_KEY_GROUP) ||
445d2d7a00aSAdrian Chadd 		    !sc->sc_mcastkey) {
446d2d7a00aSAdrian Chadd 			/*
447d2d7a00aSAdrian Chadd 			 * XXX we pre-allocate the global keys so
448d2d7a00aSAdrian Chadd 			 * have no way to check if they've already
449d2d7a00aSAdrian Chadd 			 * been allocated.
450d2d7a00aSAdrian Chadd 			 */
451d2d7a00aSAdrian Chadd 			*keyix = *rxkeyix = k - vap->iv_nw_keys;
452d2d7a00aSAdrian Chadd 			return 1;
453d2d7a00aSAdrian Chadd 		}
454d2d7a00aSAdrian Chadd 		/*
455d2d7a00aSAdrian Chadd 		 * Group key and device supports multicast key search.
456d2d7a00aSAdrian Chadd 		 */
457d2d7a00aSAdrian Chadd 		k->wk_keyix = IEEE80211_KEYIX_NONE;
458d2d7a00aSAdrian Chadd 	}
459d2d7a00aSAdrian Chadd 
460d2d7a00aSAdrian Chadd 	/*
461d2d7a00aSAdrian Chadd 	 * We allocate two pair for TKIP when using the h/w to do
462d2d7a00aSAdrian Chadd 	 * the MIC.  For everything else, including software crypto,
463d2d7a00aSAdrian Chadd 	 * we allocate a single entry.  Note that s/w crypto requires
464d2d7a00aSAdrian Chadd 	 * a pass-through slot on the 5211 and 5212.  The 5210 does
465d2d7a00aSAdrian Chadd 	 * not support pass-through cache entries and we map all
466d2d7a00aSAdrian Chadd 	 * those requests to slot 0.
467d2d7a00aSAdrian Chadd 	 */
468d2d7a00aSAdrian Chadd 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
469d2d7a00aSAdrian Chadd 		return key_alloc_single(sc, keyix, rxkeyix);
470d2d7a00aSAdrian Chadd 	} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
471d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
472d2d7a00aSAdrian Chadd 		if (sc->sc_splitmic)
473d2d7a00aSAdrian Chadd 			return key_alloc_2pair(sc, keyix, rxkeyix);
474d2d7a00aSAdrian Chadd 		else
475d2d7a00aSAdrian Chadd 			return key_alloc_pair(sc, keyix, rxkeyix);
476d2d7a00aSAdrian Chadd 	} else {
477d2d7a00aSAdrian Chadd 		return key_alloc_single(sc, keyix, rxkeyix);
478d2d7a00aSAdrian Chadd 	}
479d2d7a00aSAdrian Chadd }
480d2d7a00aSAdrian Chadd 
481d2d7a00aSAdrian Chadd /*
482d2d7a00aSAdrian Chadd  * Delete an entry in the key cache allocated by ath_key_alloc.
483d2d7a00aSAdrian Chadd  */
484d2d7a00aSAdrian Chadd int
485d2d7a00aSAdrian Chadd ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
486d2d7a00aSAdrian Chadd {
487d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
488d2d7a00aSAdrian Chadd 	struct ath_hal *ah = sc->sc_ah;
489d2d7a00aSAdrian Chadd 	const struct ieee80211_cipher *cip = k->wk_cipher;
490d2d7a00aSAdrian Chadd 	u_int keyix = k->wk_keyix;
491d2d7a00aSAdrian Chadd 
492d2d7a00aSAdrian Chadd 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix);
493d2d7a00aSAdrian Chadd 
494d2d7a00aSAdrian Chadd 	ath_hal_keyreset(ah, keyix);
495d2d7a00aSAdrian Chadd 	/*
496d2d7a00aSAdrian Chadd 	 * Handle split tx/rx keying required for TKIP with h/w MIC.
497d2d7a00aSAdrian Chadd 	 */
498d2d7a00aSAdrian Chadd 	if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
499d2d7a00aSAdrian Chadd 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && sc->sc_splitmic)
500d2d7a00aSAdrian Chadd 		ath_hal_keyreset(ah, keyix+32);		/* RX key */
501d2d7a00aSAdrian Chadd 	if (keyix >= IEEE80211_WEP_NKID) {
502d2d7a00aSAdrian Chadd 		/*
503d2d7a00aSAdrian Chadd 		 * Don't touch keymap entries for global keys so
504d2d7a00aSAdrian Chadd 		 * they are never considered for dynamic allocation.
505d2d7a00aSAdrian Chadd 		 */
506d2d7a00aSAdrian Chadd 		clrbit(sc->sc_keymap, keyix);
507d2d7a00aSAdrian Chadd 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
508d2d7a00aSAdrian Chadd 		    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
509d2d7a00aSAdrian Chadd 			clrbit(sc->sc_keymap, keyix+64);	/* TX key MIC */
510d2d7a00aSAdrian Chadd 			if (sc->sc_splitmic) {
511d2d7a00aSAdrian Chadd 				/* +32 for RX key, +32+64 for RX key MIC */
512d2d7a00aSAdrian Chadd 				clrbit(sc->sc_keymap, keyix+32);
513d2d7a00aSAdrian Chadd 				clrbit(sc->sc_keymap, keyix+32+64);
514d2d7a00aSAdrian Chadd 			}
515d2d7a00aSAdrian Chadd 		}
516d2d7a00aSAdrian Chadd 	}
517d2d7a00aSAdrian Chadd 	return 1;
518d2d7a00aSAdrian Chadd }
519d2d7a00aSAdrian Chadd 
520d2d7a00aSAdrian Chadd /*
521d2d7a00aSAdrian Chadd  * Set the key cache contents for the specified key.  Key cache
522d2d7a00aSAdrian Chadd  * slot(s) must already have been allocated by ath_key_alloc.
523d2d7a00aSAdrian Chadd  */
524d2d7a00aSAdrian Chadd int
525d2d7a00aSAdrian Chadd ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
526d2d7a00aSAdrian Chadd 	const u_int8_t mac[IEEE80211_ADDR_LEN])
527d2d7a00aSAdrian Chadd {
528d2d7a00aSAdrian Chadd 	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
529d2d7a00aSAdrian Chadd 
53055c7b877SAdrian Chadd 	return ath_keyset(sc, vap, k, vap->iv_bss);
531d2d7a00aSAdrian Chadd }
532