Commit 3cfcf6ac6d69dc290e96416731eea5c88ac7d426
Committed by
John W. Linville
1 parent
765cb46a3f
Exists in
master
and in
7 other branches
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>
Showing 14 changed files with 317 additions and 21 deletions Side-by-side Diff
- drivers/net/wireless/ath5k/pcu.c
- include/linux/ieee80211.h
- include/linux/nl80211.h
- include/net/cfg80211.h
- include/net/mac80211.h
- net/mac80211/cfg.c
- net/mac80211/debugfs_key.c
- net/mac80211/debugfs_key.h
- net/mac80211/ieee80211_i.h
- net/mac80211/key.c
- net/mac80211/key.h
- net/mac80211/rx.c
- net/mac80211/tx.c
- net/wireless/nl80211.c
drivers/net/wireless/ath5k/pcu.c
include/linux/ieee80211.h
include/linux/nl80211.h
... | ... | @@ -72,8 +72,8 @@ |
72 | 72 | * |
73 | 73 | * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified |
74 | 74 | * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. |
75 | - * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or | |
76 | - * %NL80211_ATTR_KEY_THRESHOLD. | |
75 | + * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, | |
76 | + * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. | |
77 | 77 | * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, |
78 | 78 | * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER |
79 | 79 | * attributes. |
... | ... | @@ -345,6 +345,8 @@ |
345 | 345 | NL80211_ATTR_WIPHY_TXQ_PARAMS, |
346 | 346 | NL80211_ATTR_WIPHY_FREQ, |
347 | 347 | NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
348 | + | |
349 | + NL80211_ATTR_KEY_DEFAULT_MGMT, | |
348 | 350 | |
349 | 351 | /* add attributes here, update the policy in nl80211.c */ |
350 | 352 |
include/net/cfg80211.h
... | ... | @@ -473,6 +473,8 @@ |
473 | 473 | * |
474 | 474 | * @set_default_key: set the default key on an interface |
475 | 475 | * |
476 | + * @set_default_mgmt_key: set the default management frame key on an interface | |
477 | + * | |
476 | 478 | * @add_beacon: Add a beacon with given parameters, @head, @interval |
477 | 479 | * and @dtim_period will be valid, @tail is optional. |
478 | 480 | * @set_beacon: Change the beacon parameters for an access point mode |
... | ... | @@ -520,6 +522,9 @@ |
520 | 522 | int (*set_default_key)(struct wiphy *wiphy, |
521 | 523 | struct net_device *netdev, |
522 | 524 | u8 key_index); |
525 | + int (*set_default_mgmt_key)(struct wiphy *wiphy, | |
526 | + struct net_device *netdev, | |
527 | + u8 key_index); | |
523 | 528 | |
524 | 529 | int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, |
525 | 530 | struct beacon_parameters *info); |
include/net/mac80211.h
... | ... | @@ -651,11 +651,13 @@ |
651 | 651 | * @ALG_WEP: WEP40 or WEP104 |
652 | 652 | * @ALG_TKIP: TKIP |
653 | 653 | * @ALG_CCMP: CCMP (AES) |
654 | + * @ALG_AES_CMAC: AES-128-CMAC | |
654 | 655 | */ |
655 | 656 | enum ieee80211_key_alg { |
656 | 657 | ALG_WEP, |
657 | 658 | ALG_TKIP, |
658 | 659 | ALG_CCMP, |
660 | + ALG_AES_CMAC, | |
659 | 661 | }; |
660 | 662 | |
661 | 663 | /** |
net/mac80211/cfg.c
... | ... | @@ -133,6 +133,9 @@ |
133 | 133 | case WLAN_CIPHER_SUITE_CCMP: |
134 | 134 | alg = ALG_CCMP; |
135 | 135 | break; |
136 | + case WLAN_CIPHER_SUITE_AES_CMAC: | |
137 | + alg = ALG_AES_CMAC; | |
138 | + break; | |
136 | 139 | default: |
137 | 140 | return -EINVAL; |
138 | 141 | } |
... | ... | @@ -275,6 +278,17 @@ |
275 | 278 | else |
276 | 279 | params.cipher = WLAN_CIPHER_SUITE_WEP104; |
277 | 280 | break; |
281 | + case ALG_AES_CMAC: | |
282 | + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; | |
283 | + seq[0] = key->u.aes_cmac.tx_pn[5]; | |
284 | + seq[1] = key->u.aes_cmac.tx_pn[4]; | |
285 | + seq[2] = key->u.aes_cmac.tx_pn[3]; | |
286 | + seq[3] = key->u.aes_cmac.tx_pn[2]; | |
287 | + seq[4] = key->u.aes_cmac.tx_pn[1]; | |
288 | + seq[5] = key->u.aes_cmac.tx_pn[0]; | |
289 | + params.seq = seq; | |
290 | + params.seq_len = 6; | |
291 | + break; | |
278 | 292 | } |
279 | 293 | |
280 | 294 | params.key = key->conf.key; |
... | ... | @@ -304,6 +318,22 @@ |
304 | 318 | return 0; |
305 | 319 | } |
306 | 320 | |
321 | +static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |
322 | + struct net_device *dev, | |
323 | + u8 key_idx) | |
324 | +{ | |
325 | + struct ieee80211_sub_if_data *sdata; | |
326 | + | |
327 | + rcu_read_lock(); | |
328 | + | |
329 | + sdata = IEEE80211_DEV_TO_SUB_IF(dev); | |
330 | + ieee80211_set_default_mgmt_key(sdata, key_idx); | |
331 | + | |
332 | + rcu_read_unlock(); | |
333 | + | |
334 | + return 0; | |
335 | +} | |
336 | + | |
307 | 337 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
308 | 338 | { |
309 | 339 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
... | ... | @@ -1153,6 +1183,7 @@ |
1153 | 1183 | .del_key = ieee80211_del_key, |
1154 | 1184 | .get_key = ieee80211_get_key, |
1155 | 1185 | .set_default_key = ieee80211_config_default_key, |
1186 | + .set_default_mgmt_key = ieee80211_config_default_mgmt_key, | |
1156 | 1187 | .add_beacon = ieee80211_add_beacon, |
1157 | 1188 | .set_beacon = ieee80211_set_beacon, |
1158 | 1189 | .del_beacon = ieee80211_del_beacon, |
net/mac80211/debugfs_key.c
... | ... | @@ -76,6 +76,9 @@ |
76 | 76 | case ALG_CCMP: |
77 | 77 | alg = "CCMP\n"; |
78 | 78 | break; |
79 | + case ALG_AES_CMAC: | |
80 | + alg = "AES-128-CMAC\n"; | |
81 | + break; | |
79 | 82 | default: |
80 | 83 | return 0; |
81 | 84 | } |
... | ... | @@ -105,6 +108,12 @@ |
105 | 108 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
106 | 109 | tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); |
107 | 110 | break; |
111 | + case ALG_AES_CMAC: | |
112 | + tpn = key->u.aes_cmac.tx_pn; | |
113 | + len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | |
114 | + tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], | |
115 | + tpn[5]); | |
116 | + break; | |
108 | 117 | default: |
109 | 118 | return 0; |
110 | 119 | } |
... | ... | @@ -142,6 +151,14 @@ |
142 | 151 | } |
143 | 152 | len = p - buf; |
144 | 153 | break; |
154 | + case ALG_AES_CMAC: | |
155 | + rpn = key->u.aes_cmac.rx_pn; | |
156 | + p += scnprintf(p, sizeof(buf)+buf-p, | |
157 | + "%02x%02x%02x%02x%02x%02x\n", | |
158 | + rpn[0], rpn[1], rpn[2], | |
159 | + rpn[3], rpn[4], rpn[5]); | |
160 | + len = p - buf; | |
161 | + break; | |
145 | 162 | default: |
146 | 163 | return 0; |
147 | 164 | } |
148 | 165 | |
149 | 166 | |
... | ... | @@ -156,13 +173,40 @@ |
156 | 173 | char buf[20]; |
157 | 174 | int len; |
158 | 175 | |
159 | - if (key->conf.alg != ALG_CCMP) | |
176 | + switch (key->conf.alg) { | |
177 | + case ALG_CCMP: | |
178 | + len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | |
179 | + break; | |
180 | + case ALG_AES_CMAC: | |
181 | + len = scnprintf(buf, sizeof(buf), "%u\n", | |
182 | + key->u.aes_cmac.replays); | |
183 | + break; | |
184 | + default: | |
160 | 185 | return 0; |
161 | - len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | |
186 | + } | |
162 | 187 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); |
163 | 188 | } |
164 | 189 | KEY_OPS(replays); |
165 | 190 | |
191 | +static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |
192 | + size_t count, loff_t *ppos) | |
193 | +{ | |
194 | + struct ieee80211_key *key = file->private_data; | |
195 | + char buf[20]; | |
196 | + int len; | |
197 | + | |
198 | + switch (key->conf.alg) { | |
199 | + case ALG_AES_CMAC: | |
200 | + len = scnprintf(buf, sizeof(buf), "%u\n", | |
201 | + key->u.aes_cmac.icverrors); | |
202 | + break; | |
203 | + default: | |
204 | + return 0; | |
205 | + } | |
206 | + return simple_read_from_buffer(userbuf, count, ppos, buf, len); | |
207 | +} | |
208 | +KEY_OPS(icverrors); | |
209 | + | |
166 | 210 | static ssize_t key_key_read(struct file *file, char __user *userbuf, |
167 | 211 | size_t count, loff_t *ppos) |
168 | 212 | { |
... | ... | @@ -222,6 +266,7 @@ |
222 | 266 | DEBUGFS_ADD(tx_spec); |
223 | 267 | DEBUGFS_ADD(rx_spec); |
224 | 268 | DEBUGFS_ADD(replays); |
269 | + DEBUGFS_ADD(icverrors); | |
225 | 270 | DEBUGFS_ADD(key); |
226 | 271 | DEBUGFS_ADD(ifindex); |
227 | 272 | }; |
... | ... | @@ -243,6 +288,7 @@ |
243 | 288 | DEBUGFS_DEL(tx_spec); |
244 | 289 | DEBUGFS_DEL(rx_spec); |
245 | 290 | DEBUGFS_DEL(replays); |
291 | + DEBUGFS_DEL(icverrors); | |
246 | 292 | DEBUGFS_DEL(key); |
247 | 293 | DEBUGFS_DEL(ifindex); |
248 | 294 | |
... | ... | @@ -278,6 +324,35 @@ |
278 | 324 | |
279 | 325 | debugfs_remove(sdata->common_debugfs.default_key); |
280 | 326 | sdata->common_debugfs.default_key = NULL; |
327 | +} | |
328 | + | |
329 | +void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata) | |
330 | +{ | |
331 | + char buf[50]; | |
332 | + struct ieee80211_key *key; | |
333 | + | |
334 | + if (!sdata->debugfsdir) | |
335 | + return; | |
336 | + | |
337 | + /* this is running under the key lock */ | |
338 | + | |
339 | + key = sdata->default_mgmt_key; | |
340 | + if (key) { | |
341 | + sprintf(buf, "../keys/%d", key->debugfs.cnt); | |
342 | + sdata->common_debugfs.default_mgmt_key = | |
343 | + debugfs_create_symlink("default_mgmt_key", | |
344 | + sdata->debugfsdir, buf); | |
345 | + } else | |
346 | + ieee80211_debugfs_key_remove_mgmt_default(sdata); | |
347 | +} | |
348 | + | |
349 | +void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata) | |
350 | +{ | |
351 | + if (!sdata) | |
352 | + return; | |
353 | + | |
354 | + debugfs_remove(sdata->common_debugfs.default_mgmt_key); | |
355 | + sdata->common_debugfs.default_mgmt_key = NULL; | |
281 | 356 | } |
282 | 357 | |
283 | 358 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
net/mac80211/debugfs_key.h
... | ... | @@ -6,6 +6,10 @@ |
6 | 6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); |
7 | 7 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); |
8 | 8 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); |
9 | +void ieee80211_debugfs_key_add_mgmt_default( | |
10 | + struct ieee80211_sub_if_data *sdata); | |
11 | +void ieee80211_debugfs_key_remove_mgmt_default( | |
12 | + struct ieee80211_sub_if_data *sdata); | |
9 | 13 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
10 | 14 | struct sta_info *sta); |
11 | 15 | #else |
... | ... | @@ -17,6 +21,12 @@ |
17 | 21 | struct ieee80211_sub_if_data *sdata) |
18 | 22 | {} |
19 | 23 | static inline void ieee80211_debugfs_key_remove_default( |
24 | + struct ieee80211_sub_if_data *sdata) | |
25 | +{} | |
26 | +static inline void ieee80211_debugfs_key_add_mgmt_default( | |
27 | + struct ieee80211_sub_if_data *sdata) | |
28 | +{} | |
29 | +static inline void ieee80211_debugfs_key_remove_mgmt_default( | |
20 | 30 | struct ieee80211_sub_if_data *sdata) |
21 | 31 | {} |
22 | 32 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
net/mac80211/ieee80211_i.h
... | ... | @@ -409,8 +409,10 @@ |
409 | 409 | unsigned int fragment_next; |
410 | 410 | |
411 | 411 | #define NUM_DEFAULT_KEYS 4 |
412 | - struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; | |
412 | +#define NUM_DEFAULT_MGMT_KEYS 2 | |
413 | + struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | |
413 | 414 | struct ieee80211_key *default_key; |
415 | + struct ieee80211_key *default_mgmt_key; | |
414 | 416 | |
415 | 417 | u16 sequence_number; |
416 | 418 | |
... | ... | @@ -482,6 +484,7 @@ |
482 | 484 | } debugfs; |
483 | 485 | struct { |
484 | 486 | struct dentry *default_key; |
487 | + struct dentry *default_mgmt_key; | |
485 | 488 | } common_debugfs; |
486 | 489 | |
487 | 490 | #ifdef CONFIG_MAC80211_MESH |
net/mac80211/key.c
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | #include "ieee80211_i.h" |
19 | 19 | #include "debugfs_key.h" |
20 | 20 | #include "aes_ccm.h" |
21 | +#include "aes_cmac.h" | |
21 | 22 | |
22 | 23 | |
23 | 24 | /** |
24 | 25 | |
25 | 26 | |
... | ... | @@ -215,13 +216,38 @@ |
215 | 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; | |
218 | 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 | + | |
244 | + | |
219 | 245 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
220 | 246 | struct sta_info *sta, |
221 | 247 | struct ieee80211_key *old, |
222 | 248 | struct ieee80211_key *new) |
223 | 249 | { |
224 | - int idx, defkey; | |
250 | + int idx, defkey, defmgmtkey; | |
225 | 251 | |
226 | 252 | if (new) |
227 | 253 | list_add(&new->list, &sdata->key_list); |
228 | 254 | |
229 | 255 | |
... | ... | @@ -237,13 +263,19 @@ |
237 | 263 | idx = new->conf.keyidx; |
238 | 264 | |
239 | 265 | defkey = old && sdata->default_key == old; |
266 | + defmgmtkey = old && sdata->default_mgmt_key == old; | |
240 | 267 | |
241 | 268 | if (defkey && !new) |
242 | 269 | __ieee80211_set_default_key(sdata, -1); |
270 | + if (defmgmtkey && !new) | |
271 | + __ieee80211_set_default_mgmt_key(sdata, -1); | |
243 | 272 | |
244 | 273 | rcu_assign_pointer(sdata->keys[idx], new); |
245 | 274 | if (defkey && new) |
246 | 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 | 281 | if (old) { |
... | ... | @@ -262,7 +294,7 @@ |
262 | 294 | { |
263 | 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 | 299 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
268 | 300 | if (!key) |
... | ... | @@ -291,6 +323,10 @@ |
291 | 323 | key->conf.iv_len = CCMP_HDR_LEN; |
292 | 324 | key->conf.icv_len = CCMP_MIC_LEN; |
293 | 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 | 331 | memcpy(key->conf.key, key_data, key_len); |
296 | 332 | INIT_LIST_HEAD(&key->list); |
... | ... | @@ -308,6 +344,19 @@ |
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 | 360 | return key; |
312 | 361 | } |
313 | 362 | |
... | ... | @@ -461,6 +510,8 @@ |
461 | 510 | |
462 | 511 | if (key->conf.alg == ALG_CCMP) |
463 | 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 | 515 | ieee80211_debugfs_key_remove(key); |
465 | 516 | |
466 | 517 | kfree(key); |
... | ... | @@ -483,6 +534,7 @@ |
483 | 534 | list_del_init(&key->todo); |
484 | 535 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | |
485 | 536 | KEY_FLAG_TODO_DEFKEY | |
537 | + KEY_FLAG_TODO_DEFMGMTKEY | | |
486 | 538 | KEY_FLAG_TODO_HWACCEL_ADD | |
487 | 539 | KEY_FLAG_TODO_HWACCEL_REMOVE | |
488 | 540 | KEY_FLAG_TODO_DELETE); |
... | ... | @@ -500,6 +552,11 @@ |
500 | 552 | ieee80211_debugfs_key_add_default(key->sdata); |
501 | 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 | 560 | if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { |
504 | 561 | ieee80211_key_enable_hw_accel(key); |
505 | 562 | work_done = true; |
... | ... | @@ -535,6 +592,7 @@ |
535 | 592 | ieee80211_key_lock(); |
536 | 593 | |
537 | 594 | ieee80211_debugfs_key_remove_default(sdata); |
595 | + ieee80211_debugfs_key_remove_mgmt_default(sdata); | |
538 | 596 | |
539 | 597 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
540 | 598 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
net/mac80211/key.h
... | ... | @@ -46,6 +46,8 @@ |
46 | 46 | * acceleration. |
47 | 47 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. |
48 | 48 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. |
49 | + * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs | |
50 | + * to be updated. | |
49 | 51 | */ |
50 | 52 | enum ieee80211_internal_key_flags { |
51 | 53 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
... | ... | @@ -54,6 +56,7 @@ |
54 | 56 | KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), |
55 | 57 | KEY_FLAG_TODO_DEFKEY = BIT(4), |
56 | 58 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), |
59 | + KEY_FLAG_TODO_DEFMGMTKEY = BIT(6), | |
57 | 60 | }; |
58 | 61 | |
59 | 62 | struct tkip_ctx { |
... | ... | @@ -124,6 +127,7 @@ |
124 | 127 | struct dentry *tx_spec; |
125 | 128 | struct dentry *rx_spec; |
126 | 129 | struct dentry *replays; |
130 | + struct dentry *icverrors; | |
127 | 131 | struct dentry *key; |
128 | 132 | struct dentry *ifindex; |
129 | 133 | int cnt; |
... | ... | @@ -150,6 +154,8 @@ |
150 | 154 | struct sta_info *sta); |
151 | 155 | void ieee80211_key_free(struct ieee80211_key *key); |
152 | 156 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); |
157 | +void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |
158 | + int idx); | |
153 | 159 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
154 | 160 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
155 | 161 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
net/mac80211/rx.c
... | ... | @@ -446,6 +446,52 @@ |
446 | 446 | return RX_CONTINUE; |
447 | 447 | } |
448 | 448 | |
449 | + | |
450 | +static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) | |
451 | +{ | |
452 | + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
453 | + | |
454 | + if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) | |
455 | + return 0; | |
456 | + | |
457 | + return ieee80211_is_robust_mgmt_frame(hdr); | |
458 | +} | |
459 | + | |
460 | + | |
461 | +static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) | |
462 | +{ | |
463 | + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
464 | + | |
465 | + if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) | |
466 | + return 0; | |
467 | + | |
468 | + return ieee80211_is_robust_mgmt_frame(hdr); | |
469 | +} | |
470 | + | |
471 | + | |
472 | +/* Get the BIP key index from MMIE; return -1 if this is not a BIP frame */ | |
473 | +static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |
474 | +{ | |
475 | + struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | |
476 | + struct ieee80211_mmie *mmie; | |
477 | + | |
478 | + if (skb->len < 24 + sizeof(*mmie) || | |
479 | + !is_multicast_ether_addr(hdr->da)) | |
480 | + return -1; | |
481 | + | |
482 | + if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | |
483 | + return -1; /* not a robust management frame */ | |
484 | + | |
485 | + mmie = (struct ieee80211_mmie *) | |
486 | + (skb->data + skb->len - sizeof(*mmie)); | |
487 | + if (mmie->element_id != WLAN_EID_MMIE || | |
488 | + mmie->length != sizeof(*mmie) - 2) | |
489 | + return -1; | |
490 | + | |
491 | + return le16_to_cpu(mmie->key_id); | |
492 | +} | |
493 | + | |
494 | + | |
449 | 495 | static ieee80211_rx_result |
450 | 496 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
451 | 497 | { |
452 | 498 | |
453 | 499 | |
454 | 500 | |
... | ... | @@ -561,21 +607,23 @@ |
561 | 607 | int hdrlen; |
562 | 608 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
563 | 609 | struct ieee80211_key *stakey = NULL; |
610 | + int mmie_keyidx = -1; | |
564 | 611 | |
565 | 612 | /* |
566 | 613 | * Key selection 101 |
567 | 614 | * |
568 | - * There are three types of keys: | |
615 | + * There are four types of keys: | |
569 | 616 | * - GTK (group keys) |
617 | + * - IGTK (group keys for management frames) | |
570 | 618 | * - PTK (pairwise keys) |
571 | 619 | * - STK (station-to-station pairwise keys) |
572 | 620 | * |
573 | 621 | * When selecting a key, we have to distinguish between multicast |
574 | 622 | * (including broadcast) and unicast frames, the latter can only |
575 | - * use PTKs and STKs while the former always use GTKs. Unless, of | |
576 | - * course, actual WEP keys ("pre-RSNA") are used, then unicast | |
577 | - * frames can also use key indizes like GTKs. Hence, if we don't | |
578 | - * have a PTK/STK we check the key index for a WEP key. | |
623 | + * use PTKs and STKs while the former always use GTKs and IGTKs. | |
624 | + * Unless, of course, actual WEP keys ("pre-RSNA") are used, then | |
625 | + * unicast frames can also use key indices like GTKs. Hence, if we | |
626 | + * don't have a PTK/STK we check the key index for a WEP key. | |
579 | 627 | * |
580 | 628 | * Note that in a regular BSS, multicast frames are sent by the |
581 | 629 | * AP only, associated stations unicast the frame to the AP first |
... | ... | @@ -588,8 +636,14 @@ |
588 | 636 | * possible. |
589 | 637 | */ |
590 | 638 | |
591 | - if (!ieee80211_has_protected(hdr->frame_control)) | |
592 | - return RX_CONTINUE; | |
639 | + if (!ieee80211_has_protected(hdr->frame_control)) { | |
640 | + if (!ieee80211_is_mgmt(hdr->frame_control) || | |
641 | + rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP)) | |
642 | + return RX_CONTINUE; | |
643 | + mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | |
644 | + if (mmie_keyidx < 0) | |
645 | + return RX_CONTINUE; | |
646 | + } | |
593 | 647 | |
594 | 648 | /* |
595 | 649 | * No point in finding a key and decrypting if the frame is neither |
... | ... | @@ -603,6 +657,16 @@ |
603 | 657 | |
604 | 658 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { |
605 | 659 | rx->key = stakey; |
660 | + } else if (mmie_keyidx >= 0) { | |
661 | + /* Broadcast/multicast robust management frame / BIP */ | |
662 | + if ((rx->status->flag & RX_FLAG_DECRYPTED) && | |
663 | + (rx->status->flag & RX_FLAG_IV_STRIPPED)) | |
664 | + return RX_CONTINUE; | |
665 | + | |
666 | + if (mmie_keyidx < NUM_DEFAULT_KEYS || | |
667 | + mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | |
668 | + return RX_DROP_MONITOR; /* unexpected BIP keyidx */ | |
669 | + rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | |
606 | 670 | } else { |
607 | 671 | /* |
608 | 672 | * The device doesn't give us the IV so we won't be |
... | ... | @@ -665,6 +729,9 @@ |
665 | 729 | case ALG_CCMP: |
666 | 730 | result = ieee80211_crypto_ccmp_decrypt(rx); |
667 | 731 | break; |
732 | + case ALG_AES_CMAC: | |
733 | + result = ieee80211_crypto_aes_cmac_decrypt(rx); | |
734 | + break; | |
668 | 735 | } |
669 | 736 | |
670 | 737 | /* either the frame has been decrypted or will be dropped */ |
... | ... | @@ -1112,6 +1179,15 @@ |
1112 | 1179 | /* Drop unencrypted frames if key is set. */ |
1113 | 1180 | if (unlikely(!ieee80211_has_protected(fc) && |
1114 | 1181 | !ieee80211_is_nullfunc(fc) && |
1182 | + (!ieee80211_is_mgmt(fc) || | |
1183 | + (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && | |
1184 | + rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) && | |
1185 | + (rx->key || rx->sdata->drop_unencrypted))) | |
1186 | + return -EACCES; | |
1187 | + /* BIP does not use Protected field, so need to check MMIE */ | |
1188 | + if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) && | |
1189 | + ieee80211_is_multicast_robust_mgmt_frame(rx->skb) && | |
1190 | + ieee80211_get_mmie_keyidx(rx->skb) < 0 && | |
1115 | 1191 | (rx->key || rx->sdata->drop_unencrypted))) |
1116 | 1192 | return -EACCES; |
1117 | 1193 |
net/mac80211/tx.c
... | ... | @@ -425,6 +425,9 @@ |
425 | 425 | tx->key = NULL; |
426 | 426 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) |
427 | 427 | tx->key = key; |
428 | + else if (ieee80211_is_mgmt(hdr->frame_control) && | |
429 | + (key = rcu_dereference(tx->sdata->default_mgmt_key))) | |
430 | + tx->key = key; | |
428 | 431 | else if ((key = rcu_dereference(tx->sdata->default_key))) |
429 | 432 | tx->key = key; |
430 | 433 | else if (tx->sdata->drop_unencrypted && |
... | ... | @@ -453,6 +456,10 @@ |
453 | 456 | tx->skb)) |
454 | 457 | tx->key = NULL; |
455 | 458 | break; |
459 | + case ALG_AES_CMAC: | |
460 | + if (!ieee80211_is_mgmt(hdr->frame_control)) | |
461 | + tx->key = NULL; | |
462 | + break; | |
456 | 463 | } |
457 | 464 | } |
458 | 465 | |
... | ... | @@ -808,6 +815,8 @@ |
808 | 815 | return ieee80211_crypto_tkip_encrypt(tx); |
809 | 816 | case ALG_CCMP: |
810 | 817 | return ieee80211_crypto_ccmp_encrypt(tx); |
818 | + case ALG_AES_CMAC: | |
819 | + return ieee80211_crypto_aes_cmac_encrypt(tx); | |
811 | 820 | } |
812 | 821 | |
813 | 822 | /* not reached */ |
net/wireless/nl80211.c
... | ... | @@ -738,7 +738,7 @@ |
738 | 738 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
739 | 739 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
740 | 740 | |
741 | - if (key_idx > 3) | |
741 | + if (key_idx > 5) | |
742 | 742 | return -EINVAL; |
743 | 743 | |
744 | 744 | if (info->attrs[NL80211_ATTR_MAC]) |
745 | 745 | |
746 | 746 | |
747 | 747 | |
748 | 748 | |
... | ... | @@ -804,30 +804,41 @@ |
804 | 804 | int err; |
805 | 805 | struct net_device *dev; |
806 | 806 | u8 key_idx; |
807 | + int (*func)(struct wiphy *wiphy, struct net_device *netdev, | |
808 | + u8 key_index); | |
807 | 809 | |
808 | 810 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) |
809 | 811 | return -EINVAL; |
810 | 812 | |
811 | 813 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
812 | 814 | |
813 | - if (key_idx > 3) | |
815 | + if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) { | |
816 | + if (key_idx < 4 || key_idx > 5) | |
817 | + return -EINVAL; | |
818 | + } else if (key_idx > 3) | |
814 | 819 | return -EINVAL; |
815 | 820 | |
816 | 821 | /* currently only support setting default key */ |
817 | - if (!info->attrs[NL80211_ATTR_KEY_DEFAULT]) | |
822 | + if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] && | |
823 | + !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | |
818 | 824 | return -EINVAL; |
819 | 825 | |
820 | 826 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
821 | 827 | if (err) |
822 | 828 | return err; |
823 | 829 | |
824 | - if (!drv->ops->set_default_key) { | |
830 | + if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) | |
831 | + func = drv->ops->set_default_key; | |
832 | + else | |
833 | + func = drv->ops->set_default_mgmt_key; | |
834 | + | |
835 | + if (!func) { | |
825 | 836 | err = -EOPNOTSUPP; |
826 | 837 | goto out; |
827 | 838 | } |
828 | 839 | |
829 | 840 | rtnl_lock(); |
830 | - err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); | |
841 | + err = func(&drv->wiphy, dev, key_idx); | |
831 | 842 | rtnl_unlock(); |
832 | 843 | |
833 | 844 | out: |
... | ... | @@ -863,7 +874,7 @@ |
863 | 874 | if (info->attrs[NL80211_ATTR_MAC]) |
864 | 875 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
865 | 876 | |
866 | - if (key_idx > 3) | |
877 | + if (key_idx > 5) | |
867 | 878 | return -EINVAL; |
868 | 879 | |
869 | 880 | /* |
... | ... | @@ -894,6 +905,10 @@ |
894 | 905 | if (params.key_len != 13) |
895 | 906 | return -EINVAL; |
896 | 907 | break; |
908 | + case WLAN_CIPHER_SUITE_AES_CMAC: | |
909 | + if (params.key_len != 16) | |
910 | + return -EINVAL; | |
911 | + break; | |
897 | 912 | default: |
898 | 913 | return -EINVAL; |
899 | 914 | } |
... | ... | @@ -928,7 +943,7 @@ |
928 | 943 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
929 | 944 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
930 | 945 | |
931 | - if (key_idx > 3) | |
946 | + if (key_idx > 5) | |
932 | 947 | return -EINVAL; |
933 | 948 | |
934 | 949 | if (info->attrs[NL80211_ATTR_MAC]) |