key->conf.keyidx = idx;
key->conf.keylen = key_len;
memcpy(key->conf.key, key_data, key_len);
+ INIT_LIST_HEAD(&key->list);
if (alg == ALG_CCMP) {
/*
ieee80211_set_default_key(sdata, -1);
rcu_assign_pointer(sdata->keys[idx], new);
+ if (new)
+ list_add(&new->list, &sdata->key_list);
if (defkey && new)
ieee80211_set_default_key(sdata, new->conf.keyidx);
if (key) {
ieee80211_key_mark_hw_accel_off(key);
- list_del(&key->list);
+ /*
+ * We'll use an empty list to indicate that the key
+ * has already been removed.
+ */
+ list_del_init(&key->list);
}
}
__ieee80211_key_replace(sdata, sta, old_key, key);
- list_add(&key->list, &sdata->key_list);
-
- synchronize_rcu();
+ if (old_key) {
+ synchronize_rcu();
+ ieee80211_key_free(old_key);
+ }
- ieee80211_key_free(old_key);
- ieee80211_key_enable_hw_accel(key);
+ if (netif_running(sdata->dev))
+ ieee80211_key_enable_hw_accel(key);
}
void ieee80211_key_free(struct ieee80211_key *key)
* Because other code may have key reference (RCU protected)
* right now, we then wait for a grace period before freeing
* it.
+ * An empty list indicates it was never added to the key list
+ * or has been removed already. It may, however, still be in
+ * hardware for acceleration.
*/
- __ieee80211_key_replace(key->sdata, key->sta, key, NULL);
+ if (!list_empty(&key->list))
+ __ieee80211_key_replace(key->sdata, key->sta,
+ key, NULL);
synchronize_rcu();