cfg80211: respect iface combinations when starting operation
authorMichal Kazior <michal.kazior@tieto.com>
Fri, 29 Jun 2012 10:47:08 +0000 (12:47 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 29 Jun 2012 11:39:19 +0000 (13:39 +0200)
devlist_mtx locking is changed to accomodate changes.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/core.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/util.c

index b26695ad3e97ddb6913e40ecff3f2c615c54b073..ca2b95f248464b16b38af752a5c51c47cf1ee844 100644 (file)
@@ -990,7 +990,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        return notifier_from_errno(-EOPNOTSUPP);
                if (rfkill_blocked(rdev->rfkill))
                        return notifier_from_errno(-ERFKILL);
+               mutex_lock(&rdev->devlist_mtx);
                ret = cfg80211_can_add_interface(rdev, wdev->iftype);
+               mutex_unlock(&rdev->devlist_mtx);
                if (ret)
                        return notifier_from_errno(ret);
                cfg80211_lock_rdev(rdev);
index b90fd86b2d1890fa494bea918195b000f5d1f0dd..ca5672f6ee2f79925906e78dcb188ebbd32e17a6 100644 (file)
@@ -118,6 +118,16 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
        wdev->wext.ibss.channel = params->channel;
 #endif
        wdev->sme_state = CFG80211_SME_CONNECTING;
+
+       err = cfg80211_can_use_chan(rdev, wdev, params->channel,
+                                   params->channel_fixed
+                                   ? CHAN_MODE_SHARED
+                                   : CHAN_MODE_EXCLUSIVE);
+       if (err) {
+               wdev->connect_keys = NULL;
+               return err;
+       }
+
        err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
        if (err) {
                wdev->connect_keys = NULL;
index bab3813447238656ec1ae397492299fd9519069c..c384e77ff77a4e8c2f62398c7559361c5033ad03 100644 (file)
@@ -155,6 +155,11 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                                          setup->channel_type))
                return -EINVAL;
 
+       err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
+                                   CHAN_MODE_SHARED);
+       if (err)
+               return err;
+
        err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -173,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
+       mutex_lock(&rdev->devlist_mtx);
        wdev_lock(wdev);
        err = __cfg80211_join_mesh(rdev, dev, setup, conf);
        wdev_unlock(wdev);
+       mutex_unlock(&rdev->devlist_mtx);
 
        return err;
 }
@@ -208,6 +215,11 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
                if (!netif_running(wdev->netdev))
                        return -ENETDOWN;
 
+               err = cfg80211_can_use_chan(rdev, wdev, channel,
+                                           CHAN_MODE_SHARED);
+               if (err)
+                       return err;
+
                err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
                                                           wdev->netdev,
                                                           channel);
index a7882eb8c46e9d345358e9b86a4a111eddc835c4..d4fece3bb18a8215ce30fd55e748e7f59b5bcee1 100644 (file)
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
        if (!req.bss)
                return -ENOENT;
 
+       err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
+                                   CHAN_MODE_SHARED);
+       if (err)
+               goto out;
+
        err = rdev->ops->auth(&rdev->wiphy, dev, &req);
 
+out:
        cfg80211_put_bss(req.bss);
        return err;
 }
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 {
        int err;
 
+       mutex_lock(&rdev->devlist_mtx);
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                   ssid, ssid_len, ie, ie_len,
                                   key, key_len, key_idx);
        wdev_unlock(dev->ieee80211_ptr);
+       mutex_unlock(&rdev->devlist_mtx);
 
        return err;
 }
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                return -ENOENT;
        }
 
+       err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
+                                   CHAN_MODE_SHARED);
+       if (err)
+               goto out;
+
        err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
 
+out:
        if (err) {
                if (was_connected)
                        wdev->sme_state = CFG80211_SME_CONNECTED;
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
+       mutex_lock(&rdev->devlist_mtx);
        wdev_lock(wdev);
        err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                    ssid, ssid_len, ie, ie_len, use_mfp, crypt,
                                    assoc_flags, ht_capa, ht_capa_mask);
        wdev_unlock(wdev);
+       mutex_unlock(&rdev->devlist_mtx);
 
        return err;
 }
index 5d29ed1f7c62bfc64305ceff1903383ea8745504..77102e66f1eac1cc2e38cb00e429e96580b7acc7 100644 (file)
@@ -2478,6 +2478,14 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                                          params.channel_type))
                return -EINVAL;
 
+       mutex_lock(&rdev->devlist_mtx);
+       err = cfg80211_can_use_chan(rdev, wdev, params.channel,
+                                   CHAN_MODE_SHARED);
+       mutex_unlock(&rdev->devlist_mtx);
+
+       if (err)
+               return err;
+
        err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
        if (!err) {
                wdev->preset_chan = params.channel;
index 4713cea9a2fa62b1118d3162ca182d6809f8c3f0..a9260ac85cf182482d0a60a139386545292a2e67 100644 (file)
@@ -805,8 +805,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                return -EBUSY;
 
        if (ntype != otype && netif_running(dev)) {
+               mutex_lock(&rdev->devlist_mtx);
                err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
                                                    ntype);
+               mutex_unlock(&rdev->devlist_mtx);
                if (err)
                        return err;
 
@@ -956,6 +958,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
        int i, j;
 
        ASSERT_RTNL();
+       lockdep_assert_held(&rdev->devlist_mtx);
 
        /* Always allow software iftypes */
        if (rdev->wiphy.software_iftypes & BIT(iftype))
@@ -979,7 +982,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                break;
        }
 
-       mutex_lock(&rdev->devlist_mtx);
        list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
                if (wdev_iter == wdev)
                        continue;
@@ -999,10 +1001,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                if (!used_channels[i] || used_channels[i] == ch)
                                        break;
 
-                       if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
-                               mutex_unlock(&rdev->devlist_mtx);
+                       if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS)
                                return -EBUSY;
-                       }
 
                        if (used_channels[i] == NULL) {
                                used_channels[i] = ch;
@@ -1018,7 +1018,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                total++;
                used_iftypes |= BIT(wdev_iter->iftype);
        }
-       mutex_unlock(&rdev->devlist_mtx);
 
        if (total == 1)
                return 0;