Search Linux Wireless

Re: [PATCH v4] cfg80211: validate channel settings across interfaces

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Johannes,

This patch is now in wireless-testing and it is causing a problem for
me. This was determined using bisect.

I am able to bring the interface up and scan, but when I try to
associate I get a hang.

For example, when I run:
$ iwconfig wlan0 channel <ch> essid <essid>

then the command prompt never returns and system becomes progressively
unresponsive. The logs do not contain any details of the problem.

Reinette


On Fri, 2009-08-07 at 08:22 -0700, Johannes Berg wrote:
> Currently, there's a problem that affects regulatory
> enforcement and connection stability, in that it is
> possible to switch the channel while connected to a
> network or joined to an IBSS.
> 
> The problem comes from the fact that we only validate
> the channel against the current interface's type, not
> against any other interface. Thus, you have any type
> of interface up, additionally bring up a monitor mode
> interface and switch the channel on the monitor. This
> will obviously also switch the channel on the other
> interface.
> 
> The problem now is that if you do that while sending
> beacons for IBSS mode, you can switch to a disabled
> channel or a channel that doesn't allow beaconing.
> Combined with a managed mode interface connected to
> an AP instead of an IBSS interface, you can easily
> break the connection that way.
> 
> To fix this, this patch validates any channel change
> with all available interfaces, and disallows such
> changes on secondary interfaces if another interface
> is connected to an AP or joined to an IBSS.
> 
> Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
> ---
> v2: * rebase
> v3: * fix error code (-EBUSY instead of -EINVAL)
>     * fix locking (need devlist_mtx instead of rdev mtx)
> v4: * use SINGLE_DEPTH_NESTING instead of 1
> 
>  net/wireless/Makefile      |    3 +
>  net/wireless/chan.c        |   88 +++++++++++++++++++++++++++++++++++++++++++++
>  net/wireless/core.h        |    6 +++
>  net/wireless/ibss.c        |   63 ++++++++++++++++++++------------
>  net/wireless/nl80211.c     |   54 ++++++---------------------
>  net/wireless/sme.c         |    9 ++++
>  net/wireless/wext-compat.c |   55 +++++++++-------------------
>  net/wireless/wext-compat.h |    3 -
>  net/wireless/wext-sme.c    |   67 ++++++++++++++++++----------------
>  9 files changed, 215 insertions(+), 133 deletions(-)
> 
> --- wireless-testing.orig/net/wireless/Makefile 2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/Makefile      2009-08-07 14:50:11.000000000 +0200
> @@ -5,7 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib8
>  obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
>  obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
> 
> -cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
> +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
> +cfg80211-y += mlme.o ibss.o sme.o chan.o
>  cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
>  cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
> 
> --- /dev/null   1970-01-01 00:00:00.000000000 +0000
> +++ wireless-testing/net/wireless/chan.c        2009-08-07 17:20:41.000000000 +0200
> @@ -0,0 +1,88 @@
> +/*
> + * This file contains helper code to handle channel
> + * settings and keeping track of what is possible at
> + * any point in time.
> + *
> + * Copyright 2009      Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
> + */
> +
> +#include <net/cfg80211.h>
> +#include "core.h"
> +
> +struct ieee80211_channel *
> +rdev_fixed_channel(struct cfg80211_registered_device *rdev,
> +                  struct wireless_dev *for_wdev)
> +{
> +       struct wireless_dev *wdev;
> +       struct ieee80211_channel *result = NULL;
> +
> +       WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
> +
> +       list_for_each_entry(wdev, &rdev->netdev_list, list) {
> +               if (wdev == for_wdev)
> +                       continue;
> +
> +               /*
> +                * Lock manually to tell lockdep about allowed
> +                * nesting here if for_wdev->mtx is held already.
> +                * This is ok as it's all under the rdev devlist
> +                * mutex and as such can only be done once at any
> +                * given time.
> +                */
> +               mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
> +               if (wdev->current_bss)
> +                       result = wdev->current_bss->pub.channel;
> +               wdev_unlock(wdev);
> +
> +               if (result)
> +                       break;
> +       }
> +
> +       return result;
> +}
> +
> +int rdev_set_freq(struct cfg80211_registered_device *rdev,
> +                 int freq, enum nl80211_channel_type channel_type)
> +{
> +       struct ieee80211_channel *chan;
> +       struct ieee80211_sta_ht_cap *ht_cap;
> +       int result;
> +
> +       if (rdev_fixed_channel(rdev, NULL))
> +               return -EBUSY;
> +
> +       if (!rdev->ops->set_channel)
> +               return -EOPNOTSUPP;
> +
> +       chan = ieee80211_get_channel(&rdev->wiphy, freq);
> +
> +       /* Primary channel not allowed */
> +       if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
> +               return -EINVAL;
> +
> +       if (channel_type == NL80211_CHAN_HT40MINUS &&
> +           chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
> +               return -EINVAL;
> +       else if (channel_type == NL80211_CHAN_HT40PLUS &&
> +                chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
> +               return -EINVAL;
> +
> +       ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
> +
> +       if (channel_type != NL80211_CHAN_NO_HT) {
> +               if (!ht_cap->ht_supported)
> +                       return -EINVAL;
> +
> +               if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
> +                   ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
> +                       return -EINVAL;
> +       }
> +
> +       result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
> +       if (result)
> +               return result;
> +
> +       rdev->channel = chan;
> +
> +       return 0;
> +}
> --- wireless-testing.orig/net/wireless/core.h   2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/core.h        2009-08-07 17:20:31.000000000 +0200
> @@ -366,4 +366,10 @@ void cfg80211_sme_disassoc(struct net_de
>  void __cfg80211_scan_done(struct work_struct *wk);
>  void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
> 
> +struct ieee80211_channel *
> +rdev_fixed_channel(struct cfg80211_registered_device *rdev,
> +                  struct wireless_dev *for_wdev);
> +int rdev_set_freq(struct cfg80211_registered_device *rdev,
> +                 int freq, enum nl80211_channel_type channel_type);
> +
>  #endif /* __NET_WIRELESS_CORE_H */
> --- wireless-testing.orig/net/wireless/nl80211.c        2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/nl80211.c     2009-08-07 17:20:30.000000000 +0200
> @@ -701,15 +701,8 @@ static int nl80211_set_wiphy(struct sk_b
> 
>         if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
>                 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
> -               struct ieee80211_channel *chan;
> -               struct ieee80211_sta_ht_cap *ht_cap;
>                 u32 freq;
> 
> -               if (!rdev->ops->set_channel) {
> -                       result = -EOPNOTSUPP;
> -                       goto bad_res;
> -               }
> -
>                 result = -EINVAL;
> 
>                 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
> @@ -723,42 +716,12 @@ static int nl80211_set_wiphy(struct sk_b
>                 }
> 
>                 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
> -               chan = ieee80211_get_channel(&rdev->wiphy, freq);
> -
> -               /* Primary channel not allowed */
> -               if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
> -                       goto bad_res;
> -
> -               if (channel_type == NL80211_CHAN_HT40MINUS &&
> -                   (chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
> -                       goto bad_res;
> -               else if (channel_type == NL80211_CHAN_HT40PLUS &&
> -                        (chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
> -                       goto bad_res;
> -
> -               /*
> -                * At this point we know if that if HT40 was requested
> -                * we are allowed to use it and the extension channel
> -                * exists.
> -                */
> 
> -               ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
> -
> -               /* no HT capabilities or intolerant */
> -               if (channel_type != NL80211_CHAN_NO_HT) {
> -                       if (!ht_cap->ht_supported)
> -                               goto bad_res;
> -                       if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
> -                           (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
> -                               goto bad_res;
> -               }
> -
> -               result = rdev->ops->set_channel(&rdev->wiphy, chan,
> -                                               channel_type);
> +               mutex_lock(&rdev->devlist_mtx);
> +               result = rdev_set_freq(rdev, freq, channel_type);
> +               mutex_unlock(&rdev->devlist_mtx);
>                 if (result)
>                         goto bad_res;
> -
> -               rdev->channel = chan;
>         }
> 
>         changed = 0;
> @@ -3453,7 +3416,7 @@ static int nl80211_associate(struct sk_b
>         struct cfg80211_registered_device *rdev;
>         struct net_device *dev;
>         struct cfg80211_crypto_settings crypto;
> -       struct ieee80211_channel *chan;
> +       struct ieee80211_channel *chan, *fixedchan;
>         const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
>         int err, ssid_len, ie_len = 0;
>         bool use_mfp = false;
> @@ -3496,6 +3459,15 @@ static int nl80211_associate(struct sk_b
>                 goto out;
>         }
> 
> +       mutex_lock(&rdev->devlist_mtx);
> +       fixedchan = rdev_fixed_channel(rdev, NULL);
> +       if (fixedchan && chan != fixedchan) {
> +               err = -EBUSY;
> +               mutex_unlock(&rdev->devlist_mtx);
> +               goto out;
> +       }
> +       mutex_unlock(&rdev->devlist_mtx);
> +
>         ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
>         ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
> 
> --- wireless-testing.orig/net/wireless/wext-compat.c    2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/wext-compat.c 2009-08-07 15:38:35.000000000 +0200
> @@ -267,39 +267,26 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange
>   * @wiphy: the wiphy
>   * @freq: the wext freq encoding
>   *
> - * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
> + * Returns a frequency, or a negative error code, or 0 for auto.
>   */
> -struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
> -                                            struct iw_freq *freq)
> +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
>  {
> -       struct ieee80211_channel *chan;
> -       int f;
> -
>         /*
> -        * Parse frequency - return NULL for auto and
> +        * Parse frequency - return 0 for auto and
>          * -EINVAL for impossible things.
>          */
>         if (freq->e == 0) {
>                 if (freq->m < 0)
> -                       return NULL;
> -               f = ieee80211_channel_to_frequency(freq->m);
> +                       return 0;
> +               return ieee80211_channel_to_frequency(freq->m);
>         } else {
>                 int i, div = 1000000;
>                 for (i = 0; i < freq->e; i++)
>                         div /= 10;
>                 if (div <= 0)
> -                       return ERR_PTR(-EINVAL);
> -               f = freq->m / div;
> +                       return -EINVAL;
> +               return freq->m / div;
>         }
> -
> -       /*
> -        * Look up channel struct and return -EINVAL when
> -        * it cannot be found.
> -        */
> -       chan = ieee80211_get_channel(wiphy, f);
> -       if (!chan)
> -               return ERR_PTR(-EINVAL);
> -       return chan;
>  }
> 
>  int cfg80211_wext_siwrts(struct net_device *dev,
> @@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencod
> 
>  int cfg80211_wext_siwfreq(struct net_device *dev,
>                           struct iw_request_info *info,
> -                         struct iw_freq *freq, char *extra)
> +                         struct iw_freq *wextfreq, char *extra)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
>         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
> -       struct ieee80211_channel *chan;
> -       int err;
> +       int freq, err;
> 
>         switch (wdev->iftype) {
>         case NL80211_IFTYPE_STATION:
> -               return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
> +               return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
>         case NL80211_IFTYPE_ADHOC:
> -               return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
> +               return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
>         default:
> -               chan = cfg80211_wext_freq(wdev->wiphy, freq);
> -               if (!chan)
> +               freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
> +               if (freq < 0)
> +                       return freq;
> +               if (freq == 0)
>                         return -EINVAL;
> -               if (IS_ERR(chan))
> -                       return PTR_ERR(chan);
> -               err = rdev->ops->set_channel(wdev->wiphy, chan,
> -                                            NL80211_CHAN_NO_HT);
> -               if (err)
> -                       return err;
> -               rdev->channel = chan;
> -               return 0;
> +               mutex_lock(&rdev->devlist_mtx);
> +               err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
> +               mutex_unlock(&rdev->devlist_mtx);
> +               return err;
>         }
>  }
> -EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
> 
>  int cfg80211_wext_giwfreq(struct net_device *dev,
>                           struct iw_request_info *info,
> --- wireless-testing.orig/net/wireless/wext-compat.h    2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/wext-compat.h 2009-08-07 14:50:11.000000000 +0200
> @@ -42,8 +42,7 @@ int cfg80211_mgd_wext_giwessid(struct ne
>                                struct iw_request_info *info,
>                                struct iw_point *data, char *ssid);
> 
> -struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
> -                                            struct iw_freq *freq);
> +int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq);
> 
> 
>  extern const struct iw_handler_def cfg80211_wext_handler;
> --- wireless-testing.orig/net/wireless/ibss.c   2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/ibss.c        2009-08-07 15:45:29.000000000 +0200
> @@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211
>                          struct cfg80211_cached_keys *connkeys)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct ieee80211_channel *chan;
>         int err;
> 
>         ASSERT_WDEV_LOCK(wdev);
> 
> +       chan = rdev_fixed_channel(rdev, wdev);
> +       if (chan && chan != params->channel)
> +               return -EBUSY;
> +
>         if (wdev->ssid_len)
>                 return -EALREADY;
> 
> @@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_r
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
>         int err;
> 
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
>         err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
>         wdev_unlock(wdev);
> +       mutex_unlock(&rdev->devlist_mtx);
> 
>         return err;
>  }
> @@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80
> 
>  int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
>                                struct iw_request_info *info,
> -                              struct iw_freq *freq, char *extra)
> +                              struct iw_freq *wextfreq, char *extra)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> -       struct ieee80211_channel *chan;
> -       int err;
> +       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
> +       struct ieee80211_channel *chan = NULL;
> +       int err, freq;
> 
>         /* call only for ibss! */
>         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
>                 return -EINVAL;
> 
> -       if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
> +       if (!rdev->ops->join_ibss)
>                 return -EOPNOTSUPP;
> 
> -       chan = cfg80211_wext_freq(wdev->wiphy, freq);
> -       if (chan && IS_ERR(chan))
> -               return PTR_ERR(chan);
> -
> -       if (chan &&
> -           (chan->flags & IEEE80211_CHAN_NO_IBSS ||
> -            chan->flags & IEEE80211_CHAN_DISABLED))
> -               return -EINVAL;
> +       freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
> +       if (freq < 0)
> +               return freq;
> +
> +       if (freq) {
> +               chan = ieee80211_get_channel(wdev->wiphy, freq);
> +               if (!chan)
> +                       return -EINVAL;
> +               if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
> +                   chan->flags & IEEE80211_CHAN_DISABLED)
> +                       return -EINVAL;
> +       }
> 
>         if (wdev->wext.ibss.channel == chan)
>                 return 0;
> @@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct ne
>         wdev_lock(wdev);
>         err = 0;
>         if (wdev->ssid_len)
> -               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
> -                                           dev, true);
> +               err = __cfg80211_leave_ibss(rdev, dev, true);
>         wdev_unlock(wdev);
> 
>         if (err)
> @@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct ne
>                 wdev->wext.ibss.channel_fixed = false;
>         }
> 
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> -       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_ibss_wext_join(rdev, wdev);
>         wdev_unlock(wdev);
> +       mutex_unlock(&rdev->devlist_mtx);
> 
>         return err;
>  }
> @@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct n
>                                 struct iw_point *data, char *ssid)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
>         size_t len = data->length;
>         int err;
> 
> @@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct n
>         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
>                 return -EINVAL;
> 
> -       if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
> +       if (!rdev->ops->join_ibss)
>                 return -EOPNOTSUPP;
> 
>         wdev_lock(wdev);
>         err = 0;
>         if (wdev->ssid_len)
> -               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
> -                                           dev, true);
> +               err = __cfg80211_leave_ibss(rdev, dev, true);
>         wdev_unlock(wdev);
> 
>         if (err)
> @@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct n
>         memcpy(wdev->wext.ibss.ssid, ssid, len);
>         wdev->wext.ibss.ssid_len = len;
> 
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> -       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_ibss_wext_join(rdev, wdev);
>         wdev_unlock(wdev);
> +       mutex_unlock(&rdev->devlist_mtx);
> 
>         return err;
>  }
> @@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_
>                              struct sockaddr *ap_addr, char *extra)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
>         u8 *bssid = ap_addr->sa_data;
>         int err;
> 
> @@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_
>         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
>                 return -EINVAL;
> 
> -       if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
> +       if (!rdev->ops->join_ibss)
>                 return -EOPNOTSUPP;
> 
>         if (ap_addr->sa_family != ARPHRD_ETHER)
> @@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_
>         wdev_lock(wdev);
>         err = 0;
>         if (wdev->ssid_len)
> -               err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
> -                                           dev, true);
> +               err = __cfg80211_leave_ibss(rdev, dev, true);
>         wdev_unlock(wdev);
> 
>         if (err)
> @@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_
>         } else
>                 wdev->wext.ibss.bssid = NULL;
> 
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> -       err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_ibss_wext_join(rdev, wdev);
>         wdev_unlock(wdev);
> +       mutex_unlock(&rdev->devlist_mtx);
> 
>         return err;
>  }
> --- wireless-testing.orig/net/wireless/wext-sme.c       2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/wext-sme.c    2009-08-07 17:20:31.000000000 +0200
> @@ -52,25 +52,31 @@ int cfg80211_mgd_wext_connect(struct cfg
> 
>  int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
>                               struct iw_request_info *info,
> -                             struct iw_freq *freq, char *extra)
> +                             struct iw_freq *wextfreq, char *extra)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
>         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
> -       struct ieee80211_channel *chan;
> -       int err;
> +       struct ieee80211_channel *chan = NULL;
> +       int err, freq;
> 
>         /* call only for station! */
>         if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
>                 return -EINVAL;
> 
> -       chan = cfg80211_wext_freq(wdev->wiphy, freq);
> -       if (chan && IS_ERR(chan))
> -               return PTR_ERR(chan);
> -
> -       if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
> -               return -EINVAL;
> +       freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
> +       if (freq < 0)
> +               return freq;
> +
> +       if (freq) {
> +               chan = ieee80211_get_channel(wdev->wiphy, freq);
> +               if (!chan)
> +                       return -EINVAL;
> +               if (chan->flags & IEEE80211_CHAN_DISABLED)
> +                       return -EINVAL;
> +       }
> 
>         cfg80211_lock_rdev(rdev);
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> 
>         if (wdev->sme_state != CFG80211_SME_IDLE) {
> @@ -84,9 +90,8 @@ int cfg80211_mgd_wext_siwfreq(struct net
>                 /* if SSID set, we'll try right again, avoid event */
>                 if (wdev->wext.connect.ssid_len)
>                         event = false;
> -               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
> -                                           dev, WLAN_REASON_DEAUTH_LEAVING,
> -                                           event);
> +               err = __cfg80211_disconnect(rdev, dev,
> +                                           WLAN_REASON_DEAUTH_LEAVING, event);
>                 if (err)
>                         goto out;
>         }
> @@ -95,17 +100,15 @@ int cfg80211_mgd_wext_siwfreq(struct net
>         wdev->wext.connect.channel = chan;
> 
>         /* SSID is not set, we just want to switch channel */
> -       if (wdev->wext.connect.ssid_len && chan) {
> -               err = -EOPNOTSUPP;
> -               if (rdev->ops->set_channel)
> -                       err = rdev->ops->set_channel(wdev->wiphy, chan,
> -                                                    NL80211_CHAN_NO_HT);
> +       if (chan && !wdev->wext.connect.ssid_len) {
> +               err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
>                 goto out;
>         }
> 
> -       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_mgd_wext_connect(rdev, wdev);
>   out:
>         wdev_unlock(wdev);
> +       mutex_unlock(&rdev->devlist_mtx);
>         cfg80211_unlock_rdev(rdev);
>         return err;
>  }
> @@ -143,6 +146,7 @@ int cfg80211_mgd_wext_siwessid(struct ne
>                                struct iw_point *data, char *ssid)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
>         size_t len = data->length;
>         int err;
> 
> @@ -157,7 +161,8 @@ int cfg80211_mgd_wext_siwessid(struct ne
>         if (len > 0 && ssid[len - 1] == '\0')
>                 len--;
> 
> -       cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
> +       cfg80211_lock_rdev(rdev);
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> 
>         err = 0;
> @@ -173,9 +178,8 @@ int cfg80211_mgd_wext_siwessid(struct ne
>                 /* if SSID set now, we'll try to connect, avoid event */
>                 if (len)
>                         event = false;
> -               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
> -                                           dev, WLAN_REASON_DEAUTH_LEAVING,
> -                                           event);
> +               err = __cfg80211_disconnect(rdev, dev,
> +                                           WLAN_REASON_DEAUTH_LEAVING, event);
>                 if (err)
>                         goto out;
>         }
> @@ -186,10 +190,11 @@ int cfg80211_mgd_wext_siwessid(struct ne
> 
>         wdev->wext.connect.crypto.control_port = false;
> 
> -       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_mgd_wext_connect(rdev, wdev);
>   out:
>         wdev_unlock(wdev);
> -       cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
> +       mutex_unlock(&rdev->devlist_mtx);
> +       cfg80211_unlock_rdev(rdev);
>         return err;
>  }
> 
> @@ -230,6 +235,7 @@ int cfg80211_mgd_wext_siwap(struct net_d
>                             struct sockaddr *ap_addr, char *extra)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
>         u8 *bssid = ap_addr->sa_data;
>         int err;
> 
> @@ -244,7 +250,8 @@ int cfg80211_mgd_wext_siwap(struct net_d
>         if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
>                 bssid = NULL;
> 
> -       cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
> +       cfg80211_lock_rdev(rdev);
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(wdev);
> 
>         if (wdev->sme_state != CFG80211_SME_IDLE) {
> @@ -258,9 +265,8 @@ int cfg80211_mgd_wext_siwap(struct net_d
>                     compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
>                         goto out;
> 
> -               err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
> -                                           dev, WLAN_REASON_DEAUTH_LEAVING,
> -                                           false);
> +               err = __cfg80211_disconnect(rdev, dev,
> +                                           WLAN_REASON_DEAUTH_LEAVING, false);
>                 if (err)
>                         goto out;
>         }
> @@ -271,10 +277,11 @@ int cfg80211_mgd_wext_siwap(struct net_d
>         } else
>                 wdev->wext.connect.bssid = NULL;
> 
> -       err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
> +       err = cfg80211_mgd_wext_connect(rdev, wdev);
>   out:
>         wdev_unlock(wdev);
> -       cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
> +       mutex_unlock(&rdev->devlist_mtx);
> +       cfg80211_unlock_rdev(rdev);
>         return err;
>  }
> 
> --- wireless-testing.orig/net/wireless/sme.c    2009-08-07 14:50:09.000000000 +0200
> +++ wireless-testing/net/wireless/sme.c 2009-08-07 17:20:31.000000000 +0200
> @@ -256,9 +256,11 @@ void cfg80211_sme_scan_done(struct net_d
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> 
> +       mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
>         wdev_lock(wdev);
>         __cfg80211_sme_scan_done(dev);
>         wdev_unlock(wdev);
> +       mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
>  }
> 
>  void cfg80211_sme_rx_auth(struct net_device *dev,
> @@ -644,6 +646,7 @@ int __cfg80211_connect(struct cfg80211_r
>                        struct cfg80211_cached_keys *connkeys)
>  {
>         struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct ieee80211_channel *chan;
>         int err;
> 
>         ASSERT_WDEV_LOCK(wdev);
> @@ -651,6 +654,10 @@ int __cfg80211_connect(struct cfg80211_r
>         if (wdev->sme_state != CFG80211_SME_IDLE)
>                 return -EALREADY;
> 
> +       chan = rdev_fixed_channel(rdev, wdev);
> +       if (chan && chan != connect->channel)
> +               return -EBUSY;
> +
>         if (WARN_ON(wdev->connect_keys)) {
>                 kfree(wdev->connect_keys);
>                 wdev->connect_keys = NULL;
> @@ -771,9 +778,11 @@ int cfg80211_connect(struct cfg80211_reg
>  {
>         int err;
> 
> +       mutex_lock(&rdev->devlist_mtx);
>         wdev_lock(dev->ieee80211_ptr);
>         err = __cfg80211_connect(rdev, dev, connect, connkeys);
>         wdev_unlock(dev->ieee80211_ptr);
> +       mutex_unlock(&rdev->devlist_mtx);
> 
>         return err;
>  }
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux