mac80211: fix key vs. sta locking problems
[deliverable/linux.git] / net / mac80211 / cfg.c
index 5f8db5cab65dbd9fff2895d5cfe931844d0a500f..fe05a7b85dc62a0b4867773b399a5bf41ee7ae86 100644 (file)
@@ -135,6 +135,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta = NULL;
        enum ieee80211_key_alg alg;
        struct ieee80211_key *key;
+       int err;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -157,17 +158,24 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        if (!key)
                return -ENOMEM;
 
+       rcu_read_lock();
+
        if (mac_addr) {
                sta = sta_info_get(sdata->local, mac_addr);
                if (!sta) {
                        ieee80211_key_free(key);
-                       return -ENOENT;
+                       err = -ENOENT;
+                       goto out_unlock;
                }
        }
 
        ieee80211_key_link(key, sdata, sta);
 
-       return 0;
+       err = 0;
+ out_unlock:
+       rcu_read_unlock();
+
+       return err;
 }
 
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
@@ -179,28 +187,37 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       rcu_read_lock();
+
        if (mac_addr) {
+               ret = -ENOENT;
+
                sta = sta_info_get(sdata->local, mac_addr);
                if (!sta)
-                       return -ENOENT;
+                       goto out_unlock;
 
-               ret = 0;
                if (sta->key) {
                        ieee80211_key_free(sta->key);
                        WARN_ON(sta->key);
-               } else
-                       ret = -ENOENT;
+                       ret = 0;
+               }
 
-               return ret;
+               goto out_unlock;
        }
 
-       if (!sdata->keys[key_idx])
-               return -ENOENT;
+       if (!sdata->keys[key_idx]) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
 
        ieee80211_key_free(sdata->keys[key_idx]);
        WARN_ON(sdata->keys[key_idx]);
 
-       return 0;
+       ret = 0;
+ out_unlock:
+       rcu_read_unlock();
+
+       return ret;
 }
 
 static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
@@ -217,6 +234,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        u16 iv16;
        int err = -ENOENT;
 
+       rcu_read_lock();
+
        if (mac_addr) {
                sta = sta_info_get(sdata->local, mac_addr);
                if (!sta)
@@ -280,6 +299,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        err = 0;
 
  out:
+       rcu_read_unlock();
        return err;
 }
 
@@ -289,9 +309,13 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata;
 
+       rcu_read_lock();
+
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        ieee80211_set_default_key(sdata, key_idx);
 
+       rcu_read_unlock();
+
        return 0;
 }
 
This page took 0.032754 seconds and 5 git commands to generate.