xref: /freebsd/sys/net80211/ieee80211_crypto.c (revision 5c8a7b1b058f82427b99b67819d3002753f116b7)
11a1e1d21SSam Leffler /*-
27535e66aSSam Leffler  * Copyright (c) 2001 Atsushi Onoe
31f1d7810SSam Leffler  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
41a1e1d21SSam Leffler  * All rights reserved.
51a1e1d21SSam Leffler  *
61a1e1d21SSam Leffler  * Redistribution and use in source and binary forms, with or without
71a1e1d21SSam Leffler  * modification, are permitted provided that the following conditions
81a1e1d21SSam Leffler  * are met:
91a1e1d21SSam Leffler  * 1. Redistributions of source code must retain the above copyright
107535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
117535e66aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
127535e66aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
137535e66aSSam Leffler  *    documentation and/or other materials provided with the distribution.
147535e66aSSam Leffler  * 3. The name of the author may not be used to endorse or promote products
157535e66aSSam Leffler  *    derived from this software without specific prior written permission.
161a1e1d21SSam Leffler  *
171a1e1d21SSam Leffler  * Alternatively, this software may be distributed under the terms of the
181a1e1d21SSam Leffler  * GNU General Public License ("GPL") version 2 as published by the Free
191a1e1d21SSam Leffler  * Software Foundation.
201a1e1d21SSam Leffler  *
217535e66aSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
227535e66aSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
237535e66aSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
247535e66aSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
257535e66aSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
267535e66aSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
277535e66aSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
287535e66aSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
297535e66aSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
307535e66aSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311a1e1d21SSam Leffler  */
321a1e1d21SSam Leffler 
331a1e1d21SSam Leffler #include <sys/cdefs.h>
341a1e1d21SSam Leffler __FBSDID("$FreeBSD$");
351a1e1d21SSam Leffler 
368a1b9b6aSSam Leffler /*
378a1b9b6aSSam Leffler  * IEEE 802.11 generic crypto support.
388a1b9b6aSSam Leffler  */
391a1e1d21SSam Leffler #include <sys/param.h>
401a1e1d21SSam Leffler #include <sys/mbuf.h>
411a1e1d21SSam Leffler 
428a1b9b6aSSam Leffler #include <sys/socket.h>
431a1e1d21SSam Leffler 
441a1e1d21SSam Leffler #include <net/if.h>
451a1e1d21SSam Leffler #include <net/if_media.h>
468a1b9b6aSSam Leffler #include <net/ethernet.h>		/* XXX ETHER_HDR_LEN */
471a1e1d21SSam Leffler 
481a1e1d21SSam Leffler #include <net80211/ieee80211_var.h>
491a1e1d21SSam Leffler 
508a1b9b6aSSam Leffler /*
518a1b9b6aSSam Leffler  * Table of registered cipher modules.
528a1b9b6aSSam Leffler  */
538a1b9b6aSSam Leffler static	const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX];
541a1e1d21SSam Leffler 
558a1b9b6aSSam Leffler static	int _ieee80211_crypto_delkey(struct ieee80211com *,
568a1b9b6aSSam Leffler 		struct ieee80211_key *);
571a1e1d21SSam Leffler 
588a1b9b6aSSam Leffler /*
598a1b9b6aSSam Leffler  * Default "null" key management routines.
608a1b9b6aSSam Leffler  */
618a1b9b6aSSam Leffler static int
628a1b9b6aSSam Leffler null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k)
631a1e1d21SSam Leffler {
645c8a7b1bSSam Leffler 	if (!(&ic->ic_nw_keys[0] <= k &&
655c8a7b1bSSam Leffler 	     k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
665c8a7b1bSSam Leffler 		/*
675c8a7b1bSSam Leffler 		 * Not in the global key table, the driver should handle this
685c8a7b1bSSam Leffler 		 * by allocating a slot in the h/w key table/cache.  In
695c8a7b1bSSam Leffler 		 * lieu of that return key slot 0 for any unicast key
705c8a7b1bSSam Leffler 		 * request.  We disallow the request if this is a group key.
715c8a7b1bSSam Leffler 		 * This default policy does the right thing for legacy hardware
725c8a7b1bSSam Leffler 		 * with a 4 key table.  It also handles devices that pass
735c8a7b1bSSam Leffler 		 * packets through untouched when marked with the WEP bit
745c8a7b1bSSam Leffler 		 * and key index 0.
755c8a7b1bSSam Leffler 		 */
765c8a7b1bSSam Leffler 		if ((k->wk_flags & IEEE80211_KEY_GROUP) == 0)
775c8a7b1bSSam Leffler 			return 0;	/* NB: use key index 0 for ucast key */
785c8a7b1bSSam Leffler 		else
798a1b9b6aSSam Leffler 			return IEEE80211_KEYIX_NONE;
808a1b9b6aSSam Leffler 	}
815c8a7b1bSSam Leffler 	return k - ic->ic_nw_keys;
825c8a7b1bSSam Leffler }
838a1b9b6aSSam Leffler static int
848a1b9b6aSSam Leffler null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
858a1b9b6aSSam Leffler {
868a1b9b6aSSam Leffler 	return 1;
878a1b9b6aSSam Leffler }
888a1b9b6aSSam Leffler static 	int
898a1b9b6aSSam Leffler null_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
908a1b9b6aSSam Leffler 	     const u_int8_t mac[IEEE80211_ADDR_LEN])
918a1b9b6aSSam Leffler {
928a1b9b6aSSam Leffler 	return 1;
938a1b9b6aSSam Leffler }
948a1b9b6aSSam Leffler static void null_key_update(struct ieee80211com *ic) {}
958a1b9b6aSSam Leffler 
968a1b9b6aSSam Leffler /*
978a1b9b6aSSam Leffler  * Write-arounds for common operations.
988a1b9b6aSSam Leffler  */
998a1b9b6aSSam Leffler static __inline void
1008a1b9b6aSSam Leffler cipher_detach(struct ieee80211_key *key)
1018a1b9b6aSSam Leffler {
1028a1b9b6aSSam Leffler 	key->wk_cipher->ic_detach(key);
1038a1b9b6aSSam Leffler }
1048a1b9b6aSSam Leffler 
1058a1b9b6aSSam Leffler static __inline void *
1068a1b9b6aSSam Leffler cipher_attach(struct ieee80211com *ic, struct ieee80211_key *key)
1078a1b9b6aSSam Leffler {
1088a1b9b6aSSam Leffler 	return key->wk_cipher->ic_attach(ic, key);
1098a1b9b6aSSam Leffler }
1108a1b9b6aSSam Leffler 
1118a1b9b6aSSam Leffler /*
1128a1b9b6aSSam Leffler  * Wrappers for driver key management methods.
1138a1b9b6aSSam Leffler  */
1148a1b9b6aSSam Leffler static __inline int
1158a1b9b6aSSam Leffler dev_key_alloc(struct ieee80211com *ic,
1168a1b9b6aSSam Leffler 	const struct ieee80211_key *key)
1178a1b9b6aSSam Leffler {
1188a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_alloc(ic, key);
1198a1b9b6aSSam Leffler }
1208a1b9b6aSSam Leffler 
1218a1b9b6aSSam Leffler static __inline int
1228a1b9b6aSSam Leffler dev_key_delete(struct ieee80211com *ic,
1238a1b9b6aSSam Leffler 	const struct ieee80211_key *key)
1248a1b9b6aSSam Leffler {
1258a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_delete(ic, key);
1268a1b9b6aSSam Leffler }
1278a1b9b6aSSam Leffler 
1288a1b9b6aSSam Leffler static __inline int
1298a1b9b6aSSam Leffler dev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key,
1308a1b9b6aSSam Leffler 	const u_int8_t mac[IEEE80211_ADDR_LEN])
1318a1b9b6aSSam Leffler {
1328a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_set(ic, key, mac);
1338a1b9b6aSSam Leffler }
1341a1e1d21SSam Leffler 
1351a1e1d21SSam Leffler /*
1361a1e1d21SSam Leffler  * Setup crypto support.
1371a1e1d21SSam Leffler  */
1381a1e1d21SSam Leffler void
1398a1b9b6aSSam Leffler ieee80211_crypto_attach(struct ieee80211com *ic)
1401a1e1d21SSam Leffler {
1418a1b9b6aSSam Leffler 	struct ieee80211_crypto_state *cs = &ic->ic_crypto;
1428a1b9b6aSSam Leffler 	int i;
1431a1e1d21SSam Leffler 
1448a1b9b6aSSam Leffler 	/* NB: we assume everything is pre-zero'd */
1458a1b9b6aSSam Leffler 	cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
1468a1b9b6aSSam Leffler 	ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
1478a1b9b6aSSam Leffler 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
148dd70e17bSSam Leffler 		ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i],
149dd70e17bSSam Leffler 			IEEE80211_KEYIX_NONE);
1501a1e1d21SSam Leffler 	/*
1518a1b9b6aSSam Leffler 	 * Initialize the driver key support routines to noop entries.
1528a1b9b6aSSam Leffler 	 * This is useful especially for the cipher test modules.
1531a1e1d21SSam Leffler 	 */
1548a1b9b6aSSam Leffler 	cs->cs_key_alloc = null_key_alloc;
1558a1b9b6aSSam Leffler 	cs->cs_key_set = null_key_set;
1568a1b9b6aSSam Leffler 	cs->cs_key_delete = null_key_delete;
1578a1b9b6aSSam Leffler 	cs->cs_key_update_begin = null_key_update;
1588a1b9b6aSSam Leffler 	cs->cs_key_update_end = null_key_update;
1591a1e1d21SSam Leffler }
1601a1e1d21SSam Leffler 
1618a1b9b6aSSam Leffler /*
1628a1b9b6aSSam Leffler  * Teardown crypto support.
1638a1b9b6aSSam Leffler  */
1648a1b9b6aSSam Leffler void
1658a1b9b6aSSam Leffler ieee80211_crypto_detach(struct ieee80211com *ic)
1668a1b9b6aSSam Leffler {
1678a1b9b6aSSam Leffler 	ieee80211_crypto_delglobalkeys(ic);
1681a1e1d21SSam Leffler }
1691a1e1d21SSam Leffler 
1708a1b9b6aSSam Leffler /*
1718a1b9b6aSSam Leffler  * Register a crypto cipher module.
1728a1b9b6aSSam Leffler  */
1738a1b9b6aSSam Leffler void
1748a1b9b6aSSam Leffler ieee80211_crypto_register(const struct ieee80211_cipher *cip)
1758a1b9b6aSSam Leffler {
1768a1b9b6aSSam Leffler 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
1778a1b9b6aSSam Leffler 		printf("%s: cipher %s has an invalid cipher index %u\n",
1788a1b9b6aSSam Leffler 			__func__, cip->ic_name, cip->ic_cipher);
1798a1b9b6aSSam Leffler 		return;
1808a1b9b6aSSam Leffler 	}
1818a1b9b6aSSam Leffler 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
1828a1b9b6aSSam Leffler 		printf("%s: cipher %s registered with a different template\n",
1838a1b9b6aSSam Leffler 			__func__, cip->ic_name);
1848a1b9b6aSSam Leffler 		return;
1858a1b9b6aSSam Leffler 	}
1868a1b9b6aSSam Leffler 	ciphers[cip->ic_cipher] = cip;
1878a1b9b6aSSam Leffler }
1888a1b9b6aSSam Leffler 
1898a1b9b6aSSam Leffler /*
1908a1b9b6aSSam Leffler  * Unregister a crypto cipher module.
1918a1b9b6aSSam Leffler  */
1928a1b9b6aSSam Leffler void
1938a1b9b6aSSam Leffler ieee80211_crypto_unregister(const struct ieee80211_cipher *cip)
1948a1b9b6aSSam Leffler {
1958a1b9b6aSSam Leffler 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
1968a1b9b6aSSam Leffler 		printf("%s: cipher %s has an invalid cipher index %u\n",
1978a1b9b6aSSam Leffler 			__func__, cip->ic_name, cip->ic_cipher);
1988a1b9b6aSSam Leffler 		return;
1998a1b9b6aSSam Leffler 	}
2008a1b9b6aSSam Leffler 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
2018a1b9b6aSSam Leffler 		printf("%s: cipher %s registered with a different template\n",
2028a1b9b6aSSam Leffler 			__func__, cip->ic_name);
2038a1b9b6aSSam Leffler 		return;
2048a1b9b6aSSam Leffler 	}
2058a1b9b6aSSam Leffler 	/* NB: don't complain about not being registered */
2068a1b9b6aSSam Leffler 	/* XXX disallow if references */
2078a1b9b6aSSam Leffler 	ciphers[cip->ic_cipher] = NULL;
2088a1b9b6aSSam Leffler }
2098a1b9b6aSSam Leffler 
2108a1b9b6aSSam Leffler int
2118a1b9b6aSSam Leffler ieee80211_crypto_available(u_int cipher)
2128a1b9b6aSSam Leffler {
2138a1b9b6aSSam Leffler 	return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL;
2148a1b9b6aSSam Leffler }
2158a1b9b6aSSam Leffler 
2168a1b9b6aSSam Leffler /* XXX well-known names! */
2178a1b9b6aSSam Leffler static const char *cipher_modnames[] = {
2188a1b9b6aSSam Leffler 	"wlan_wep",	/* IEEE80211_CIPHER_WEP */
2198a1b9b6aSSam Leffler 	"wlan_tkip",	/* IEEE80211_CIPHER_TKIP */
2208a1b9b6aSSam Leffler 	"wlan_aes_ocb",	/* IEEE80211_CIPHER_AES_OCB */
2218a1b9b6aSSam Leffler 	"wlan_ccmp",	/* IEEE80211_CIPHER_AES_CCM */
2228a1b9b6aSSam Leffler 	"wlan_ckip",	/* IEEE80211_CIPHER_CKIP */
2238a1b9b6aSSam Leffler };
2248a1b9b6aSSam Leffler 
2258a1b9b6aSSam Leffler /*
2268a1b9b6aSSam Leffler  * Establish a relationship between the specified key and cipher
227dd70e17bSSam Leffler  * and, if necessary, allocate a hardware index from the driver.
228dd70e17bSSam Leffler  * Note that when a fixed key index is required it must be specified
229dd70e17bSSam Leffler  * and we blindly assign it w/o consulting the driver (XXX).
2308a1b9b6aSSam Leffler  *
2318a1b9b6aSSam Leffler  * This must be the first call applied to a key; all the other key
2328a1b9b6aSSam Leffler  * routines assume wk_cipher is setup.
2338a1b9b6aSSam Leffler  *
2348a1b9b6aSSam Leffler  * Locking must be handled by the caller using:
2358a1b9b6aSSam Leffler  *	ieee80211_key_update_begin(ic);
2368a1b9b6aSSam Leffler  *	ieee80211_key_update_end(ic);
2378a1b9b6aSSam Leffler  */
2388a1b9b6aSSam Leffler int
2398a1b9b6aSSam Leffler ieee80211_crypto_newkey(struct ieee80211com *ic,
240dd70e17bSSam Leffler 	int cipher, int flags, struct ieee80211_key *key)
2418a1b9b6aSSam Leffler {
2428a1b9b6aSSam Leffler #define	N(a)	(sizeof(a) / sizeof(a[0]))
2438a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
2448a1b9b6aSSam Leffler 	void *keyctx;
2458a1b9b6aSSam Leffler 	int oflags;
2468a1b9b6aSSam Leffler 
2478a1b9b6aSSam Leffler 	/*
2488a1b9b6aSSam Leffler 	 * Validate cipher and set reference to cipher routines.
2498a1b9b6aSSam Leffler 	 */
2508a1b9b6aSSam Leffler 	if (cipher >= IEEE80211_CIPHER_MAX) {
2518a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2528a1b9b6aSSam Leffler 			"%s: invalid cipher %u\n", __func__, cipher);
2538a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_badcipher++;
2548a1b9b6aSSam Leffler 		return 0;
2558a1b9b6aSSam Leffler 	}
2568a1b9b6aSSam Leffler 	cip = ciphers[cipher];
2578a1b9b6aSSam Leffler 	if (cip == NULL) {
2588a1b9b6aSSam Leffler 		/*
2598a1b9b6aSSam Leffler 		 * Auto-load cipher module if we have a well-known name
2608a1b9b6aSSam Leffler 		 * for it.  It might be better to use string names rather
2618a1b9b6aSSam Leffler 		 * than numbers and craft a module name based on the cipher
2628a1b9b6aSSam Leffler 		 * name; e.g. wlan_cipher_<cipher-name>.
2638a1b9b6aSSam Leffler 		 */
2648a1b9b6aSSam Leffler 		if (cipher < N(cipher_modnames)) {
2658a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2668a1b9b6aSSam Leffler 				"%s: unregistered cipher %u, load module %s\n",
2678a1b9b6aSSam Leffler 				__func__, cipher, cipher_modnames[cipher]);
2688a1b9b6aSSam Leffler 			ieee80211_load_module(cipher_modnames[cipher]);
2698a1b9b6aSSam Leffler 			/*
2708a1b9b6aSSam Leffler 			 * If cipher module loaded it should immediately
2718a1b9b6aSSam Leffler 			 * call ieee80211_crypto_register which will fill
2728a1b9b6aSSam Leffler 			 * in the entry in the ciphers array.
2738a1b9b6aSSam Leffler 			 */
2748a1b9b6aSSam Leffler 			cip = ciphers[cipher];
2758a1b9b6aSSam Leffler 		}
2768a1b9b6aSSam Leffler 		if (cip == NULL) {
2778a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2788a1b9b6aSSam Leffler 				"%s: unable to load cipher %u, module %s\n",
2798a1b9b6aSSam Leffler 				__func__, cipher,
2808a1b9b6aSSam Leffler 				cipher < N(cipher_modnames) ?
2818a1b9b6aSSam Leffler 					cipher_modnames[cipher] : "<unknown>");
2828a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_nocipher++;
2838a1b9b6aSSam Leffler 			return 0;
2848a1b9b6aSSam Leffler 		}
2858a1b9b6aSSam Leffler 	}
2868a1b9b6aSSam Leffler 
2878a1b9b6aSSam Leffler 	oflags = key->wk_flags;
288dd70e17bSSam Leffler 	flags &= IEEE80211_KEY_COMMON;
2898a1b9b6aSSam Leffler 	/*
2908a1b9b6aSSam Leffler 	 * If the hardware does not support the cipher then
2918a1b9b6aSSam Leffler 	 * fallback to a host-based implementation.
2928a1b9b6aSSam Leffler 	 */
2938a1b9b6aSSam Leffler 	if ((ic->ic_caps & (1<<cipher)) == 0) {
2948a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2958a1b9b6aSSam Leffler 		    "%s: no h/w support for cipher %s, falling back to s/w\n",
2968a1b9b6aSSam Leffler 		    __func__, cip->ic_name);
297dd70e17bSSam Leffler 		flags |= IEEE80211_KEY_SWCRYPT;
2988a1b9b6aSSam Leffler 	}
2998a1b9b6aSSam Leffler 	/*
3008a1b9b6aSSam Leffler 	 * Hardware TKIP with software MIC is an important
3018a1b9b6aSSam Leffler 	 * combination; we handle it by flagging each key,
3028a1b9b6aSSam Leffler 	 * the cipher modules honor it.
3038a1b9b6aSSam Leffler 	 */
3048a1b9b6aSSam Leffler 	if (cipher == IEEE80211_CIPHER_TKIP &&
3058a1b9b6aSSam Leffler 	    (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) {
3068a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3078a1b9b6aSSam Leffler 		    "%s: no h/w support for TKIP MIC, falling back to s/w\n",
3088a1b9b6aSSam Leffler 		    __func__);
309dd70e17bSSam Leffler 		flags |= IEEE80211_KEY_SWMIC;
3108a1b9b6aSSam Leffler 	}
3118a1b9b6aSSam Leffler 
3128a1b9b6aSSam Leffler 	/*
3138a1b9b6aSSam Leffler 	 * Bind cipher to key instance.  Note we do this
3148a1b9b6aSSam Leffler 	 * after checking the device capabilities so the
3158a1b9b6aSSam Leffler 	 * cipher module can optimize space usage based on
3168a1b9b6aSSam Leffler 	 * whether or not it needs to do the cipher work.
3178a1b9b6aSSam Leffler 	 */
318dd70e17bSSam Leffler 	if (key->wk_cipher != cip || key->wk_flags != flags) {
3198a1b9b6aSSam Leffler again:
320dd70e17bSSam Leffler 		/*
321dd70e17bSSam Leffler 		 * Fillin the flags so cipher modules can see s/w
322dd70e17bSSam Leffler 		 * crypto requirements and potentially allocate
323dd70e17bSSam Leffler 		 * different state and/or attach different method
324dd70e17bSSam Leffler 		 * pointers.
325dd70e17bSSam Leffler 		 *
326dd70e17bSSam Leffler 		 * XXX this is not right when s/w crypto fallback
327dd70e17bSSam Leffler 		 *     fails and we try to restore previous state.
328dd70e17bSSam Leffler 		 */
329dd70e17bSSam Leffler 		key->wk_flags = flags;
3308a1b9b6aSSam Leffler 		keyctx = cip->ic_attach(ic, key);
3318a1b9b6aSSam Leffler 		if (keyctx == NULL) {
3328a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3338a1b9b6aSSam Leffler 				"%s: unable to attach cipher %s\n",
3348a1b9b6aSSam Leffler 				__func__, cip->ic_name);
3358a1b9b6aSSam Leffler 			key->wk_flags = oflags;	/* restore old flags */
3368a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_attachfail++;
3378a1b9b6aSSam Leffler 			return 0;
3388a1b9b6aSSam Leffler 		}
3398a1b9b6aSSam Leffler 		cipher_detach(key);
3408a1b9b6aSSam Leffler 		key->wk_cipher = cip;		/* XXX refcnt? */
3418a1b9b6aSSam Leffler 		key->wk_private = keyctx;
3428a1b9b6aSSam Leffler 	}
343dd70e17bSSam Leffler 	/*
344dd70e17bSSam Leffler 	 * Commit to requested usage so driver can see the flags.
345dd70e17bSSam Leffler 	 */
346dd70e17bSSam Leffler 	key->wk_flags = flags;
3478a1b9b6aSSam Leffler 
3488a1b9b6aSSam Leffler 	/*
3498a1b9b6aSSam Leffler 	 * Ask the driver for a key index if we don't have one.
3508a1b9b6aSSam Leffler 	 * Note that entries in the global key table always have
3518a1b9b6aSSam Leffler 	 * an index; this means it's safe to call this routine
3528a1b9b6aSSam Leffler 	 * for these entries just to setup the reference to the
3538a1b9b6aSSam Leffler 	 * cipher template.  Note also that when using software
3548a1b9b6aSSam Leffler 	 * crypto we also call the driver to give us a key index.
3558a1b9b6aSSam Leffler 	 */
3568a1b9b6aSSam Leffler 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
3578a1b9b6aSSam Leffler 		key->wk_keyix = dev_key_alloc(ic, key);
3588a1b9b6aSSam Leffler 		if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
3598a1b9b6aSSam Leffler 			/*
3608a1b9b6aSSam Leffler 			 * Driver has no room; fallback to doing crypto
3618a1b9b6aSSam Leffler 			 * in the host.  We change the flags and start the
3628a1b9b6aSSam Leffler 			 * procedure over.  If we get back here then there's
3638a1b9b6aSSam Leffler 			 * no hope and we bail.  Note that this can leave
3648a1b9b6aSSam Leffler 			 * the key in a inconsistent state if the caller
3658a1b9b6aSSam Leffler 			 * continues to use it.
3668a1b9b6aSSam Leffler 			 */
3678a1b9b6aSSam Leffler 			if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
3688a1b9b6aSSam Leffler 				ic->ic_stats.is_crypto_swfallback++;
3698a1b9b6aSSam Leffler 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3708a1b9b6aSSam Leffler 				    "%s: no h/w resources for cipher %s, "
3718a1b9b6aSSam Leffler 				    "falling back to s/w\n", __func__,
3728a1b9b6aSSam Leffler 				    cip->ic_name);
3738a1b9b6aSSam Leffler 				oflags = key->wk_flags;
374dd70e17bSSam Leffler 				flags |= IEEE80211_KEY_SWCRYPT;
3758a1b9b6aSSam Leffler 				if (cipher == IEEE80211_CIPHER_TKIP)
376dd70e17bSSam Leffler 					flags |= IEEE80211_KEY_SWMIC;
3778a1b9b6aSSam Leffler 				goto again;
3788a1b9b6aSSam Leffler 			}
3798a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_keyfail++;
3808a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3818a1b9b6aSSam Leffler 			    "%s: unable to setup cipher %s\n",
3828a1b9b6aSSam Leffler 			    __func__, cip->ic_name);
3838a1b9b6aSSam Leffler 			return 0;
3848a1b9b6aSSam Leffler 		}
3858a1b9b6aSSam Leffler 	}
3868a1b9b6aSSam Leffler 	return 1;
3878a1b9b6aSSam Leffler #undef N
3888a1b9b6aSSam Leffler }
3898a1b9b6aSSam Leffler 
3908a1b9b6aSSam Leffler /*
3918a1b9b6aSSam Leffler  * Remove the key (no locking, for internal use).
3928a1b9b6aSSam Leffler  */
3938a1b9b6aSSam Leffler static int
3948a1b9b6aSSam Leffler _ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
3958a1b9b6aSSam Leffler {
3968a1b9b6aSSam Leffler 	u_int16_t keyix;
3978a1b9b6aSSam Leffler 
3988a1b9b6aSSam Leffler 	KASSERT(key->wk_cipher != NULL, ("No cipher!"));
3998a1b9b6aSSam Leffler 
400fc508e8eSSam Leffler 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
401fc508e8eSSam Leffler 	    "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n",
402fc508e8eSSam Leffler 	    __func__, key->wk_cipher->ic_name,
403fc508e8eSSam Leffler 	    key->wk_keyix, key->wk_flags,
404fc508e8eSSam Leffler 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
405fc508e8eSSam Leffler 
4068a1b9b6aSSam Leffler 	keyix = key->wk_keyix;
4078a1b9b6aSSam Leffler 	if (keyix != IEEE80211_KEYIX_NONE) {
4088a1b9b6aSSam Leffler 		/*
4098a1b9b6aSSam Leffler 		 * Remove hardware entry.
4108a1b9b6aSSam Leffler 		 */
4118a1b9b6aSSam Leffler 		/* XXX key cache */
4128a1b9b6aSSam Leffler 		if (!dev_key_delete(ic, key)) {
4138a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
4148a1b9b6aSSam Leffler 			    "%s: driver did not delete key index %u\n",
4158a1b9b6aSSam Leffler 			    __func__, keyix);
4168a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_delkey++;
4178a1b9b6aSSam Leffler 			/* XXX recovery? */
4188a1b9b6aSSam Leffler 		}
4198a1b9b6aSSam Leffler 	}
4208a1b9b6aSSam Leffler 	cipher_detach(key);
4218a1b9b6aSSam Leffler 	memset(key, 0, sizeof(*key));
422dd70e17bSSam Leffler 	ieee80211_crypto_resetkey(ic, key, IEEE80211_KEYIX_NONE);
4238a1b9b6aSSam Leffler 	return 1;
4248a1b9b6aSSam Leffler }
4258a1b9b6aSSam Leffler 
4268a1b9b6aSSam Leffler /*
4278a1b9b6aSSam Leffler  * Remove the specified key.
4288a1b9b6aSSam Leffler  */
4298a1b9b6aSSam Leffler int
4308a1b9b6aSSam Leffler ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
4318a1b9b6aSSam Leffler {
4328a1b9b6aSSam Leffler 	int status;
4338a1b9b6aSSam Leffler 
4348a1b9b6aSSam Leffler 	ieee80211_key_update_begin(ic);
4358a1b9b6aSSam Leffler 	status = _ieee80211_crypto_delkey(ic, key);
4368a1b9b6aSSam Leffler 	ieee80211_key_update_end(ic);
4378a1b9b6aSSam Leffler 	return status;
4388a1b9b6aSSam Leffler }
4398a1b9b6aSSam Leffler 
4408a1b9b6aSSam Leffler /*
4418a1b9b6aSSam Leffler  * Clear the global key table.
4428a1b9b6aSSam Leffler  */
4438a1b9b6aSSam Leffler void
4448a1b9b6aSSam Leffler ieee80211_crypto_delglobalkeys(struct ieee80211com *ic)
4458a1b9b6aSSam Leffler {
4468a1b9b6aSSam Leffler 	int i;
4478a1b9b6aSSam Leffler 
4488a1b9b6aSSam Leffler 	ieee80211_key_update_begin(ic);
4498a1b9b6aSSam Leffler 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
4508a1b9b6aSSam Leffler 		(void) _ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]);
4518a1b9b6aSSam Leffler 	ieee80211_key_update_end(ic);
4528a1b9b6aSSam Leffler }
4538a1b9b6aSSam Leffler 
4548a1b9b6aSSam Leffler /*
4558a1b9b6aSSam Leffler  * Set the contents of the specified key.
4568a1b9b6aSSam Leffler  *
4578a1b9b6aSSam Leffler  * Locking must be handled by the caller using:
4588a1b9b6aSSam Leffler  *	ieee80211_key_update_begin(ic);
4598a1b9b6aSSam Leffler  *	ieee80211_key_update_end(ic);
4608a1b9b6aSSam Leffler  */
4618a1b9b6aSSam Leffler int
4628a1b9b6aSSam Leffler ieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key,
4638a1b9b6aSSam Leffler 		const u_int8_t macaddr[IEEE80211_ADDR_LEN])
4648a1b9b6aSSam Leffler {
4658a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip = key->wk_cipher;
4668a1b9b6aSSam Leffler 
4678a1b9b6aSSam Leffler 	KASSERT(cip != NULL, ("No cipher!"));
4688a1b9b6aSSam Leffler 
469fc508e8eSSam Leffler 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
470fc508e8eSSam Leffler 	    "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n",
471fc508e8eSSam Leffler 	    __func__, cip->ic_name, key->wk_keyix,
472fc508e8eSSam Leffler 	    key->wk_flags, ether_sprintf(macaddr),
473fc508e8eSSam Leffler 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
474fc508e8eSSam Leffler 
4758a1b9b6aSSam Leffler 	/*
4768a1b9b6aSSam Leffler 	 * Give cipher a chance to validate key contents.
4778a1b9b6aSSam Leffler 	 * XXX should happen before modifying state.
4788a1b9b6aSSam Leffler 	 */
4798a1b9b6aSSam Leffler 	if (!cip->ic_setkey(key)) {
4808a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
4818a1b9b6aSSam Leffler 		    "%s: cipher %s rejected key index %u len %u flags 0x%x\n",
4828a1b9b6aSSam Leffler 		    __func__, cip->ic_name, key->wk_keyix,
4838a1b9b6aSSam Leffler 		    key->wk_keylen, key->wk_flags);
4848a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_setkey_cipher++;
4858a1b9b6aSSam Leffler 		return 0;
4868a1b9b6aSSam Leffler 	}
4878a1b9b6aSSam Leffler 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
4888a1b9b6aSSam Leffler 		/* XXX nothing allocated, should not happen */
4898a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
4908a1b9b6aSSam Leffler 		    "%s: no key index; should not happen!\n", __func__);
4918a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_setkey_nokey++;
4928a1b9b6aSSam Leffler 		return 0;
4938a1b9b6aSSam Leffler 	}
4948a1b9b6aSSam Leffler 	return dev_key_set(ic, key, macaddr);
4958a1b9b6aSSam Leffler }
4968a1b9b6aSSam Leffler 
4978a1b9b6aSSam Leffler /*
4988a1b9b6aSSam Leffler  * Add privacy headers appropriate for the specified key.
4998a1b9b6aSSam Leffler  */
5008a1b9b6aSSam Leffler struct ieee80211_key *
5018a1b9b6aSSam Leffler ieee80211_crypto_encap(struct ieee80211com *ic,
5028a1b9b6aSSam Leffler 	struct ieee80211_node *ni, struct mbuf *m)
5038a1b9b6aSSam Leffler {
5048a1b9b6aSSam Leffler 	struct ieee80211_key *k;
5058a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
5068a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
507dd70e17bSSam Leffler 	u_int8_t keyid;
5088a1b9b6aSSam Leffler 
5098a1b9b6aSSam Leffler 	/*
5108a1b9b6aSSam Leffler 	 * Multicast traffic always uses the multicast key.
5118a1b9b6aSSam Leffler 	 * Otherwise if a unicast key is set we use that and
5128a1b9b6aSSam Leffler 	 * it is always key index 0.  When no unicast key is
5138a1b9b6aSSam Leffler 	 * set we fall back to the default transmit key.
5148a1b9b6aSSam Leffler 	 */
5158a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
5168a1b9b6aSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
5178a1b9b6aSSam Leffler 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
5188a1b9b6aSSam Leffler 		if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) {
5198a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
520fc508e8eSSam Leffler 			    "[%s] no default transmit key (%s) deftxkey %u\n",
521fc508e8eSSam Leffler 			    ether_sprintf(wh->i_addr1), __func__,
522fc508e8eSSam Leffler 			    ic->ic_def_txkey);
5238a1b9b6aSSam Leffler 			ic->ic_stats.is_tx_nodefkey++;
5248a1b9b6aSSam Leffler 			return NULL;
5258a1b9b6aSSam Leffler 		}
526dd70e17bSSam Leffler 		keyid = ic->ic_def_txkey;
5278a1b9b6aSSam Leffler 		k = &ic->ic_nw_keys[ic->ic_def_txkey];
5288a1b9b6aSSam Leffler 	} else {
529dd70e17bSSam Leffler 		keyid = 0;
5308a1b9b6aSSam Leffler 		k = &ni->ni_ucastkey;
5318a1b9b6aSSam Leffler 	}
5328a1b9b6aSSam Leffler 	cip = k->wk_cipher;
533dd70e17bSSam Leffler 	return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
5348a1b9b6aSSam Leffler }
5358a1b9b6aSSam Leffler 
5368a1b9b6aSSam Leffler /*
5378a1b9b6aSSam Leffler  * Validate and strip privacy headers (and trailer) for a
5388a1b9b6aSSam Leffler  * received frame that has the WEP/Privacy bit set.
5398a1b9b6aSSam Leffler  */
5408a1b9b6aSSam Leffler struct ieee80211_key *
5418a1b9b6aSSam Leffler ieee80211_crypto_decap(struct ieee80211com *ic,
5422cc12adeSSam Leffler 	struct ieee80211_node *ni, struct mbuf *m, int hdrlen)
5438a1b9b6aSSam Leffler {
5448a1b9b6aSSam Leffler #define	IEEE80211_WEP_HDRLEN	(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
5458a1b9b6aSSam Leffler #define	IEEE80211_WEP_MINLEN \
5468a1b9b6aSSam Leffler 	(sizeof(struct ieee80211_frame) + ETHER_HDR_LEN + \
5478a1b9b6aSSam Leffler 	IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
5488a1b9b6aSSam Leffler 	struct ieee80211_key *k;
5498a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
5508a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
5517432b7ccSSam Leffler 	const u_int8_t *ivp;
5528a1b9b6aSSam Leffler 	u_int8_t keyid;
5538a1b9b6aSSam Leffler 
5548a1b9b6aSSam Leffler 	/* NB: this minimum size data frame could be bigger */
5558a1b9b6aSSam Leffler 	if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
5568a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
5578a1b9b6aSSam Leffler 			"%s: WEP data frame too short, len %u\n",
5588a1b9b6aSSam Leffler 			__func__, m->m_pkthdr.len);
5598a1b9b6aSSam Leffler 		ic->ic_stats.is_rx_tooshort++;	/* XXX need unique stat? */
5601a1e1d21SSam Leffler 		return NULL;
5611a1e1d21SSam Leffler 	}
5621a1e1d21SSam Leffler 
5631a1e1d21SSam Leffler 	/*
5648a1b9b6aSSam Leffler 	 * Locate the key. If unicast and there is no unicast
5658a1b9b6aSSam Leffler 	 * key then we fall back to the key id in the header.
5668a1b9b6aSSam Leffler 	 * This assumes unicast keys are only configured when
5678a1b9b6aSSam Leffler 	 * the key id in the header is meaningless (typically 0).
5681a1e1d21SSam Leffler 	 */
5698a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
5707432b7ccSSam Leffler 	ivp = mtod(m, const u_int8_t *) + hdrlen;	/* XXX contig */
5718a1b9b6aSSam Leffler 	keyid = ivp[IEEE80211_WEP_IVLEN];
5728a1b9b6aSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
5738a1b9b6aSSam Leffler 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none)
5748a1b9b6aSSam Leffler 		k = &ic->ic_nw_keys[keyid >> 6];
5751a1e1d21SSam Leffler 	else
5768a1b9b6aSSam Leffler 		k = &ni->ni_ucastkey;
5771a1e1d21SSam Leffler 
5781a1e1d21SSam Leffler 	/*
5798a1b9b6aSSam Leffler 	 * Insure crypto header is contiguous for all decap work.
5801a1e1d21SSam Leffler 	 */
5818a1b9b6aSSam Leffler 	cip = k->wk_cipher;
5828a1b9b6aSSam Leffler 	if (m->m_len < hdrlen + cip->ic_header &&
5838a1b9b6aSSam Leffler 	    (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) {
5848a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
5858a1b9b6aSSam Leffler 		    "[%s] unable to pullup %s header\n",
5868a1b9b6aSSam Leffler 		    ether_sprintf(wh->i_addr2), cip->ic_name);
5878a1b9b6aSSam Leffler 		ic->ic_stats.is_rx_wepfail++;	/* XXX */
5888a1b9b6aSSam Leffler 		return 0;
5898a1b9b6aSSam Leffler 	}
5901a1e1d21SSam Leffler 
5912cc12adeSSam Leffler 	return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
5928a1b9b6aSSam Leffler #undef IEEE80211_WEP_MINLEN
5938a1b9b6aSSam Leffler #undef IEEE80211_WEP_HDRLEN
5941a1e1d21SSam Leffler }
595