1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 2001 Atsushi Onoe |
---|
5 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
---|
6 | * All rights reserved. |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions |
---|
10 | * are met: |
---|
11 | * 1. Redistributions of source code must retain the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer. |
---|
13 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
14 | * notice, this list of conditions and the following disclaimer in the |
---|
15 | * documentation and/or other materials provided with the distribution. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
27 | */ |
---|
28 | |
---|
29 | #include <sys/cdefs.h> |
---|
30 | __FBSDID("$FreeBSD$"); |
---|
31 | |
---|
32 | /* |
---|
33 | * IEEE 802.11 generic crypto support. |
---|
34 | */ |
---|
35 | #include <rtems/bsd/local/opt_wlan.h> |
---|
36 | |
---|
37 | #include <rtems/bsd/sys/param.h> |
---|
38 | #include <sys/kernel.h> |
---|
39 | #include <sys/malloc.h> |
---|
40 | #include <sys/mbuf.h> |
---|
41 | |
---|
42 | #include <sys/socket.h> |
---|
43 | |
---|
44 | #include <net/if.h> |
---|
45 | #include <net/if_media.h> |
---|
46 | #include <net/ethernet.h> /* XXX ETHER_HDR_LEN */ |
---|
47 | |
---|
48 | #include <net80211/ieee80211_var.h> |
---|
49 | |
---|
50 | MALLOC_DEFINE(M_80211_CRYPTO, "80211crypto", "802.11 crypto state"); |
---|
51 | |
---|
52 | static int _ieee80211_crypto_delkey(struct ieee80211vap *, |
---|
53 | struct ieee80211_key *); |
---|
54 | |
---|
55 | /* |
---|
56 | * Table of registered cipher modules. |
---|
57 | */ |
---|
58 | static const struct ieee80211_cipher *ciphers[IEEE80211_CIPHER_MAX]; |
---|
59 | |
---|
60 | /* |
---|
61 | * Default "null" key management routines. |
---|
62 | */ |
---|
63 | static int |
---|
64 | null_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, |
---|
65 | ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) |
---|
66 | { |
---|
67 | if (!(&vap->iv_nw_keys[0] <= k && |
---|
68 | k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { |
---|
69 | /* |
---|
70 | * Not in the global key table, the driver should handle this |
---|
71 | * by allocating a slot in the h/w key table/cache. In |
---|
72 | * lieu of that return key slot 0 for any unicast key |
---|
73 | * request. We disallow the request if this is a group key. |
---|
74 | * This default policy does the right thing for legacy hardware |
---|
75 | * with a 4 key table. It also handles devices that pass |
---|
76 | * packets through untouched when marked with the WEP bit |
---|
77 | * and key index 0. |
---|
78 | */ |
---|
79 | if (k->wk_flags & IEEE80211_KEY_GROUP) |
---|
80 | return 0; |
---|
81 | *keyix = 0; /* NB: use key index 0 for ucast key */ |
---|
82 | } else { |
---|
83 | *keyix = k - vap->iv_nw_keys; |
---|
84 | } |
---|
85 | *rxkeyix = IEEE80211_KEYIX_NONE; /* XXX maybe *keyix? */ |
---|
86 | return 1; |
---|
87 | } |
---|
88 | static int |
---|
89 | null_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) |
---|
90 | { |
---|
91 | return 1; |
---|
92 | } |
---|
93 | static int |
---|
94 | null_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, |
---|
95 | const uint8_t mac[IEEE80211_ADDR_LEN]) |
---|
96 | { |
---|
97 | return 1; |
---|
98 | } |
---|
99 | static void null_key_update(struct ieee80211vap *vap) {} |
---|
100 | |
---|
101 | /* |
---|
102 | * Write-arounds for common operations. |
---|
103 | */ |
---|
104 | static __inline void |
---|
105 | cipher_detach(struct ieee80211_key *key) |
---|
106 | { |
---|
107 | key->wk_cipher->ic_detach(key); |
---|
108 | } |
---|
109 | |
---|
110 | static __inline void * |
---|
111 | cipher_attach(struct ieee80211vap *vap, struct ieee80211_key *key) |
---|
112 | { |
---|
113 | return key->wk_cipher->ic_attach(vap, key); |
---|
114 | } |
---|
115 | |
---|
116 | /* |
---|
117 | * Wrappers for driver key management methods. |
---|
118 | */ |
---|
119 | static __inline int |
---|
120 | dev_key_alloc(struct ieee80211vap *vap, |
---|
121 | struct ieee80211_key *key, |
---|
122 | ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) |
---|
123 | { |
---|
124 | return vap->iv_key_alloc(vap, key, keyix, rxkeyix); |
---|
125 | } |
---|
126 | |
---|
127 | static __inline int |
---|
128 | dev_key_delete(struct ieee80211vap *vap, |
---|
129 | const struct ieee80211_key *key) |
---|
130 | { |
---|
131 | return vap->iv_key_delete(vap, key); |
---|
132 | } |
---|
133 | |
---|
134 | static __inline int |
---|
135 | dev_key_set(struct ieee80211vap *vap, const struct ieee80211_key *key) |
---|
136 | { |
---|
137 | return vap->iv_key_set(vap, key, key->wk_macaddr); |
---|
138 | } |
---|
139 | |
---|
140 | /* |
---|
141 | * Setup crypto support for a device/shared instance. |
---|
142 | */ |
---|
143 | void |
---|
144 | ieee80211_crypto_attach(struct ieee80211com *ic) |
---|
145 | { |
---|
146 | /* NB: we assume everything is pre-zero'd */ |
---|
147 | ciphers[IEEE80211_CIPHER_NONE] = &ieee80211_cipher_none; |
---|
148 | } |
---|
149 | |
---|
150 | /* |
---|
151 | * Teardown crypto support. |
---|
152 | */ |
---|
153 | void |
---|
154 | ieee80211_crypto_detach(struct ieee80211com *ic) |
---|
155 | { |
---|
156 | } |
---|
157 | |
---|
158 | /* |
---|
159 | * Setup crypto support for a vap. |
---|
160 | */ |
---|
161 | void |
---|
162 | ieee80211_crypto_vattach(struct ieee80211vap *vap) |
---|
163 | { |
---|
164 | int i; |
---|
165 | |
---|
166 | /* NB: we assume everything is pre-zero'd */ |
---|
167 | vap->iv_max_keyix = IEEE80211_WEP_NKID; |
---|
168 | vap->iv_def_txkey = IEEE80211_KEYIX_NONE; |
---|
169 | for (i = 0; i < IEEE80211_WEP_NKID; i++) |
---|
170 | ieee80211_crypto_resetkey(vap, &vap->iv_nw_keys[i], |
---|
171 | IEEE80211_KEYIX_NONE); |
---|
172 | /* |
---|
173 | * Initialize the driver key support routines to noop entries. |
---|
174 | * This is useful especially for the cipher test modules. |
---|
175 | */ |
---|
176 | vap->iv_key_alloc = null_key_alloc; |
---|
177 | vap->iv_key_set = null_key_set; |
---|
178 | vap->iv_key_delete = null_key_delete; |
---|
179 | vap->iv_key_update_begin = null_key_update; |
---|
180 | vap->iv_key_update_end = null_key_update; |
---|
181 | } |
---|
182 | |
---|
183 | /* |
---|
184 | * Teardown crypto support for a vap. |
---|
185 | */ |
---|
186 | void |
---|
187 | ieee80211_crypto_vdetach(struct ieee80211vap *vap) |
---|
188 | { |
---|
189 | ieee80211_crypto_delglobalkeys(vap); |
---|
190 | } |
---|
191 | |
---|
192 | /* |
---|
193 | * Register a crypto cipher module. |
---|
194 | */ |
---|
195 | void |
---|
196 | ieee80211_crypto_register(const struct ieee80211_cipher *cip) |
---|
197 | { |
---|
198 | if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { |
---|
199 | printf("%s: cipher %s has an invalid cipher index %u\n", |
---|
200 | __func__, cip->ic_name, cip->ic_cipher); |
---|
201 | return; |
---|
202 | } |
---|
203 | if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { |
---|
204 | printf("%s: cipher %s registered with a different template\n", |
---|
205 | __func__, cip->ic_name); |
---|
206 | return; |
---|
207 | } |
---|
208 | ciphers[cip->ic_cipher] = cip; |
---|
209 | } |
---|
210 | |
---|
211 | /* |
---|
212 | * Unregister a crypto cipher module. |
---|
213 | */ |
---|
214 | void |
---|
215 | ieee80211_crypto_unregister(const struct ieee80211_cipher *cip) |
---|
216 | { |
---|
217 | if (cip->ic_cipher >= IEEE80211_CIPHER_MAX) { |
---|
218 | printf("%s: cipher %s has an invalid cipher index %u\n", |
---|
219 | __func__, cip->ic_name, cip->ic_cipher); |
---|
220 | return; |
---|
221 | } |
---|
222 | if (ciphers[cip->ic_cipher] != NULL && ciphers[cip->ic_cipher] != cip) { |
---|
223 | printf("%s: cipher %s registered with a different template\n", |
---|
224 | __func__, cip->ic_name); |
---|
225 | return; |
---|
226 | } |
---|
227 | /* NB: don't complain about not being registered */ |
---|
228 | /* XXX disallow if references */ |
---|
229 | ciphers[cip->ic_cipher] = NULL; |
---|
230 | } |
---|
231 | |
---|
232 | int |
---|
233 | ieee80211_crypto_available(u_int cipher) |
---|
234 | { |
---|
235 | return cipher < IEEE80211_CIPHER_MAX && ciphers[cipher] != NULL; |
---|
236 | } |
---|
237 | |
---|
238 | /* XXX well-known names! */ |
---|
239 | static const char *cipher_modnames[IEEE80211_CIPHER_MAX] = { |
---|
240 | [IEEE80211_CIPHER_WEP] = "wlan_wep", |
---|
241 | [IEEE80211_CIPHER_TKIP] = "wlan_tkip", |
---|
242 | [IEEE80211_CIPHER_AES_OCB] = "wlan_aes_ocb", |
---|
243 | [IEEE80211_CIPHER_AES_CCM] = "wlan_ccmp", |
---|
244 | [IEEE80211_CIPHER_TKIPMIC] = "#4", /* NB: reserved */ |
---|
245 | [IEEE80211_CIPHER_CKIP] = "wlan_ckip", |
---|
246 | [IEEE80211_CIPHER_NONE] = "wlan_none", |
---|
247 | }; |
---|
248 | |
---|
249 | /* NB: there must be no overlap between user-supplied and device-owned flags */ |
---|
250 | CTASSERT((IEEE80211_KEY_COMMON & IEEE80211_KEY_DEVICE) == 0); |
---|
251 | |
---|
252 | /* |
---|
253 | * Establish a relationship between the specified key and cipher |
---|
254 | * and, if necessary, allocate a hardware index from the driver. |
---|
255 | * Note that when a fixed key index is required it must be specified. |
---|
256 | * |
---|
257 | * This must be the first call applied to a key; all the other key |
---|
258 | * routines assume wk_cipher is setup. |
---|
259 | * |
---|
260 | * Locking must be handled by the caller using: |
---|
261 | * ieee80211_key_update_begin(vap); |
---|
262 | * ieee80211_key_update_end(vap); |
---|
263 | */ |
---|
264 | int |
---|
265 | ieee80211_crypto_newkey(struct ieee80211vap *vap, |
---|
266 | int cipher, int flags, struct ieee80211_key *key) |
---|
267 | { |
---|
268 | struct ieee80211com *ic = vap->iv_ic; |
---|
269 | const struct ieee80211_cipher *cip; |
---|
270 | ieee80211_keyix keyix, rxkeyix; |
---|
271 | void *keyctx; |
---|
272 | int oflags; |
---|
273 | |
---|
274 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
275 | "%s: cipher %u flags 0x%x keyix %u\n", |
---|
276 | __func__, cipher, flags, key->wk_keyix); |
---|
277 | |
---|
278 | /* |
---|
279 | * Validate cipher and set reference to cipher routines. |
---|
280 | */ |
---|
281 | if (cipher >= IEEE80211_CIPHER_MAX) { |
---|
282 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
283 | "%s: invalid cipher %u\n", __func__, cipher); |
---|
284 | vap->iv_stats.is_crypto_badcipher++; |
---|
285 | return 0; |
---|
286 | } |
---|
287 | cip = ciphers[cipher]; |
---|
288 | if (cip == NULL) { |
---|
289 | /* |
---|
290 | * Auto-load cipher module if we have a well-known name |
---|
291 | * for it. It might be better to use string names rather |
---|
292 | * than numbers and craft a module name based on the cipher |
---|
293 | * name; e.g. wlan_cipher_<cipher-name>. |
---|
294 | */ |
---|
295 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
296 | "%s: unregistered cipher %u, load module %s\n", |
---|
297 | __func__, cipher, cipher_modnames[cipher]); |
---|
298 | ieee80211_load_module(cipher_modnames[cipher]); |
---|
299 | /* |
---|
300 | * If cipher module loaded it should immediately |
---|
301 | * call ieee80211_crypto_register which will fill |
---|
302 | * in the entry in the ciphers array. |
---|
303 | */ |
---|
304 | cip = ciphers[cipher]; |
---|
305 | if (cip == NULL) { |
---|
306 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
307 | "%s: unable to load cipher %u, module %s\n", |
---|
308 | __func__, cipher, cipher_modnames[cipher]); |
---|
309 | vap->iv_stats.is_crypto_nocipher++; |
---|
310 | return 0; |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | oflags = key->wk_flags; |
---|
315 | flags &= IEEE80211_KEY_COMMON; |
---|
316 | /* NB: preserve device attributes */ |
---|
317 | flags |= (oflags & IEEE80211_KEY_DEVICE); |
---|
318 | /* |
---|
319 | * If the hardware does not support the cipher then |
---|
320 | * fallback to a host-based implementation. |
---|
321 | */ |
---|
322 | if ((ic->ic_cryptocaps & (1<<cipher)) == 0) { |
---|
323 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
324 | "%s: no h/w support for cipher %s, falling back to s/w\n", |
---|
325 | __func__, cip->ic_name); |
---|
326 | flags |= IEEE80211_KEY_SWCRYPT; |
---|
327 | } |
---|
328 | /* |
---|
329 | * Hardware TKIP with software MIC is an important |
---|
330 | * combination; we handle it by flagging each key, |
---|
331 | * the cipher modules honor it. |
---|
332 | */ |
---|
333 | if (cipher == IEEE80211_CIPHER_TKIP && |
---|
334 | (ic->ic_cryptocaps & IEEE80211_CRYPTO_TKIPMIC) == 0) { |
---|
335 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
336 | "%s: no h/w support for TKIP MIC, falling back to s/w\n", |
---|
337 | __func__); |
---|
338 | flags |= IEEE80211_KEY_SWMIC; |
---|
339 | } |
---|
340 | |
---|
341 | /* |
---|
342 | * Bind cipher to key instance. Note we do this |
---|
343 | * after checking the device capabilities so the |
---|
344 | * cipher module can optimize space usage based on |
---|
345 | * whether or not it needs to do the cipher work. |
---|
346 | */ |
---|
347 | if (key->wk_cipher != cip || key->wk_flags != flags) { |
---|
348 | /* |
---|
349 | * Fillin the flags so cipher modules can see s/w |
---|
350 | * crypto requirements and potentially allocate |
---|
351 | * different state and/or attach different method |
---|
352 | * pointers. |
---|
353 | */ |
---|
354 | key->wk_flags = flags; |
---|
355 | keyctx = cip->ic_attach(vap, key); |
---|
356 | if (keyctx == NULL) { |
---|
357 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
358 | "%s: unable to attach cipher %s\n", |
---|
359 | __func__, cip->ic_name); |
---|
360 | key->wk_flags = oflags; /* restore old flags */ |
---|
361 | vap->iv_stats.is_crypto_attachfail++; |
---|
362 | return 0; |
---|
363 | } |
---|
364 | cipher_detach(key); |
---|
365 | key->wk_cipher = cip; /* XXX refcnt? */ |
---|
366 | key->wk_private = keyctx; |
---|
367 | } |
---|
368 | |
---|
369 | /* |
---|
370 | * Ask the driver for a key index if we don't have one. |
---|
371 | * Note that entries in the global key table always have |
---|
372 | * an index; this means it's safe to call this routine |
---|
373 | * for these entries just to setup the reference to the |
---|
374 | * cipher template. Note also that when using software |
---|
375 | * crypto we also call the driver to give us a key index. |
---|
376 | */ |
---|
377 | if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) { |
---|
378 | if (!dev_key_alloc(vap, key, &keyix, &rxkeyix)) { |
---|
379 | /* |
---|
380 | * Unable to setup driver state. |
---|
381 | */ |
---|
382 | vap->iv_stats.is_crypto_keyfail++; |
---|
383 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
384 | "%s: unable to setup cipher %s\n", |
---|
385 | __func__, cip->ic_name); |
---|
386 | return 0; |
---|
387 | } |
---|
388 | if (key->wk_flags != flags) { |
---|
389 | /* |
---|
390 | * Driver overrode flags we setup; typically because |
---|
391 | * resources were unavailable to handle _this_ key. |
---|
392 | * Re-attach the cipher context to allow cipher |
---|
393 | * modules to handle differing requirements. |
---|
394 | */ |
---|
395 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
396 | "%s: driver override for cipher %s, flags " |
---|
397 | "0x%x -> 0x%x\n", __func__, cip->ic_name, |
---|
398 | oflags, key->wk_flags); |
---|
399 | keyctx = cip->ic_attach(vap, key); |
---|
400 | if (keyctx == NULL) { |
---|
401 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
402 | "%s: unable to attach cipher %s with " |
---|
403 | "flags 0x%x\n", __func__, cip->ic_name, |
---|
404 | key->wk_flags); |
---|
405 | key->wk_flags = oflags; /* restore old flags */ |
---|
406 | vap->iv_stats.is_crypto_attachfail++; |
---|
407 | return 0; |
---|
408 | } |
---|
409 | cipher_detach(key); |
---|
410 | key->wk_cipher = cip; /* XXX refcnt? */ |
---|
411 | key->wk_private = keyctx; |
---|
412 | } |
---|
413 | key->wk_keyix = keyix; |
---|
414 | key->wk_rxkeyix = rxkeyix; |
---|
415 | key->wk_flags |= IEEE80211_KEY_DEVKEY; |
---|
416 | } |
---|
417 | return 1; |
---|
418 | } |
---|
419 | |
---|
420 | /* |
---|
421 | * Remove the key (no locking, for internal use). |
---|
422 | */ |
---|
423 | static int |
---|
424 | _ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key) |
---|
425 | { |
---|
426 | KASSERT(key->wk_cipher != NULL, ("No cipher!")); |
---|
427 | |
---|
428 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
429 | "%s: %s keyix %u flags 0x%x rsc %ju tsc %ju len %u\n", |
---|
430 | __func__, key->wk_cipher->ic_name, |
---|
431 | key->wk_keyix, key->wk_flags, |
---|
432 | key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc, |
---|
433 | key->wk_keylen); |
---|
434 | |
---|
435 | if (key->wk_flags & IEEE80211_KEY_DEVKEY) { |
---|
436 | /* |
---|
437 | * Remove hardware entry. |
---|
438 | */ |
---|
439 | /* XXX key cache */ |
---|
440 | if (!dev_key_delete(vap, key)) { |
---|
441 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
442 | "%s: driver did not delete key index %u\n", |
---|
443 | __func__, key->wk_keyix); |
---|
444 | vap->iv_stats.is_crypto_delkey++; |
---|
445 | /* XXX recovery? */ |
---|
446 | } |
---|
447 | } |
---|
448 | cipher_detach(key); |
---|
449 | memset(key, 0, sizeof(*key)); |
---|
450 | ieee80211_crypto_resetkey(vap, key, IEEE80211_KEYIX_NONE); |
---|
451 | return 1; |
---|
452 | } |
---|
453 | |
---|
454 | /* |
---|
455 | * Remove the specified key. |
---|
456 | */ |
---|
457 | int |
---|
458 | ieee80211_crypto_delkey(struct ieee80211vap *vap, struct ieee80211_key *key) |
---|
459 | { |
---|
460 | int status; |
---|
461 | |
---|
462 | ieee80211_key_update_begin(vap); |
---|
463 | status = _ieee80211_crypto_delkey(vap, key); |
---|
464 | ieee80211_key_update_end(vap); |
---|
465 | return status; |
---|
466 | } |
---|
467 | |
---|
468 | /* |
---|
469 | * Clear the global key table. |
---|
470 | */ |
---|
471 | void |
---|
472 | ieee80211_crypto_delglobalkeys(struct ieee80211vap *vap) |
---|
473 | { |
---|
474 | int i; |
---|
475 | |
---|
476 | ieee80211_key_update_begin(vap); |
---|
477 | for (i = 0; i < IEEE80211_WEP_NKID; i++) |
---|
478 | (void) _ieee80211_crypto_delkey(vap, &vap->iv_nw_keys[i]); |
---|
479 | ieee80211_key_update_end(vap); |
---|
480 | } |
---|
481 | |
---|
482 | /* |
---|
483 | * Set the contents of the specified key. |
---|
484 | * |
---|
485 | * Locking must be handled by the caller using: |
---|
486 | * ieee80211_key_update_begin(vap); |
---|
487 | * ieee80211_key_update_end(vap); |
---|
488 | */ |
---|
489 | int |
---|
490 | ieee80211_crypto_setkey(struct ieee80211vap *vap, struct ieee80211_key *key) |
---|
491 | { |
---|
492 | const struct ieee80211_cipher *cip = key->wk_cipher; |
---|
493 | |
---|
494 | KASSERT(cip != NULL, ("No cipher!")); |
---|
495 | |
---|
496 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
497 | "%s: %s keyix %u flags 0x%x mac %s rsc %ju tsc %ju len %u\n", |
---|
498 | __func__, cip->ic_name, key->wk_keyix, |
---|
499 | key->wk_flags, ether_sprintf(key->wk_macaddr), |
---|
500 | key->wk_keyrsc[IEEE80211_NONQOS_TID], key->wk_keytsc, |
---|
501 | key->wk_keylen); |
---|
502 | |
---|
503 | if ((key->wk_flags & IEEE80211_KEY_DEVKEY) == 0) { |
---|
504 | /* XXX nothing allocated, should not happen */ |
---|
505 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
506 | "%s: no device key setup done; should not happen!\n", |
---|
507 | __func__); |
---|
508 | vap->iv_stats.is_crypto_setkey_nokey++; |
---|
509 | return 0; |
---|
510 | } |
---|
511 | /* |
---|
512 | * Give cipher a chance to validate key contents. |
---|
513 | * XXX should happen before modifying state. |
---|
514 | */ |
---|
515 | if (!cip->ic_setkey(key)) { |
---|
516 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_CRYPTO, |
---|
517 | "%s: cipher %s rejected key index %u len %u flags 0x%x\n", |
---|
518 | __func__, cip->ic_name, key->wk_keyix, |
---|
519 | key->wk_keylen, key->wk_flags); |
---|
520 | vap->iv_stats.is_crypto_setkey_cipher++; |
---|
521 | return 0; |
---|
522 | } |
---|
523 | return dev_key_set(vap, key); |
---|
524 | } |
---|
525 | |
---|
526 | /* |
---|
527 | * Add privacy headers appropriate for the specified key. |
---|
528 | */ |
---|
529 | struct ieee80211_key * |
---|
530 | ieee80211_crypto_encap(struct ieee80211_node *ni, struct mbuf *m) |
---|
531 | { |
---|
532 | struct ieee80211vap *vap = ni->ni_vap; |
---|
533 | struct ieee80211_key *k; |
---|
534 | struct ieee80211_frame *wh; |
---|
535 | const struct ieee80211_cipher *cip; |
---|
536 | uint8_t keyid; |
---|
537 | |
---|
538 | /* |
---|
539 | * Multicast traffic always uses the multicast key. |
---|
540 | * Otherwise if a unicast key is set we use that and |
---|
541 | * it is always key index 0. When no unicast key is |
---|
542 | * set we fall back to the default transmit key. |
---|
543 | */ |
---|
544 | wh = mtod(m, struct ieee80211_frame *); |
---|
545 | if (IEEE80211_IS_MULTICAST(wh->i_addr1) || |
---|
546 | IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { |
---|
547 | if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE) { |
---|
548 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, |
---|
549 | wh->i_addr1, |
---|
550 | "no default transmit key (%s) deftxkey %u", |
---|
551 | __func__, vap->iv_def_txkey); |
---|
552 | vap->iv_stats.is_tx_nodefkey++; |
---|
553 | return NULL; |
---|
554 | } |
---|
555 | keyid = vap->iv_def_txkey; |
---|
556 | k = &vap->iv_nw_keys[vap->iv_def_txkey]; |
---|
557 | } else { |
---|
558 | keyid = 0; |
---|
559 | k = &ni->ni_ucastkey; |
---|
560 | } |
---|
561 | cip = k->wk_cipher; |
---|
562 | return (cip->ic_encap(k, m, keyid<<6) ? k : NULL); |
---|
563 | } |
---|
564 | |
---|
565 | /* |
---|
566 | * Validate and strip privacy headers (and trailer) for a |
---|
567 | * received frame that has the WEP/Privacy bit set. |
---|
568 | */ |
---|
569 | struct ieee80211_key * |
---|
570 | ieee80211_crypto_decap(struct ieee80211_node *ni, struct mbuf *m, int hdrlen) |
---|
571 | { |
---|
572 | #define IEEE80211_WEP_HDRLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) |
---|
573 | #define IEEE80211_WEP_MINLEN \ |
---|
574 | (sizeof(struct ieee80211_frame) + \ |
---|
575 | IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN) |
---|
576 | struct ieee80211vap *vap = ni->ni_vap; |
---|
577 | struct ieee80211_key *k; |
---|
578 | struct ieee80211_frame *wh; |
---|
579 | const struct ieee80211_cipher *cip; |
---|
580 | uint8_t keyid; |
---|
581 | |
---|
582 | /* NB: this minimum size data frame could be bigger */ |
---|
583 | if (m->m_pkthdr.len < IEEE80211_WEP_MINLEN) { |
---|
584 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, |
---|
585 | "%s: WEP data frame too short, len %u\n", |
---|
586 | __func__, m->m_pkthdr.len); |
---|
587 | vap->iv_stats.is_rx_tooshort++; /* XXX need unique stat? */ |
---|
588 | return NULL; |
---|
589 | } |
---|
590 | |
---|
591 | /* |
---|
592 | * Locate the key. If unicast and there is no unicast |
---|
593 | * key then we fall back to the key id in the header. |
---|
594 | * This assumes unicast keys are only configured when |
---|
595 | * the key id in the header is meaningless (typically 0). |
---|
596 | */ |
---|
597 | wh = mtod(m, struct ieee80211_frame *); |
---|
598 | m_copydata(m, hdrlen + IEEE80211_WEP_IVLEN, sizeof(keyid), &keyid); |
---|
599 | if (IEEE80211_IS_MULTICAST(wh->i_addr1) || |
---|
600 | IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) |
---|
601 | k = &vap->iv_nw_keys[keyid >> 6]; |
---|
602 | else |
---|
603 | k = &ni->ni_ucastkey; |
---|
604 | |
---|
605 | /* |
---|
606 | * Insure crypto header is contiguous for all decap work. |
---|
607 | */ |
---|
608 | cip = k->wk_cipher; |
---|
609 | if (m->m_len < hdrlen + cip->ic_header && |
---|
610 | (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) { |
---|
611 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, |
---|
612 | "unable to pullup %s header", cip->ic_name); |
---|
613 | vap->iv_stats.is_rx_wepfail++; /* XXX */ |
---|
614 | return NULL; |
---|
615 | } |
---|
616 | |
---|
617 | return (cip->ic_decap(k, m, hdrlen) ? k : NULL); |
---|
618 | #undef IEEE80211_WEP_MINLEN |
---|
619 | #undef IEEE80211_WEP_HDRLEN |
---|
620 | } |
---|
621 | |
---|
622 | static void |
---|
623 | load_ucastkey(void *arg, struct ieee80211_node *ni) |
---|
624 | { |
---|
625 | struct ieee80211vap *vap = ni->ni_vap; |
---|
626 | struct ieee80211_key *k; |
---|
627 | |
---|
628 | if (vap->iv_state != IEEE80211_S_RUN) |
---|
629 | return; |
---|
630 | k = &ni->ni_ucastkey; |
---|
631 | if (k->wk_flags & IEEE80211_KEY_DEVKEY) |
---|
632 | dev_key_set(vap, k); |
---|
633 | } |
---|
634 | |
---|
635 | /* |
---|
636 | * Re-load all keys known to the 802.11 layer that may |
---|
637 | * have hardware state backing them. This is used by |
---|
638 | * drivers on resume to push keys down into the device. |
---|
639 | */ |
---|
640 | void |
---|
641 | ieee80211_crypto_reload_keys(struct ieee80211com *ic) |
---|
642 | { |
---|
643 | struct ieee80211vap *vap; |
---|
644 | int i; |
---|
645 | |
---|
646 | /* |
---|
647 | * Keys in the global key table of each vap. |
---|
648 | */ |
---|
649 | /* NB: used only during resume so don't lock for now */ |
---|
650 | TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { |
---|
651 | if (vap->iv_state != IEEE80211_S_RUN) |
---|
652 | continue; |
---|
653 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { |
---|
654 | const struct ieee80211_key *k = &vap->iv_nw_keys[i]; |
---|
655 | if (k->wk_flags & IEEE80211_KEY_DEVKEY) |
---|
656 | dev_key_set(vap, k); |
---|
657 | } |
---|
658 | } |
---|
659 | /* |
---|
660 | * Unicast keys. |
---|
661 | */ |
---|
662 | ieee80211_iterate_nodes(&ic->ic_sta, load_ucastkey, NULL); |
---|
663 | } |
---|