cfg80211: prohibit scanning the same channel more than once
authorJohannes Berg <johannes@sipsolutions.net>
Wed, 17 Jun 2009 15:41:49 +0000 (17:41 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 10 Jul 2009 18:57:54 +0000 (14:57 -0400)
It isn't very useful to scan the same channel more than once
during a given scan, and some hardware (notably iwlwifi) can
only scan a limited number of channels at a time. To prevent
any overflows, simply disallow scanning any channel multiple
times in a given scan command. This is a small change in the
userspace ABI, but the only user, wpa_supplicant, never asks
for a scan with the same frequency listed twice.

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

index 5a6c4ca593989b44b9ecb1e5786f78fff61a51e3..7946b82c5716854b370773b7d5294ad208de06e6 100644 (file)
@@ -2695,6 +2695,31 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        return r;
 }
 
+static int validate_scan_freqs(struct nlattr *freqs)
+{
+       struct nlattr *attr1, *attr2;
+       int n_channels = 0, tmp1, tmp2;
+
+       nla_for_each_nested(attr1, freqs, tmp1) {
+               n_channels++;
+               /*
+                * Some hardware has a limited channel list for
+                * scanning, and it is pretty much nonsensical
+                * to scan for a channel twice, so disallow that
+                * and don't require drivers to check that the
+                * channel list they get isn't longer than what
+                * they can scan, as long as they can scan all
+                * the channels they registered at once.
+                */
+               nla_for_each_nested(attr2, freqs, tmp2)
+                       if (attr1 != attr2 &&
+                           nla_get_u32(attr1) == nla_get_u32(attr2))
+                               return 0;
+       }
+
+       return n_channels;
+}
+
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
@@ -2704,7 +2729,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        struct ieee80211_channel *channel;
        struct nlattr *attr;
        struct wiphy *wiphy;
-       int err, tmp, n_ssids = 0, n_channels = 0, i;
+       int err, tmp, n_ssids = 0, n_channels, i;
        enum ieee80211_band band;
        size_t ie_len;
 
@@ -2735,13 +2760,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
-               nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
-                       n_channels++;
+               n_channels = validate_scan_freqs(
+                               info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
                if (!n_channels) {
                        err = -EINVAL;
                        goto out;
                }
        } else {
+               n_channels = 0;
+
                for (band = 0; band < IEEE80211_NUM_BANDS; band++)
                        if (wiphy->bands[band])
                                n_channels += wiphy->bands[band]->n_channels;