aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/key.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/key.c')
-rw-r--r--net/mac80211/key.c27
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
262void ieee80211_key_free(struct ieee80211_key *key) 270void 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