diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-10-05 13:39:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-06 16:30:40 -0400 |
commit | e31b82136d1adc7a599b6e99d3321e5831841f5a (patch) | |
tree | c72d78d4cccfd08587e909c7efe59956f1cbc23e /net | |
parent | 53f73c09d64f1fa7d7e6e8b6bb7468d42eddc92d (diff) |
cfg80211/mac80211: allow per-station GTKs
This adds API to allow adding per-station GTKs,
updates mac80211 to support it, and also allows
drivers to remove a key from hwaccel again when
this may be necessary due to multiple GTKs.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 32 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/key.c | 95 | ||||
-rw-r--r-- | net/mac80211/key.h | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 41 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 10 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/ibss.c | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 87 | ||||
-rw-r--r-- | net/wireless/sme.c | 2 | ||||
-rw-r--r-- | net/wireless/util.c | 12 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 38 |
14 files changed, 239 insertions, 95 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 94bf550bd4c9..8b0e874a3d65 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -103,7 +103,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 105 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
106 | u8 key_idx, const u8 *mac_addr, | 106 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
107 | struct key_params *params) | 107 | struct key_params *params) |
108 | { | 108 | { |
109 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 109 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -131,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
131 | if (IS_ERR(key)) | 131 | if (IS_ERR(key)) |
132 | return PTR_ERR(key); | 132 | return PTR_ERR(key); |
133 | 133 | ||
134 | if (pairwise) | ||
135 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | ||
136 | |||
134 | mutex_lock(&sdata->local->sta_mtx); | 137 | mutex_lock(&sdata->local->sta_mtx); |
135 | 138 | ||
136 | if (mac_addr) { | 139 | if (mac_addr) { |
@@ -153,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
153 | } | 156 | } |
154 | 157 | ||
155 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 158 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
156 | u8 key_idx, const u8 *mac_addr) | 159 | u8 key_idx, bool pairwise, const u8 *mac_addr) |
157 | { | 160 | { |
158 | struct ieee80211_sub_if_data *sdata; | 161 | struct ieee80211_sub_if_data *sdata; |
159 | struct sta_info *sta; | 162 | struct sta_info *sta; |
@@ -170,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
170 | if (!sta) | 173 | if (!sta) |
171 | goto out_unlock; | 174 | goto out_unlock; |
172 | 175 | ||
173 | if (sta->key) { | 176 | if (pairwise) { |
174 | ieee80211_key_free(sdata->local, sta->key); | 177 | if (sta->ptk) { |
175 | WARN_ON(sta->key); | 178 | ieee80211_key_free(sdata->local, sta->ptk); |
176 | ret = 0; | 179 | ret = 0; |
180 | } | ||
181 | } else { | ||
182 | if (sta->gtk[key_idx]) { | ||
183 | ieee80211_key_free(sdata->local, | ||
184 | sta->gtk[key_idx]); | ||
185 | ret = 0; | ||
186 | } | ||
177 | } | 187 | } |
178 | 188 | ||
179 | goto out_unlock; | 189 | goto out_unlock; |
@@ -195,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
195 | } | 205 | } |
196 | 206 | ||
197 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 207 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
198 | u8 key_idx, const u8 *mac_addr, void *cookie, | 208 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
209 | void *cookie, | ||
199 | void (*callback)(void *cookie, | 210 | void (*callback)(void *cookie, |
200 | struct key_params *params)) | 211 | struct key_params *params)) |
201 | { | 212 | { |
@@ -203,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
203 | struct sta_info *sta = NULL; | 214 | struct sta_info *sta = NULL; |
204 | u8 seq[6] = {0}; | 215 | u8 seq[6] = {0}; |
205 | struct key_params params; | 216 | struct key_params params; |
206 | struct ieee80211_key *key; | 217 | struct ieee80211_key *key = NULL; |
207 | u32 iv32; | 218 | u32 iv32; |
208 | u16 iv16; | 219 | u16 iv16; |
209 | int err = -ENOENT; | 220 | int err = -ENOENT; |
@@ -217,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
217 | if (!sta) | 228 | if (!sta) |
218 | goto out; | 229 | goto out; |
219 | 230 | ||
220 | key = sta->key; | 231 | if (pairwise) |
232 | key = sta->ptk; | ||
233 | else if (key_idx < NUM_DEFAULT_KEYS) | ||
234 | key = sta->gtk[key_idx]; | ||
221 | } else | 235 | } else |
222 | key = sdata->keys[key_idx]; | 236 | key = sdata->keys[key_idx]; |
223 | 237 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 76c2b50ec6f8..f0610fa4fbe0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -549,8 +549,6 @@ struct ieee80211_sub_if_data { | |||
549 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; | 549 | struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; |
550 | unsigned int fragment_next; | 550 | unsigned int fragment_next; |
551 | 551 | ||
552 | #define NUM_DEFAULT_KEYS 4 | ||
553 | #define NUM_DEFAULT_MGMT_KEYS 2 | ||
554 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 552 | struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
555 | struct ieee80211_key *default_key; | 553 | struct ieee80211_key *default_key; |
556 | struct ieee80211_key *default_mgmt_key; | 554 | struct ieee80211_key *default_mgmt_key; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 6a63d1abd14d..ccd676b2f599 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
68 | 68 | ||
69 | might_sleep(); | 69 | might_sleep(); |
70 | 70 | ||
71 | if (!key->local->ops->set_key) { | 71 | if (!key->local->ops->set_key) |
72 | ret = -EOPNOTSUPP; | ||
73 | goto out_unsupported; | 72 | goto out_unsupported; |
74 | } | ||
75 | 73 | ||
76 | assert_key_lock(key->local); | 74 | assert_key_lock(key->local); |
77 | 75 | ||
78 | sta = get_sta_for_key(key); | 76 | sta = get_sta_for_key(key); |
79 | 77 | ||
78 | /* | ||
79 | * If this is a per-STA GTK, check if it | ||
80 | * is supported; if not, return. | ||
81 | */ | ||
82 | if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) && | ||
83 | !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) | ||
84 | goto out_unsupported; | ||
85 | |||
80 | sdata = key->sdata; | 86 | sdata = key->sdata; |
81 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 87 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
82 | sdata = container_of(sdata->bss, | 88 | sdata = container_of(sdata->bss, |
@@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
85 | 91 | ||
86 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); | 92 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); |
87 | 93 | ||
88 | if (!ret) | 94 | if (!ret) { |
89 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 95 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
96 | return 0; | ||
97 | } | ||
90 | 98 | ||
91 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 99 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) |
92 | wiphy_err(key->local->hw.wiphy, | 100 | wiphy_err(key->local->hw.wiphy, |
93 | "failed to set key (%d, %pM) to hardware (%d)\n", | 101 | "failed to set key (%d, %pM) to hardware (%d)\n", |
94 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 102 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
95 | 103 | ||
96 | out_unsupported: | 104 | out_unsupported: |
97 | if (ret) { | 105 | switch (key->conf.cipher) { |
98 | switch (key->conf.cipher) { | 106 | case WLAN_CIPHER_SUITE_WEP40: |
99 | case WLAN_CIPHER_SUITE_WEP40: | 107 | case WLAN_CIPHER_SUITE_WEP104: |
100 | case WLAN_CIPHER_SUITE_WEP104: | 108 | case WLAN_CIPHER_SUITE_TKIP: |
101 | case WLAN_CIPHER_SUITE_TKIP: | 109 | case WLAN_CIPHER_SUITE_CCMP: |
102 | case WLAN_CIPHER_SUITE_CCMP: | 110 | case WLAN_CIPHER_SUITE_AES_CMAC: |
103 | case WLAN_CIPHER_SUITE_AES_CMAC: | 111 | /* all of these we can do in software */ |
104 | /* all of these we can do in software */ | 112 | return 0; |
105 | ret = 0; | 113 | default: |
106 | break; | 114 | return -EINVAL; |
107 | default: | ||
108 | ret = -EINVAL; | ||
109 | } | ||
110 | } | 115 | } |
111 | |||
112 | return ret; | ||
113 | } | 116 | } |
114 | 117 | ||
115 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 118 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
@@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
147 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 150 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
148 | } | 151 | } |
149 | 152 | ||
153 | void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) | ||
154 | { | ||
155 | struct ieee80211_key *key; | ||
156 | |||
157 | key = container_of(key_conf, struct ieee80211_key, conf); | ||
158 | |||
159 | might_sleep(); | ||
160 | assert_key_lock(key->local); | ||
161 | |||
162 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
163 | |||
164 | /* | ||
165 | * Flush TX path to avoid attempts to use this key | ||
166 | * after this function returns. Until then, drivers | ||
167 | * must be prepared to handle the key. | ||
168 | */ | ||
169 | synchronize_rcu(); | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(ieee80211_key_removed); | ||
172 | |||
150 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | 173 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, |
151 | int idx) | 174 | int idx) |
152 | { | 175 | { |
@@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |||
202 | 225 | ||
203 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | 226 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
204 | struct sta_info *sta, | 227 | struct sta_info *sta, |
228 | bool pairwise, | ||
205 | struct ieee80211_key *old, | 229 | struct ieee80211_key *old, |
206 | struct ieee80211_key *new) | 230 | struct ieee80211_key *new) |
207 | { | 231 | { |
@@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
210 | if (new) | 234 | if (new) |
211 | list_add(&new->list, &sdata->key_list); | 235 | list_add(&new->list, &sdata->key_list); |
212 | 236 | ||
213 | if (sta) { | 237 | if (sta && pairwise) { |
214 | rcu_assign_pointer(sta->key, new); | 238 | rcu_assign_pointer(sta->ptk, new); |
239 | } else if (sta) { | ||
240 | if (old) | ||
241 | idx = old->conf.keyidx; | ||
242 | else | ||
243 | idx = new->conf.keyidx; | ||
244 | rcu_assign_pointer(sta->gtk[idx], new); | ||
215 | } else { | 245 | } else { |
216 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | 246 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
217 | 247 | ||
@@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
355 | { | 385 | { |
356 | struct ieee80211_key *old_key; | 386 | struct ieee80211_key *old_key; |
357 | int idx, ret; | 387 | int idx, ret; |
388 | bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; | ||
358 | 389 | ||
359 | BUG_ON(!sdata); | 390 | BUG_ON(!sdata); |
360 | BUG_ON(!key); | 391 | BUG_ON(!key); |
@@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
371 | */ | 402 | */ |
372 | if (test_sta_flags(sta, WLAN_STA_WME)) | 403 | if (test_sta_flags(sta, WLAN_STA_WME)) |
373 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | 404 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; |
374 | |||
375 | /* | ||
376 | * This key is for a specific sta interface, | ||
377 | * inform the driver that it should try to store | ||
378 | * this key as pairwise key. | ||
379 | */ | ||
380 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | ||
381 | } else { | 405 | } else { |
382 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 406 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
383 | struct sta_info *ap; | 407 | struct sta_info *ap; |
@@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
399 | 423 | ||
400 | mutex_lock(&sdata->local->key_mtx); | 424 | mutex_lock(&sdata->local->key_mtx); |
401 | 425 | ||
402 | if (sta) | 426 | if (sta && pairwise) |
403 | old_key = sta->key; | 427 | old_key = sta->ptk; |
428 | else if (sta) | ||
429 | old_key = sta->gtk[idx]; | ||
404 | else | 430 | else |
405 | old_key = sdata->keys[idx]; | 431 | old_key = sdata->keys[idx]; |
406 | 432 | ||
407 | __ieee80211_key_replace(sdata, sta, old_key, key); | 433 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
408 | __ieee80211_key_destroy(old_key); | 434 | __ieee80211_key_destroy(old_key); |
409 | 435 | ||
410 | ieee80211_debugfs_key_add(key); | 436 | ieee80211_debugfs_key_add(key); |
@@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key) | |||
423 | */ | 449 | */ |
424 | if (key->sdata) | 450 | if (key->sdata) |
425 | __ieee80211_key_replace(key->sdata, key->sta, | 451 | __ieee80211_key_replace(key->sdata, key->sta, |
426 | key, NULL); | 452 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
453 | key, NULL); | ||
427 | __ieee80211_key_destroy(key); | 454 | __ieee80211_key_destroy(key); |
428 | } | 455 | } |
429 | 456 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index cb9a4a65cc68..0db1c0f5f697 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/rcupdate.h> | 16 | #include <linux/rcupdate.h> |
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | ||
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | ||
21 | |||
19 | #define WEP_IV_LEN 4 | 22 | #define WEP_IV_LEN 4 |
20 | #define WEP_ICV_LEN 4 | 23 | #define WEP_ICV_LEN 4 |
21 | #define ALG_TKIP_KEY_LEN 32 | 24 | #define ALG_TKIP_KEY_LEN 32 |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b3e161ffa4b3..b67221def584 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -846,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
846 | int keyidx; | 846 | int keyidx; |
847 | int hdrlen; | 847 | int hdrlen; |
848 | ieee80211_rx_result result = RX_DROP_UNUSABLE; | 848 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
849 | struct ieee80211_key *stakey = NULL; | 849 | struct ieee80211_key *sta_ptk = NULL; |
850 | int mmie_keyidx = -1; | 850 | int mmie_keyidx = -1; |
851 | __le16 fc; | 851 | __le16 fc; |
852 | 852 | ||
@@ -888,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
888 | rx->key = NULL; | 888 | rx->key = NULL; |
889 | 889 | ||
890 | if (rx->sta) | 890 | if (rx->sta) |
891 | stakey = rcu_dereference(rx->sta->key); | 891 | sta_ptk = rcu_dereference(rx->sta->ptk); |
892 | 892 | ||
893 | fc = hdr->frame_control; | 893 | fc = hdr->frame_control; |
894 | 894 | ||
895 | if (!ieee80211_has_protected(fc)) | 895 | if (!ieee80211_has_protected(fc)) |
896 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 896 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
897 | 897 | ||
898 | if (!is_multicast_ether_addr(hdr->addr1) && stakey) { | 898 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { |
899 | rx->key = stakey; | 899 | rx->key = sta_ptk; |
900 | if ((status->flag & RX_FLAG_DECRYPTED) && | 900 | if ((status->flag & RX_FLAG_DECRYPTED) && |
901 | (status->flag & RX_FLAG_IV_STRIPPED)) | 901 | (status->flag & RX_FLAG_IV_STRIPPED)) |
902 | return RX_CONTINUE; | 902 | return RX_CONTINUE; |
@@ -912,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
912 | if (mmie_keyidx < NUM_DEFAULT_KEYS || | 912 | if (mmie_keyidx < NUM_DEFAULT_KEYS || |
913 | mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 913 | mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
914 | return RX_DROP_MONITOR; /* unexpected BIP keyidx */ | 914 | return RX_DROP_MONITOR; /* unexpected BIP keyidx */ |
915 | rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | 915 | if (rx->sta) |
916 | rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); | ||
917 | if (!rx->key) | ||
918 | rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); | ||
916 | } else if (!ieee80211_has_protected(fc)) { | 919 | } else if (!ieee80211_has_protected(fc)) { |
917 | /* | 920 | /* |
918 | * The frame was not protected, so skip decryption. However, we | 921 | * The frame was not protected, so skip decryption. However, we |
@@ -955,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
955 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | 958 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); |
956 | keyidx = keyid >> 6; | 959 | keyidx = keyid >> 6; |
957 | 960 | ||
958 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); | 961 | /* check per-station GTK first, if multicast packet */ |
962 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | ||
963 | rx->key = rcu_dereference(rx->sta->gtk[keyidx]); | ||
959 | 964 | ||
960 | /* | 965 | /* if not found, try default key */ |
961 | * RSNA-protected unicast frames should always be sent with | 966 | if (!rx->key) { |
962 | * pairwise or station-to-station keys, but for WEP we allow | 967 | rx->key = rcu_dereference(rx->sdata->keys[keyidx]); |
963 | * using a key index as well. | 968 | |
964 | */ | 969 | /* |
965 | if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && | 970 | * RSNA-protected unicast frames should always be |
966 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && | 971 | * sent with pairwise or station-to-station keys, |
967 | !is_multicast_ether_addr(hdr->addr1)) | 972 | * but for WEP we allow using a key index as well. |
968 | rx->key = NULL; | 973 | */ |
974 | if (rx->key && | ||
975 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
976 | rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 && | ||
977 | !is_multicast_ether_addr(hdr->addr1)) | ||
978 | rx->key = NULL; | ||
979 | } | ||
969 | } | 980 | } |
970 | 981 | ||
971 | if (rx->key) { | 982 | if (rx->key) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index aeaf2d6fccc8..6d8f897d8763 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
616 | struct ieee80211_sub_if_data *sdata; | 616 | struct ieee80211_sub_if_data *sdata; |
617 | struct sk_buff *skb; | 617 | struct sk_buff *skb; |
618 | unsigned long flags; | 618 | unsigned long flags; |
619 | int ret; | 619 | int ret, i; |
620 | 620 | ||
621 | might_sleep(); | 621 | might_sleep(); |
622 | 622 | ||
@@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
644 | if (ret) | 644 | if (ret) |
645 | return ret; | 645 | return ret; |
646 | 646 | ||
647 | if (sta->key) { | 647 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
648 | ieee80211_key_free(local, sta->key); | 648 | ieee80211_key_free(local, sta->gtk[i]); |
649 | WARN_ON(sta->key); | 649 | if (sta->ptk) |
650 | } | 650 | ieee80211_key_free(local, sta->ptk); |
651 | 651 | ||
652 | sta->dead = true; | 652 | sta->dead = true; |
653 | 653 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index cf21a2e8134f..9265acadef32 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -199,7 +199,8 @@ enum plink_state { | |||
199 | * @hnext: hash table linked list pointer | 199 | * @hnext: hash table linked list pointer |
200 | * @local: pointer to the global information | 200 | * @local: pointer to the global information |
201 | * @sdata: virtual interface this station belongs to | 201 | * @sdata: virtual interface this station belongs to |
202 | * @key: peer key negotiated with this station, if any | 202 | * @ptk: peer key negotiated with this station, if any |
203 | * @gtk: group keys negotiated with this station, if any | ||
203 | * @rate_ctrl: rate control algorithm reference | 204 | * @rate_ctrl: rate control algorithm reference |
204 | * @rate_ctrl_priv: rate control private per-STA pointer | 205 | * @rate_ctrl_priv: rate control private per-STA pointer |
205 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 206 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
@@ -254,7 +255,8 @@ struct sta_info { | |||
254 | struct sta_info *hnext; | 255 | struct sta_info *hnext; |
255 | struct ieee80211_local *local; | 256 | struct ieee80211_local *local; |
256 | struct ieee80211_sub_if_data *sdata; | 257 | struct ieee80211_sub_if_data *sdata; |
257 | struct ieee80211_key *key; | 258 | struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
259 | struct ieee80211_key *ptk; | ||
258 | struct rate_control_ref *rate_ctrl; | 260 | struct rate_control_ref *rate_ctrl; |
259 | void *rate_ctrl_priv; | 261 | void *rate_ctrl_priv; |
260 | spinlock_t lock; | 262 | spinlock_t lock; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 258fbdbedbdf..96c594309506 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -532,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
532 | 532 | ||
533 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) | 533 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) |
534 | tx->key = NULL; | 534 | tx->key = NULL; |
535 | else if (tx->sta && (key = rcu_dereference(tx->sta->key))) | 535 | else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) |
536 | tx->key = key; | 536 | tx->key = key; |
537 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 537 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
538 | is_multicast_ether_addr(hdr->addr1) && | 538 | is_multicast_ether_addr(hdr->addr1) && |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 37580e090a3d..2d1d4c70113c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | |||
375 | /* internal helpers */ | 375 | /* internal helpers */ |
376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 376 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
377 | struct key_params *params, int key_idx, | 377 | struct key_params *params, int key_idx, |
378 | const u8 *mac_addr); | 378 | bool pairwise, const u8 *mac_addr); |
379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 379 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
380 | size_t ie_len, u16 reason, bool from_ap); | 380 | size_t ie_len, u16 reason, bool from_ap); |
381 | void cfg80211_sme_scan_done(struct net_device *dev); | 381 | void cfg80211_sme_scan_done(struct net_device *dev); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 8cb6e08373b9..f33fbb79437c 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
160 | */ | 160 | */ |
161 | if (rdev->ops->del_key) | 161 | if (rdev->ops->del_key) |
162 | for (i = 0; i < 6; i++) | 162 | for (i = 0; i < 6; i++) |
163 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 163 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
164 | 164 | ||
165 | if (wdev->current_bss) { | 165 | if (wdev->current_bss) { |
166 | cfg80211_unhold_bss(wdev->current_bss); | 166 | cfg80211_unhold_bss(wdev->current_bss); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0c9497170f1f..8826888cc14e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -93,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
93 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 93 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
94 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 94 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
95 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 95 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
96 | [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 }, | ||
96 | 97 | ||
97 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 98 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
98 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 99 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -168,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
168 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | 169 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, |
169 | }; | 170 | }; |
170 | 171 | ||
171 | /* policy for the attributes */ | 172 | /* policy for the key attributes */ |
172 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | 173 | static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { |
173 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, | 174 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN }, |
174 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | 175 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, |
@@ -176,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
176 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | 177 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, |
177 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | 178 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, |
178 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 179 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
180 | [NL80211_KEY_TYPE] = { .type = NLA_U32 }, | ||
179 | }; | 181 | }; |
180 | 182 | ||
181 | /* ifidx get helper */ | 183 | /* ifidx get helper */ |
@@ -306,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
306 | struct key_parse { | 308 | struct key_parse { |
307 | struct key_params p; | 309 | struct key_params p; |
308 | int idx; | 310 | int idx; |
311 | int type; | ||
309 | bool def, defmgmt; | 312 | bool def, defmgmt; |
310 | }; | 313 | }; |
311 | 314 | ||
@@ -336,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | |||
336 | if (tb[NL80211_KEY_CIPHER]) | 339 | if (tb[NL80211_KEY_CIPHER]) |
337 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | 340 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); |
338 | 341 | ||
342 | if (tb[NL80211_KEY_TYPE]) { | ||
343 | k->type = nla_get_u32(tb[NL80211_KEY_TYPE]); | ||
344 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
339 | return 0; | 348 | return 0; |
340 | } | 349 | } |
341 | 350 | ||
@@ -360,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | |||
360 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | 369 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; |
361 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | 370 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; |
362 | 371 | ||
372 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | ||
373 | k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | ||
374 | if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
363 | return 0; | 378 | return 0; |
364 | } | 379 | } |
365 | 380 | ||
@@ -369,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | |||
369 | 384 | ||
370 | memset(k, 0, sizeof(*k)); | 385 | memset(k, 0, sizeof(*k)); |
371 | k->idx = -1; | 386 | k->idx = -1; |
387 | k->type = -1; | ||
372 | 388 | ||
373 | if (info->attrs[NL80211_ATTR_KEY]) | 389 | if (info->attrs[NL80211_ATTR_KEY]) |
374 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | 390 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); |
@@ -433,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, | |||
433 | } else if (parse.defmgmt) | 449 | } else if (parse.defmgmt) |
434 | goto error; | 450 | goto error; |
435 | err = cfg80211_validate_key_settings(rdev, &parse.p, | 451 | err = cfg80211_validate_key_settings(rdev, &parse.p, |
436 | parse.idx, NULL); | 452 | parse.idx, false, NULL); |
437 | if (err) | 453 | if (err) |
438 | goto error; | 454 | goto error; |
439 | result->params[parse.idx].cipher = parse.p.cipher; | 455 | result->params[parse.idx].cipher = parse.p.cipher; |
@@ -516,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
516 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 532 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
517 | dev->wiphy.max_scan_ie_len); | 533 | dev->wiphy.max_scan_ie_len); |
518 | 534 | ||
535 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | ||
536 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | ||
537 | |||
519 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 538 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
520 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 539 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
521 | dev->wiphy.cipher_suites); | 540 | dev->wiphy.cipher_suites); |
@@ -1446,7 +1465,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1446 | int err; | 1465 | int err; |
1447 | struct net_device *dev = info->user_ptr[1]; | 1466 | struct net_device *dev = info->user_ptr[1]; |
1448 | u8 key_idx = 0; | 1467 | u8 key_idx = 0; |
1449 | u8 *mac_addr = NULL; | 1468 | const u8 *mac_addr = NULL; |
1469 | bool pairwise; | ||
1450 | struct get_key_cookie cookie = { | 1470 | struct get_key_cookie cookie = { |
1451 | .error = 0, | 1471 | .error = 0, |
1452 | }; | 1472 | }; |
@@ -1462,6 +1482,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1462 | if (info->attrs[NL80211_ATTR_MAC]) | 1482 | if (info->attrs[NL80211_ATTR_MAC]) |
1463 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1483 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1464 | 1484 | ||
1485 | pairwise = !!mac_addr; | ||
1486 | if (info->attrs[NL80211_ATTR_KEY_TYPE]) { | ||
1487 | u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]); | ||
1488 | if (kt >= NUM_NL80211_KEYTYPES) | ||
1489 | return -EINVAL; | ||
1490 | if (kt != NL80211_KEYTYPE_GROUP && | ||
1491 | kt != NL80211_KEYTYPE_PAIRWISE) | ||
1492 | return -EINVAL; | ||
1493 | pairwise = kt == NL80211_KEYTYPE_PAIRWISE; | ||
1494 | } | ||
1495 | |||
1465 | if (!rdev->ops->get_key) | 1496 | if (!rdev->ops->get_key) |
1466 | return -EOPNOTSUPP; | 1497 | return -EOPNOTSUPP; |
1467 | 1498 | ||
@@ -1482,8 +1513,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1482 | if (mac_addr) | 1513 | if (mac_addr) |
1483 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1514 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1484 | 1515 | ||
1485 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr, | 1516 | if (pairwise && mac_addr && |
1486 | &cookie, get_key_callback); | 1517 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) |
1518 | return -ENOENT; | ||
1519 | |||
1520 | err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise, | ||
1521 | mac_addr, &cookie, get_key_callback); | ||
1487 | 1522 | ||
1488 | if (err) | 1523 | if (err) |
1489 | goto free_msg; | 1524 | goto free_msg; |
@@ -1553,7 +1588,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1553 | int err; | 1588 | int err; |
1554 | struct net_device *dev = info->user_ptr[1]; | 1589 | struct net_device *dev = info->user_ptr[1]; |
1555 | struct key_parse key; | 1590 | struct key_parse key; |
1556 | u8 *mac_addr = NULL; | 1591 | const u8 *mac_addr = NULL; |
1557 | 1592 | ||
1558 | err = nl80211_parse_key(info, &key); | 1593 | err = nl80211_parse_key(info, &key); |
1559 | if (err) | 1594 | if (err) |
@@ -1565,16 +1600,31 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1565 | if (info->attrs[NL80211_ATTR_MAC]) | 1600 | if (info->attrs[NL80211_ATTR_MAC]) |
1566 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1601 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1567 | 1602 | ||
1603 | if (key.type == -1) { | ||
1604 | if (mac_addr) | ||
1605 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1606 | else | ||
1607 | key.type = NL80211_KEYTYPE_GROUP; | ||
1608 | } | ||
1609 | |||
1610 | /* for now */ | ||
1611 | if (key.type != NL80211_KEYTYPE_PAIRWISE && | ||
1612 | key.type != NL80211_KEYTYPE_GROUP) | ||
1613 | return -EINVAL; | ||
1614 | |||
1568 | if (!rdev->ops->add_key) | 1615 | if (!rdev->ops->add_key) |
1569 | return -EOPNOTSUPP; | 1616 | return -EOPNOTSUPP; |
1570 | 1617 | ||
1571 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) | 1618 | if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, |
1619 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1620 | mac_addr)) | ||
1572 | return -EINVAL; | 1621 | return -EINVAL; |
1573 | 1622 | ||
1574 | wdev_lock(dev->ieee80211_ptr); | 1623 | wdev_lock(dev->ieee80211_ptr); |
1575 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1624 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1576 | if (!err) | 1625 | if (!err) |
1577 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, | 1626 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, |
1627 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1578 | mac_addr, &key.p); | 1628 | mac_addr, &key.p); |
1579 | wdev_unlock(dev->ieee80211_ptr); | 1629 | wdev_unlock(dev->ieee80211_ptr); |
1580 | 1630 | ||
@@ -1596,13 +1646,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1596 | if (info->attrs[NL80211_ATTR_MAC]) | 1646 | if (info->attrs[NL80211_ATTR_MAC]) |
1597 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1647 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1598 | 1648 | ||
1649 | if (key.type == -1) { | ||
1650 | if (mac_addr) | ||
1651 | key.type = NL80211_KEYTYPE_PAIRWISE; | ||
1652 | else | ||
1653 | key.type = NL80211_KEYTYPE_GROUP; | ||
1654 | } | ||
1655 | |||
1656 | /* for now */ | ||
1657 | if (key.type != NL80211_KEYTYPE_PAIRWISE && | ||
1658 | key.type != NL80211_KEYTYPE_GROUP) | ||
1659 | return -EINVAL; | ||
1660 | |||
1599 | if (!rdev->ops->del_key) | 1661 | if (!rdev->ops->del_key) |
1600 | return -EOPNOTSUPP; | 1662 | return -EOPNOTSUPP; |
1601 | 1663 | ||
1602 | wdev_lock(dev->ieee80211_ptr); | 1664 | wdev_lock(dev->ieee80211_ptr); |
1603 | err = nl80211_key_allowed(dev->ieee80211_ptr); | 1665 | err = nl80211_key_allowed(dev->ieee80211_ptr); |
1666 | |||
1667 | if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr && | ||
1668 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
1669 | err = -ENOENT; | ||
1670 | |||
1604 | if (!err) | 1671 | if (!err) |
1605 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); | 1672 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, |
1673 | key.type == NL80211_KEYTYPE_PAIRWISE, | ||
1674 | mac_addr); | ||
1606 | 1675 | ||
1607 | #ifdef CONFIG_CFG80211_WEXT | 1676 | #ifdef CONFIG_CFG80211_WEXT |
1608 | if (!err) { | 1677 | if (!err) { |
@@ -3212,6 +3281,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
3212 | return err; | 3281 | return err; |
3213 | 3282 | ||
3214 | if (key.idx >= 0) { | 3283 | if (key.idx >= 0) { |
3284 | if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP) | ||
3285 | return -EINVAL; | ||
3215 | if (!key.p.key || !key.p.key_len) | 3286 | if (!key.p.key || !key.p.key_len) |
3216 | return -EINVAL; | 3287 | return -EINVAL; |
3217 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || | 3288 | if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 || |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f161b9844542..e17b0bee6bdc 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
698 | */ | 698 | */ |
699 | if (rdev->ops->del_key) | 699 | if (rdev->ops->del_key) |
700 | for (i = 0; i < 6; i++) | 700 | for (i = 0; i < 6; i++) |
701 | rdev->ops->del_key(wdev->wiphy, dev, i, NULL); | 701 | rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL); |
702 | 702 | ||
703 | #ifdef CONFIG_CFG80211_WEXT | 703 | #ifdef CONFIG_CFG80211_WEXT |
704 | memset(&wrqu, 0, sizeof(wrqu)); | 704 | memset(&wrqu, 0, sizeof(wrqu)); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index fb5448f7d55a..76120aeda57d 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
144 | 144 | ||
145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 145 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
146 | struct key_params *params, int key_idx, | 146 | struct key_params *params, int key_idx, |
147 | const u8 *mac_addr) | 147 | bool pairwise, const u8 *mac_addr) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | 150 | ||
151 | if (key_idx > 5) | 151 | if (key_idx > 5) |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | 153 | ||
154 | if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | if (pairwise && !mac_addr) | ||
158 | return -EINVAL; | ||
159 | |||
154 | /* | 160 | /* |
155 | * Disallow pairwise keys with non-zero index unless it's WEP | 161 | * Disallow pairwise keys with non-zero index unless it's WEP |
156 | * (because current deployments use pairwise WEP keys with | 162 | * (because current deployments use pairwise WEP keys with |
157 | * non-zero indizes but 802.11i clearly specifies to use zero) | 163 | * non-zero indizes but 802.11i clearly specifies to use zero) |
158 | */ | 164 | */ |
159 | if (mac_addr && key_idx && | 165 | if (pairwise && key_idx && |
160 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && | 166 | params->cipher != WLAN_CIPHER_SUITE_WEP40 && |
161 | params->cipher != WLAN_CIPHER_SUITE_WEP104) | 167 | params->cipher != WLAN_CIPHER_SUITE_WEP104) |
162 | return -EINVAL; | 168 | return -EINVAL; |
@@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
677 | for (i = 0; i < 6; i++) { | 683 | for (i = 0; i < 6; i++) { |
678 | if (!wdev->connect_keys->params[i].cipher) | 684 | if (!wdev->connect_keys->params[i].cipher) |
679 | continue; | 685 | continue; |
680 | if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL, | 686 | if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL, |
681 | &wdev->connect_keys->params[i])) { | 687 | &wdev->connect_keys->params[i])) { |
682 | printk(KERN_ERR "%s: failed to set key %d\n", | 688 | printk(KERN_ERR "%s: failed to set key %d\n", |
683 | dev->name, i); | 689 | dev->name, i); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7e5c3a45f811..6002265289c6 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev, | |||
432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 432 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
433 | 433 | ||
434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 434 | static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
435 | struct net_device *dev, const u8 *addr, | 435 | struct net_device *dev, bool pairwise, |
436 | bool remove, bool tx_key, int idx, | 436 | const u8 *addr, bool remove, bool tx_key, |
437 | struct key_params *params) | 437 | int idx, struct key_params *params) |
438 | { | 438 | { |
439 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 439 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
440 | int err, i; | 440 | int err, i; |
441 | bool rejoin = false; | 441 | bool rejoin = false; |
442 | 442 | ||
443 | if (pairwise && !addr) | ||
444 | return -EINVAL; | ||
445 | |||
443 | if (!wdev->wext.keys) { | 446 | if (!wdev->wext.keys) { |
444 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 447 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
445 | GFP_KERNEL); | 448 | GFP_KERNEL); |
@@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
478 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); | 481 | __cfg80211_leave_ibss(rdev, wdev->netdev, true); |
479 | rejoin = true; | 482 | rejoin = true; |
480 | } | 483 | } |
481 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); | 484 | |
485 | if (!pairwise && addr && | ||
486 | !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) | ||
487 | err = -ENOENT; | ||
488 | else | ||
489 | err = rdev->ops->del_key(&rdev->wiphy, dev, idx, | ||
490 | pairwise, addr); | ||
482 | } | 491 | } |
483 | wdev->wext.connect.privacy = false; | 492 | wdev->wext.connect.privacy = false; |
484 | /* | 493 | /* |
@@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
507 | if (addr) | 516 | if (addr) |
508 | tx_key = false; | 517 | tx_key = false; |
509 | 518 | ||
510 | if (cfg80211_validate_key_settings(rdev, params, idx, addr)) | 519 | if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr)) |
511 | return -EINVAL; | 520 | return -EINVAL; |
512 | 521 | ||
513 | err = 0; | 522 | err = 0; |
514 | if (wdev->current_bss) | 523 | if (wdev->current_bss) |
515 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); | 524 | err = rdev->ops->add_key(&rdev->wiphy, dev, idx, |
525 | pairwise, addr, params); | ||
516 | if (err) | 526 | if (err) |
517 | return err; | 527 | return err; |
518 | 528 | ||
@@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
563 | } | 573 | } |
564 | 574 | ||
565 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 575 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, |
566 | struct net_device *dev, const u8 *addr, | 576 | struct net_device *dev, bool pairwise, |
567 | bool remove, bool tx_key, int idx, | 577 | const u8 *addr, bool remove, bool tx_key, |
568 | struct key_params *params) | 578 | int idx, struct key_params *params) |
569 | { | 579 | { |
570 | int err; | 580 | int err; |
571 | 581 | ||
572 | /* devlist mutex needed for possible IBSS re-join */ | 582 | /* devlist mutex needed for possible IBSS re-join */ |
573 | mutex_lock(&rdev->devlist_mtx); | 583 | mutex_lock(&rdev->devlist_mtx); |
574 | wdev_lock(dev->ieee80211_ptr); | 584 | wdev_lock(dev->ieee80211_ptr); |
575 | err = __cfg80211_set_encryption(rdev, dev, addr, remove, | 585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
576 | tx_key, idx, params); | 586 | remove, tx_key, idx, params); |
577 | wdev_unlock(dev->ieee80211_ptr); | 587 | wdev_unlock(dev->ieee80211_ptr); |
578 | mutex_unlock(&rdev->devlist_mtx); | 588 | mutex_unlock(&rdev->devlist_mtx); |
579 | 589 | ||
@@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev, | |||
635 | else if (!remove) | 645 | else if (!remove) |
636 | return -EINVAL; | 646 | return -EINVAL; |
637 | 647 | ||
638 | return cfg80211_set_encryption(rdev, dev, NULL, remove, | 648 | return cfg80211_set_encryption(rdev, dev, false, NULL, remove, |
639 | wdev->wext.default_key == -1, | 649 | wdev->wext.default_key == -1, |
640 | idx, ¶ms); | 650 | idx, ¶ms); |
641 | } | 651 | } |
@@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev, | |||
725 | } | 735 | } |
726 | 736 | ||
727 | return cfg80211_set_encryption( | 737 | return cfg80211_set_encryption( |
728 | rdev, dev, addr, remove, | 738 | rdev, dev, |
739 | !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), | ||
740 | addr, remove, | ||
729 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | 741 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, |
730 | idx, ¶ms); | 742 | idx, ¶ms); |
731 | } | 743 | } |