cfg80211: validate scan channels
Johannes Berg [Mon, 2 Nov 2009 12:32:03 +0000 (13:32 +0100)]
Currently it is possible to request a scan on only
disabled channels, which could be problematic for
some drivers. Reject such scans, and also ignore
disabled channels that are given. This resuls in
the scan begin/end event only including channels
that are actually used.

This makes the mac80211 check for disabled channels
superfluous. At the same time, remove the no-IBSS
check from mac80211 -- nothing says that we should
not find any networks on channels that cannot be
used for an IBSS, even when operating in IBSS mode.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

net/mac80211/scan.c
net/wireless/nl80211.c
net/wireless/scan.c

index 88a9a1b..4cf387c 100644 (file)
@@ -614,23 +614,14 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 {
        int skip;
        struct ieee80211_channel *chan;
-       struct ieee80211_sub_if_data *sdata = local->scan_sdata;
 
        skip = 0;
        chan = local->scan_req->channels[local->scan_channel_idx];
 
-       if (chan->flags & IEEE80211_CHAN_DISABLED ||
-           (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-            chan->flags & IEEE80211_CHAN_NO_IBSS))
+       local->scan_channel = chan;
+       if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
                skip = 1;
 
-       if (!skip) {
-               local->scan_channel = chan;
-               if (ieee80211_hw_config(local,
-                                       IEEE80211_CONF_CHANGE_CHANNEL))
-                       skip = 1;
-       }
-
        /* advance state machine to next channel/band */
        local->scan_channel_idx++;
 
index f483941..8ed62b6 100644 (file)
@@ -2988,7 +2988,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       request->n_channels = n_channels;
        if (n_ssids)
                request->ssids = (void *)&request->channels[n_channels];
        request->n_ssids = n_ssids;
@@ -2999,32 +2998,53 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                        request->ie = (void *)(request->channels + n_channels);
        }
 
+       i = 0;
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                /* user specified, bail out if channel not found */
-               request->n_channels = n_channels;
-               i = 0;
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
-                       request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr));
-                       if (!request->channels[i]) {
+                       struct ieee80211_channel *chan;
+
+                       chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+
+                       if (!chan) {
                                err = -EINVAL;
                                goto out_free;
                        }
+
+                       /* ignore disabled channels */
+                       if (chan->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       request->channels[i] = chan;
                        i++;
                }
        } else {
                /* all channels */
-               i = 0;
                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                        int j;
                        if (!wiphy->bands[band])
                                continue;
                        for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
-                               request->channels[i] = &wiphy->bands[band]->channels[j];
+                               struct ieee80211_channel *chan;
+
+                               chan = &wiphy->bands[band]->channels[j];
+
+                               if (chan->flags & IEEE80211_CHAN_DISABLED)
+                                       continue;
+
+                               request->channels[i] = chan;
                                i++;
                        }
                }
        }
 
+       if (!i) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       request->n_channels = i;
+
        i = 0;
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
index 2e8c515..e2d344f 100644 (file)
@@ -650,9 +650,15 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        i = 0;
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                int j;
+
                if (!wiphy->bands[band])
                        continue;
+
                for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+                       /* ignore disabled channels */
+                       if (wiphy->bands[band]->channels[j].flags &
+                                               IEEE80211_CHAN_DISABLED)
+                               continue;
 
                        /* If we have a wireless request structure and the
                         * wireless request specifies frequencies, then search