xref: /netbsd/sys/net80211/ieee80211_crypto.c (revision 83228edf)
1*83228edfSmaxv /*	$NetBSD: ieee80211_crypto.c,v 1.23 2018/05/08 07:02:07 maxv Exp $	*/
2a8560c32Smaxv 
3a8560c32Smaxv /*
440e261aaSdyoung  * Copyright (c) 2001 Atsushi Onoe
590634029Sdyoung  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
640e261aaSdyoung  * All rights reserved.
740e261aaSdyoung  *
840e261aaSdyoung  * Redistribution and use in source and binary forms, with or without
940e261aaSdyoung  * modification, are permitted provided that the following conditions
1040e261aaSdyoung  * are met:
1140e261aaSdyoung  * 1. Redistributions of source code must retain the above copyright
1240e261aaSdyoung  *    notice, this list of conditions and the following disclaimer.
1340e261aaSdyoung  * 2. Redistributions in binary form must reproduce the above copyright
1440e261aaSdyoung  *    notice, this list of conditions and the following disclaimer in the
1540e261aaSdyoung  *    documentation and/or other materials provided with the distribution.
1640e261aaSdyoung  * 3. The name of the author may not be used to endorse or promote products
1740e261aaSdyoung  *    derived from this software without specific prior written permission.
1840e261aaSdyoung  *
1940e261aaSdyoung  * Alternatively, this software may be distributed under the terms of the
2040e261aaSdyoung  * GNU General Public License ("GPL") version 2 as published by the Free
2140e261aaSdyoung  * Software Foundation.
2240e261aaSdyoung  *
2340e261aaSdyoung  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2440e261aaSdyoung  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2540e261aaSdyoung  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2640e261aaSdyoung  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2740e261aaSdyoung  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2840e261aaSdyoung  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2940e261aaSdyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3040e261aaSdyoung  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3140e261aaSdyoung  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3240e261aaSdyoung  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3340e261aaSdyoung  */
3440e261aaSdyoung 
3540e261aaSdyoung #include <sys/cdefs.h>
366e8d0b71Sdyoung #ifdef __FreeBSD__
3787515e34Sskrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto.c,v 1.12 2005/08/08 18:46:35 sam Exp $");
3890634029Sdyoung #endif
3990634029Sdyoung #ifdef __NetBSD__
40*83228edfSmaxv __KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto.c,v 1.23 2018/05/08 07:02:07 maxv Exp $");
416e8d0b71Sdyoung #endif
4240e261aaSdyoung 
43082aeae6Spooka #ifdef _KERNEL_OPT
4440e261aaSdyoung #include "opt_inet.h"
45082aeae6Spooka #endif
4640e261aaSdyoung 
4790634029Sdyoung /*
4890634029Sdyoung  * IEEE 802.11 generic crypto support.
4990634029Sdyoung  */
5040e261aaSdyoung #include <sys/param.h>
5140e261aaSdyoung #include <sys/mbuf.h>
5290634029Sdyoung 
5340e261aaSdyoung #include <sys/socket.h>
5440e261aaSdyoung #include <sys/sockio.h>
5540e261aaSdyoung #include <sys/endian.h>
5640e261aaSdyoung #include <sys/errno.h>
5740e261aaSdyoung #include <sys/proc.h>
5840e261aaSdyoung #include <sys/sysctl.h>
5940e261aaSdyoung 
6040e261aaSdyoung #include <net/if.h>
6140e261aaSdyoung #include <net/if_media.h>
6240e261aaSdyoung #include <net/if_arp.h>
63847c5ca1Sdyoung #include <net/if_ether.h>
6440e261aaSdyoung #include <net/if_llc.h>
6540e261aaSdyoung 
6690634029Sdyoung #include <net80211/ieee80211_netbsd.h>
6740e261aaSdyoung #include <net80211/ieee80211_var.h>
6840e261aaSdyoung 
6990634029Sdyoung /*
7090634029Sdyoung  * Table of registered cipher modules.
7190634029Sdyoung  */
7290634029Sdyoung static const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX];
7340e261aaSdyoung 
7440e261aaSdyoung #ifdef INET
7540e261aaSdyoung #include <netinet/in.h>
76847c5ca1Sdyoung #include <net/if_ether.h>
77847c5ca1Sdyoung #endif
7840e261aaSdyoung 
7990634029Sdyoung static int _ieee80211_crypto_delkey(struct ieee80211com *,
8090634029Sdyoung     struct ieee80211_key *);
8140e261aaSdyoung 
8290634029Sdyoung /*
8390634029Sdyoung  * Default "null" key management routines.
8490634029Sdyoung  */
8590634029Sdyoung static int
null_key_alloc(struct ieee80211com * ic,const struct ieee80211_key * k,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)8687515e34Sskrll null_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
8787515e34Sskrll     ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
8840e261aaSdyoung {
89d2ba8780Sdyoung 	if (!(&ic->ic_nw_keys[0] <= k &&
90d2ba8780Sdyoung 	     k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
91d2ba8780Sdyoung 		/*
92d2ba8780Sdyoung 		 * Not in the global key table, the driver should handle this
93d2ba8780Sdyoung 		 * by allocating a slot in the h/w key table/cache.  In
94d2ba8780Sdyoung 		 * lieu of that return key slot 0 for any unicast key
95d2ba8780Sdyoung 		 * request.  We disallow the request if this is a group key.
96d2ba8780Sdyoung 		 * This default policy does the right thing for legacy hardware
97d2ba8780Sdyoung 		 * with a 4 key table.  It also handles devices that pass
98d2ba8780Sdyoung 		 * packets through untouched when marked with the WEP bit
99d2ba8780Sdyoung 		 * and key index 0.
100d2ba8780Sdyoung 		 */
10187515e34Sskrll 		if (k->wk_flags & IEEE80211_KEY_GROUP)
10287515e34Sskrll 			return 0;
10387515e34Sskrll 		*keyix = 0;	/* NB: use key index 0 for ucast key */
10487515e34Sskrll 	} else {
10587515e34Sskrll 		*keyix = k - ic->ic_nw_keys;
10690634029Sdyoung 	}
10787515e34Sskrll 	*rxkeyix = IEEE80211_KEYIX_NONE;	/* XXX maybe *keyix? */
10887515e34Sskrll 	return 1;
109d2ba8780Sdyoung }
110a8560c32Smaxv 
11190634029Sdyoung static int
null_key_delete(struct ieee80211com * ic,const struct ieee80211_key * k)112a8560c32Smaxv null_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
11390634029Sdyoung {
11490634029Sdyoung 	return 1;
11590634029Sdyoung }
116a8560c32Smaxv 
11790634029Sdyoung static int
null_key_set(struct ieee80211com * ic,const struct ieee80211_key * k,const u_int8_t mac[IEEE80211_ADDR_LEN])118a8560c32Smaxv null_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
119168cd830Schristos     const u_int8_t mac[IEEE80211_ADDR_LEN])
12090634029Sdyoung {
12190634029Sdyoung 	return 1;
12290634029Sdyoung }
123a8560c32Smaxv 
124a8560c32Smaxv static void
null_key_update(struct ieee80211com * ic)125a8560c32Smaxv null_key_update(struct ieee80211com *ic)
126a8560c32Smaxv {
127a8560c32Smaxv 	;
128a8560c32Smaxv }
12990634029Sdyoung 
13090634029Sdyoung /*
13190634029Sdyoung  * Write-arounds for common operations.
13290634029Sdyoung  */
13390634029Sdyoung static __inline void
cipher_detach(struct ieee80211_key * key)13490634029Sdyoung cipher_detach(struct ieee80211_key *key)
13590634029Sdyoung {
13690634029Sdyoung 	key->wk_cipher->ic_detach(key);
13790634029Sdyoung }
13890634029Sdyoung 
13990634029Sdyoung /*
14090634029Sdyoung  * Wrappers for driver key management methods.
14190634029Sdyoung  */
14290634029Sdyoung static __inline int
dev_key_alloc(struct ieee80211com * ic,const struct ieee80211_key * key,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)143a8560c32Smaxv dev_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *key,
14487515e34Sskrll     ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
14590634029Sdyoung {
14687515e34Sskrll 	return ic->ic_crypto.cs_key_alloc(ic, key, keyix, rxkeyix);
14790634029Sdyoung }
14890634029Sdyoung 
14990634029Sdyoung static __inline int
dev_key_delete(struct ieee80211com * ic,const struct ieee80211_key * key)150a8560c32Smaxv dev_key_delete(struct ieee80211com *ic, const struct ieee80211_key *key)
15190634029Sdyoung {
15290634029Sdyoung 	return ic->ic_crypto.cs_key_delete(ic, key);
15390634029Sdyoung }
15490634029Sdyoung 
15590634029Sdyoung static __inline int
dev_key_set(struct ieee80211com * ic,const struct ieee80211_key * key,const u_int8_t mac[IEEE80211_ADDR_LEN])15690634029Sdyoung dev_key_set(struct ieee80211com *ic, const struct ieee80211_key *key,
15790634029Sdyoung     const u_int8_t mac[IEEE80211_ADDR_LEN])
15890634029Sdyoung {
15990634029Sdyoung 	return ic->ic_crypto.cs_key_set(ic, key, mac);
16090634029Sdyoung }
16140e261aaSdyoung 
16240e261aaSdyoung /*
16340e261aaSdyoung  * Setup crypto support.
16440e261aaSdyoung  */
16540e261aaSdyoung void
ieee80211_crypto_attach(struct ieee80211com * ic)16690634029Sdyoung ieee80211_crypto_attach(struct ieee80211com *ic)
16740e261aaSdyoung {
16890634029Sdyoung 	struct ieee80211_crypto_state *cs = &ic->ic_crypto;
16990634029Sdyoung 	int i;
17040e261aaSdyoung 
17190634029Sdyoung 	/* NB: we assume everything is pre-zero'd */
17290634029Sdyoung 	cs->cs_def_txkey = IEEE80211_KEYIX_NONE;
17387515e34Sskrll 	cs->cs_max_keyix = IEEE80211_WEP_NKID;
17490634029Sdyoung 	ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
17590634029Sdyoung 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
17690634029Sdyoung 		ieee80211_crypto_resetkey(ic, &cs->cs_nw_keys[i],
17790634029Sdyoung 			IEEE80211_KEYIX_NONE);
17840e261aaSdyoung 	/*
17990634029Sdyoung 	 * Initialize the driver key support routines to noop entries.
18090634029Sdyoung 	 * This is useful especially for the cipher test modules.
18140e261aaSdyoung 	 */
18290634029Sdyoung 	cs->cs_key_alloc = null_key_alloc;
18390634029Sdyoung 	cs->cs_key_set = null_key_set;
18490634029Sdyoung 	cs->cs_key_delete = null_key_delete;
18590634029Sdyoung 	cs->cs_key_update_begin = null_key_update;
18690634029Sdyoung 	cs->cs_key_update_end = null_key_update;
18740e261aaSdyoung }
18840e261aaSdyoung 
18990634029Sdyoung /*
19090634029Sdyoung  * Teardown crypto support.
19190634029Sdyoung  */
19290634029Sdyoung void
ieee80211_crypto_detach(struct ieee80211com * ic)19390634029Sdyoung ieee80211_crypto_detach(struct ieee80211com *ic)
19490634029Sdyoung {
19590634029Sdyoung 	ieee80211_crypto_delglobalkeys(ic);
19640e261aaSdyoung }
19740e261aaSdyoung 
19890634029Sdyoung /*
19990634029Sdyoung  * Register a crypto cipher module.
20090634029Sdyoung  */
20190634029Sdyoung void
ieee80211_crypto_register(const struct ieee80211_cipher * cip)20290634029Sdyoung ieee80211_crypto_register(const struct ieee80211_cipher *cip)
20390634029Sdyoung {
20490634029Sdyoung 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
20590634029Sdyoung 		printf("%s: cipher %s has an invalid cipher index %u\n",
20690634029Sdyoung 			__func__, cip->ic_name, cip->ic_cipher);
20790634029Sdyoung 		return;
20890634029Sdyoung 	}
20990634029Sdyoung 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
21090634029Sdyoung 		printf("%s: cipher %s registered with a different template\n",
21190634029Sdyoung 			__func__, cip->ic_name);
21290634029Sdyoung 		return;
21390634029Sdyoung 	}
21490634029Sdyoung 	ciphers[cip->ic_cipher] = cip;
21590634029Sdyoung }
21690634029Sdyoung 
21790634029Sdyoung /*
21890634029Sdyoung  * Unregister a crypto cipher module.
21990634029Sdyoung  */
22090634029Sdyoung void
ieee80211_crypto_unregister(const struct ieee80211_cipher * cip)22190634029Sdyoung ieee80211_crypto_unregister(const struct ieee80211_cipher *cip)
22290634029Sdyoung {
22390634029Sdyoung 	if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
22490634029Sdyoung 		printf("%s: cipher %s has an invalid cipher index %u\n",
22590634029Sdyoung 			__func__, cip->ic_name, cip->ic_cipher);
22690634029Sdyoung 		return;
22790634029Sdyoung 	}
22890634029Sdyoung 	if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
22990634029Sdyoung 		printf("%s: cipher %s registered with a different template\n",
23090634029Sdyoung 			__func__, cip->ic_name);
23190634029Sdyoung 		return;
23290634029Sdyoung 	}
23390634029Sdyoung 	/* NB: don't complain about not being registered */
23490634029Sdyoung 	/* XXX disallow if references */
23590634029Sdyoung 	ciphers[cip->ic_cipher] = NULL;
23690634029Sdyoung }
23790634029Sdyoung 
23890634029Sdyoung int
ieee80211_crypto_available(u_int cipher)23990634029Sdyoung ieee80211_crypto_available(u_int cipher)
24090634029Sdyoung {
24190634029Sdyoung 	return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL;
24290634029Sdyoung }
24390634029Sdyoung 
24490634029Sdyoung /* XXX well-known names! */
24590634029Sdyoung static const char *cipher_modnames[] = {
24690634029Sdyoung 	"wlan_wep",	/* IEEE80211_CIPHER_WEP */
24790634029Sdyoung 	"wlan_tkip",	/* IEEE80211_CIPHER_TKIP */
24890634029Sdyoung 	"wlan_aes_ocb",	/* IEEE80211_CIPHER_AES_OCB */
24990634029Sdyoung 	"wlan_ccmp",	/* IEEE80211_CIPHER_AES_CCM */
25090634029Sdyoung 	"wlan_ckip",	/* IEEE80211_CIPHER_CKIP */
25190634029Sdyoung };
25290634029Sdyoung 
25390634029Sdyoung /*
25490634029Sdyoung  * Establish a relationship between the specified key and cipher
25590634029Sdyoung  * and, if necessary, allocate a hardware index from the driver.
25690634029Sdyoung  * Note that when a fixed key index is required it must be specified
25790634029Sdyoung  * and we blindly assign it w/o consulting the driver (XXX).
25890634029Sdyoung  *
25990634029Sdyoung  * This must be the first call applied to a key; all the other key
26090634029Sdyoung  * routines assume wk_cipher is setup.
26190634029Sdyoung  *
26290634029Sdyoung  * Locking must be handled by the caller using:
26390634029Sdyoung  *	ieee80211_key_update_begin(ic);
26490634029Sdyoung  *	ieee80211_key_update_end(ic);
26590634029Sdyoung  */
26690634029Sdyoung int
ieee80211_crypto_newkey(struct ieee80211com * ic,int cipher,int flags,struct ieee80211_key * key)267a8560c32Smaxv ieee80211_crypto_newkey(struct ieee80211com *ic, int cipher, int flags,
268a8560c32Smaxv     struct ieee80211_key *key)
26990634029Sdyoung {
27090634029Sdyoung #define	N(a)	(sizeof(a) / sizeof(a[0]))
27190634029Sdyoung 	const struct ieee80211_cipher *cip;
27287515e34Sskrll 	ieee80211_keyix keyix, rxkeyix;
27390634029Sdyoung 	void *keyctx;
27490634029Sdyoung 	int oflags;
27590634029Sdyoung 
27690634029Sdyoung 	/*
27790634029Sdyoung 	 * Validate cipher and set reference to cipher routines.
27890634029Sdyoung 	 */
27990634029Sdyoung 	if (cipher >= IEEE80211_CIPHER_MAX) {
28090634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
28190634029Sdyoung 			"%s: invalid cipher %u\n", __func__, cipher);
28290634029Sdyoung 		ic->ic_stats.is_crypto_badcipher++;
28390634029Sdyoung 		return 0;
28490634029Sdyoung 	}
28590634029Sdyoung 	cip = ciphers[cipher];
286a8560c32Smaxv 
28790634029Sdyoung 	if (cip == NULL) {
28890634029Sdyoung 		/*
28990634029Sdyoung 		 * Auto-load cipher module if we have a well-known name
29090634029Sdyoung 		 * for it.  It might be better to use string names rather
29190634029Sdyoung 		 * than numbers and craft a module name based on the cipher
29290634029Sdyoung 		 * name; e.g. wlan_cipher_<cipher-name>.
29390634029Sdyoung 		 */
29490634029Sdyoung 		if (cipher < N(cipher_modnames)) {
29590634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
29690634029Sdyoung 				"%s: unregistered cipher %u, load module %s\n",
29790634029Sdyoung 				__func__, cipher, cipher_modnames[cipher]);
29890634029Sdyoung 			ieee80211_load_module(cipher_modnames[cipher]);
29990634029Sdyoung 			/*
30090634029Sdyoung 			 * If cipher module loaded it should immediately
30190634029Sdyoung 			 * call ieee80211_crypto_register which will fill
30290634029Sdyoung 			 * in the entry in the ciphers array.
30390634029Sdyoung 			 */
30490634029Sdyoung 			cip = ciphers[cipher];
30590634029Sdyoung 		}
30690634029Sdyoung 		if (cip == NULL) {
30790634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
30890634029Sdyoung 				"%s: unable to load cipher %u, module %s\n",
30990634029Sdyoung 				__func__, cipher,
31090634029Sdyoung 				cipher < N(cipher_modnames) ?
31190634029Sdyoung 					cipher_modnames[cipher] : "<unknown>");
31290634029Sdyoung 			ic->ic_stats.is_crypto_nocipher++;
31390634029Sdyoung 			return 0;
31490634029Sdyoung 		}
31590634029Sdyoung 	}
31690634029Sdyoung 
31790634029Sdyoung 	oflags = key->wk_flags;
31890634029Sdyoung 	flags &= IEEE80211_KEY_COMMON;
319a8560c32Smaxv 
32090634029Sdyoung 	/*
32190634029Sdyoung 	 * If the hardware does not support the cipher then
32290634029Sdyoung 	 * fall back to a host-based implementation.
32390634029Sdyoung 	 */
32490634029Sdyoung 	if ((ic->ic_caps & (1<<cipher)) == 0) {
32590634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
32690634029Sdyoung 		    "%s: no h/w support for cipher %s, falling back to s/w\n",
32790634029Sdyoung 		    __func__, cip->ic_name);
32890634029Sdyoung 		flags |= IEEE80211_KEY_SWCRYPT;
32990634029Sdyoung 	}
330a8560c32Smaxv 
33190634029Sdyoung 	/*
33290634029Sdyoung 	 * Hardware TKIP with software MIC is an important
33390634029Sdyoung 	 * combination; we handle it by flagging each key,
33490634029Sdyoung 	 * the cipher modules honor it.
33590634029Sdyoung 	 */
33690634029Sdyoung 	if (cipher == IEEE80211_CIPHER_TKIP &&
33790634029Sdyoung 	    (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) {
33890634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
33990634029Sdyoung 		    "%s: no h/w support for TKIP MIC, falling back to s/w\n",
34090634029Sdyoung 		    __func__);
34190634029Sdyoung 		flags |= IEEE80211_KEY_SWMIC;
34290634029Sdyoung 	}
34390634029Sdyoung 
34490634029Sdyoung 	/*
34590634029Sdyoung 	 * Bind cipher to key instance.  Note we do this
34690634029Sdyoung 	 * after checking the device capabilities so the
34790634029Sdyoung 	 * cipher module can optimize space usage based on
34890634029Sdyoung 	 * whether or not it needs to do the cipher work.
34990634029Sdyoung 	 */
35090634029Sdyoung 	if (key->wk_cipher != cip || key->wk_flags != flags) {
35190634029Sdyoung again:
35290634029Sdyoung 		/*
35390634029Sdyoung 		 * Fillin the flags so cipher modules can see s/w
35490634029Sdyoung 		 * crypto requirements and potentially allocate
35590634029Sdyoung 		 * different state and/or attach different method
35690634029Sdyoung 		 * pointers.
35790634029Sdyoung 		 *
35890634029Sdyoung 		 * XXX this is not right when s/w crypto fallback
35990634029Sdyoung 		 *     fails and we try to restore previous state.
36090634029Sdyoung 		 */
36190634029Sdyoung 		key->wk_flags = flags;
36290634029Sdyoung 		keyctx = cip->ic_attach(ic, key);
36390634029Sdyoung 		if (keyctx == NULL) {
36490634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
36590634029Sdyoung 				"%s: unable to attach cipher %s\n",
36690634029Sdyoung 				__func__, cip->ic_name);
36790634029Sdyoung 			key->wk_flags = oflags;	/* restore old flags */
36890634029Sdyoung 			ic->ic_stats.is_crypto_attachfail++;
36990634029Sdyoung 			return 0;
37090634029Sdyoung 		}
37190634029Sdyoung 		cipher_detach(key);
37290634029Sdyoung 		key->wk_cipher = cip;		/* XXX refcnt? */
37390634029Sdyoung 		key->wk_private = keyctx;
37490634029Sdyoung 	}
37590634029Sdyoung 	/*
37690634029Sdyoung 	 * Commit to requested usage so driver can see the flags.
37790634029Sdyoung 	 */
37890634029Sdyoung 	key->wk_flags = flags;
37990634029Sdyoung 
38090634029Sdyoung 	/*
38190634029Sdyoung 	 * Ask the driver for a key index if we don't have one.
38290634029Sdyoung 	 * Note that entries in the global key table always have
38390634029Sdyoung 	 * an index; this means it's safe to call this routine
38490634029Sdyoung 	 * for these entries just to setup the reference to the
38590634029Sdyoung 	 * cipher template.  Note also that when using software
38690634029Sdyoung 	 * crypto we also call the driver to give us a key index.
38790634029Sdyoung 	 */
38890634029Sdyoung 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
38987515e34Sskrll 		if (!dev_key_alloc(ic, key, &keyix, &rxkeyix)) {
39090634029Sdyoung 			/*
39190634029Sdyoung 			 * Driver has no room; fallback to doing crypto
39290634029Sdyoung 			 * in the host.  We change the flags and start the
39390634029Sdyoung 			 * procedure over.  If we get back here then there's
39490634029Sdyoung 			 * no hope and we bail.  Note that this can leave
39590634029Sdyoung 			 * the key in a inconsistent state if the caller
39690634029Sdyoung 			 * continues to use it.
39790634029Sdyoung 			 */
39890634029Sdyoung 			if ((key->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
39990634029Sdyoung 				ic->ic_stats.is_crypto_swfallback++;
40090634029Sdyoung 				IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
40190634029Sdyoung 				    "%s: no h/w resources for cipher %s, "
40290634029Sdyoung 				    "falling back to s/w\n", __func__,
40390634029Sdyoung 				    cip->ic_name);
40490634029Sdyoung 				oflags = key->wk_flags;
40590634029Sdyoung 				flags |= IEEE80211_KEY_SWCRYPT;
40690634029Sdyoung 				if (cipher == IEEE80211_CIPHER_TKIP)
40790634029Sdyoung 					flags |= IEEE80211_KEY_SWMIC;
40890634029Sdyoung 				goto again;
40990634029Sdyoung 			}
41090634029Sdyoung 			ic->ic_stats.is_crypto_keyfail++;
41190634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
41290634029Sdyoung 			    "%s: unable to setup cipher %s\n",
41390634029Sdyoung 			    __func__, cip->ic_name);
41490634029Sdyoung 			return 0;
41590634029Sdyoung 		}
41687515e34Sskrll 		key->wk_keyix = keyix;
41787515e34Sskrll 		key->wk_rxkeyix = rxkeyix;
41890634029Sdyoung 	}
41990634029Sdyoung 	return 1;
42090634029Sdyoung #undef N
42190634029Sdyoung }
42290634029Sdyoung 
42390634029Sdyoung /*
42490634029Sdyoung  * Remove the key (no locking, for internal use).
42590634029Sdyoung  */
42690634029Sdyoung static int
_ieee80211_crypto_delkey(struct ieee80211com * ic,struct ieee80211_key * key)42790634029Sdyoung _ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
42890634029Sdyoung {
42987515e34Sskrll 	ieee80211_keyix keyix;
43090634029Sdyoung 
43190634029Sdyoung 	IASSERT(key->wk_cipher != NULL, ("No cipher!"));
43290634029Sdyoung 
43390634029Sdyoung 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
43490634029Sdyoung 	    "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n",
43590634029Sdyoung 	    __func__, key->wk_cipher->ic_name,
43690634029Sdyoung 	    key->wk_keyix, key->wk_flags,
43790634029Sdyoung 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
43890634029Sdyoung 
43990634029Sdyoung 	keyix = key->wk_keyix;
44090634029Sdyoung 	if (keyix != IEEE80211_KEYIX_NONE) {
44190634029Sdyoung 		/*
44290634029Sdyoung 		 * Remove hardware entry.
44390634029Sdyoung 		 */
44490634029Sdyoung 		/* XXX key cache */
44590634029Sdyoung 		if (!dev_key_delete(ic, key)) {
44690634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
44790634029Sdyoung 			    "%s: driver did not delete key index %u\n",
44890634029Sdyoung 			    __func__, keyix);
44990634029Sdyoung 			ic->ic_stats.is_crypto_delkey++;
45090634029Sdyoung 			/* XXX recovery? */
45190634029Sdyoung 		}
45290634029Sdyoung 	}
45390634029Sdyoung 	cipher_detach(key);
45490634029Sdyoung 	memset(key, 0, sizeof(*key));
45590634029Sdyoung 	ieee80211_crypto_resetkey(ic, key, IEEE80211_KEYIX_NONE);
45690634029Sdyoung 	return 1;
45790634029Sdyoung }
45890634029Sdyoung 
45990634029Sdyoung /*
46090634029Sdyoung  * Remove the specified key.
46190634029Sdyoung  */
46290634029Sdyoung int
ieee80211_crypto_delkey(struct ieee80211com * ic,struct ieee80211_key * key)46390634029Sdyoung ieee80211_crypto_delkey(struct ieee80211com *ic, struct ieee80211_key *key)
46490634029Sdyoung {
46590634029Sdyoung 	int status;
46690634029Sdyoung 
46790634029Sdyoung 	ieee80211_key_update_begin(ic);
46890634029Sdyoung 	status = _ieee80211_crypto_delkey(ic, key);
46990634029Sdyoung 	ieee80211_key_update_end(ic);
47090634029Sdyoung 	return status;
47190634029Sdyoung }
47290634029Sdyoung 
47390634029Sdyoung /*
47490634029Sdyoung  * Clear the global key table.
47590634029Sdyoung  */
47690634029Sdyoung void
ieee80211_crypto_delglobalkeys(struct ieee80211com * ic)47790634029Sdyoung ieee80211_crypto_delglobalkeys(struct ieee80211com *ic)
47890634029Sdyoung {
47990634029Sdyoung 	int i;
48090634029Sdyoung 
48190634029Sdyoung 	ieee80211_key_update_begin(ic);
48290634029Sdyoung 	for (i = 0; i < IEEE80211_WEP_NKID; i++)
48390634029Sdyoung 		(void)_ieee80211_crypto_delkey(ic, &ic->ic_nw_keys[i]);
48490634029Sdyoung 	ieee80211_key_update_end(ic);
48590634029Sdyoung }
48690634029Sdyoung 
48790634029Sdyoung /*
48890634029Sdyoung  * Set the contents of the specified key.
48990634029Sdyoung  *
49090634029Sdyoung  * Locking must be handled by the caller using:
49190634029Sdyoung  *	ieee80211_key_update_begin(ic);
49290634029Sdyoung  *	ieee80211_key_update_end(ic);
49390634029Sdyoung  */
49490634029Sdyoung int
ieee80211_crypto_setkey(struct ieee80211com * ic,struct ieee80211_key * key,const u_int8_t macaddr[IEEE80211_ADDR_LEN])49590634029Sdyoung ieee80211_crypto_setkey(struct ieee80211com *ic, struct ieee80211_key *key,
49690634029Sdyoung     const u_int8_t macaddr[IEEE80211_ADDR_LEN])
49790634029Sdyoung {
49890634029Sdyoung 	const struct ieee80211_cipher *cip = key->wk_cipher;
49990634029Sdyoung 
50090634029Sdyoung 	IASSERT(cip != NULL, ("No cipher!"));
50190634029Sdyoung 
50290634029Sdyoung 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
50390634029Sdyoung 	    "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n",
50490634029Sdyoung 	    __func__, cip->ic_name, key->wk_keyix,
50590634029Sdyoung 	    key->wk_flags, ether_sprintf(macaddr),
50690634029Sdyoung 	    key->wk_keyrsc, key->wk_keytsc, key->wk_keylen);
50790634029Sdyoung 
50890634029Sdyoung 	/*
50990634029Sdyoung 	 * Give cipher a chance to validate key contents.
51090634029Sdyoung 	 * XXX should happen before modifying state.
51190634029Sdyoung 	 */
51290634029Sdyoung 	if (!cip->ic_setkey(key)) {
51390634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
51490634029Sdyoung 		    "%s: cipher %s rejected key index %u len %u flags 0x%x\n",
51590634029Sdyoung 		    __func__, cip->ic_name, key->wk_keyix,
51690634029Sdyoung 		    key->wk_keylen, key->wk_flags);
51790634029Sdyoung 		ic->ic_stats.is_crypto_setkey_cipher++;
51890634029Sdyoung 		return 0;
51990634029Sdyoung 	}
52090634029Sdyoung 	if (key->wk_keyix == IEEE80211_KEYIX_NONE) {
52190634029Sdyoung 		/* XXX nothing allocated, should not happen */
52290634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
52390634029Sdyoung 		    "%s: no key index; should not happen!\n", __func__);
52490634029Sdyoung 		ic->ic_stats.is_crypto_setkey_nokey++;
52590634029Sdyoung 		return 0;
52690634029Sdyoung 	}
52790634029Sdyoung 	return dev_key_set(ic, key, macaddr);
52890634029Sdyoung }
52990634029Sdyoung 
53090634029Sdyoung /*
53190634029Sdyoung  * Add privacy headers appropriate for the specified key.
532d1b4a5beSmaxv  *
533d1b4a5beSmaxv  * XXX XXX XXX: Here we modify 'm', and potentially reallocate it. We
534d1b4a5beSmaxv  * should pass back to the caller the updated pointer to avoid
535d1b4a5beSmaxv  * use-after-frees. This can be done by changing the argument to be **m,
536d1b4a5beSmaxv  * but many drivers will have to be changed accordingly.
53790634029Sdyoung  */
53890634029Sdyoung struct ieee80211_key *
ieee80211_crypto_encap(struct ieee80211com * ic,struct ieee80211_node * ni,struct mbuf * m)539a8560c32Smaxv ieee80211_crypto_encap(struct ieee80211com *ic, struct ieee80211_node *ni,
540a8560c32Smaxv     struct mbuf *m)
54190634029Sdyoung {
54290634029Sdyoung 	struct ieee80211_key *k;
54390634029Sdyoung 	struct ieee80211_frame *wh;
54490634029Sdyoung 	const struct ieee80211_cipher *cip;
545a8560c32Smaxv 	u_int8_t keyid, *hdr;
546a8560c32Smaxv 	int hdrlen;
54790634029Sdyoung 
54890634029Sdyoung 	/*
54990634029Sdyoung 	 * Multicast traffic always uses the multicast key.
55090634029Sdyoung 	 * Otherwise if a unicast key is set we use that and
55190634029Sdyoung 	 * it is always key index 0.  When no unicast key is
55290634029Sdyoung 	 * set we fall back to the default transmit key.
55390634029Sdyoung 	 */
55490634029Sdyoung 	wh = mtod(m, struct ieee80211_frame *);
55590634029Sdyoung 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
55690634029Sdyoung 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
55790634029Sdyoung 		if (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) {
55890634029Sdyoung 			IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
55990634029Sdyoung 			    "[%s] no default transmit key (%s) deftxkey %u\n",
56090634029Sdyoung 			    ether_sprintf(wh->i_addr1), __func__,
56190634029Sdyoung 			    ic->ic_def_txkey);
56290634029Sdyoung 			ic->ic_stats.is_tx_nodefkey++;
56387515e34Sskrll 			return NULL;
56490634029Sdyoung 		}
56590634029Sdyoung 		keyid = ic->ic_def_txkey;
56690634029Sdyoung 		k = &ic->ic_nw_keys[ic->ic_def_txkey];
56790634029Sdyoung 	} else {
56890634029Sdyoung 		keyid = 0;
56990634029Sdyoung 		k = &ni->ni_ucastkey;
57090634029Sdyoung 	}
57190634029Sdyoung 	cip = k->wk_cipher;
572a8560c32Smaxv 
573a8560c32Smaxv 	/*
574a8560c32Smaxv 	 * The crypto header is added after the IEEE802.11 header. Prepend
575a8560c32Smaxv 	 * the size of the crypto header, and move the IEEE802.11 header back
576a8560c32Smaxv 	 * to the beginning of the mbuf. Ensure everything is contiguous.
577a8560c32Smaxv 	 */
578a8560c32Smaxv 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
579a8560c32Smaxv 	M_PREPEND(m, cip->ic_header, M_NOWAIT);
580a8560c32Smaxv 	if (m && m->m_len < hdrlen + cip->ic_header) {
581a8560c32Smaxv 		m = m_pullup(m, hdrlen + cip->ic_header);
582a8560c32Smaxv 	}
583a8560c32Smaxv 	if (m == NULL) {
584a8560c32Smaxv 		return NULL;
585a8560c32Smaxv 	}
586a8560c32Smaxv 	hdr = mtod(m, u_int8_t *);
587a8560c32Smaxv 	memmove(hdr, hdr + cip->ic_header, hdrlen);
588a8560c32Smaxv 
58987515e34Sskrll 	return (cip->ic_encap(k, m, keyid<<6) ? k : NULL);
59040e261aaSdyoung }
59140e261aaSdyoung 
5929af01d3aSmaxv #define	IEEE80211_WEP_HDRLEN	(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
5939af01d3aSmaxv #define	IEEE80211_WEP_MINLEN \
5949af01d3aSmaxv 	(sizeof(struct ieee80211_frame) + \
5959af01d3aSmaxv 	IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
5969af01d3aSmaxv 
59740e261aaSdyoung /*
59890634029Sdyoung  * Validate and strip privacy headers (and trailer) for a
59990634029Sdyoung  * received frame that has the WEP/Privacy bit set.
60040e261aaSdyoung  */
60190634029Sdyoung struct ieee80211_key *
ieee80211_crypto_decap(struct ieee80211com * ic,struct ieee80211_node * ni,struct mbuf ** mp,int hdrlen)60290634029Sdyoung ieee80211_crypto_decap(struct ieee80211com *ic,
603fa370b63Smaxv     struct ieee80211_node *ni, struct mbuf **mp, int hdrlen)
60440e261aaSdyoung {
6059af01d3aSmaxv 	const struct ieee80211_cipher *cip;
60690634029Sdyoung 	struct ieee80211_key *k;
60790634029Sdyoung 	struct ieee80211_frame *wh;
608fa370b63Smaxv 	struct mbuf *m = *mp;
60990634029Sdyoung 	u_int8_t keyid;
61040e261aaSdyoung 
611671dd6e4Smaxv 	KASSERT((m->m_flags & M_PKTHDR) != 0);
612671dd6e4Smaxv 
613671dd6e4Smaxv 	/*
614671dd6e4Smaxv 	 * This minimum size data frame could be bigger. It is re-checked
615671dd6e4Smaxv 	 * below.
616671dd6e4Smaxv 	 */
61790634029Sdyoung 	if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
61890634029Sdyoung 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
61990634029Sdyoung 			"%s: WEP data frame too short, len %u\n",
62090634029Sdyoung 			__func__, m->m_pkthdr.len);
6219af01d3aSmaxv 		ic->ic_stats.is_rx_tooshort++;
62290634029Sdyoung 		return NULL;
62340e261aaSdyoung 	}
62440e261aaSdyoung 
62540e261aaSdyoung 	/*
62690634029Sdyoung 	 * Locate the key. If unicast and there is no unicast
62790634029Sdyoung 	 * key then we fall back to the key id in the header.
62890634029Sdyoung 	 * This assumes unicast keys are only configured when
62990634029Sdyoung 	 * the key id in the header is meaningless (typically 0).
63040e261aaSdyoung 	 */
63190634029Sdyoung 	wh = mtod(m, struct ieee80211_frame *);
632d339db42Sdyoung 	m_copydata(m, hdrlen + IEEE80211_WEP_IVLEN, sizeof(keyid), &keyid);
63390634029Sdyoung 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
6349af01d3aSmaxv 	    ni->ni_ucastkey.wk_cipher == &ieee80211_cipher_none) {
63590634029Sdyoung 		k = &ic->ic_nw_keys[keyid >> 6];
6369af01d3aSmaxv 	} else {
63790634029Sdyoung 		k = &ni->ni_ucastkey;
6389af01d3aSmaxv 	}
63940e261aaSdyoung 
64090634029Sdyoung 	/*
64190634029Sdyoung 	 * Insure crypto header is contiguous for all decap work.
64290634029Sdyoung 	 */
64390634029Sdyoung 	cip = k->wk_cipher;
6449af01d3aSmaxv 	if (m->m_len < hdrlen + cip->ic_header) {
6459af01d3aSmaxv 		m = m_pullup(m, hdrlen + cip->ic_header);
6469af01d3aSmaxv 		*mp = m;
6479af01d3aSmaxv 	}
6489af01d3aSmaxv 
6499af01d3aSmaxv 	if (m == NULL) {
650d1b4a5beSmaxv 		ic->ic_stats.is_rx_tooshort++;
651e16ddd31Sdyoung 		return NULL;
65290634029Sdyoung 	}
65340e261aaSdyoung 
654671dd6e4Smaxv 	/*
655671dd6e4Smaxv 	 * Ensure there is a header+trailer included.
656671dd6e4Smaxv 	 */
657671dd6e4Smaxv 	if (m->m_pkthdr.len < hdrlen + cip->ic_header + cip->ic_trailer) {
658671dd6e4Smaxv 		IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
659671dd6e4Smaxv 			"%s: WEP data frame too short, len %u\n",
660671dd6e4Smaxv 			__func__, m->m_pkthdr.len);
661671dd6e4Smaxv 		ic->ic_stats.is_rx_tooshort++;
662671dd6e4Smaxv 		return NULL;
663671dd6e4Smaxv 	}
664671dd6e4Smaxv 
665d2ba8780Sdyoung 	return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
66640e261aaSdyoung }
667