132176cfdSRui Paulo /*-
2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe
332176cfdSRui Paulo * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
4f186073cSJoerg Sonnenberger * All rights reserved.
5f186073cSJoerg Sonnenberger *
6f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
7f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions
8f186073cSJoerg Sonnenberger * are met:
9f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
10f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer.
11f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
12f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
13f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
14f186073cSJoerg Sonnenberger *
15f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25f186073cSJoerg Sonnenberger */
26f186073cSJoerg Sonnenberger
27085ff963SMatthew Dillon #include <sys/cdefs.h>
28085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
29085ff963SMatthew Dillon
30841ab66cSSepherosa Ziehau /*
31841ab66cSSepherosa Ziehau * IEEE 802.11 generic crypto support.
32841ab66cSSepherosa Ziehau */
3332176cfdSRui Paulo #include "opt_wlan.h"
3432176cfdSRui Paulo
35f186073cSJoerg Sonnenberger #include <sys/param.h>
3632176cfdSRui Paulo #include <sys/kernel.h>
3732176cfdSRui Paulo #include <sys/malloc.h>
38f186073cSJoerg Sonnenberger #include <sys/mbuf.h>
39f186073cSJoerg Sonnenberger
40841ab66cSSepherosa Ziehau #include <sys/socket.h>
41f186073cSJoerg Sonnenberger
42f186073cSJoerg Sonnenberger #include <net/if.h>
43*bff82488SAaron LI #include <net/if_var.h>
44841ab66cSSepherosa Ziehau #include <net/if_media.h>
45841ab66cSSepherosa Ziehau #include <net/ethernet.h> /* XXX ETHER_HDR_LEN */
46f186073cSJoerg Sonnenberger
47f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h>
48f186073cSJoerg Sonnenberger
4932176cfdSRui Paulo MALLOC_DEFINE(M_80211_CRYPTO, "80211crypto", "802.11 crypto state");
5032176cfdSRui Paulo
5132176cfdSRui Paulo static int _ieee80211_crypto_delkey(struct ieee80211vap *,
5232176cfdSRui Paulo struct ieee80211_key *);
5332176cfdSRui Paulo
54841ab66cSSepherosa Ziehau /*
55841ab66cSSepherosa Ziehau * Table of registered cipher modules.
56841ab66cSSepherosa Ziehau */
57841ab66cSSepherosa Ziehau static const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX];
58f186073cSJoerg Sonnenberger
59841ab66cSSepherosa Ziehau /*
60841ab66cSSepherosa Ziehau * Default "null" key management routines.
61841ab66cSSepherosa Ziehau */
62841ab66cSSepherosa Ziehau static int
null_key_alloc(struct ieee80211vap * vap,struct ieee80211_key * k,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)6332176cfdSRui Paulo null_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
64841ab66cSSepherosa Ziehau ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
65f186073cSJoerg Sonnenberger {
6632176cfdSRui Paulo if (!(&vap->iv_nw_keys[0] <= k &&
6732176cfdSRui Paulo k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
68841ab66cSSepherosa Ziehau /*
69841ab66cSSepherosa Ziehau * Not in the global key table, the driver should handle this
70841ab66cSSepherosa Ziehau * by allocating a slot in the h/w key table/cache. In
71841ab66cSSepherosa Ziehau * lieu of that return key slot 0 for any unicast key
72841ab66cSSepherosa Ziehau * request. We disallow the request if this is a group key.
73841ab66cSSepherosa Ziehau * This default policy does the right thing for legacy hardware
74841ab66cSSepherosa Ziehau * with a 4 key table. It also handles devices that pass
75841ab66cSSepherosa Ziehau * packets through untouched when marked with the WEP bit
76841ab66cSSepherosa Ziehau * and key index 0.
77841ab66cSSepherosa Ziehau */
78841ab66cSSepherosa Ziehau if (k->wk_flags & IEEE80211_KEY_GROUP)
79841ab66cSSepherosa Ziehau return 0;
80841ab66cSSepherosa Ziehau *keyix = 0; /* NB: use key index 0 for ucast key */
81841ab66cSSepherosa Ziehau } else {
8232176cfdSRui Paulo *keyix = k - vap->iv_nw_keys;
83841ab66cSSepherosa Ziehau }
84841ab66cSSepherosa Ziehau *rxkeyix = IEEE80211_KEYIX_NONE; /* XXX maybe *keyix? */
85841ab66cSSepherosa Ziehau return 1;
86841ab66cSSepherosa Ziehau }
87841ab66cSSepherosa Ziehau static int
null_key_delete(struct ieee80211vap * vap,const struct ieee80211_key * k)8832176cfdSRui Paulo null_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
89841ab66cSSepherosa Ziehau {
90841ab66cSSepherosa Ziehau return 1;
91841ab66cSSepherosa Ziehau }
92841ab66cSSepherosa Ziehau static int
null_key_set(struct ieee80211vap * vap,const struct ieee80211_key * k)934f655ef5SMatthew Dillon null_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
94841ab66cSSepherosa Ziehau {
95841ab66cSSepherosa Ziehau return 1;
96841ab66cSSepherosa Ziehau }
null_key_update(struct ieee80211vap * vap)9732176cfdSRui Paulo static void null_key_update(struct ieee80211vap *vap) {}
98841ab66cSSepherosa Ziehau
99841ab66cSSepherosa Ziehau /*
100841ab66cSSepherosa Ziehau * Write-arounds for common operations.
101841ab66cSSepherosa Ziehau */
102841ab66cSSepherosa Ziehau static __inline void
cipher_detach(struct ieee80211_key * key)103841ab66cSSepherosa Ziehau cipher_detach(struct ieee80211_key *key)
104841ab66cSSepherosa Ziehau {
105841ab66cSSepherosa Ziehau key->wk_cipher->ic_detach(key);
106841ab66cSSepherosa Ziehau }
107841ab66cSSepherosa Ziehau
108841ab66cSSepherosa Ziehau static __inline void *
cipher_attach(struct ieee80211vap * vap,struct ieee80211_key * key)10932176cfdSRui Paulo cipher_attach(struct ieee80211vap *vap, struct ieee80211_key *key)
110841ab66cSSepherosa Ziehau {
11132176cfdSRui Paulo return key->wk_cipher->ic_attach(vap, key);
112841ab66cSSepherosa Ziehau }
113841ab66cSSepherosa Ziehau
114841ab66cSSepherosa Ziehau /*
115841ab66cSSepherosa Ziehau * Wrappers for driver key management methods.
116841ab66cSSepherosa Ziehau */
117841ab66cSSepherosa Ziehau static __inline int
dev_key_alloc(struct ieee80211vap * vap,struct ieee80211_key * key,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)11832176cfdSRui Paulo dev_key_alloc(struct ieee80211vap *vap,
11932176cfdSRui Paulo struct ieee80211_key *key,
120841ab66cSSepherosa Ziehau ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
121841ab66cSSepherosa Ziehau {
12232176cfdSRui Paulo return vap->iv_key_alloc(vap, key, keyix, rxkeyix);
123841ab66cSSepherosa Ziehau }
124841ab66cSSepherosa Ziehau
125841ab66cSSepherosa Ziehau static __inline int
dev_key_delete(struct ieee80211vap * vap,const struct ieee80211_key * key)12632176cfdSRui Paulo dev_key_delete(struct ieee80211vap *vap,
127841ab66cSSepherosa Ziehau const struct ieee80211_key *key)
128841ab66cSSepherosa Ziehau {
12932176cfdSRui Paulo return vap->iv_key_delete(vap, key);
130841ab66cSSepherosa Ziehau }
131841ab66cSSepherosa Ziehau
132841ab66cSSepherosa Ziehau static __inline int
dev_key_set(struct ieee80211vap * vap,const struct ieee80211_key * key)13332176cfdSRui Paulo dev_key_set(struct ieee80211vap *vap, const struct ieee80211_key *key)
134841ab66cSSepherosa Ziehau {
1354f655ef5SMatthew Dillon return vap->iv_key_set(vap, key);
136841ab66cSSepherosa Ziehau }
137f186073cSJoerg Sonnenberger
138f186073cSJoerg Sonnenberger /*
13932176cfdSRui Paulo * Setup crypto support for a device/shared instance.
140f186073cSJoerg Sonnenberger */
141f186073cSJoerg Sonnenberger void
ieee80211_crypto_attach(struct ieee80211com * ic)142841ab66cSSepherosa Ziehau ieee80211_crypto_attach(struct ieee80211com *ic)
143f186073cSJoerg Sonnenberger {
144841ab66cSSepherosa Ziehau /* NB: we assume everything is pre-zero'd */
145841ab66cSSepherosa Ziehau ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none;
146f186073cSJoerg Sonnenberger }
147f186073cSJoerg Sonnenberger
148841ab66cSSepherosa Ziehau /*
149841ab66cSSepherosa Ziehau * Teardown crypto support.
150841ab66cSSepherosa Ziehau */
151841ab66cSSepherosa Ziehau void
ieee80211_crypto_detach(struct ieee80211com * ic)152841ab66cSSepherosa Ziehau ieee80211_crypto_detach(struct ieee80211com *ic)
153841ab66cSSepherosa Ziehau {
15432176cfdSRui Paulo }
15532176cfdSRui Paulo
15632176cfdSRui Paulo /*
15732176cfdSRui Paulo * Setup crypto support for a vap.
15832176cfdSRui Paulo */
15932176cfdSRui Paulo void
ieee80211_crypto_vattach(struct ieee80211vap * vap)16032176cfdSRui Paulo ieee80211_crypto_vattach(struct ieee80211vap *vap)
16132176cfdSRui Paulo {
16232176cfdSRui Paulo int i;
16332176cfdSRui Paulo
16432176cfdSRui Paulo /* NB: we assume everything is pre-zero'd */
16532176cfdSRui Paulo vap->iv_max_keyix = IEEE80211_WEP_NKID;
16632176cfdSRui Paulo vap->iv_def_txkey = IEEE80211_KEYIX_NONE;
16732176cfdSRui Paulo for (i = 0; i < IEEE80211_WEP_NKID; i++)
16832176cfdSRui Paulo ieee80211_crypto_resetkey(vap, &vap->iv_nw_keys[i],
16932176cfdSRui Paulo IEEE80211_KEYIX_NONE);
17032176cfdSRui Paulo /*
17132176cfdSRui Paulo * Initialize the driver key support routines to noop entries.
17232176cfdSRui Paulo * This is useful especially for the cipher test modules.
17332176cfdSRui Paulo */
17432176cfdSRui Paulo vap->iv_key_alloc = null_key_alloc;
17532176cfdSRui Paulo vap->iv_key_set = null_key_set;
17632176cfdSRui Paulo vap->iv_key_delete = null_key_delete;
17732176cfdSRui Paulo vap->iv_key_update_begin = null_key_update;
17832176cfdSRui Paulo vap->iv_key_update_end = null_key_update;
17932176cfdSRui Paulo }
18032176cfdSRui Paulo
18132176cfdSRui Paulo /*
18232176cfdSRui Paulo * Teardown crypto support for a vap.
18332176cfdSRui Paulo */
18432176cfdSRui Paulo void
ieee80211_crypto_vdetach(struct ieee80211vap * vap)18532176cfdSRui Paulo ieee80211_crypto_vdetach(struct ieee80211vap *vap)
18632176cfdSRui Paulo {
18732176cfdSRui Paulo ieee80211_crypto_delglobalkeys(vap);
188f186073cSJoerg Sonnenberger }
189f186073cSJoerg Sonnenberger
190841ab66cSSepherosa Ziehau /*
191841ab66cSSepherosa Ziehau * Register a crypto cipher module.
192841ab66cSSepherosa Ziehau */
193841ab66cSSepherosa Ziehau void
ieee80211_crypto_register(const struct ieee80211_cipher * cip)194841ab66cSSepherosa Ziehau ieee80211_crypto_register(const struct ieee80211_cipher *cip)
195841ab66cSSepherosa Ziehau {
196841ab66cSSepherosa Ziehau if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
197a6ec04bcSSascha Wildner kprintf("%s: cipher %s has an invalid cipher index %u\n",
198841ab66cSSepherosa Ziehau __func__, cip->ic_name, cip->ic_cipher);
199841ab66cSSepherosa Ziehau return;
200841ab66cSSepherosa Ziehau }
201841ab66cSSepherosa Ziehau if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
202a6ec04bcSSascha Wildner kprintf("%s: cipher %s registered with a different template\n",
203841ab66cSSepherosa Ziehau __func__, cip->ic_name);
204841ab66cSSepherosa Ziehau return;
205841ab66cSSepherosa Ziehau }
206841ab66cSSepherosa Ziehau ciphers[cip->ic_cipher] = cip;
207841ab66cSSepherosa Ziehau }
208841ab66cSSepherosa Ziehau
209841ab66cSSepherosa Ziehau /*
210841ab66cSSepherosa Ziehau * Unregister a crypto cipher module.
211841ab66cSSepherosa Ziehau */
212841ab66cSSepherosa Ziehau void
ieee80211_crypto_unregister(const struct ieee80211_cipher * cip)213841ab66cSSepherosa Ziehau ieee80211_crypto_unregister(const struct ieee80211_cipher *cip)
214841ab66cSSepherosa Ziehau {
215841ab66cSSepherosa Ziehau if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) {
216a6ec04bcSSascha Wildner kprintf("%s: cipher %s has an invalid cipher index %u\n",
217841ab66cSSepherosa Ziehau __func__, cip->ic_name, cip->ic_cipher);
218841ab66cSSepherosa Ziehau return;
219841ab66cSSepherosa Ziehau }
220841ab66cSSepherosa Ziehau if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) {
221a6ec04bcSSascha Wildner kprintf("%s: cipher %s registered with a different template\n",
222841ab66cSSepherosa Ziehau __func__, cip->ic_name);
223841ab66cSSepherosa Ziehau return;
224841ab66cSSepherosa Ziehau }
225841ab66cSSepherosa Ziehau /* NB: don't complain about not being registered */
226841ab66cSSepherosa Ziehau /* XXX disallow if references */
227841ab66cSSepherosa Ziehau ciphers[cip->ic_cipher] = NULL;
228841ab66cSSepherosa Ziehau }
229841ab66cSSepherosa Ziehau
230841ab66cSSepherosa Ziehau int
ieee80211_crypto_available(u_int cipher)231841ab66cSSepherosa Ziehau ieee80211_crypto_available(u_int cipher)
232841ab66cSSepherosa Ziehau {
233841ab66cSSepherosa Ziehau return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL;
234841ab66cSSepherosa Ziehau }
235841ab66cSSepherosa Ziehau
236841ab66cSSepherosa Ziehau /* XXX well-known names! */
23732176cfdSRui Paulo static const char *cipher_modnames[IEEE80211_CIPHER_MAX] = {
23832176cfdSRui Paulo [IEEE80211_CIPHER_WEP] = "wlan_wep",
23932176cfdSRui Paulo [IEEE80211_CIPHER_TKIP] = "wlan_tkip",
24032176cfdSRui Paulo [IEEE80211_CIPHER_AES_OCB] = "wlan_aes_ocb",
24132176cfdSRui Paulo [IEEE80211_CIPHER_AES_CCM] = "wlan_ccmp",
24232176cfdSRui Paulo [IEEE80211_CIPHER_TKIPMIC] = "#4", /* NB: reserved */
24332176cfdSRui Paulo [IEEE80211_CIPHER_CKIP] = "wlan_ckip",
24432176cfdSRui Paulo [IEEE80211_CIPHER_NONE] = "wlan_none",
245841ab66cSSepherosa Ziehau };
246841ab66cSSepherosa Ziehau
24732176cfdSRui Paulo /* NB: there must be no overlap between user-supplied and device-owned flags */
24832176cfdSRui Paulo CTASSERT((IEEE80211_KEY_COMMON & IEEE80211_KEY_DEVICE) == 0);
24932176cfdSRui Paulo
250841ab66cSSepherosa Ziehau /*
251841ab66cSSepherosa Ziehau * Establish a relationship between the specified key and cipher
252841ab66cSSepherosa Ziehau * and, if necessary, allocate a hardware index from the driver.
25332176cfdSRui Paulo * Note that when a fixed key index is required it must be specified.
254841ab66cSSepherosa Ziehau *
255841ab66cSSepherosa Ziehau * This must be the first call applied to a key; all the other key
256841ab66cSSepherosa Ziehau * routines assume wk_cipher is setup.
257841ab66cSSepherosa Ziehau *
258841ab66cSSepherosa Ziehau * Locking must be handled by the caller using:
25932176cfdSRui Paulo * ieee80211_key_update_begin(vap);
26032176cfdSRui Paulo * ieee80211_key_update_end(vap);
261841ab66cSSepherosa Ziehau */
262841ab66cSSepherosa Ziehau int
ieee80211_crypto_newkey(struct ieee80211vap * vap,int cipher,int flags,struct ieee80211_key * key)26332176cfdSRui Paulo ieee80211_crypto_newkey(struct ieee80211vap *vap,
264841ab66cSSepherosa Ziehau int cipher, int flags, struct ieee80211_key *key)
265841ab66cSSepherosa Ziehau {
26632176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic;
267841ab66cSSepherosa Ziehau const struct ieee80211_cipher *cip;
268841ab66cSSepherosa Ziehau ieee80211_keyix keyix, rxkeyix;
269841ab66cSSepherosa Ziehau void *keyctx;
270841ab66cSSepherosa Ziehau int oflags;
271841ab66cSSepherosa Ziehau
27232176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
27332176cfdSRui Paulo "%s: cipher %u flags 0x%x keyix %u\n",
27432176cfdSRui Paulo __func__, cipher, flags, key->wk_keyix);
27532176cfdSRui Paulo
276841ab66cSSepherosa Ziehau /*
277841ab66cSSepherosa Ziehau * Validate cipher and set reference to cipher routines.
278841ab66cSSepherosa Ziehau */
279841ab66cSSepherosa Ziehau if (cipher >= IEEE80211_CIPHER_MAX) {
28032176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
281841ab66cSSepherosa Ziehau "%s: invalid cipher %u\n", __func__, cipher);
28232176cfdSRui Paulo vap->iv_stats.is_crypto_badcipher++;
283841ab66cSSepherosa Ziehau return 0;
284841ab66cSSepherosa Ziehau }
285841ab66cSSepherosa Ziehau cip = ciphers[cipher];
286841ab66cSSepherosa Ziehau if (cip == NULL) {
287841ab66cSSepherosa Ziehau /*
288841ab66cSSepherosa Ziehau * Auto-load cipher module if we have a well-known name
289841ab66cSSepherosa Ziehau * for it. It might be better to use string names rather
290841ab66cSSepherosa Ziehau * than numbers and craft a module name based on the cipher
291841ab66cSSepherosa Ziehau * name; e.g. wlan_cipher_<cipher-name>.
292841ab66cSSepherosa Ziehau */
29332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
294841ab66cSSepherosa Ziehau "%s: unregistered cipher %u, load module %s\n",
295841ab66cSSepherosa Ziehau __func__, cipher, cipher_modnames[cipher]);
296841ab66cSSepherosa Ziehau ieee80211_load_module(cipher_modnames[cipher]);
297841ab66cSSepherosa Ziehau /*
298841ab66cSSepherosa Ziehau * If cipher module loaded it should immediately
299841ab66cSSepherosa Ziehau * call ieee80211_crypto_register which will fill
300841ab66cSSepherosa Ziehau * in the entry in the ciphers array.
301841ab66cSSepherosa Ziehau */
302841ab66cSSepherosa Ziehau cip = ciphers[cipher];
303841ab66cSSepherosa Ziehau if (cip == NULL) {
30432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
305841ab66cSSepherosa Ziehau "%s: unable to load cipher %u, module %s\n",
30632176cfdSRui Paulo __func__, cipher, cipher_modnames[cipher]);
30732176cfdSRui Paulo vap->iv_stats.is_crypto_nocipher++;
308841ab66cSSepherosa Ziehau return 0;
309841ab66cSSepherosa Ziehau }
310841ab66cSSepherosa Ziehau }
311841ab66cSSepherosa Ziehau
312841ab66cSSepherosa Ziehau oflags = key->wk_flags;
313841ab66cSSepherosa Ziehau flags &= IEEE80211_KEY_COMMON;
31432176cfdSRui Paulo /* NB: preserve device attributes */
31532176cfdSRui Paulo flags |= (oflags & IEEE80211_KEY_DEVICE);
316841ab66cSSepherosa Ziehau /*
317841ab66cSSepherosa Ziehau * If the hardware does not support the cipher then
318841ab66cSSepherosa Ziehau * fallback to a host-based implementation.
319841ab66cSSepherosa Ziehau */
32032176cfdSRui Paulo if ((ic->ic_cryptocaps & (1<<cipher)) == 0) {
32132176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
322841ab66cSSepherosa Ziehau "%s: no h/w support for cipher %s, falling back to s/w\n",
323841ab66cSSepherosa Ziehau __func__, cip->ic_name);
324841ab66cSSepherosa Ziehau flags |= IEEE80211_KEY_SWCRYPT;
325841ab66cSSepherosa Ziehau }
326841ab66cSSepherosa Ziehau /*
327841ab66cSSepherosa Ziehau * Hardware TKIP with software MIC is an important
328841ab66cSSepherosa Ziehau * combination; we handle it by flagging each key,
329841ab66cSSepherosa Ziehau * the cipher modules honor it.
330841ab66cSSepherosa Ziehau */
331841ab66cSSepherosa Ziehau if (cipher == IEEE80211_CIPHER_TKIP &&
33232176cfdSRui Paulo (ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIPMIC) == 0) {
33332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
334841ab66cSSepherosa Ziehau "%s: no h/w support for TKIP MIC, falling back to s/w\n",
335841ab66cSSepherosa Ziehau __func__);
336841ab66cSSepherosa Ziehau flags |= IEEE80211_KEY_SWMIC;
337841ab66cSSepherosa Ziehau }
338841ab66cSSepherosa Ziehau
339841ab66cSSepherosa Ziehau /*
340841ab66cSSepherosa Ziehau * Bind cipher to key instance. Note we do this
341841ab66cSSepherosa Ziehau * after checking the device capabilities so the
342841ab66cSSepherosa Ziehau * cipher module can optimize space usage based on
343841ab66cSSepherosa Ziehau * whether or not it needs to do the cipher work.
344841ab66cSSepherosa Ziehau */
345841ab66cSSepherosa Ziehau if (key->wk_cipher != cip || key->wk_flags != flags) {
346841ab66cSSepherosa Ziehau /*
347841ab66cSSepherosa Ziehau * Fillin the flags so cipher modules can see s/w
348841ab66cSSepherosa Ziehau * crypto requirements and potentially allocate
349841ab66cSSepherosa Ziehau * different state and/or attach different method
350841ab66cSSepherosa Ziehau * pointers.
351841ab66cSSepherosa Ziehau */
352841ab66cSSepherosa Ziehau key->wk_flags = flags;
35332176cfdSRui Paulo keyctx = cip->ic_attach(vap, key);
354841ab66cSSepherosa Ziehau if (keyctx == NULL) {
35532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
356841ab66cSSepherosa Ziehau "%s: unable to attach cipher %s\n",
357841ab66cSSepherosa Ziehau __func__, cip->ic_name);
358841ab66cSSepherosa Ziehau key->wk_flags = oflags; /* restore old flags */
35932176cfdSRui Paulo vap->iv_stats.is_crypto_attachfail++;
360841ab66cSSepherosa Ziehau return 0;
361841ab66cSSepherosa Ziehau }
36232176cfdSRui Paulo cipher_detach(key);
363841ab66cSSepherosa Ziehau key->wk_cipher = cip; /* XXX refcnt? */
364841ab66cSSepherosa Ziehau key->wk_private = keyctx;
365841ab66cSSepherosa Ziehau }
366841ab66cSSepherosa Ziehau
367841ab66cSSepherosa Ziehau /*
368841ab66cSSepherosa Ziehau * Ask the driver for a key index if we don't have one.
369841ab66cSSepherosa Ziehau * Note that entries in the global key table always have
370841ab66cSSepherosa Ziehau * an index; this means it's safe to call this routine
371841ab66cSSepherosa Ziehau * for these entries just to setup the reference to the
372841ab66cSSepherosa Ziehau * cipher template. Note also that when using software
373841ab66cSSepherosa Ziehau * crypto we also call the driver to give us a key index.
374841ab66cSSepherosa Ziehau */
37532176cfdSRui Paulo if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) {
37632176cfdSRui Paulo if (!dev_key_alloc(vap, key, &keyix, &rxkeyix)) {
377841ab66cSSepherosa Ziehau /*
37832176cfdSRui Paulo * Unable to setup driver state.
379841ab66cSSepherosa Ziehau */
38032176cfdSRui Paulo vap->iv_stats.is_crypto_keyfail++;
38132176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
382841ab66cSSepherosa Ziehau "%s: unable to setup cipher %s\n",
383841ab66cSSepherosa Ziehau __func__, cip->ic_name);
384841ab66cSSepherosa Ziehau return 0;
385841ab66cSSepherosa Ziehau }
38632176cfdSRui Paulo if (key->wk_flags != flags) {
38732176cfdSRui Paulo /*
38832176cfdSRui Paulo * Driver overrode flags we setup; typically because
38932176cfdSRui Paulo * resources were unavailable to handle _this_ key.
39032176cfdSRui Paulo * Re-attach the cipher context to allow cipher
39132176cfdSRui Paulo * modules to handle differing requirements.
39232176cfdSRui Paulo */
39332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
39432176cfdSRui Paulo "%s: driver override for cipher %s, flags "
39532176cfdSRui Paulo "0x%x -> 0x%x\n", __func__, cip->ic_name,
39632176cfdSRui Paulo oflags, key->wk_flags);
39732176cfdSRui Paulo keyctx = cip->ic_attach(vap, key);
39832176cfdSRui Paulo if (keyctx == NULL) {
39932176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
40032176cfdSRui Paulo "%s: unable to attach cipher %s with "
40132176cfdSRui Paulo "flags 0x%x\n", __func__, cip->ic_name,
40232176cfdSRui Paulo key->wk_flags);
40332176cfdSRui Paulo key->wk_flags = oflags; /* restore old flags */
40432176cfdSRui Paulo vap->iv_stats.is_crypto_attachfail++;
40532176cfdSRui Paulo return 0;
40632176cfdSRui Paulo }
40732176cfdSRui Paulo cipher_detach(key);
40832176cfdSRui Paulo key->wk_cipher = cip; /* XXX refcnt? */
40932176cfdSRui Paulo key->wk_private = keyctx;
41032176cfdSRui Paulo }
411841ab66cSSepherosa Ziehau key->wk_keyix = keyix;
412841ab66cSSepherosa Ziehau key->wk_rxkeyix = rxkeyix;
41332176cfdSRui Paulo key->wk_flags |= IEEE80211_KEY_DEVKEY;
414841ab66cSSepherosa Ziehau }
415841ab66cSSepherosa Ziehau return 1;
416841ab66cSSepherosa Ziehau }
417841ab66cSSepherosa Ziehau
418841ab66cSSepherosa Ziehau /*
419841ab66cSSepherosa Ziehau * Remove the key (no locking, for internal use).
420841ab66cSSepherosa Ziehau */
421841ab66cSSepherosa Ziehau static int
_ieee80211_crypto_delkey(struct ieee80211vap * vap,struct ieee80211_key * key)42232176cfdSRui Paulo _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
423841ab66cSSepherosa Ziehau {
424841ab66cSSepherosa Ziehau KASSERT(key->wk_cipher != NULL, ("No cipher!"));
425841ab66cSSepherosa Ziehau
42632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
427841ab66cSSepherosa Ziehau "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n",
428841ab66cSSepherosa Ziehau __func__, key->wk_cipher->ic_name,
429841ab66cSSepherosa Ziehau key->wk_keyix, key->wk_flags,
43032176cfdSRui Paulo key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
43132176cfdSRui Paulo key->wk_keylen);
432841ab66cSSepherosa Ziehau
43332176cfdSRui Paulo if (key->wk_flags & IEEE80211_KEY_DEVKEY) {
434841ab66cSSepherosa Ziehau /*
435841ab66cSSepherosa Ziehau * Remove hardware entry.
436841ab66cSSepherosa Ziehau */
437841ab66cSSepherosa Ziehau /* XXX key cache */
43832176cfdSRui Paulo if (!dev_key_delete(vap, key)) {
43932176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
440841ab66cSSepherosa Ziehau "%s: driver did not delete key index %u\n",
44132176cfdSRui Paulo __func__, key->wk_keyix);
44232176cfdSRui Paulo vap->iv_stats.is_crypto_delkey++;
443841ab66cSSepherosa Ziehau /* XXX recovery? */
444841ab66cSSepherosa Ziehau }
445841ab66cSSepherosa Ziehau }
446841ab66cSSepherosa Ziehau cipher_detach(key);
447841ab66cSSepherosa Ziehau memset(key, 0, sizeof(*key));
44832176cfdSRui Paulo ieee80211_crypto_resetkey(vap, key, IEEE80211_KEYIX_NONE);
449841ab66cSSepherosa Ziehau return 1;
450841ab66cSSepherosa Ziehau }
451841ab66cSSepherosa Ziehau
452841ab66cSSepherosa Ziehau /*
453841ab66cSSepherosa Ziehau * Remove the specified key.
454841ab66cSSepherosa Ziehau */
455841ab66cSSepherosa Ziehau int
ieee80211_crypto_delkey(struct ieee80211vap * vap,struct ieee80211_key * key)45632176cfdSRui Paulo ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key)
457841ab66cSSepherosa Ziehau {
458841ab66cSSepherosa Ziehau int status;
459841ab66cSSepherosa Ziehau
46032176cfdSRui Paulo ieee80211_key_update_begin(vap);
46132176cfdSRui Paulo status = _ieee80211_crypto_delkey(vap, key);
46232176cfdSRui Paulo ieee80211_key_update_end(vap);
463841ab66cSSepherosa Ziehau return status;
464841ab66cSSepherosa Ziehau }
465841ab66cSSepherosa Ziehau
466841ab66cSSepherosa Ziehau /*
467841ab66cSSepherosa Ziehau * Clear the global key table.
468841ab66cSSepherosa Ziehau */
469841ab66cSSepherosa Ziehau void
ieee80211_crypto_delglobalkeys(struct ieee80211vap * vap)47032176cfdSRui Paulo ieee80211_crypto_delglobalkeys(struct ieee80211vap *vap)
471841ab66cSSepherosa Ziehau {
472841ab66cSSepherosa Ziehau int i;
473841ab66cSSepherosa Ziehau
47432176cfdSRui Paulo ieee80211_key_update_begin(vap);
475841ab66cSSepherosa Ziehau for (i = 0; i < IEEE80211_WEP_NKID; i++)
47632176cfdSRui Paulo (void) _ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[i]);
47732176cfdSRui Paulo ieee80211_key_update_end(vap);
478841ab66cSSepherosa Ziehau }
479841ab66cSSepherosa Ziehau
480841ab66cSSepherosa Ziehau /*
481841ab66cSSepherosa Ziehau * Set the contents of the specified key.
482841ab66cSSepherosa Ziehau *
483841ab66cSSepherosa Ziehau * Locking must be handled by the caller using:
48432176cfdSRui Paulo * ieee80211_key_update_begin(vap);
48532176cfdSRui Paulo * ieee80211_key_update_end(vap);
486841ab66cSSepherosa Ziehau */
487841ab66cSSepherosa Ziehau int
ieee80211_crypto_setkey(struct ieee80211vap * vap,struct ieee80211_key * key)48832176cfdSRui Paulo ieee80211_crypto_setkey(struct ieee80211vap *vap, struct ieee80211_key *key)
489841ab66cSSepherosa Ziehau {
490841ab66cSSepherosa Ziehau const struct ieee80211_cipher *cip = key->wk_cipher;
491841ab66cSSepherosa Ziehau
492841ab66cSSepherosa Ziehau KASSERT(cip != NULL, ("No cipher!"));
493841ab66cSSepherosa Ziehau
49432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
4951e290df3SAntonio Huete Jimenez "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n",
496841ab66cSSepherosa Ziehau __func__, cip->ic_name, key->wk_keyix,
497085ff963SMatthew Dillon key->wk_flags, ether_sprintf(key->wk_macaddr),
49832176cfdSRui Paulo key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc,
49932176cfdSRui Paulo key->wk_keylen);
500841ab66cSSepherosa Ziehau
50132176cfdSRui Paulo if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) {
50232176cfdSRui Paulo /* XXX nothing allocated, should not happen */
50332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
50432176cfdSRui Paulo "%s: no device key setup done; should not happen!\n",
50532176cfdSRui Paulo __func__);
50632176cfdSRui Paulo vap->iv_stats.is_crypto_setkey_nokey++;
50732176cfdSRui Paulo return 0;
50832176cfdSRui Paulo }
509841ab66cSSepherosa Ziehau /*
510841ab66cSSepherosa Ziehau * Give cipher a chance to validate key contents.
511841ab66cSSepherosa Ziehau * XXX should happen before modifying state.
512841ab66cSSepherosa Ziehau */
513841ab66cSSepherosa Ziehau if (!cip->ic_setkey(key)) {
51432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO,
515841ab66cSSepherosa Ziehau "%s: cipher %s rejected key index %u len %u flags 0x%x\n",
516841ab66cSSepherosa Ziehau __func__, cip->ic_name, key->wk_keyix,
517841ab66cSSepherosa Ziehau key->wk_keylen, key->wk_flags);
51832176cfdSRui Paulo vap->iv_stats.is_crypto_setkey_cipher++;
519841ab66cSSepherosa Ziehau return 0;
520841ab66cSSepherosa Ziehau }
52132176cfdSRui Paulo return dev_key_set(vap, key);
522841ab66cSSepherosa Ziehau }
523841ab66cSSepherosa Ziehau
5244f655ef5SMatthew Dillon uint8_t
ieee80211_crypto_get_keyid(struct ieee80211vap * vap,struct ieee80211_key * k)5254f655ef5SMatthew Dillon ieee80211_crypto_get_keyid(struct ieee80211vap *vap, struct ieee80211_key *k)
5264f655ef5SMatthew Dillon {
5274f655ef5SMatthew Dillon if (k >= &vap->iv_nw_keys[0] &&
5284f655ef5SMatthew Dillon k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])
5294f655ef5SMatthew Dillon return (k - vap->iv_nw_keys);
5304f655ef5SMatthew Dillon else
5314f655ef5SMatthew Dillon return (0);
5324f655ef5SMatthew Dillon }
5334f655ef5SMatthew Dillon
534841ab66cSSepherosa Ziehau struct ieee80211_key *
ieee80211_crypto_get_txkey(struct ieee80211_node * ni,struct mbuf * m)5354f655ef5SMatthew Dillon ieee80211_crypto_get_txkey(struct ieee80211_node *ni, struct mbuf *m)
536841ab66cSSepherosa Ziehau {
53732176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap;
538841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
539841ab66cSSepherosa Ziehau
540841ab66cSSepherosa Ziehau /*
541841ab66cSSepherosa Ziehau * Multicast traffic always uses the multicast key.
542841ab66cSSepherosa Ziehau * Otherwise if a unicast key is set we use that and
543841ab66cSSepherosa Ziehau * it is always key index 0. When no unicast key is
544841ab66cSSepherosa Ziehau * set we fall back to the default transmit key.
545841ab66cSSepherosa Ziehau */
546841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
547841ab66cSSepherosa Ziehau if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
54832176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) {
54932176cfdSRui Paulo if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE) {
55032176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
55132176cfdSRui Paulo wh->i_addr1,
55232176cfdSRui Paulo "no default transmit key (%s) deftxkey %u",
55332176cfdSRui Paulo __func__, vap->iv_def_txkey);
55432176cfdSRui Paulo vap->iv_stats.is_tx_nodefkey++;
555841ab66cSSepherosa Ziehau return NULL;
556841ab66cSSepherosa Ziehau }
5574f655ef5SMatthew Dillon return &vap->iv_nw_keys[vap->iv_def_txkey];
558841ab66cSSepherosa Ziehau }
5594f655ef5SMatthew Dillon
5604f655ef5SMatthew Dillon return &ni->ni_ucastkey;
5614f655ef5SMatthew Dillon }
5624f655ef5SMatthew Dillon
5634f655ef5SMatthew Dillon /*
5644f655ef5SMatthew Dillon * Add privacy headers appropriate for the specified key.
5654f655ef5SMatthew Dillon */
5664f655ef5SMatthew Dillon struct ieee80211_key *
ieee80211_crypto_encap(struct ieee80211_node * ni,struct mbuf * m)5674f655ef5SMatthew Dillon ieee80211_crypto_encap(struct ieee80211_node *ni, struct mbuf *m)
5684f655ef5SMatthew Dillon {
5694f655ef5SMatthew Dillon struct ieee80211_key *k;
5704f655ef5SMatthew Dillon const struct ieee80211_cipher *cip;
5714f655ef5SMatthew Dillon
5724f655ef5SMatthew Dillon if ((k = ieee80211_crypto_get_txkey(ni, m)) != NULL) {
57332176cfdSRui Paulo cip = k->wk_cipher;
5744f655ef5SMatthew Dillon return (cip->ic_encap(k, m) ? k : NULL);
5754f655ef5SMatthew Dillon }
5764f655ef5SMatthew Dillon
5774f655ef5SMatthew Dillon return NULL;
578841ab66cSSepherosa Ziehau }
579841ab66cSSepherosa Ziehau
580841ab66cSSepherosa Ziehau /*
581841ab66cSSepherosa Ziehau * Validate and strip privacy headers (and trailer) for a
582841ab66cSSepherosa Ziehau * received frame that has the WEP/Privacy bit set.
583841ab66cSSepherosa Ziehau */
584841ab66cSSepherosa Ziehau struct ieee80211_key *
ieee80211_crypto_decap(struct ieee80211_node * ni,struct mbuf * m,int hdrlen)58532176cfdSRui Paulo ieee80211_crypto_decap(struct ieee80211_node *ni, struct mbuf *m, int hdrlen)
586841ab66cSSepherosa Ziehau {
587841ab66cSSepherosa Ziehau #define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
588841ab66cSSepherosa Ziehau #define IEEE80211_WEP_MINLEN \
589841ab66cSSepherosa Ziehau (sizeof(struct ieee80211_frame) + \
590841ab66cSSepherosa Ziehau IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
59132176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap;
592841ab66cSSepherosa Ziehau struct ieee80211_key *k;
593841ab66cSSepherosa Ziehau struct ieee80211_frame *wh;
594841ab66cSSepherosa Ziehau const struct ieee80211_cipher *cip;
595841ab66cSSepherosa Ziehau uint8_t keyid;
596841ab66cSSepherosa Ziehau
597841ab66cSSepherosa Ziehau /* NB: this minimum size data frame could be bigger */
598841ab66cSSepherosa Ziehau if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) {
59932176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
600841ab66cSSepherosa Ziehau "%s: WEP data frame too short, len %u\n",
601841ab66cSSepherosa Ziehau __func__, m->m_pkthdr.len);
60232176cfdSRui Paulo vap->iv_stats.is_rx_tooshort++; /* XXX need unique stat? */
603f186073cSJoerg Sonnenberger return NULL;
604f186073cSJoerg Sonnenberger }
605f186073cSJoerg Sonnenberger
606f186073cSJoerg Sonnenberger /*
607841ab66cSSepherosa Ziehau * Locate the key. If unicast and there is no unicast
608841ab66cSSepherosa Ziehau * key then we fall back to the key id in the header.
609841ab66cSSepherosa Ziehau * This assumes unicast keys are only configured when
610841ab66cSSepherosa Ziehau * the key id in the header is meaningless (typically 0).
611f186073cSJoerg Sonnenberger */
612841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *);
61332176cfdSRui Paulo m_copydata(m, hdrlen + IEEE80211_WEP_IVLEN, sizeof(keyid), &keyid);
614841ab66cSSepherosa Ziehau if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
61532176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey))
61632176cfdSRui Paulo k = &vap->iv_nw_keys[keyid >> 6];
617f186073cSJoerg Sonnenberger else
618841ab66cSSepherosa Ziehau k = &ni->ni_ucastkey;
619f186073cSJoerg Sonnenberger
620f186073cSJoerg Sonnenberger /*
621841ab66cSSepherosa Ziehau * Insure crypto header is contiguous for all decap work.
622f186073cSJoerg Sonnenberger */
623841ab66cSSepherosa Ziehau cip = k->wk_cipher;
624841ab66cSSepherosa Ziehau if (m->m_len < hdrlen + cip->ic_header &&
625841ab66cSSepherosa Ziehau (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) {
62632176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
62732176cfdSRui Paulo "unable to pullup %s header", cip->ic_name);
62832176cfdSRui Paulo vap->iv_stats.is_rx_wepfail++; /* XXX */
62932176cfdSRui Paulo return NULL;
630841ab66cSSepherosa Ziehau }
631f186073cSJoerg Sonnenberger
632841ab66cSSepherosa Ziehau return (cip->ic_decap(k, m, hdrlen) ? k : NULL);
633841ab66cSSepherosa Ziehau #undef IEEE80211_WEP_MINLEN
634841ab66cSSepherosa Ziehau #undef IEEE80211_WEP_HDRLEN
635f186073cSJoerg Sonnenberger }
6366bd66811SSepherosa Ziehau
63732176cfdSRui Paulo static void
load_ucastkey(void * arg,struct ieee80211_node * ni)63832176cfdSRui Paulo load_ucastkey(void *arg, struct ieee80211_node *ni)
6396bd66811SSepherosa Ziehau {
64032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap;
6416bd66811SSepherosa Ziehau struct ieee80211_key *k;
6426bd66811SSepherosa Ziehau
64332176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_RUN)
64432176cfdSRui Paulo return;
6456bd66811SSepherosa Ziehau k = &ni->ni_ucastkey;
64632176cfdSRui Paulo if (k->wk_flags & IEEE80211_KEY_DEVKEY)
64732176cfdSRui Paulo dev_key_set(vap, k);
6486bd66811SSepherosa Ziehau }
64932176cfdSRui Paulo
65032176cfdSRui Paulo /*
65132176cfdSRui Paulo * Re-load all keys known to the 802.11 layer that may
65232176cfdSRui Paulo * have hardware state backing them. This is used by
65332176cfdSRui Paulo * drivers on resume to push keys down into the device.
65432176cfdSRui Paulo */
65532176cfdSRui Paulo void
ieee80211_crypto_reload_keys(struct ieee80211com * ic)65632176cfdSRui Paulo ieee80211_crypto_reload_keys(struct ieee80211com *ic)
65732176cfdSRui Paulo {
65832176cfdSRui Paulo struct ieee80211vap *vap;
65932176cfdSRui Paulo int i;
66032176cfdSRui Paulo
66132176cfdSRui Paulo /*
66232176cfdSRui Paulo * Keys in the global key table of each vap.
66332176cfdSRui Paulo */
66432176cfdSRui Paulo /* NB: used only during resume so don't lock for now */
66532176cfdSRui Paulo TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
66632176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_RUN)
66732176cfdSRui Paulo continue;
66832176cfdSRui Paulo for (i = 0; i < IEEE80211_WEP_NKID; i++) {
66932176cfdSRui Paulo const struct ieee80211_key *k = &vap->iv_nw_keys[i];
67032176cfdSRui Paulo if (k->wk_flags & IEEE80211_KEY_DEVKEY)
67132176cfdSRui Paulo dev_key_set(vap, k);
67232176cfdSRui Paulo }
67332176cfdSRui Paulo }
67432176cfdSRui Paulo /*
67532176cfdSRui Paulo * Unicast keys.
67632176cfdSRui Paulo */
67732176cfdSRui Paulo ieee80211_iterate_nodes(&ic->ic_sta, load_ucastkey, NULL);
6786bd66811SSepherosa Ziehau }
679