diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/mac80211/key.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 291 |
1 files changed, 178 insertions, 113 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 1b9d87ed143a..f825e2f0a57e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -30,26 +30,27 @@ | |||
30 | * keys and per-station keys. Since each station belongs to an interface, | 30 | * keys and per-station keys. Since each station belongs to an interface, |
31 | * each station key also belongs to that interface. | 31 | * each station key also belongs to that interface. |
32 | * | 32 | * |
33 | * Hardware acceleration is done on a best-effort basis, for each key | 33 | * Hardware acceleration is done on a best-effort basis for algorithms |
34 | * that is eligible the hardware is asked to enable that key but if | 34 | * that are implemented in software, for each key the hardware is asked |
35 | * it cannot do that they key is simply kept for software encryption. | 35 | * to enable that key for offloading but if it cannot do that the key is |
36 | * There is currently no way of knowing this except by looking into | 36 | * simply kept for software encryption (unless it is for an algorithm |
37 | * debugfs. | 37 | * that isn't implemented in software). |
38 | * There is currently no way of knowing whether a key is handled in SW | ||
39 | * or HW except by looking into debugfs. | ||
38 | * | 40 | * |
39 | * All key operations are protected internally. | 41 | * All key management is internally protected by a mutex. Within all |
40 | * | 42 | * other parts of mac80211, key references are, just as STA structure |
41 | * Within mac80211, key references are, just as STA structure references, | 43 | * references, protected by RCU. Note, however, that some things are |
42 | * protected by RCU. Note, however, that some things are unprotected, | 44 | * unprotected, namely the key->sta dereferences within the hardware |
43 | * namely the key->sta dereferences within the hardware acceleration | 45 | * acceleration functions. This means that sta_info_destroy() must |
44 | * functions. This means that sta_info_destroy() must remove the key | 46 | * remove the key which waits for an RCU grace period. |
45 | * which waits for an RCU grace period. | ||
46 | */ | 47 | */ |
47 | 48 | ||
48 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 49 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
49 | 50 | ||
50 | static void assert_key_lock(struct ieee80211_local *local) | 51 | static void assert_key_lock(struct ieee80211_local *local) |
51 | { | 52 | { |
52 | WARN_ON(!mutex_is_locked(&local->key_mtx)); | 53 | lockdep_assert_held(&local->key_mtx); |
53 | } | 54 | } |
54 | 55 | ||
55 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | 56 | static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) |
@@ -60,7 +61,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | |||
60 | return NULL; | 61 | return NULL; |
61 | } | 62 | } |
62 | 63 | ||
63 | static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 64 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
64 | { | 65 | { |
65 | struct ieee80211_sub_if_data *sdata; | 66 | struct ieee80211_sub_if_data *sdata; |
66 | struct ieee80211_sta *sta; | 67 | struct ieee80211_sta *sta; |
@@ -69,28 +70,57 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
69 | might_sleep(); | 70 | might_sleep(); |
70 | 71 | ||
71 | if (!key->local->ops->set_key) | 72 | if (!key->local->ops->set_key) |
72 | return; | 73 | goto out_unsupported; |
73 | 74 | ||
74 | assert_key_lock(key->local); | 75 | assert_key_lock(key->local); |
75 | 76 | ||
76 | sta = get_sta_for_key(key); | 77 | sta = get_sta_for_key(key); |
77 | 78 | ||
79 | /* | ||
80 | * If this is a per-STA GTK, check if it | ||
81 | * is supported; if not, return. | ||
82 | */ | ||
83 | if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) && | ||
84 | !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)) | ||
85 | goto out_unsupported; | ||
86 | |||
78 | sdata = key->sdata; | 87 | sdata = key->sdata; |
79 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 88 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
89 | /* | ||
90 | * The driver doesn't know anything about VLAN interfaces. | ||
91 | * Hence, don't send GTKs for VLAN interfaces to the driver. | ||
92 | */ | ||
93 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
94 | goto out_unsupported; | ||
80 | sdata = container_of(sdata->bss, | 95 | sdata = container_of(sdata->bss, |
81 | struct ieee80211_sub_if_data, | 96 | struct ieee80211_sub_if_data, |
82 | u.ap); | 97 | u.ap); |
98 | } | ||
83 | 99 | ||
84 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); | 100 | ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); |
85 | 101 | ||
86 | if (!ret) | 102 | if (!ret) { |
87 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 103 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
104 | return 0; | ||
105 | } | ||
88 | 106 | ||
89 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 107 | if (ret != -ENOSPC && ret != -EOPNOTSUPP) |
90 | printk(KERN_ERR "mac80211-%s: failed to set key " | 108 | wiphy_err(key->local->hw.wiphy, |
91 | "(%d, %pM) to hardware (%d)\n", | 109 | "failed to set key (%d, %pM) to hardware (%d)\n", |
92 | wiphy_name(key->local->hw.wiphy), | 110 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
93 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | 111 | |
112 | out_unsupported: | ||
113 | switch (key->conf.cipher) { | ||
114 | case WLAN_CIPHER_SUITE_WEP40: | ||
115 | case WLAN_CIPHER_SUITE_WEP104: | ||
116 | case WLAN_CIPHER_SUITE_TKIP: | ||
117 | case WLAN_CIPHER_SUITE_CCMP: | ||
118 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
119 | /* all of these we can do in software */ | ||
120 | return 0; | ||
121 | default: | ||
122 | return -EINVAL; | ||
123 | } | ||
94 | } | 124 | } |
95 | 125 | ||
96 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 126 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
@@ -121,36 +151,56 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
121 | sta, &key->conf); | 151 | sta, &key->conf); |
122 | 152 | ||
123 | if (ret) | 153 | if (ret) |
124 | printk(KERN_ERR "mac80211-%s: failed to remove key " | 154 | wiphy_err(key->local->hw.wiphy, |
125 | "(%d, %pM) from hardware (%d)\n", | 155 | "failed to remove key (%d, %pM) from hardware (%d)\n", |
126 | wiphy_name(key->local->hw.wiphy), | 156 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); |
127 | key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); | ||
128 | 157 | ||
129 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 158 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
130 | } | 159 | } |
131 | 160 | ||
161 | void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) | ||
162 | { | ||
163 | struct ieee80211_key *key; | ||
164 | |||
165 | key = container_of(key_conf, struct ieee80211_key, conf); | ||
166 | |||
167 | might_sleep(); | ||
168 | assert_key_lock(key->local); | ||
169 | |||
170 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
171 | |||
172 | /* | ||
173 | * Flush TX path to avoid attempts to use this key | ||
174 | * after this function returns. Until then, drivers | ||
175 | * must be prepared to handle the key. | ||
176 | */ | ||
177 | synchronize_rcu(); | ||
178 | } | ||
179 | EXPORT_SYMBOL_GPL(ieee80211_key_removed); | ||
180 | |||
132 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | 181 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, |
133 | int idx) | 182 | int idx, bool uni, bool multi) |
134 | { | 183 | { |
135 | struct ieee80211_key *key = NULL; | 184 | struct ieee80211_key *key = NULL; |
136 | 185 | ||
137 | assert_key_lock(sdata->local); | 186 | assert_key_lock(sdata->local); |
138 | 187 | ||
139 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 188 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) |
140 | key = sdata->keys[idx]; | 189 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
141 | 190 | ||
142 | rcu_assign_pointer(sdata->default_key, key); | 191 | if (uni) |
192 | rcu_assign_pointer(sdata->default_unicast_key, key); | ||
193 | if (multi) | ||
194 | rcu_assign_pointer(sdata->default_multicast_key, key); | ||
143 | 195 | ||
144 | if (key) { | 196 | ieee80211_debugfs_key_update_default(sdata); |
145 | ieee80211_debugfs_key_remove_default(key->sdata); | ||
146 | ieee80211_debugfs_key_add_default(key->sdata); | ||
147 | } | ||
148 | } | 197 | } |
149 | 198 | ||
150 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | 199 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
200 | bool uni, bool multi) | ||
151 | { | 201 | { |
152 | mutex_lock(&sdata->local->key_mtx); | 202 | mutex_lock(&sdata->local->key_mtx); |
153 | __ieee80211_set_default_key(sdata, idx); | 203 | __ieee80211_set_default_key(sdata, idx, uni, multi); |
154 | mutex_unlock(&sdata->local->key_mtx); | 204 | mutex_unlock(&sdata->local->key_mtx); |
155 | } | 205 | } |
156 | 206 | ||
@@ -163,14 +213,11 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
163 | 213 | ||
164 | if (idx >= NUM_DEFAULT_KEYS && | 214 | if (idx >= NUM_DEFAULT_KEYS && |
165 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) | 215 | idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) |
166 | key = sdata->keys[idx]; | 216 | key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
167 | 217 | ||
168 | rcu_assign_pointer(sdata->default_mgmt_key, key); | 218 | rcu_assign_pointer(sdata->default_mgmt_key, key); |
169 | 219 | ||
170 | if (key) { | 220 | ieee80211_debugfs_key_update_default(sdata); |
171 | ieee80211_debugfs_key_remove_mgmt_default(key->sdata); | ||
172 | ieee80211_debugfs_key_add_mgmt_default(key->sdata); | ||
173 | } | ||
174 | } | 221 | } |
175 | 222 | ||
176 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | 223 | void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, |
@@ -184,16 +231,24 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |||
184 | 231 | ||
185 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | 232 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, |
186 | struct sta_info *sta, | 233 | struct sta_info *sta, |
234 | bool pairwise, | ||
187 | struct ieee80211_key *old, | 235 | struct ieee80211_key *old, |
188 | struct ieee80211_key *new) | 236 | struct ieee80211_key *new) |
189 | { | 237 | { |
190 | int idx, defkey, defmgmtkey; | 238 | int idx; |
239 | bool defunikey, defmultikey, defmgmtkey; | ||
191 | 240 | ||
192 | if (new) | 241 | if (new) |
193 | list_add(&new->list, &sdata->key_list); | 242 | list_add(&new->list, &sdata->key_list); |
194 | 243 | ||
195 | if (sta) { | 244 | if (sta && pairwise) { |
196 | rcu_assign_pointer(sta->key, new); | 245 | rcu_assign_pointer(sta->ptk, new); |
246 | } else if (sta) { | ||
247 | if (old) | ||
248 | idx = old->conf.keyidx; | ||
249 | else | ||
250 | idx = new->conf.keyidx; | ||
251 | rcu_assign_pointer(sta->gtk[idx], new); | ||
197 | } else { | 252 | } else { |
198 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | 253 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
199 | 254 | ||
@@ -202,45 +257,51 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
202 | else | 257 | else |
203 | idx = new->conf.keyidx; | 258 | idx = new->conf.keyidx; |
204 | 259 | ||
205 | defkey = old && sdata->default_key == old; | 260 | defunikey = old && |
206 | defmgmtkey = old && sdata->default_mgmt_key == old; | 261 | old == key_mtx_dereference(sdata->local, |
207 | 262 | sdata->default_unicast_key); | |
208 | if (defkey && !new) | 263 | defmultikey = old && |
209 | __ieee80211_set_default_key(sdata, -1); | 264 | old == key_mtx_dereference(sdata->local, |
265 | sdata->default_multicast_key); | ||
266 | defmgmtkey = old && | ||
267 | old == key_mtx_dereference(sdata->local, | ||
268 | sdata->default_mgmt_key); | ||
269 | |||
270 | if (defunikey && !new) | ||
271 | __ieee80211_set_default_key(sdata, -1, true, false); | ||
272 | if (defmultikey && !new) | ||
273 | __ieee80211_set_default_key(sdata, -1, false, true); | ||
210 | if (defmgmtkey && !new) | 274 | if (defmgmtkey && !new) |
211 | __ieee80211_set_default_mgmt_key(sdata, -1); | 275 | __ieee80211_set_default_mgmt_key(sdata, -1); |
212 | 276 | ||
213 | rcu_assign_pointer(sdata->keys[idx], new); | 277 | rcu_assign_pointer(sdata->keys[idx], new); |
214 | if (defkey && new) | 278 | if (defunikey && new) |
215 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | 279 | __ieee80211_set_default_key(sdata, new->conf.keyidx, |
280 | true, false); | ||
281 | if (defmultikey && new) | ||
282 | __ieee80211_set_default_key(sdata, new->conf.keyidx, | ||
283 | false, true); | ||
216 | if (defmgmtkey && new) | 284 | if (defmgmtkey && new) |
217 | __ieee80211_set_default_mgmt_key(sdata, | 285 | __ieee80211_set_default_mgmt_key(sdata, |
218 | new->conf.keyidx); | 286 | new->conf.keyidx); |
219 | } | 287 | } |
220 | 288 | ||
221 | if (old) { | 289 | if (old) |
222 | /* | 290 | list_del(&old->list); |
223 | * We'll use an empty list to indicate that the key | ||
224 | * has already been removed. | ||
225 | */ | ||
226 | list_del_init(&old->list); | ||
227 | } | ||
228 | } | 291 | } |
229 | 292 | ||
230 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | 293 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
231 | int idx, | ||
232 | size_t key_len, | ||
233 | const u8 *key_data, | 294 | const u8 *key_data, |
234 | size_t seq_len, const u8 *seq) | 295 | size_t seq_len, const u8 *seq) |
235 | { | 296 | { |
236 | struct ieee80211_key *key; | 297 | struct ieee80211_key *key; |
237 | int i, j; | 298 | int i, j, err; |
238 | 299 | ||
239 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); | 300 | BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS); |
240 | 301 | ||
241 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); | 302 | key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); |
242 | if (!key) | 303 | if (!key) |
243 | return NULL; | 304 | return ERR_PTR(-ENOMEM); |
244 | 305 | ||
245 | /* | 306 | /* |
246 | * Default to software encryption; we'll later upload the | 307 | * Default to software encryption; we'll later upload the |
@@ -249,15 +310,16 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
249 | key->conf.flags = 0; | 310 | key->conf.flags = 0; |
250 | key->flags = 0; | 311 | key->flags = 0; |
251 | 312 | ||
252 | key->conf.alg = alg; | 313 | key->conf.cipher = cipher; |
253 | key->conf.keyidx = idx; | 314 | key->conf.keyidx = idx; |
254 | key->conf.keylen = key_len; | 315 | key->conf.keylen = key_len; |
255 | switch (alg) { | 316 | switch (cipher) { |
256 | case ALG_WEP: | 317 | case WLAN_CIPHER_SUITE_WEP40: |
318 | case WLAN_CIPHER_SUITE_WEP104: | ||
257 | key->conf.iv_len = WEP_IV_LEN; | 319 | key->conf.iv_len = WEP_IV_LEN; |
258 | key->conf.icv_len = WEP_ICV_LEN; | 320 | key->conf.icv_len = WEP_ICV_LEN; |
259 | break; | 321 | break; |
260 | case ALG_TKIP: | 322 | case WLAN_CIPHER_SUITE_TKIP: |
261 | key->conf.iv_len = TKIP_IV_LEN; | 323 | key->conf.iv_len = TKIP_IV_LEN; |
262 | key->conf.icv_len = TKIP_ICV_LEN; | 324 | key->conf.icv_len = TKIP_ICV_LEN; |
263 | if (seq) { | 325 | if (seq) { |
@@ -269,7 +331,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
269 | } | 331 | } |
270 | } | 332 | } |
271 | break; | 333 | break; |
272 | case ALG_CCMP: | 334 | case WLAN_CIPHER_SUITE_CCMP: |
273 | key->conf.iv_len = CCMP_HDR_LEN; | 335 | key->conf.iv_len = CCMP_HDR_LEN; |
274 | key->conf.icv_len = CCMP_MIC_LEN; | 336 | key->conf.icv_len = CCMP_MIC_LEN; |
275 | if (seq) { | 337 | if (seq) { |
@@ -278,42 +340,38 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
278 | key->u.ccmp.rx_pn[i][j] = | 340 | key->u.ccmp.rx_pn[i][j] = |
279 | seq[CCMP_PN_LEN - j - 1]; | 341 | seq[CCMP_PN_LEN - j - 1]; |
280 | } | 342 | } |
281 | break; | ||
282 | case ALG_AES_CMAC: | ||
283 | key->conf.iv_len = 0; | ||
284 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
285 | if (seq) | ||
286 | for (j = 0; j < 6; j++) | ||
287 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | ||
288 | break; | ||
289 | } | ||
290 | memcpy(key->conf.key, key_data, key_len); | ||
291 | INIT_LIST_HEAD(&key->list); | ||
292 | |||
293 | if (alg == ALG_CCMP) { | ||
294 | /* | 343 | /* |
295 | * Initialize AES key state here as an optimization so that | 344 | * Initialize AES key state here as an optimization so that |
296 | * it does not need to be initialized for every packet. | 345 | * it does not need to be initialized for every packet. |
297 | */ | 346 | */ |
298 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); | 347 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); |
299 | if (!key->u.ccmp.tfm) { | 348 | if (IS_ERR(key->u.ccmp.tfm)) { |
349 | err = PTR_ERR(key->u.ccmp.tfm); | ||
300 | kfree(key); | 350 | kfree(key); |
301 | return NULL; | 351 | return ERR_PTR(err); |
302 | } | 352 | } |
303 | } | 353 | break; |
304 | 354 | case WLAN_CIPHER_SUITE_AES_CMAC: | |
305 | if (alg == ALG_AES_CMAC) { | 355 | key->conf.iv_len = 0; |
356 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
357 | if (seq) | ||
358 | for (j = 0; j < 6; j++) | ||
359 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | ||
306 | /* | 360 | /* |
307 | * Initialize AES key state here as an optimization so that | 361 | * Initialize AES key state here as an optimization so that |
308 | * it does not need to be initialized for every packet. | 362 | * it does not need to be initialized for every packet. |
309 | */ | 363 | */ |
310 | key->u.aes_cmac.tfm = | 364 | key->u.aes_cmac.tfm = |
311 | ieee80211_aes_cmac_key_setup(key_data); | 365 | ieee80211_aes_cmac_key_setup(key_data); |
312 | if (!key->u.aes_cmac.tfm) { | 366 | if (IS_ERR(key->u.aes_cmac.tfm)) { |
367 | err = PTR_ERR(key->u.aes_cmac.tfm); | ||
313 | kfree(key); | 368 | kfree(key); |
314 | return NULL; | 369 | return ERR_PTR(err); |
315 | } | 370 | } |
371 | break; | ||
316 | } | 372 | } |
373 | memcpy(key->conf.key, key_data, key_len); | ||
374 | INIT_LIST_HEAD(&key->list); | ||
317 | 375 | ||
318 | return key; | 376 | return key; |
319 | } | 377 | } |
@@ -323,12 +381,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
323 | if (!key) | 381 | if (!key) |
324 | return; | 382 | return; |
325 | 383 | ||
384 | /* | ||
385 | * Synchronize so the TX path can no longer be using | ||
386 | * this key before we free/remove it. | ||
387 | */ | ||
388 | synchronize_rcu(); | ||
389 | |||
326 | if (key->local) | 390 | if (key->local) |
327 | ieee80211_key_disable_hw_accel(key); | 391 | ieee80211_key_disable_hw_accel(key); |
328 | 392 | ||
329 | if (key->conf.alg == ALG_CCMP) | 393 | if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP) |
330 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 394 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
331 | if (key->conf.alg == ALG_AES_CMAC) | 395 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
332 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 396 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
333 | if (key->local) | 397 | if (key->local) |
334 | ieee80211_debugfs_key_remove(key); | 398 | ieee80211_debugfs_key_remove(key); |
@@ -336,16 +400,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
336 | kfree(key); | 400 | kfree(key); |
337 | } | 401 | } |
338 | 402 | ||
339 | void ieee80211_key_link(struct ieee80211_key *key, | 403 | int ieee80211_key_link(struct ieee80211_key *key, |
340 | struct ieee80211_sub_if_data *sdata, | 404 | struct ieee80211_sub_if_data *sdata, |
341 | struct sta_info *sta) | 405 | struct sta_info *sta) |
342 | { | 406 | { |
343 | struct ieee80211_key *old_key; | 407 | struct ieee80211_key *old_key; |
344 | int idx; | 408 | int idx, ret; |
409 | bool pairwise; | ||
345 | 410 | ||
346 | BUG_ON(!sdata); | 411 | BUG_ON(!sdata); |
347 | BUG_ON(!key); | 412 | BUG_ON(!key); |
348 | 413 | ||
414 | pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; | ||
349 | idx = key->conf.keyidx; | 415 | idx = key->conf.keyidx; |
350 | key->local = sdata->local; | 416 | key->local = sdata->local; |
351 | key->sdata = sdata; | 417 | key->sdata = sdata; |
@@ -358,20 +424,13 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
358 | */ | 424 | */ |
359 | if (test_sta_flags(sta, WLAN_STA_WME)) | 425 | if (test_sta_flags(sta, WLAN_STA_WME)) |
360 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | 426 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; |
361 | |||
362 | /* | ||
363 | * This key is for a specific sta interface, | ||
364 | * inform the driver that it should try to store | ||
365 | * this key as pairwise key. | ||
366 | */ | ||
367 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | ||
368 | } else { | 427 | } else { |
369 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 428 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
370 | struct sta_info *ap; | 429 | struct sta_info *ap; |
371 | 430 | ||
372 | /* | 431 | /* |
373 | * We're getting a sta pointer in, | 432 | * We're getting a sta pointer in, so must be under |
374 | * so must be under RCU read lock. | 433 | * appropriate locking for sta_info_get(). |
375 | */ | 434 | */ |
376 | 435 | ||
377 | /* same here, the AP could be using QoS */ | 436 | /* same here, the AP could be using QoS */ |
@@ -386,38 +445,43 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
386 | 445 | ||
387 | mutex_lock(&sdata->local->key_mtx); | 446 | mutex_lock(&sdata->local->key_mtx); |
388 | 447 | ||
389 | if (sta) | 448 | if (sta && pairwise) |
390 | old_key = sta->key; | 449 | old_key = key_mtx_dereference(sdata->local, sta->ptk); |
450 | else if (sta) | ||
451 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | ||
391 | else | 452 | else |
392 | old_key = sdata->keys[idx]; | 453 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
393 | 454 | ||
394 | __ieee80211_key_replace(sdata, sta, old_key, key); | 455 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
395 | __ieee80211_key_destroy(old_key); | 456 | __ieee80211_key_destroy(old_key); |
396 | 457 | ||
397 | ieee80211_debugfs_key_add(key); | 458 | ieee80211_debugfs_key_add(key); |
398 | 459 | ||
399 | ieee80211_key_enable_hw_accel(key); | 460 | ret = ieee80211_key_enable_hw_accel(key); |
400 | 461 | ||
401 | mutex_unlock(&sdata->local->key_mtx); | 462 | mutex_unlock(&sdata->local->key_mtx); |
463 | |||
464 | return ret; | ||
402 | } | 465 | } |
403 | 466 | ||
404 | static void __ieee80211_key_free(struct ieee80211_key *key) | 467 | void __ieee80211_key_free(struct ieee80211_key *key) |
405 | { | 468 | { |
469 | if (!key) | ||
470 | return; | ||
471 | |||
406 | /* | 472 | /* |
407 | * Replace key with nothingness if it was ever used. | 473 | * Replace key with nothingness if it was ever used. |
408 | */ | 474 | */ |
409 | if (key->sdata) | 475 | if (key->sdata) |
410 | __ieee80211_key_replace(key->sdata, key->sta, | 476 | __ieee80211_key_replace(key->sdata, key->sta, |
411 | key, NULL); | 477 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
478 | key, NULL); | ||
412 | __ieee80211_key_destroy(key); | 479 | __ieee80211_key_destroy(key); |
413 | } | 480 | } |
414 | 481 | ||
415 | void ieee80211_key_free(struct ieee80211_local *local, | 482 | void ieee80211_key_free(struct ieee80211_local *local, |
416 | struct ieee80211_key *key) | 483 | struct ieee80211_key *key) |
417 | { | 484 | { |
418 | if (!key) | ||
419 | return; | ||
420 | |||
421 | mutex_lock(&local->key_mtx); | 485 | mutex_lock(&local->key_mtx); |
422 | __ieee80211_key_free(key); | 486 | __ieee80211_key_free(key); |
423 | mutex_unlock(&local->key_mtx); | 487 | mutex_unlock(&local->key_mtx); |
@@ -460,11 +524,12 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
460 | 524 | ||
461 | mutex_lock(&sdata->local->key_mtx); | 525 | mutex_lock(&sdata->local->key_mtx); |
462 | 526 | ||
463 | ieee80211_debugfs_key_remove_default(sdata); | ||
464 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 527 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
465 | 528 | ||
466 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 529 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
467 | __ieee80211_key_free(key); | 530 | __ieee80211_key_free(key); |
468 | 531 | ||
532 | ieee80211_debugfs_key_update_default(sdata); | ||
533 | |||
469 | mutex_unlock(&sdata->local->key_mtx); | 534 | mutex_unlock(&sdata->local->key_mtx); |
470 | } | 535 | } |