aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2009-01-08 06:32:02 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:03 -0500
commit3cfcf6ac6d69dc290e96416731eea5c88ac7d426 (patch)
tree35bc626e2e3f7c37a7eb50c1f057adb4830eccc6
parent765cb46a3fc856245ea68a7c961ac87c77e4ae2d (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>
-rw-r--r--drivers/net/wireless/ath5k/pcu.c3
-rw-r--r--include/linux/ieee80211.h1
-rw-r--r--include/linux/nl80211.h6
-rw-r--r--include/net/cfg80211.h5
-rw-r--r--include/net/mac80211.h2
-rw-r--r--net/mac80211/cfg.c31
-rw-r--r--net/mac80211/debugfs_key.c79
-rw-r--r--net/mac80211/debugfs_key.h10
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/key.c62
-rw-r--r--net/mac80211/key.h6
-rw-r--r--net/mac80211/rx.c90
-rw-r--r--net/mac80211/tx.c9
-rw-r--r--net/wireless/nl80211.c29
14 files changed, 317 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index 5b416ed65299..e758b70ab7eb 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -1026,6 +1026,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key)
1026 return AR5K_KEYTABLE_TYPE_40; 1026 return AR5K_KEYTABLE_TYPE_40;
1027 else if (key->keylen == LEN_WEP104) 1027 else if (key->keylen == LEN_WEP104)
1028 return AR5K_KEYTABLE_TYPE_104; 1028 return AR5K_KEYTABLE_TYPE_104;
1029 return -EINVAL;
1030 default:
1031 return -EINVAL;
1029 } 1032 }
1030 return -EINVAL; 1033 return -EINVAL;
1031} 1034}
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index cceb9e86c744..df98a8a549a2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1139,6 +1139,7 @@ enum ieee80211_back_parties {
1139/* reserved: 0x000FAC03 */ 1139/* reserved: 0x000FAC03 */
1140#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 1140#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
1141#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 1141#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
1142#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
1142 1143
1143#define WLAN_MAX_KEY_LEN 32 1144#define WLAN_MAX_KEY_LEN 32
1144 1145
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 218f0e73a7ae..ee742bc9761e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -72,8 +72,8 @@
72 * 72 *
73 * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified 73 * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
74 * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. 74 * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
75 * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or 75 * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
76 * %NL80211_ATTR_KEY_THRESHOLD. 76 * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
77 * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, 77 * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
78 * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER 78 * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
79 * attributes. 79 * attributes.
@@ -346,6 +346,8 @@ enum nl80211_attrs {
346 NL80211_ATTR_WIPHY_FREQ, 346 NL80211_ATTR_WIPHY_FREQ,
347 NL80211_ATTR_WIPHY_CHANNEL_TYPE, 347 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
348 348
349 NL80211_ATTR_KEY_DEFAULT_MGMT,
350
349 /* add attributes here, update the policy in nl80211.c */ 351 /* add attributes here, update the policy in nl80211.c */
350 352
351 __NL80211_ATTR_AFTER_LAST, 353 __NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6619ed106134..df78abc496f1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -473,6 +473,8 @@ struct ieee80211_channel;
473 * 473 *
474 * @set_default_key: set the default key on an interface 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 * @add_beacon: Add a beacon with given parameters, @head, @interval 478 * @add_beacon: Add a beacon with given parameters, @head, @interval
477 * and @dtim_period will be valid, @tail is optional. 479 * and @dtim_period will be valid, @tail is optional.
478 * @set_beacon: Change the beacon parameters for an access point mode 480 * @set_beacon: Change the beacon parameters for an access point mode
@@ -520,6 +522,9 @@ struct cfg80211_ops {
520 int (*set_default_key)(struct wiphy *wiphy, 522 int (*set_default_key)(struct wiphy *wiphy,
521 struct net_device *netdev, 523 struct net_device *netdev,
522 u8 key_index); 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 int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, 529 int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev,
525 struct beacon_parameters *info); 530 struct beacon_parameters *info);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 8a305bfdb87b..61f1f37a9e27 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -651,11 +651,13 @@ struct ieee80211_if_conf {
651 * @ALG_WEP: WEP40 or WEP104 651 * @ALG_WEP: WEP40 or WEP104
652 * @ALG_TKIP: TKIP 652 * @ALG_TKIP: TKIP
653 * @ALG_CCMP: CCMP (AES) 653 * @ALG_CCMP: CCMP (AES)
654 * @ALG_AES_CMAC: AES-128-CMAC
654 */ 655 */
655enum ieee80211_key_alg { 656enum ieee80211_key_alg {
656 ALG_WEP, 657 ALG_WEP,
657 ALG_TKIP, 658 ALG_TKIP,
658 ALG_CCMP, 659 ALG_CCMP,
660 ALG_AES_CMAC,
659}; 661};
660 662
661/** 663/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 309d9189aa49..72c106915433 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -133,6 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
133 case WLAN_CIPHER_SUITE_CCMP: 133 case WLAN_CIPHER_SUITE_CCMP:
134 alg = ALG_CCMP; 134 alg = ALG_CCMP;
135 break; 135 break;
136 case WLAN_CIPHER_SUITE_AES_CMAC:
137 alg = ALG_AES_CMAC;
138 break;
136 default: 139 default:
137 return -EINVAL; 140 return -EINVAL;
138 } 141 }
@@ -275,6 +278,17 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
275 else 278 else
276 params.cipher = WLAN_CIPHER_SUITE_WEP104; 279 params.cipher = WLAN_CIPHER_SUITE_WEP104;
277 break; 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 params.key = key->conf.key; 294 params.key = key->conf.key;
@@ -304,6 +318,22 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
304 return 0; 318 return 0;
305} 319}
306 320
321static 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
307static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) 337static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
308{ 338{
309 struct ieee80211_sub_if_data *sdata = sta->sdata; 339 struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -1153,6 +1183,7 @@ struct cfg80211_ops mac80211_config_ops = {
1153 .del_key = ieee80211_del_key, 1183 .del_key = ieee80211_del_key,
1154 .get_key = ieee80211_get_key, 1184 .get_key = ieee80211_get_key,
1155 .set_default_key = ieee80211_config_default_key, 1185 .set_default_key = ieee80211_config_default_key,
1186 .set_default_mgmt_key = ieee80211_config_default_mgmt_key,
1156 .add_beacon = ieee80211_add_beacon, 1187 .add_beacon = ieee80211_add_beacon,
1157 .set_beacon = ieee80211_set_beacon, 1188 .set_beacon = ieee80211_set_beacon,
1158 .del_beacon = ieee80211_del_beacon, 1189 .del_beacon = ieee80211_del_beacon,
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 6424ac565ae0..99c752588b30 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -76,6 +76,9 @@ static ssize_t key_algorithm_read(struct file *file,
76 case ALG_CCMP: 76 case ALG_CCMP:
77 alg = "CCMP\n"; 77 alg = "CCMP\n";
78 break; 78 break;
79 case ALG_AES_CMAC:
80 alg = "AES-128-CMAC\n";
81 break;
79 default: 82 default:
80 return 0; 83 return 0;
81 } 84 }
@@ -105,6 +108,12 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
105 len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", 108 len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
106 tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); 109 tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
107 break; 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 default: 117 default:
109 return 0; 118 return 0;
110 } 119 }
@@ -142,6 +151,14 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
142 } 151 }
143 len = p - buf; 152 len = p - buf;
144 break; 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 default: 162 default:
146 return 0; 163 return 0;
147 } 164 }
@@ -156,13 +173,40 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf,
156 char buf[20]; 173 char buf[20];
157 int len; 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 return 0; 185 return 0;
161 len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); 186 }
162 return simple_read_from_buffer(userbuf, count, ppos, buf, len); 187 return simple_read_from_buffer(userbuf, count, ppos, buf, len);
163} 188}
164KEY_OPS(replays); 189KEY_OPS(replays);
165 190
191static 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}
208KEY_OPS(icverrors);
209
166static ssize_t key_key_read(struct file *file, char __user *userbuf, 210static ssize_t key_key_read(struct file *file, char __user *userbuf,
167 size_t count, loff_t *ppos) 211 size_t count, loff_t *ppos)
168{ 212{
@@ -222,6 +266,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
222 DEBUGFS_ADD(tx_spec); 266 DEBUGFS_ADD(tx_spec);
223 DEBUGFS_ADD(rx_spec); 267 DEBUGFS_ADD(rx_spec);
224 DEBUGFS_ADD(replays); 268 DEBUGFS_ADD(replays);
269 DEBUGFS_ADD(icverrors);
225 DEBUGFS_ADD(key); 270 DEBUGFS_ADD(key);
226 DEBUGFS_ADD(ifindex); 271 DEBUGFS_ADD(ifindex);
227}; 272};
@@ -243,6 +288,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
243 DEBUGFS_DEL(tx_spec); 288 DEBUGFS_DEL(tx_spec);
244 DEBUGFS_DEL(rx_spec); 289 DEBUGFS_DEL(rx_spec);
245 DEBUGFS_DEL(replays); 290 DEBUGFS_DEL(replays);
291 DEBUGFS_DEL(icverrors);
246 DEBUGFS_DEL(key); 292 DEBUGFS_DEL(key);
247 DEBUGFS_DEL(ifindex); 293 DEBUGFS_DEL(ifindex);
248 294
@@ -280,6 +326,35 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
280 sdata->common_debugfs.default_key = NULL; 326 sdata->common_debugfs.default_key = NULL;
281} 327}
282 328
329void 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
349void 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;
356}
357
283void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 358void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
284 struct sta_info *sta) 359 struct sta_info *sta)
285{ 360{
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h
index b1a3754ee240..54717b4e1371 100644
--- a/net/mac80211/debugfs_key.h
+++ b/net/mac80211/debugfs_key.h
@@ -6,6 +6,10 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key);
6void ieee80211_debugfs_key_remove(struct ieee80211_key *key); 6void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
7void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); 7void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
8void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); 8void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
9void ieee80211_debugfs_key_add_mgmt_default(
10 struct ieee80211_sub_if_data *sdata);
11void ieee80211_debugfs_key_remove_mgmt_default(
12 struct ieee80211_sub_if_data *sdata);
9void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 13void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
10 struct sta_info *sta); 14 struct sta_info *sta);
11#else 15#else
@@ -19,6 +23,12 @@ static inline void ieee80211_debugfs_key_add_default(
19static inline void ieee80211_debugfs_key_remove_default( 23static inline void ieee80211_debugfs_key_remove_default(
20 struct ieee80211_sub_if_data *sdata) 24 struct ieee80211_sub_if_data *sdata)
21{} 25{}
26static inline void ieee80211_debugfs_key_add_mgmt_default(
27 struct ieee80211_sub_if_data *sdata)
28{}
29static inline void ieee80211_debugfs_key_remove_mgmt_default(
30 struct ieee80211_sub_if_data *sdata)
31{}
22static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 32static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
23 struct sta_info *sta) 33 struct sta_info *sta)
24{} 34{}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 20af92abd61d..8c3245717c55 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -409,8 +409,10 @@ struct ieee80211_sub_if_data {
409 unsigned int fragment_next; 409 unsigned int fragment_next;
410 410
411#define NUM_DEFAULT_KEYS 4 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 struct ieee80211_key *default_key; 414 struct ieee80211_key *default_key;
415 struct ieee80211_key *default_mgmt_key;
414 416
415 u16 sequence_number; 417 u16 sequence_number;
416 418
@@ -482,6 +484,7 @@ struct ieee80211_sub_if_data {
482 } debugfs; 484 } debugfs;
483 struct { 485 struct {
484 struct dentry *default_key; 486 struct dentry *default_key;
487 struct dentry *default_mgmt_key;
485 } common_debugfs; 488 } common_debugfs;
486 489
487#ifdef CONFIG_MAC80211_MESH 490#ifdef CONFIG_MAC80211_MESH
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
219static 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
234void 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
219static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, 245static 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)
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 73ac28ca2ede..215d3ef42a4f 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -46,6 +46,8 @@ struct sta_info;
46 * acceleration. 46 * acceleration.
47 * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. 47 * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
48 * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. 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 */
50enum ieee80211_internal_key_flags { 52enum ieee80211_internal_key_flags {
51 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), 53 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
@@ -54,6 +56,7 @@ enum ieee80211_internal_key_flags {
54 KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), 56 KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
55 KEY_FLAG_TODO_DEFKEY = BIT(4), 57 KEY_FLAG_TODO_DEFKEY = BIT(4),
56 KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), 58 KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
59 KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
57}; 60};
58 61
59struct tkip_ctx { 62struct tkip_ctx {
@@ -124,6 +127,7 @@ struct ieee80211_key {
124 struct dentry *tx_spec; 127 struct dentry *tx_spec;
125 struct dentry *rx_spec; 128 struct dentry *rx_spec;
126 struct dentry *replays; 129 struct dentry *replays;
130 struct dentry *icverrors;
127 struct dentry *key; 131 struct dentry *key;
128 struct dentry *ifindex; 132 struct dentry *ifindex;
129 int cnt; 133 int cnt;
@@ -150,6 +154,8 @@ void ieee80211_key_link(struct ieee80211_key *key,
150 struct sta_info *sta); 154 struct sta_info *sta);
151void ieee80211_key_free(struct ieee80211_key *key); 155void ieee80211_key_free(struct ieee80211_key *key);
152void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); 156void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
157void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
158 int idx);
153void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); 159void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
154void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); 160void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
155void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); 161void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b68e082e99ce..abc3aa583ca6 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -446,6 +446,52 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
446 return RX_CONTINUE; 446 return RX_CONTINUE;
447} 447}
448 448
449
450static 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
461static 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 */
473static 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
449static ieee80211_rx_result 495static ieee80211_rx_result
450ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) 496ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
451{ 497{
@@ -561,21 +607,23 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
561 int hdrlen; 607 int hdrlen;
562 ieee80211_rx_result result = RX_DROP_UNUSABLE; 608 ieee80211_rx_result result = RX_DROP_UNUSABLE;
563 struct ieee80211_key *stakey = NULL; 609 struct ieee80211_key *stakey = NULL;
610 int mmie_keyidx = -1;
564 611
565 /* 612 /*
566 * Key selection 101 613 * Key selection 101
567 * 614 *
568 * There are three types of keys: 615 * There are four types of keys:
569 * - GTK (group keys) 616 * - GTK (group keys)
617 * - IGTK (group keys for management frames)
570 * - PTK (pairwise keys) 618 * - PTK (pairwise keys)
571 * - STK (station-to-station pairwise keys) 619 * - STK (station-to-station pairwise keys)
572 * 620 *
573 * When selecting a key, we have to distinguish between multicast 621 * When selecting a key, we have to distinguish between multicast
574 * (including broadcast) and unicast frames, the latter can only 622 * (including broadcast) and unicast frames, the latter can only
575 * use PTKs and STKs while the former always use GTKs. Unless, of 623 * use PTKs and STKs while the former always use GTKs and IGTKs.
576 * course, actual WEP keys ("pre-RSNA") are used, then unicast 624 * Unless, of course, actual WEP keys ("pre-RSNA") are used, then
577 * frames can also use key indizes like GTKs. Hence, if we don't 625 * unicast frames can also use key indices like GTKs. Hence, if we
578 * have a PTK/STK we check the key index for a WEP key. 626 * don't have a PTK/STK we check the key index for a WEP key.
579 * 627 *
580 * Note that in a regular BSS, multicast frames are sent by the 628 * Note that in a regular BSS, multicast frames are sent by the
581 * AP only, associated stations unicast the frame to the AP first 629 * AP only, associated stations unicast the frame to the AP first
@@ -588,8 +636,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
588 * possible. 636 * possible.
589 */ 637 */
590 638
591 if (!ieee80211_has_protected(hdr->frame_control)) 639 if (!ieee80211_has_protected(hdr->frame_control)) {
592 return RX_CONTINUE; 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 * No point in finding a key and decrypting if the frame is neither 649 * No point in finding a key and decrypting if the frame is neither
@@ -603,6 +657,16 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
603 657
604 if (!is_multicast_ether_addr(hdr->addr1) && stakey) { 658 if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
605 rx->key = stakey; 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 } else { 670 } else {
607 /* 671 /*
608 * The device doesn't give us the IV so we won't be 672 * The device doesn't give us the IV so we won't be
@@ -665,6 +729,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
665 case ALG_CCMP: 729 case ALG_CCMP:
666 result = ieee80211_crypto_ccmp_decrypt(rx); 730 result = ieee80211_crypto_ccmp_decrypt(rx);
667 break; 731 break;
732 case ALG_AES_CMAC:
733 result = ieee80211_crypto_aes_cmac_decrypt(rx);
734 break;
668 } 735 }
669 736
670 /* either the frame has been decrypted or will be dropped */ 737 /* either the frame has been decrypted or will be dropped */
@@ -1112,6 +1179,15 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
1112 /* Drop unencrypted frames if key is set. */ 1179 /* Drop unencrypted frames if key is set. */
1113 if (unlikely(!ieee80211_has_protected(fc) && 1180 if (unlikely(!ieee80211_has_protected(fc) &&
1114 !ieee80211_is_nullfunc(fc) && 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 (rx->key || rx->sdata->drop_unencrypted))) 1191 (rx->key || rx->sdata->drop_unencrypted)))
1116 return -EACCES; 1192 return -EACCES;
1117 1193
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 50c6c4fabea5..ad53ea9e9c77 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -425,6 +425,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
425 tx->key = NULL; 425 tx->key = NULL;
426 else if (tx->sta && (key = rcu_dereference(tx->sta->key))) 426 else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
427 tx->key = key; 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 else if ((key = rcu_dereference(tx->sdata->default_key))) 431 else if ((key = rcu_dereference(tx->sdata->default_key)))
429 tx->key = key; 432 tx->key = key;
430 else if (tx->sdata->drop_unencrypted && 433 else if (tx->sdata->drop_unencrypted &&
@@ -453,6 +456,10 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
453 tx->skb)) 456 tx->skb))
454 tx->key = NULL; 457 tx->key = NULL;
455 break; 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 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
808 return ieee80211_crypto_tkip_encrypt(tx); 815 return ieee80211_crypto_tkip_encrypt(tx);
809 case ALG_CCMP: 816 case ALG_CCMP:
810 return ieee80211_crypto_ccmp_encrypt(tx); 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 /* not reached */ 822 /* not reached */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1e728fff474e..123d3b160fad 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -738,7 +738,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
738 if (info->attrs[NL80211_ATTR_KEY_IDX]) 738 if (info->attrs[NL80211_ATTR_KEY_IDX])
739 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 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 return -EINVAL; 742 return -EINVAL;
743 743
744 if (info->attrs[NL80211_ATTR_MAC]) 744 if (info->attrs[NL80211_ATTR_MAC])
@@ -804,30 +804,41 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
804 int err; 804 int err;
805 struct net_device *dev; 805 struct net_device *dev;
806 u8 key_idx; 806 u8 key_idx;
807 int (*func)(struct wiphy *wiphy, struct net_device *netdev,
808 u8 key_index);
807 809
808 if (!info->attrs[NL80211_ATTR_KEY_IDX]) 810 if (!info->attrs[NL80211_ATTR_KEY_IDX])
809 return -EINVAL; 811 return -EINVAL;
810 812
811 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 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 return -EINVAL; 819 return -EINVAL;
815 820
816 /* currently only support setting default key */ 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 return -EINVAL; 824 return -EINVAL;
819 825
820 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 826 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
821 if (err) 827 if (err)
822 return err; 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 err = -EOPNOTSUPP; 836 err = -EOPNOTSUPP;
826 goto out; 837 goto out;
827 } 838 }
828 839
829 rtnl_lock(); 840 rtnl_lock();
830 err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx); 841 err = func(&drv->wiphy, dev, key_idx);
831 rtnl_unlock(); 842 rtnl_unlock();
832 843
833 out: 844 out:
@@ -863,7 +874,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
863 if (info->attrs[NL80211_ATTR_MAC]) 874 if (info->attrs[NL80211_ATTR_MAC])
864 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 875 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
865 876
866 if (key_idx > 3) 877 if (key_idx > 5)
867 return -EINVAL; 878 return -EINVAL;
868 879
869 /* 880 /*
@@ -894,6 +905,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
894 if (params.key_len != 13) 905 if (params.key_len != 13)
895 return -EINVAL; 906 return -EINVAL;
896 break; 907 break;
908 case WLAN_CIPHER_SUITE_AES_CMAC:
909 if (params.key_len != 16)
910 return -EINVAL;
911 break;
897 default: 912 default:
898 return -EINVAL; 913 return -EINVAL;
899 } 914 }
@@ -928,7 +943,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
928 if (info->attrs[NL80211_ATTR_KEY_IDX]) 943 if (info->attrs[NL80211_ATTR_KEY_IDX])
929 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); 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 return -EINVAL; 947 return -EINVAL;
933 948
934 if (info->attrs[NL80211_ATTR_MAC]) 949 if (info->attrs[NL80211_ATTR_MAC])