xref: /freebsd/sys/net80211/ieee80211_crypto.c (revision 2cc12aded0081e7d6006ad1c5b74945338529081)
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 {
648a1b9b6aSSam Leffler 	return IEEE80211_KEYIX_NONE;
658a1b9b6aSSam Leffler }
668a1b9b6aSSam Leffler static int
678a1b9b6aSSam Leffler null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
688a1b9b6aSSam Leffler {
698a1b9b6aSSam Leffler 	return 1;
708a1b9b6aSSam Leffler }
718a1b9b6aSSam Leffler static 	int
728a1b9b6aSSam Leffler null_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
738a1b9b6aSSam Leffler 	     const u_int8_t mac[IEEE80211_ADDR_LEN])
748a1b9b6aSSam Leffler {
758a1b9b6aSSam Leffler 	return 1;
768a1b9b6aSSam Leffler }
778a1b9b6aSSam Leffler static void null_key_update(struct ieee80211com *ic) {}
788a1b9b6aSSam Leffler 
798a1b9b6aSSam Leffler /*
808a1b9b6aSSam Leffler  * Write-arounds for common operations.
818a1b9b6aSSam Leffler  */
828a1b9b6aSSam Leffler static __inline void
838a1b9b6aSSam Leffler cipher_detach(struct ieee80211_key *key)
848a1b9b6aSSam Leffler {
858a1b9b6aSSam Leffler 	key->wk_cipher->ic_detach(key);
868a1b9b6aSSam Leffler }
878a1b9b6aSSam Leffler 
888a1b9b6aSSam Leffler static __inline void *
898a1b9b6aSSam Leffler cipher_attach(struct ieee80211com *ic, struct ieee80211_key *key)
908a1b9b6aSSam Leffler {
918a1b9b6aSSam Leffler 	return key->wk_cipher->ic_attach(ic, key);
928a1b9b6aSSam Leffler }
938a1b9b6aSSam Leffler 
948a1b9b6aSSam Leffler /*
958a1b9b6aSSam Leffler  * Wrappers for driver key management methods.
968a1b9b6aSSam Leffler  */
978a1b9b6aSSam Leffler static __inline int
988a1b9b6aSSam Leffler dev_key_alloc(struct ieee80211com *ic,
998a1b9b6aSSam Leffler 	const struct ieee80211_key *key)
1008a1b9b6aSSam Leffler {
1018a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_alloc(ic, key);
1028a1b9b6aSSam Leffler }
1038a1b9b6aSSam Leffler 
1048a1b9b6aSSam Leffler static __inline int
1058a1b9b6aSSam Leffler dev_key_delete(struct ieee80211com *ic,
1068a1b9b6aSSam Leffler 	const struct ieee80211_key *key)
1078a1b9b6aSSam Leffler {
1088a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_delete(ic, key);
1098a1b9b6aSSam Leffler }
1108a1b9b6aSSam Leffler 
1118a1b9b6aSSam Leffler static __inline int
1128a1b9b6aSSam Leffler dev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key,
1138a1b9b6aSSam Leffler 	const u_int8_t mac[IEEE80211_ADDR_LEN])
1148a1b9b6aSSam Leffler {
1158a1b9b6aSSam Leffler 	return ic->ic_crypto.cs_key_set(ic, key, mac);
1168a1b9b6aSSam Leffler }
1171a1e1d21SSam Leffler 
1181a1e1d21SSam Leffler /*
1191a1e1d21SSam Leffler  * Setup crypto support.
1201a1e1d21SSam Leffler  */
1211a1e1d21SSam Leffler void
1228a1b9b6aSSam Leffler ieee80211_crypto_attach(struct ieee80211com *ic)
1231a1e1d21SSam Leffler {
1248a1b9b6aSSam Leffler 	struct ieee80211_crypto_state *cs = &ic->ic_crypto;
1258a1b9b6aSSam Leffler 	int i;
1261a1e1d21SSam Leffler 
1278a1b9b6aSSam Leffler 	/* NB: we assume everything is pre-zero'd */
1288a1b9b6aSSam Leffler 	cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
1298a1b9b6aSSam Leffler 	ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
1308a1b9b6aSSam Leffler 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
131dd70e17bSSam Leffler 		ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i],
132dd70e17bSSam Leffler 			IEEE80211_KEYIX_NONE);
1331a1e1d21SSam Leffler 	/*
1348a1b9b6aSSam Leffler 	 * Initialize the driver key support routines to noop entries.
1358a1b9b6aSSam Leffler 	 * This is useful especially for the cipher test modules.
1361a1e1d21SSam Leffler 	 */
1378a1b9b6aSSam Leffler 	cs->cs_key_alloc = null_key_alloc;
1388a1b9b6aSSam Leffler 	cs->cs_key_set = null_key_set;
1398a1b9b6aSSam Leffler 	cs->cs_key_delete = null_key_delete;
1408a1b9b6aSSam Leffler 	cs->cs_key_update_begin = null_key_update;
1418a1b9b6aSSam Leffler 	cs->cs_key_update_end = null_key_update;
1421a1e1d21SSam Leffler }
1431a1e1d21SSam Leffler 
1448a1b9b6aSSam Leffler /*
1458a1b9b6aSSam Leffler  * Teardown crypto support.
1468a1b9b6aSSam Leffler  */
1478a1b9b6aSSam Leffler void
1488a1b9b6aSSam Leffler ieee80211_crypto_detach(struct ieee80211com *ic)
1498a1b9b6aSSam Leffler {
1508a1b9b6aSSam Leffler 	ieee80211_crypto_delglobalkeys(ic);
1511a1e1d21SSam Leffler }
1521a1e1d21SSam Leffler 
1538a1b9b6aSSam Leffler /*
1548a1b9b6aSSam Leffler  * Register a crypto cipher module.
1558a1b9b6aSSam Leffler  */
1568a1b9b6aSSam Leffler void
1578a1b9b6aSSam Leffler ieee80211_crypto_register(const struct ieee80211_cipher *cip)
1588a1b9b6aSSam Leffler {
1598a1b9b6aSSam Leffler 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
1608a1b9b6aSSam Leffler 		printf("%s: cipher %s has an invalid cipher index %u\n",
1618a1b9b6aSSam Leffler 			__func__, cip->ic_name, cip->ic_cipher);
1628a1b9b6aSSam Leffler 		return;
1638a1b9b6aSSam Leffler 	}
1648a1b9b6aSSam Leffler 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
1658a1b9b6aSSam Leffler 		printf("%s: cipher %s registered with a different template\n",
1668a1b9b6aSSam Leffler 			__func__, cip->ic_name);
1678a1b9b6aSSam Leffler 		return;
1688a1b9b6aSSam Leffler 	}
1698a1b9b6aSSam Leffler 	ciphers[cip->ic_cipher] = cip;
1708a1b9b6aSSam Leffler }
1718a1b9b6aSSam Leffler 
1728a1b9b6aSSam Leffler /*
1738a1b9b6aSSam Leffler  * Unregister a crypto cipher module.
1748a1b9b6aSSam Leffler  */
1758a1b9b6aSSam Leffler void
1768a1b9b6aSSam Leffler ieee80211_crypto_unregister(const struct ieee80211_cipher *cip)
1778a1b9b6aSSam Leffler {
1788a1b9b6aSSam Leffler 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
1798a1b9b6aSSam Leffler 		printf("%s: cipher %s has an invalid cipher index %u\n",
1808a1b9b6aSSam Leffler 			__func__, cip->ic_name, cip->ic_cipher);
1818a1b9b6aSSam Leffler 		return;
1828a1b9b6aSSam Leffler 	}
1838a1b9b6aSSam Leffler 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
1848a1b9b6aSSam Leffler 		printf("%s: cipher %s registered with a different template\n",
1858a1b9b6aSSam Leffler 			__func__, cip->ic_name);
1868a1b9b6aSSam Leffler 		return;
1878a1b9b6aSSam Leffler 	}
1888a1b9b6aSSam Leffler 	/* NB: don't complain about not being registered */
1898a1b9b6aSSam Leffler 	/* XXX disallow if references */
1908a1b9b6aSSam Leffler 	ciphers[cip->ic_cipher] = NULL;
1918a1b9b6aSSam Leffler }
1928a1b9b6aSSam Leffler 
1938a1b9b6aSSam Leffler int
1948a1b9b6aSSam Leffler ieee80211_crypto_available(u_int cipher)
1958a1b9b6aSSam Leffler {
1968a1b9b6aSSam Leffler 	return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL;
1978a1b9b6aSSam Leffler }
1988a1b9b6aSSam Leffler 
1998a1b9b6aSSam Leffler /* XXX well-known names! */
2008a1b9b6aSSam Leffler static const char *cipher_modnames[] = {
2018a1b9b6aSSam Leffler 	"wlan_wep",	/* IEEE80211_CIPHER_WEP */
2028a1b9b6aSSam Leffler 	"wlan_tkip",	/* IEEE80211_CIPHER_TKIP */
2038a1b9b6aSSam Leffler 	"wlan_aes_ocb",	/* IEEE80211_CIPHER_AES_OCB */
2048a1b9b6aSSam Leffler 	"wlan_ccmp",	/* IEEE80211_CIPHER_AES_CCM */
2058a1b9b6aSSam Leffler 	"wlan_ckip",	/* IEEE80211_CIPHER_CKIP */
2068a1b9b6aSSam Leffler };
2078a1b9b6aSSam Leffler 
2088a1b9b6aSSam Leffler /*
2098a1b9b6aSSam Leffler  * Establish a relationship between the specified key and cipher
210dd70e17bSSam Leffler  * and, if necessary, allocate a hardware index from the driver.
211dd70e17bSSam Leffler  * Note that when a fixed key index is required it must be specified
212dd70e17bSSam Leffler  * and we blindly assign it w/o consulting the driver (XXX).
2138a1b9b6aSSam Leffler  *
2148a1b9b6aSSam Leffler  * This must be the first call applied to a key; all the other key
2158a1b9b6aSSam Leffler  * routines assume wk_cipher is setup.
2168a1b9b6aSSam Leffler  *
2178a1b9b6aSSam Leffler  * Locking must be handled by the caller using:
2188a1b9b6aSSam Leffler  *	ieee80211_key_update_begin(ic);
2198a1b9b6aSSam Leffler  *	ieee80211_key_update_end(ic);
2208a1b9b6aSSam Leffler  */
2218a1b9b6aSSam Leffler int
2228a1b9b6aSSam Leffler ieee80211_crypto_newkey(struct ieee80211com *ic,
223dd70e17bSSam Leffler 	int cipher, int flags, struct ieee80211_key *key)
2248a1b9b6aSSam Leffler {
2258a1b9b6aSSam Leffler #define	N(a)	(sizeof(a) / sizeof(a[0]))
2268a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
2278a1b9b6aSSam Leffler 	void *keyctx;
2288a1b9b6aSSam Leffler 	int oflags;
2298a1b9b6aSSam Leffler 
2308a1b9b6aSSam Leffler 	/*
2318a1b9b6aSSam Leffler 	 * Validate cipher and set reference to cipher routines.
2328a1b9b6aSSam Leffler 	 */
2338a1b9b6aSSam Leffler 	if (cipher >= IEEE80211_CIPHER_MAX) {
2348a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2358a1b9b6aSSam Leffler 			"%s: invalid cipher %u\n", __func__, cipher);
2368a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_badcipher++;
2378a1b9b6aSSam Leffler 		return 0;
2388a1b9b6aSSam Leffler 	}
2398a1b9b6aSSam Leffler 	cip = ciphers[cipher];
2408a1b9b6aSSam Leffler 	if (cip == NULL) {
2418a1b9b6aSSam Leffler 		/*
2428a1b9b6aSSam Leffler 		 * Auto-load cipher module if we have a well-known name
2438a1b9b6aSSam Leffler 		 * for it.  It might be better to use string names rather
2448a1b9b6aSSam Leffler 		 * than numbers and craft a module name based on the cipher
2458a1b9b6aSSam Leffler 		 * name; e.g. wlan_cipher_<cipher-name>.
2468a1b9b6aSSam Leffler 		 */
2478a1b9b6aSSam Leffler 		if (cipher < N(cipher_modnames)) {
2488a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2498a1b9b6aSSam Leffler 				"%s: unregistered cipher %u, load module %s\n",
2508a1b9b6aSSam Leffler 				__func__, cipher, cipher_modnames[cipher]);
2518a1b9b6aSSam Leffler 			ieee80211_load_module(cipher_modnames[cipher]);
2528a1b9b6aSSam Leffler 			/*
2538a1b9b6aSSam Leffler 			 * If cipher module loaded it should immediately
2548a1b9b6aSSam Leffler 			 * call ieee80211_crypto_register which will fill
2558a1b9b6aSSam Leffler 			 * in the entry in the ciphers array.
2568a1b9b6aSSam Leffler 			 */
2578a1b9b6aSSam Leffler 			cip = ciphers[cipher];
2588a1b9b6aSSam Leffler 		}
2598a1b9b6aSSam Leffler 		if (cip == NULL) {
2608a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2618a1b9b6aSSam Leffler 				"%s: unable to load cipher %u, module %s\n",
2628a1b9b6aSSam Leffler 				__func__, cipher,
2638a1b9b6aSSam Leffler 				cipher < N(cipher_modnames) ?
2648a1b9b6aSSam Leffler 					cipher_modnames[cipher] : "<unknown>");
2658a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_nocipher++;
2668a1b9b6aSSam Leffler 			return 0;
2678a1b9b6aSSam Leffler 		}
2688a1b9b6aSSam Leffler 	}
2698a1b9b6aSSam Leffler 
2708a1b9b6aSSam Leffler 	oflags = key->wk_flags;
271dd70e17bSSam Leffler 	flags &= IEEE80211_KEY_COMMON;
2728a1b9b6aSSam Leffler 	/*
2738a1b9b6aSSam Leffler 	 * If the hardware does not support the cipher then
2748a1b9b6aSSam Leffler 	 * fallback to a host-based implementation.
2758a1b9b6aSSam Leffler 	 */
2768a1b9b6aSSam Leffler 	if ((ic->ic_caps & (1<<cipher)) == 0) {
2778a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2788a1b9b6aSSam Leffler 		    "%s: no h/w support for cipher %s, falling back to s/w\n",
2798a1b9b6aSSam Leffler 		    __func__, cip->ic_name);
280dd70e17bSSam Leffler 		flags |= IEEE80211_KEY_SWCRYPT;
2818a1b9b6aSSam Leffler 	}
2828a1b9b6aSSam Leffler 	/*
2838a1b9b6aSSam Leffler 	 * Hardware TKIP with software MIC is an important
2848a1b9b6aSSam Leffler 	 * combination; we handle it by flagging each key,
2858a1b9b6aSSam Leffler 	 * the cipher modules honor it.
2868a1b9b6aSSam Leffler 	 */
2878a1b9b6aSSam Leffler 	if (cipher == IEEE80211_CIPHER_TKIP &&
2888a1b9b6aSSam Leffler 	    (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) {
2898a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
2908a1b9b6aSSam Leffler 		    "%s: no h/w support for TKIP MIC, falling back to s/w\n",
2918a1b9b6aSSam Leffler 		    __func__);
292dd70e17bSSam Leffler 		flags |= IEEE80211_KEY_SWMIC;
2938a1b9b6aSSam Leffler 	}
2948a1b9b6aSSam Leffler 
2958a1b9b6aSSam Leffler 	/*
2968a1b9b6aSSam Leffler 	 * Bind cipher to key instance.  Note we do this
2978a1b9b6aSSam Leffler 	 * after checking the device capabilities so the
2988a1b9b6aSSam Leffler 	 * cipher module can optimize space usage based on
2998a1b9b6aSSam Leffler 	 * whether or not it needs to do the cipher work.
3008a1b9b6aSSam Leffler 	 */
301dd70e17bSSam Leffler 	if (key->wk_cipher != cip || key->wk_flags != flags) {
3028a1b9b6aSSam Leffler again:
303dd70e17bSSam Leffler 		/*
304dd70e17bSSam Leffler 		 * Fillin the flags so cipher modules can see s/w
305dd70e17bSSam Leffler 		 * crypto requirements and potentially allocate
306dd70e17bSSam Leffler 		 * different state and/or attach different method
307dd70e17bSSam Leffler 		 * pointers.
308dd70e17bSSam Leffler 		 *
309dd70e17bSSam Leffler 		 * XXX this is not right when s/w crypto fallback
310dd70e17bSSam Leffler 		 *     fails and we try to restore previous state.
311dd70e17bSSam Leffler 		 */
312dd70e17bSSam Leffler 		key->wk_flags = flags;
3138a1b9b6aSSam Leffler 		keyctx = cip->ic_attach(ic, key);
3148a1b9b6aSSam Leffler 		if (keyctx == NULL) {
3158a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3168a1b9b6aSSam Leffler 				"%s: unable to attach cipher %s\n",
3178a1b9b6aSSam Leffler 				__func__, cip->ic_name);
3188a1b9b6aSSam Leffler 			key->wk_flags = oflags;	/* restore old flags */
3198a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_attachfail++;
3208a1b9b6aSSam Leffler 			return 0;
3218a1b9b6aSSam Leffler 		}
3228a1b9b6aSSam Leffler 		cipher_detach(key);
3238a1b9b6aSSam Leffler 		key->wk_cipher = cip;		/* XXX refcnt? */
3248a1b9b6aSSam Leffler 		key->wk_private = keyctx;
3258a1b9b6aSSam Leffler 	}
326dd70e17bSSam Leffler 	/*
327dd70e17bSSam Leffler 	 * Commit to requested usage so driver can see the flags.
328dd70e17bSSam Leffler 	 */
329dd70e17bSSam Leffler 	key->wk_flags = flags;
3308a1b9b6aSSam Leffler 
3318a1b9b6aSSam Leffler 	/*
3328a1b9b6aSSam Leffler 	 * Ask the driver for a key index if we don't have one.
3338a1b9b6aSSam Leffler 	 * Note that entries in the global key table always have
3348a1b9b6aSSam Leffler 	 * an index; this means it's safe to call this routine
3358a1b9b6aSSam Leffler 	 * for these entries just to setup the reference to the
3368a1b9b6aSSam Leffler 	 * cipher template.  Note also that when using software
3378a1b9b6aSSam Leffler 	 * crypto we also call the driver to give us a key index.
3388a1b9b6aSSam Leffler 	 */
3398a1b9b6aSSam Leffler 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
3408a1b9b6aSSam Leffler 		key->wk_keyix = dev_key_alloc(ic, key);
3418a1b9b6aSSam Leffler 		if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
3428a1b9b6aSSam Leffler 			/*
3438a1b9b6aSSam Leffler 			 * Driver has no room; fallback to doing crypto
3448a1b9b6aSSam Leffler 			 * in the host.  We change the flags and start the
3458a1b9b6aSSam Leffler 			 * procedure over.  If we get back here then there's
3468a1b9b6aSSam Leffler 			 * no hope and we bail.  Note that this can leave
3478a1b9b6aSSam Leffler 			 * the key in a inconsistent state if the caller
3488a1b9b6aSSam Leffler 			 * continues to use it.
3498a1b9b6aSSam Leffler 			 */
3508a1b9b6aSSam Leffler 			if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
3518a1b9b6aSSam Leffler 				ic->ic_stats.is_crypto_swfallback++;
3528a1b9b6aSSam Leffler 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3538a1b9b6aSSam Leffler 				    "%s: no h/w resources for cipher %s, "
3548a1b9b6aSSam Leffler 				    "falling back to s/w\n", __func__,
3558a1b9b6aSSam Leffler 				    cip->ic_name);
3568a1b9b6aSSam Leffler 				oflags = key->wk_flags;
357dd70e17bSSam Leffler 				flags |= IEEE80211_KEY_SWCRYPT;
3588a1b9b6aSSam Leffler 				if (cipher == IEEE80211_CIPHER_TKIP)
359dd70e17bSSam Leffler 					flags |= IEEE80211_KEY_SWMIC;
3608a1b9b6aSSam Leffler 				goto again;
3618a1b9b6aSSam Leffler 			}
3628a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_keyfail++;
3638a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3648a1b9b6aSSam Leffler 			    "%s: unable to setup cipher %s\n",
3658a1b9b6aSSam Leffler 			    __func__, cip->ic_name);
3668a1b9b6aSSam Leffler 			return 0;
3678a1b9b6aSSam Leffler 		}
3688a1b9b6aSSam Leffler 	}
3698a1b9b6aSSam Leffler 	return 1;
3708a1b9b6aSSam Leffler #undef N
3718a1b9b6aSSam Leffler }
3728a1b9b6aSSam Leffler 
3738a1b9b6aSSam Leffler /*
3748a1b9b6aSSam Leffler  * Remove the key (no locking, for internal use).
3758a1b9b6aSSam Leffler  */
3768a1b9b6aSSam Leffler static int
3778a1b9b6aSSam Leffler _ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
3788a1b9b6aSSam Leffler {
3798a1b9b6aSSam Leffler 	u_int16_t keyix;
3808a1b9b6aSSam Leffler 
3818a1b9b6aSSam Leffler 	KASSERT(key->wk_cipher != NULL, ("No cipher!"));
3828a1b9b6aSSam Leffler 
383fc508e8eSSam Leffler 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
384fc508e8eSSam Leffler 	    "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n",
385fc508e8eSSam Leffler 	    __func__, key->wk_cipher->ic_name,
386fc508e8eSSam Leffler 	    key->wk_keyix, key->wk_flags,
387fc508e8eSSam Leffler 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
388fc508e8eSSam Leffler 
3898a1b9b6aSSam Leffler 	keyix = key->wk_keyix;
3908a1b9b6aSSam Leffler 	if (keyix != IEEE80211_KEYIX_NONE) {
3918a1b9b6aSSam Leffler 		/*
3928a1b9b6aSSam Leffler 		 * Remove hardware entry.
3938a1b9b6aSSam Leffler 		 */
3948a1b9b6aSSam Leffler 		/* XXX key cache */
3958a1b9b6aSSam Leffler 		if (!dev_key_delete(ic, key)) {
3968a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
3978a1b9b6aSSam Leffler 			    "%s: driver did not delete key index %u\n",
3988a1b9b6aSSam Leffler 			    __func__, keyix);
3998a1b9b6aSSam Leffler 			ic->ic_stats.is_crypto_delkey++;
4008a1b9b6aSSam Leffler 			/* XXX recovery? */
4018a1b9b6aSSam Leffler 		}
4028a1b9b6aSSam Leffler 	}
4038a1b9b6aSSam Leffler 	cipher_detach(key);
4048a1b9b6aSSam Leffler 	memset(key, 0, sizeof(*key));
405dd70e17bSSam Leffler 	ieee80211_crypto_resetkey(ic, key, IEEE80211_KEYIX_NONE);
4068a1b9b6aSSam Leffler 	return 1;
4078a1b9b6aSSam Leffler }
4088a1b9b6aSSam Leffler 
4098a1b9b6aSSam Leffler /*
4108a1b9b6aSSam Leffler  * Remove the specified key.
4118a1b9b6aSSam Leffler  */
4128a1b9b6aSSam Leffler int
4138a1b9b6aSSam Leffler ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
4148a1b9b6aSSam Leffler {
4158a1b9b6aSSam Leffler 	int status;
4168a1b9b6aSSam Leffler 
4178a1b9b6aSSam Leffler 	ieee80211_key_update_begin(ic);
4188a1b9b6aSSam Leffler 	status = _ieee80211_crypto_delkey(ic, key);
4198a1b9b6aSSam Leffler 	ieee80211_key_update_end(ic);
4208a1b9b6aSSam Leffler 	return status;
4218a1b9b6aSSam Leffler }
4228a1b9b6aSSam Leffler 
4238a1b9b6aSSam Leffler /*
4248a1b9b6aSSam Leffler  * Clear the global key table.
4258a1b9b6aSSam Leffler  */
4268a1b9b6aSSam Leffler void
4278a1b9b6aSSam Leffler ieee80211_crypto_delglobalkeys(struct ieee80211com *ic)
4288a1b9b6aSSam Leffler {
4298a1b9b6aSSam Leffler 	int i;
4308a1b9b6aSSam Leffler 
4318a1b9b6aSSam Leffler 	ieee80211_key_update_begin(ic);
4328a1b9b6aSSam Leffler 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
4338a1b9b6aSSam Leffler 		(void) _ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]);
4348a1b9b6aSSam Leffler 	ieee80211_key_update_end(ic);
4358a1b9b6aSSam Leffler }
4368a1b9b6aSSam Leffler 
4378a1b9b6aSSam Leffler /*
4388a1b9b6aSSam Leffler  * Set the contents of the specified key.
4398a1b9b6aSSam Leffler  *
4408a1b9b6aSSam Leffler  * Locking must be handled by the caller using:
4418a1b9b6aSSam Leffler  *	ieee80211_key_update_begin(ic);
4428a1b9b6aSSam Leffler  *	ieee80211_key_update_end(ic);
4438a1b9b6aSSam Leffler  */
4448a1b9b6aSSam Leffler int
4458a1b9b6aSSam Leffler ieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key,
4468a1b9b6aSSam Leffler 		const u_int8_t macaddr[IEEE80211_ADDR_LEN])
4478a1b9b6aSSam Leffler {
4488a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip = key->wk_cipher;
4498a1b9b6aSSam Leffler 
4508a1b9b6aSSam Leffler 	KASSERT(cip != NULL, ("No cipher!"));
4518a1b9b6aSSam Leffler 
452fc508e8eSSam Leffler 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
453fc508e8eSSam Leffler 	    "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n",
454fc508e8eSSam Leffler 	    __func__, cip->ic_name, key->wk_keyix,
455fc508e8eSSam Leffler 	    key->wk_flags, ether_sprintf(macaddr),
456fc508e8eSSam Leffler 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
457fc508e8eSSam Leffler 
4588a1b9b6aSSam Leffler 	/*
4598a1b9b6aSSam Leffler 	 * Give cipher a chance to validate key contents.
4608a1b9b6aSSam Leffler 	 * XXX should happen before modifying state.
4618a1b9b6aSSam Leffler 	 */
4628a1b9b6aSSam Leffler 	if (!cip->ic_setkey(key)) {
4638a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
4648a1b9b6aSSam Leffler 		    "%s: cipher %s rejected key index %u len %u flags 0x%x\n",
4658a1b9b6aSSam Leffler 		    __func__, cip->ic_name, key->wk_keyix,
4668a1b9b6aSSam Leffler 		    key->wk_keylen, key->wk_flags);
4678a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_setkey_cipher++;
4688a1b9b6aSSam Leffler 		return 0;
4698a1b9b6aSSam Leffler 	}
4708a1b9b6aSSam Leffler 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
4718a1b9b6aSSam Leffler 		/* XXX nothing allocated, should not happen */
4728a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
4738a1b9b6aSSam Leffler 		    "%s: no key index; should not happen!\n", __func__);
4748a1b9b6aSSam Leffler 		ic->ic_stats.is_crypto_setkey_nokey++;
4758a1b9b6aSSam Leffler 		return 0;
4768a1b9b6aSSam Leffler 	}
4778a1b9b6aSSam Leffler 	return dev_key_set(ic, key, macaddr);
4788a1b9b6aSSam Leffler }
4798a1b9b6aSSam Leffler 
4808a1b9b6aSSam Leffler /*
4818a1b9b6aSSam Leffler  * Add privacy headers appropriate for the specified key.
4828a1b9b6aSSam Leffler  */
4838a1b9b6aSSam Leffler struct ieee80211_key *
4848a1b9b6aSSam Leffler ieee80211_crypto_encap(struct ieee80211com *ic,
4858a1b9b6aSSam Leffler 	struct ieee80211_node *ni, struct mbuf *m)
4868a1b9b6aSSam Leffler {
4878a1b9b6aSSam Leffler 	struct ieee80211_key *k;
4888a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
4898a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
490dd70e17bSSam Leffler 	u_int8_t keyid;
4918a1b9b6aSSam Leffler 
4928a1b9b6aSSam Leffler 	/*
4938a1b9b6aSSam Leffler 	 * Multicast traffic always uses the multicast key.
4948a1b9b6aSSam Leffler 	 * Otherwise if a unicast key is set we use that and
4958a1b9b6aSSam Leffler 	 * it is always key index 0.  When no unicast key is
4968a1b9b6aSSam Leffler 	 * set we fall back to the default transmit key.
4978a1b9b6aSSam Leffler 	 */
4988a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
4998a1b9b6aSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
5008a1b9b6aSSam Leffler 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
5018a1b9b6aSSam Leffler 		if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) {
5028a1b9b6aSSam Leffler 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
503fc508e8eSSam Leffler 			    "[%s] no default transmit key (%s) deftxkey %u\n",
504fc508e8eSSam Leffler 			    ether_sprintf(wh->i_addr1), __func__,
505fc508e8eSSam Leffler 			    ic->ic_def_txkey);
5068a1b9b6aSSam Leffler 			ic->ic_stats.is_tx_nodefkey++;
5078a1b9b6aSSam Leffler 			return NULL;
5088a1b9b6aSSam Leffler 		}
509dd70e17bSSam Leffler 		keyid = ic->ic_def_txkey;
5108a1b9b6aSSam Leffler 		k = &ic->ic_nw_keys[ic->ic_def_txkey];
5118a1b9b6aSSam Leffler 	} else {
512dd70e17bSSam Leffler 		keyid = 0;
5138a1b9b6aSSam Leffler 		k = &ni->ni_ucastkey;
5148a1b9b6aSSam Leffler 	}
5158a1b9b6aSSam Leffler 	cip = k->wk_cipher;
516dd70e17bSSam Leffler 	return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
5178a1b9b6aSSam Leffler }
5188a1b9b6aSSam Leffler 
5198a1b9b6aSSam Leffler /*
5208a1b9b6aSSam Leffler  * Validate and strip privacy headers (and trailer) for a
5218a1b9b6aSSam Leffler  * received frame that has the WEP/Privacy bit set.
5228a1b9b6aSSam Leffler  */
5238a1b9b6aSSam Leffler struct ieee80211_key *
5248a1b9b6aSSam Leffler ieee80211_crypto_decap(struct ieee80211com *ic,
5252cc12adeSSam Leffler 	struct ieee80211_node *ni, struct mbuf *m, int hdrlen)
5268a1b9b6aSSam Leffler {
5278a1b9b6aSSam Leffler #define	IEEE80211_WEP_HDRLEN	(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
5288a1b9b6aSSam Leffler #define	IEEE80211_WEP_MINLEN \
5298a1b9b6aSSam Leffler 	(sizeof(struct ieee80211_frame) + ETHER_HDR_LEN + \
5308a1b9b6aSSam Leffler 	IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
5318a1b9b6aSSam Leffler 	struct ieee80211_key *k;
5328a1b9b6aSSam Leffler 	struct ieee80211_frame *wh;
5338a1b9b6aSSam Leffler 	const struct ieee80211_cipher *cip;
5347432b7ccSSam Leffler 	const u_int8_t *ivp;
5358a1b9b6aSSam Leffler 	u_int8_t keyid;
5368a1b9b6aSSam Leffler 
5378a1b9b6aSSam Leffler 	/* NB: this minimum size data frame could be bigger */
5388a1b9b6aSSam Leffler 	if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
5398a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
5408a1b9b6aSSam Leffler 			"%s: WEP data frame too short, len %u\n",
5418a1b9b6aSSam Leffler 			__func__, m->m_pkthdr.len);
5428a1b9b6aSSam Leffler 		ic->ic_stats.is_rx_tooshort++;	/* XXX need unique stat? */
5431a1e1d21SSam Leffler 		return NULL;
5441a1e1d21SSam Leffler 	}
5451a1e1d21SSam Leffler 
5461a1e1d21SSam Leffler 	/*
5478a1b9b6aSSam Leffler 	 * Locate the key. If unicast and there is no unicast
5488a1b9b6aSSam Leffler 	 * key then we fall back to the key id in the header.
5498a1b9b6aSSam Leffler 	 * This assumes unicast keys are only configured when
5508a1b9b6aSSam Leffler 	 * the key id in the header is meaningless (typically 0).
5511a1e1d21SSam Leffler 	 */
5528a1b9b6aSSam Leffler 	wh = mtod(m, struct ieee80211_frame *);
5537432b7ccSSam Leffler 	ivp = mtod(m, const u_int8_t *) + hdrlen;	/* XXX contig */
5548a1b9b6aSSam Leffler 	keyid = ivp[IEEE80211_WEP_IVLEN];
5558a1b9b6aSSam Leffler 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
5568a1b9b6aSSam Leffler 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none)
5578a1b9b6aSSam Leffler 		k = &ic->ic_nw_keys[keyid >> 6];
5581a1e1d21SSam Leffler 	else
5598a1b9b6aSSam Leffler 		k = &ni->ni_ucastkey;
5601a1e1d21SSam Leffler 
5611a1e1d21SSam Leffler 	/*
5628a1b9b6aSSam Leffler 	 * Insure crypto header is contiguous for all decap work.
5631a1e1d21SSam Leffler 	 */
5648a1b9b6aSSam Leffler 	cip = k->wk_cipher;
5658a1b9b6aSSam Leffler 	if (m->m_len < hdrlen + cip->ic_header &&
5668a1b9b6aSSam Leffler 	    (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) {
5678a1b9b6aSSam Leffler 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
5688a1b9b6aSSam Leffler 		    "[%s] unable to pullup %s header\n",
5698a1b9b6aSSam Leffler 		    ether_sprintf(wh->i_addr2), cip->ic_name);
5708a1b9b6aSSam Leffler 		ic->ic_stats.is_rx_wepfail++;	/* XXX */
5718a1b9b6aSSam Leffler 		return 0;
5728a1b9b6aSSam Leffler 	}
5731a1e1d21SSam Leffler 
5742cc12adeSSam Leffler 	return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
5758a1b9b6aSSam Leffler #undef IEEE80211_WEP_MINLEN
5768a1b9b6aSSam Leffler #undef IEEE80211_WEP_HDRLEN
5771a1e1d21SSam Leffler }
578