wireless : use a dedicated workqueue for cfg80211.
[safe/jmp/linux-2.6] / net / wireless / scan.c
index 7043de6..df26228 100644 (file)
@@ -22,7 +22,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
 {
        struct cfg80211_scan_request *request;
        struct net_device *dev;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
        union iwreq_data wrqu;
 #endif
 
@@ -47,7 +47,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
        else
                nl80211_send_scan_done(rdev, dev);
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
        if (!request->aborted) {
                memset(&wrqu, 0, sizeof(wrqu));
 
@@ -88,7 +88,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
        WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
 
        request->aborted = aborted;
-       schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
+       queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
 }
 EXPORT_SYMBOL(cfg80211_scan_done);
 
@@ -141,7 +141,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
                dev->bss_generation++;
 }
 
-static u8 *find_ie(u8 num, u8 *ies, size_t len)
+static u8 *find_ie(u8 num, u8 *ies, int len)
 {
        while (len > 2 && ies[0] != num) {
                len -= ies[1] + 2;
@@ -217,7 +217,7 @@ static bool is_mesh(struct cfg80211_bss *a,
                     a->len_information_elements);
        if (!ie)
                return false;
-       if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+       if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
                return false;
 
        /*
@@ -225,7 +225,8 @@ static bool is_mesh(struct cfg80211_bss *a,
         * comparing since that may differ between stations taking
         * part in the same mesh.
         */
-       return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
+       return memcmp(ie + 2, meshcfg,
+           sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 }
 
 static int cmp_bss(struct cfg80211_bss *a,
@@ -399,7 +400,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                                  res->pub.information_elements,
                                  res->pub.len_information_elements);
                if (!meshid || !meshcfg ||
-                   meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
+                   meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
                        /* bogus mesh */
                        kref_put(&res->ref, bss_release);
                        return NULL;
@@ -592,7 +593,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 }
 EXPORT_SYMBOL(cfg80211_unlink_bss);
 
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
 int cfg80211_wext_siwscan(struct net_device *dev,
                          struct iw_request_info *info,
                          union iwreq_data *wrqu, char *extra)
@@ -607,6 +608,9 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        if (!netif_running(dev))
                return -ENETDOWN;
 
+       if (wrqu->data.length == sizeof(struct iw_scan_req))
+               wreq = (struct iw_scan_req *)extra;
+
        rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
 
        if (IS_ERR(rdev))
@@ -619,9 +623,14 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 
        wiphy = &rdev->wiphy;
 
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++)
-               if (wiphy->bands[band])
-                       n_channels += wiphy->bands[band]->n_channels;
+       /* Determine number of channels, needed to allocate creq */
+       if (wreq && wreq->num_channels)
+               n_channels = wreq->num_channels;
+       else {
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+                       if (wiphy->bands[band])
+                               n_channels += wiphy->bands[band]->n_channels;
+       }
 
        creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
                       n_channels * sizeof(void *),
@@ -638,22 +647,52 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        creq->n_channels = n_channels;
        creq->n_ssids = 1;
 
-       /* all channels */
+       /* translate "Scan on frequencies" request */
        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
+                        * for the matching hardware channel.
+                        */
+                       if (wreq && wreq->num_channels) {
+                               int k;
+                               int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
+                               for (k = 0; k < wreq->num_channels; k++) {
+                                       int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
+                                       if (wext_freq == wiphy_freq)
+                                               goto wext_freq_found;
+                               }
+                               goto wext_freq_not_found;
+                       }
+
+               wext_freq_found:
                        creq->channels[i] = &wiphy->bands[band]->channels[j];
                        i++;
+               wext_freq_not_found: ;
                }
        }
+       /* No channels found? */
+       if (!i) {
+               err = -EINVAL;
+               goto out;
+       }
 
-       /* translate scan request */
-       if (wrqu->data.length == sizeof(struct iw_scan_req)) {
-               wreq = (struct iw_scan_req *)extra;
+       /* Set real number of channels specified in creq->channels[] */
+       creq->n_channels = i;
 
+       /* translate "Scan for SSID" request */
+       if (wreq) {
                if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
                        if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
                                return -EINVAL;
@@ -827,7 +866,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
                        break;
                case WLAN_EID_MESH_CONFIG:
                        ismesh = true;
-                       if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+                       if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
                                break;
                        buf = kmalloc(50, GFP_ATOMIC);
                        if (!buf)
@@ -835,35 +874,40 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
                        cfg = ie + 2;
                        memset(&iwe, 0, sizeof(iwe));
                        iwe.cmd = IWEVCUSTOM;
-                       sprintf(buf, "Mesh network (version %d)", cfg[0]);
+                       sprintf(buf, "Mesh Network Path Selection Protocol ID: "
+                               "0x%02X", cfg[0]);
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
+                                                         &iwe, buf);
+                       sprintf(buf, "Path Selection Metric ID: 0x%02X",
+                               cfg[1]);
+                       iwe.u.data.length = strlen(buf);
+                       current_ev = iwe_stream_add_point(info, current_ev,
+                                                         end_buf,
+                                                         &iwe, buf);
+                       sprintf(buf, "Congestion Control Mode ID: 0x%02X",
+                               cfg[2]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Path Selection Protocol ID: "
-                               "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
-                                                       cfg[4]);
+                       sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Path Selection Metric ID: "
-                               "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
-                                                       cfg[8]);
+                       sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Congestion Control Mode ID: "
-                               "0x%02X%02X%02X%02X", cfg[9], cfg[10],
-                                                       cfg[11], cfg[12]);
+                       sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,
                                                          &iwe, buf);
-                       sprintf(buf, "Channel Precedence: "
-                               "0x%02X%02X%02X%02X", cfg[13], cfg[14],
-                                                       cfg[15], cfg[16]);
+                       sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
                        iwe.u.data.length = strlen(buf);
                        current_ev = iwe_stream_add_point(info, current_ev,
                                                          end_buf,