diff options
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r-- | net/mac80211/key.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 60aaaf471544..eac9c59dbc4d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -150,6 +150,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
150 | key->conf.keyidx = idx; | 150 | key->conf.keyidx = idx; |
151 | key->conf.keylen = key_len; | 151 | key->conf.keylen = key_len; |
152 | memcpy(key->conf.key, key_data, key_len); | 152 | memcpy(key->conf.key, key_data, key_len); |
153 | INIT_LIST_HEAD(&key->list); | ||
153 | 154 | ||
154 | if (alg == ALG_CCMP) { | 155 | if (alg == ALG_CCMP) { |
155 | /* | 156 | /* |
@@ -189,6 +190,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
189 | ieee80211_set_default_key(sdata, -1); | 190 | ieee80211_set_default_key(sdata, -1); |
190 | 191 | ||
191 | rcu_assign_pointer(sdata->keys[idx], new); | 192 | rcu_assign_pointer(sdata->keys[idx], new); |
193 | if (new) | ||
194 | list_add(&new->list, &sdata->key_list); | ||
192 | 195 | ||
193 | if (defkey && new) | 196 | if (defkey && new) |
194 | ieee80211_set_default_key(sdata, new->conf.keyidx); | 197 | ieee80211_set_default_key(sdata, new->conf.keyidx); |
@@ -196,7 +199,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
196 | 199 | ||
197 | if (key) { | 200 | if (key) { |
198 | ieee80211_key_mark_hw_accel_off(key); | 201 | ieee80211_key_mark_hw_accel_off(key); |
199 | list_del(&key->list); | 202 | /* |
203 | * We'll use an empty list to indicate that the key | ||
204 | * has already been removed. | ||
205 | */ | ||
206 | list_del_init(&key->list); | ||
200 | } | 207 | } |
201 | } | 208 | } |
202 | 209 | ||
@@ -251,12 +258,13 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
251 | 258 | ||
252 | __ieee80211_key_replace(sdata, sta, old_key, key); | 259 | __ieee80211_key_replace(sdata, sta, old_key, key); |
253 | 260 | ||
254 | list_add(&key->list, &sdata->key_list); | 261 | if (old_key) { |
255 | 262 | synchronize_rcu(); | |
256 | synchronize_rcu(); | 263 | ieee80211_key_free(old_key); |
264 | } | ||
257 | 265 | ||
258 | ieee80211_key_free(old_key); | 266 | if (netif_running(sdata->dev)) |
259 | ieee80211_key_enable_hw_accel(key); | 267 | ieee80211_key_enable_hw_accel(key); |
260 | } | 268 | } |
261 | 269 | ||
262 | void ieee80211_key_free(struct ieee80211_key *key) | 270 | void ieee80211_key_free(struct ieee80211_key *key) |
@@ -274,8 +282,13 @@ void ieee80211_key_free(struct ieee80211_key *key) | |||
274 | * Because other code may have key reference (RCU protected) | 282 | * Because other code may have key reference (RCU protected) |
275 | * right now, we then wait for a grace period before freeing | 283 | * right now, we then wait for a grace period before freeing |
276 | * it. | 284 | * it. |
285 | * An empty list indicates it was never added to the key list | ||
286 | * or has been removed already. It may, however, still be in | ||
287 | * hardware for acceleration. | ||
277 | */ | 288 | */ |
278 | __ieee80211_key_replace(key->sdata, key->sta, key, NULL); | 289 | if (!list_empty(&key->list)) |
290 | __ieee80211_key_replace(key->sdata, key->sta, | ||
291 | key, NULL); | ||
279 | 292 | ||
280 | synchronize_rcu(); | 293 | synchronize_rcu(); |
281 | 294 | ||