summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-27 13:39:00 +0100
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:42:07 -0500
commite4861829072c61883114c64a3af61f305a789ff0 (patch)
tree54dbd81bae2f1d21576b2a88badf113567d0efc0
parentdb4d1169d0b893bfb7923b6526748fe2c5a7373f (diff)
mac80211: fix key replacing, hw accelmaster-2008-02-29
Even though I thought about it a lot and had also tested it, some of my recent changes in the key code broke replacing keys, making the kernel oops because a key is removed from a list while not on it. This patch fixes that using the list as an indication whether or not the key is on it (an empty list means it's not on any list.) Also, this patch fixes hw accel enabling, the check for not doing hw accel when the interface is down was lost and is restored by this. Additionally, move adding the key to the list into the function __ieee80211_key_replace() for more consistency. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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 60aaaf47154..eac9c59dbc4 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,
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) {
/*
@@ -189,6 +190,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
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);
@@ -196,7 +199,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
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);
}
}
@@ -251,12 +258,13 @@ void ieee80211_key_link(struct ieee80211_key *key,
__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)
@@ -274,8 +282,13 @@ 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();