diff options
author | Jouni Malinen <j@w1.fi> | 2009-01-08 06:32:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:03 -0500 |
commit | 3cfcf6ac6d69dc290e96416731eea5c88ac7d426 (patch) | |
tree | 35bc626e2e3f7c37a7eb50c1f057adb4830eccc6 /net/mac80211/key.c | |
parent | 765cb46a3fc856245ea68a7c961ac87c77e4ae2d (diff) |
mac80211: 802.11w - Use BIP (AES-128-CMAC)
Add mechanism for managing BIP keys (IGTK) and integrate BIP into the
TX/RX paths.
Signed-off-by: Jouni Malinen <j@w1.fi>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 62 |
1 files changed, 60 insertions, 2 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b0a025c9b615..19b480de4bbc 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "ieee80211_i.h" | 18 | #include "ieee80211_i.h" |
19 | #include "debugfs_key.h" | 19 | #include "debugfs_key.h" |
20 | #include "aes_ccm.h" | 20 | #include "aes_ccm.h" |
21 | #include "aes_cmac.h" | ||
21 | 22 | ||
22 | 23 | ||
23 | /** | 24 | /** |
@@ -215,13 +216,38 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
215 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); | 216 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
216 | } | 217 | } |
217 | 218 | ||
219 | static void | ||
220 | __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | ||
221 | { | ||
222 | struct ieee80211_key *key = NULL; | ||
223 | |||
224 | if (idx >= NUM_DEFAULT_KEYS && | ||
225 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | ||
226 | key = sdata->keys[idx]; | ||
227 | |||
228 | rcu_assign_pointer(sdata->default_mgmt_key, key); | ||
229 | |||
230 | if (key) | ||
231 | add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY); | ||
232 | } | ||
233 | |||
234 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | ||
235 | int idx) | ||
236 | { | ||
237 | unsigned long flags; | ||
238 | |||
239 | spin_lock_irqsave(&sdata->local->key_lock, flags); | ||
240 | __ieee80211_set_default_mgmt_key(sdata, idx); | ||
241 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); | ||
242 | } | ||
243 | |||
218 | 244 | ||
219 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | 245 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
220 | struct sta_info *sta, | 246 | struct sta_info *sta, |
221 | struct ieee80211_key *old, | 247 | struct ieee80211_key *old, |
222 | struct ieee80211_key *new) | 248 | struct ieee80211_key *new) |
223 | { | 249 | { |
224 | int idx, defkey; | 250 | int idx, defkey, defmgmtkey; |
225 | 251 | ||
226 | if (new) | 252 | if (new) |
227 | list_add(&new->list, &sdata->key_list); | 253 | list_add(&new->list, &sdata->key_list); |
@@ -237,13 +263,19 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
237 | idx = new->conf.keyidx; | 263 | idx = new->conf.keyidx; |
238 | 264 | ||
239 | defkey = old && sdata->default_key == old; | 265 | defkey = old && sdata->default_key == old; |
266 | defmgmtkey = old && sdata->default_mgmt_key == old; | ||
240 | 267 | ||
241 | if (defkey && !new) | 268 | if (defkey && !new) |
242 | __ieee80211_set_default_key(sdata, -1); | 269 | __ieee80211_set_default_key(sdata, -1); |
270 | if (defmgmtkey && !new) | ||
271 | __ieee80211_set_default_mgmt_key(sdata, -1); | ||
243 | 272 | ||
244 | rcu_assign_pointer(sdata->keys[idx], new); | 273 | rcu_assign_pointer(sdata->keys[idx], new); |
245 | if (defkey && new) | 274 | if (defkey && new) |
246 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | 275 | __ieee80211_set_default_key(sdata, new->conf.keyidx); |
276 | if (defmgmtkey && new) | ||
277 | __ieee80211_set_default_mgmt_key(sdata, | ||
278 | new->conf.keyidx); | ||
247 | } | 279 | } |
248 | 280 | ||
249 | if (old) { | 281 | if (old) { |
@@ -262,7 +294,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
262 | { | 294 | { |
263 | struct ieee80211_key *key; | 295 | struct ieee80211_key *key; |
264 | 296 | ||
265 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); | 297 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); |
266 | 298 | ||
267 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); | 299 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
268 | if (!key) | 300 | if (!key) |
@@ -291,6 +323,10 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
291 | key->conf.iv_len = CCMP_HDR_LEN; | 323 | key->conf.iv_len = CCMP_HDR_LEN; |
292 | key->conf.icv_len = CCMP_MIC_LEN; | 324 | key->conf.icv_len = CCMP_MIC_LEN; |
293 | break; | 325 | break; |
326 | case ALG_AES_CMAC: | ||
327 | key->conf.iv_len = 0; | ||
328 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
329 | break; | ||
294 | } | 330 | } |
295 | memcpy(key->conf.key, key_data, key_len); | 331 | memcpy(key->conf.key, key_data, key_len); |
296 | INIT_LIST_HEAD(&key->list); | 332 | INIT_LIST_HEAD(&key->list); |
@@ -308,6 +344,19 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
308 | } | 344 | } |
309 | } | 345 | } |
310 | 346 | ||
347 | if (alg == ALG_AES_CMAC) { | ||
348 | /* | ||
349 | * Initialize AES key state here as an optimization so that | ||
350 | * it does not need to be initialized for every packet. | ||
351 | */ | ||
352 | key->u.aes_cmac.tfm = | ||
353 | ieee80211_aes_cmac_key_setup(key_data); | ||
354 | if (!key->u.aes_cmac.tfm) { | ||
355 | kfree(key); | ||
356 | return NULL; | ||
357 | } | ||
358 | } | ||
359 | |||
311 | return key; | 360 | return key; |
312 | } | 361 | } |
313 | 362 | ||
@@ -461,6 +510,8 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
461 | 510 | ||
462 | if (key->conf.alg == ALG_CCMP) | 511 | if (key->conf.alg == ALG_CCMP) |
463 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 512 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
513 | if (key->conf.alg == ALG_AES_CMAC) | ||
514 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | ||
464 | ieee80211_debugfs_key_remove(key); | 515 | ieee80211_debugfs_key_remove(key); |
465 | 516 | ||
466 | kfree(key); | 517 | kfree(key); |
@@ -483,6 +534,7 @@ static void __ieee80211_key_todo(void) | |||
483 | list_del_init(&key->todo); | 534 | list_del_init(&key->todo); |
484 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | | 535 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | |
485 | KEY_FLAG_TODO_DEFKEY | | 536 | KEY_FLAG_TODO_DEFKEY | |
537 | KEY_FLAG_TODO_DEFMGMTKEY | | ||
486 | KEY_FLAG_TODO_HWACCEL_ADD | | 538 | KEY_FLAG_TODO_HWACCEL_ADD | |
487 | KEY_FLAG_TODO_HWACCEL_REMOVE | | 539 | KEY_FLAG_TODO_HWACCEL_REMOVE | |
488 | KEY_FLAG_TODO_DELETE); | 540 | KEY_FLAG_TODO_DELETE); |
@@ -500,6 +552,11 @@ static void __ieee80211_key_todo(void) | |||
500 | ieee80211_debugfs_key_add_default(key->sdata); | 552 | ieee80211_debugfs_key_add_default(key->sdata); |
501 | work_done = true; | 553 | work_done = true; |
502 | } | 554 | } |
555 | if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) { | ||
556 | ieee80211_debugfs_key_remove_mgmt_default(key->sdata); | ||
557 | ieee80211_debugfs_key_add_mgmt_default(key->sdata); | ||
558 | work_done = true; | ||
559 | } | ||
503 | if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { | 560 | if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { |
504 | ieee80211_key_enable_hw_accel(key); | 561 | ieee80211_key_enable_hw_accel(key); |
505 | work_done = true; | 562 | work_done = true; |
@@ -535,6 +592,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
535 | ieee80211_key_lock(); | 592 | ieee80211_key_lock(); |
536 | 593 | ||
537 | ieee80211_debugfs_key_remove_default(sdata); | 594 | ieee80211_debugfs_key_remove_default(sdata); |
595 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | ||
538 | 596 | ||
539 | spin_lock_irqsave(&sdata->local->key_lock, flags); | 597 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
540 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 598 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |