]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - net/wireless/scan.c
Initial 2.6.37
[mcf548x/linux.git] / net / wireless / scan.c
1 /*
2  * cfg80211 scan result handling
3  *
4  * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
5  */
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <linux/netdevice.h>
10 #include <linux/wireless.h>
11 #include <linux/nl80211.h>
12 #include <linux/etherdevice.h>
13 #include <net/arp.h>
14 #include <net/cfg80211.h>
15 #include <net/iw_handler.h>
16 #include "core.h"
17 #include "nl80211.h"
18 #include "wext-compat.h"
19
20 #define IEEE80211_SCAN_RESULT_EXPIRE    (15 * HZ)
21
22 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
23 {
24         struct cfg80211_scan_request *request;
25         struct net_device *dev;
26 #ifdef CONFIG_CFG80211_WEXT
27         union iwreq_data wrqu;
28 #endif
29
30         ASSERT_RDEV_LOCK(rdev);
31
32         request = rdev->scan_req;
33
34         if (!request)
35                 return;
36
37         dev = request->dev;
38
39         /*
40          * This must be before sending the other events!
41          * Otherwise, wpa_supplicant gets completely confused with
42          * wext events.
43          */
44         cfg80211_sme_scan_done(dev);
45
46         if (request->aborted)
47                 nl80211_send_scan_aborted(rdev, dev);
48         else
49                 nl80211_send_scan_done(rdev, dev);
50
51 #ifdef CONFIG_CFG80211_WEXT
52         if (!request->aborted) {
53                 memset(&wrqu, 0, sizeof(wrqu));
54
55                 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
56         }
57 #endif
58
59         dev_put(dev);
60
61         rdev->scan_req = NULL;
62
63         /*
64          * OK. If this is invoked with "leak" then we can't
65          * free this ... but we've cleaned it up anyway. The
66          * driver failed to call the scan_done callback, so
67          * all bets are off, it might still be trying to use
68          * the scan request or not ... if it accesses the dev
69          * in there (it shouldn't anyway) then it may crash.
70          */
71         if (!leak)
72                 kfree(request);
73 }
74
75 void __cfg80211_scan_done(struct work_struct *wk)
76 {
77         struct cfg80211_registered_device *rdev;
78
79         rdev = container_of(wk, struct cfg80211_registered_device,
80                             scan_done_wk);
81
82         cfg80211_lock_rdev(rdev);
83         ___cfg80211_scan_done(rdev, false);
84         cfg80211_unlock_rdev(rdev);
85 }
86
87 void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
88 {
89         WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
90
91         request->aborted = aborted;
92         queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
93 }
94 EXPORT_SYMBOL(cfg80211_scan_done);
95
96 static void bss_release(struct kref *ref)
97 {
98         struct cfg80211_internal_bss *bss;
99
100         bss = container_of(ref, struct cfg80211_internal_bss, ref);
101         if (bss->pub.free_priv)
102                 bss->pub.free_priv(&bss->pub);
103
104         if (bss->beacon_ies_allocated)
105                 kfree(bss->pub.beacon_ies);
106         if (bss->proberesp_ies_allocated)
107                 kfree(bss->pub.proberesp_ies);
108
109         BUG_ON(atomic_read(&bss->hold));
110
111         kfree(bss);
112 }
113
114 /* must hold dev->bss_lock! */
115 void cfg80211_bss_age(struct cfg80211_registered_device *dev,
116                       unsigned long age_secs)
117 {
118         struct cfg80211_internal_bss *bss;
119         unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
120
121         list_for_each_entry(bss, &dev->bss_list, list) {
122                 bss->ts -= age_jiffies;
123         }
124 }
125
126 /* must hold dev->bss_lock! */
127 void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
128 {
129         struct cfg80211_internal_bss *bss, *tmp;
130         bool expired = false;
131
132         list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
133                 if (atomic_read(&bss->hold))
134                         continue;
135                 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
136                         continue;
137                 list_del(&bss->list);
138                 rb_erase(&bss->rbn, &dev->bss_tree);
139                 kref_put(&bss->ref, bss_release);
140                 expired = true;
141         }
142
143         if (expired)
144                 dev->bss_generation++;
145 }
146
147 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
148 {
149         while (len > 2 && ies[0] != eid) {
150                 len -= ies[1] + 2;
151                 ies += ies[1] + 2;
152         }
153         if (len < 2)
154                 return NULL;
155         if (len < 2 + ies[1])
156                 return NULL;
157         return ies;
158 }
159 EXPORT_SYMBOL(cfg80211_find_ie);
160
161 static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
162 {
163         const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
164         const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
165         int r;
166
167         if (!ie1 && !ie2)
168                 return 0;
169         if (!ie1 || !ie2)
170                 return -1;
171
172         r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
173         if (r == 0 && ie1[1] != ie2[1])
174                 return ie2[1] - ie1[1];
175         return r;
176 }
177
178 static bool is_bss(struct cfg80211_bss *a,
179                    const u8 *bssid,
180                    const u8 *ssid, size_t ssid_len)
181 {
182         const u8 *ssidie;
183
184         if (bssid && compare_ether_addr(a->bssid, bssid))
185                 return false;
186
187         if (!ssid)
188                 return true;
189
190         ssidie = cfg80211_find_ie(WLAN_EID_SSID,
191                                   a->information_elements,
192                                   a->len_information_elements);
193         if (!ssidie)
194                 return false;
195         if (ssidie[1] != ssid_len)
196                 return false;
197         return memcmp(ssidie + 2, ssid, ssid_len) == 0;
198 }
199
200 static bool is_mesh(struct cfg80211_bss *a,
201                     const u8 *meshid, size_t meshidlen,
202                     const u8 *meshcfg)
203 {
204         const u8 *ie;
205
206         if (!is_zero_ether_addr(a->bssid))
207                 return false;
208
209         ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
210                               a->information_elements,
211                               a->len_information_elements);
212         if (!ie)
213                 return false;
214         if (ie[1] != meshidlen)
215                 return false;
216         if (memcmp(ie + 2, meshid, meshidlen))
217                 return false;
218
219         ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
220                               a->information_elements,
221                               a->len_information_elements);
222         if (!ie)
223                 return false;
224         if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
225                 return false;
226
227         /*
228          * Ignore mesh capability (last two bytes of the IE) when
229          * comparing since that may differ between stations taking
230          * part in the same mesh.
231          */
232         return memcmp(ie + 2, meshcfg,
233             sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
234 }
235
236 static int cmp_bss(struct cfg80211_bss *a,
237                    struct cfg80211_bss *b)
238 {
239         int r;
240
241         if (a->channel != b->channel)
242                 return b->channel->center_freq - a->channel->center_freq;
243
244         r = memcmp(a->bssid, b->bssid, ETH_ALEN);
245         if (r)
246                 return r;
247
248         if (is_zero_ether_addr(a->bssid)) {
249                 r = cmp_ies(WLAN_EID_MESH_ID,
250                             a->information_elements,
251                             a->len_information_elements,
252                             b->information_elements,
253                             b->len_information_elements);
254                 if (r)
255                         return r;
256                 return cmp_ies(WLAN_EID_MESH_CONFIG,
257                                a->information_elements,
258                                a->len_information_elements,
259                                b->information_elements,
260                                b->len_information_elements);
261         }
262
263         return cmp_ies(WLAN_EID_SSID,
264                        a->information_elements,
265                        a->len_information_elements,
266                        b->information_elements,
267                        b->len_information_elements);
268 }
269
270 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
271                                       struct ieee80211_channel *channel,
272                                       const u8 *bssid,
273                                       const u8 *ssid, size_t ssid_len,
274                                       u16 capa_mask, u16 capa_val)
275 {
276         struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
277         struct cfg80211_internal_bss *bss, *res = NULL;
278         unsigned long now = jiffies;
279
280         spin_lock_bh(&dev->bss_lock);
281
282         list_for_each_entry(bss, &dev->bss_list, list) {
283                 if ((bss->pub.capability & capa_mask) != capa_val)
284                         continue;
285                 if (channel && bss->pub.channel != channel)
286                         continue;
287                 /* Don't get expired BSS structs */
288                 if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
289                     !atomic_read(&bss->hold))
290                         continue;
291                 if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
292                         res = bss;
293                         kref_get(&res->ref);
294                         break;
295                 }
296         }
297
298         spin_unlock_bh(&dev->bss_lock);
299         if (!res)
300                 return NULL;
301         return &res->pub;
302 }
303 EXPORT_SYMBOL(cfg80211_get_bss);
304
305 struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
306                                        struct ieee80211_channel *channel,
307                                        const u8 *meshid, size_t meshidlen,
308                                        const u8 *meshcfg)
309 {
310         struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
311         struct cfg80211_internal_bss *bss, *res = NULL;
312
313         spin_lock_bh(&dev->bss_lock);
314
315         list_for_each_entry(bss, &dev->bss_list, list) {
316                 if (channel && bss->pub.channel != channel)
317                         continue;
318                 if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
319                         res = bss;
320                         kref_get(&res->ref);
321                         break;
322                 }
323         }
324
325         spin_unlock_bh(&dev->bss_lock);
326         if (!res)
327                 return NULL;
328         return &res->pub;
329 }
330 EXPORT_SYMBOL(cfg80211_get_mesh);
331
332
333 static void rb_insert_bss(struct cfg80211_registered_device *dev,
334                           struct cfg80211_internal_bss *bss)
335 {
336         struct rb_node **p = &dev->bss_tree.rb_node;
337         struct rb_node *parent = NULL;
338         struct cfg80211_internal_bss *tbss;
339         int cmp;
340
341         while (*p) {
342                 parent = *p;
343                 tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
344
345                 cmp = cmp_bss(&bss->pub, &tbss->pub);
346
347                 if (WARN_ON(!cmp)) {
348                         /* will sort of leak this BSS */
349                         return;
350                 }
351
352                 if (cmp < 0)
353                         p = &(*p)->rb_left;
354                 else
355                         p = &(*p)->rb_right;
356         }
357
358         rb_link_node(&bss->rbn, parent, p);
359         rb_insert_color(&bss->rbn, &dev->bss_tree);
360 }
361
362 static struct cfg80211_internal_bss *
363 rb_find_bss(struct cfg80211_registered_device *dev,
364             struct cfg80211_internal_bss *res)
365 {
366         struct rb_node *n = dev->bss_tree.rb_node;
367         struct cfg80211_internal_bss *bss;
368         int r;
369
370         while (n) {
371                 bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
372                 r = cmp_bss(&res->pub, &bss->pub);
373
374                 if (r == 0)
375                         return bss;
376                 else if (r < 0)
377                         n = n->rb_left;
378                 else
379                         n = n->rb_right;
380         }
381
382         return NULL;
383 }
384
385 static struct cfg80211_internal_bss *
386 cfg80211_bss_update(struct cfg80211_registered_device *dev,
387                     struct cfg80211_internal_bss *res)
388 {
389         struct cfg80211_internal_bss *found = NULL;
390         const u8 *meshid, *meshcfg;
391
392         /*
393          * The reference to "res" is donated to this function.
394          */
395
396         if (WARN_ON(!res->pub.channel)) {
397                 kref_put(&res->ref, bss_release);
398                 return NULL;
399         }
400
401         res->ts = jiffies;
402
403         if (is_zero_ether_addr(res->pub.bssid)) {
404                 /* must be mesh, verify */
405                 meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
406                                           res->pub.information_elements,
407                                           res->pub.len_information_elements);
408                 meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
409                                            res->pub.information_elements,
410                                            res->pub.len_information_elements);
411                 if (!meshid || !meshcfg ||
412                     meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
413                         /* bogus mesh */
414                         kref_put(&res->ref, bss_release);
415                         return NULL;
416                 }
417         }
418
419         spin_lock_bh(&dev->bss_lock);
420
421         found = rb_find_bss(dev, res);
422
423         if (found) {
424                 found->pub.beacon_interval = res->pub.beacon_interval;
425                 found->pub.tsf = res->pub.tsf;
426                 found->pub.signal = res->pub.signal;
427                 found->pub.capability = res->pub.capability;
428                 found->ts = res->ts;
429
430                 /* Update IEs */
431                 if (res->pub.proberesp_ies) {
432                         size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
433                         size_t ielen = res->pub.len_proberesp_ies;
434
435                         if (found->pub.proberesp_ies &&
436                             !found->proberesp_ies_allocated &&
437                             ksize(found) >= used + ielen) {
438                                 memcpy(found->pub.proberesp_ies,
439                                        res->pub.proberesp_ies, ielen);
440                                 found->pub.len_proberesp_ies = ielen;
441                         } else {
442                                 u8 *ies = found->pub.proberesp_ies;
443
444                                 if (found->proberesp_ies_allocated)
445                                         ies = krealloc(ies, ielen, GFP_ATOMIC);
446                                 else
447                                         ies = kmalloc(ielen, GFP_ATOMIC);
448
449                                 if (ies) {
450                                         memcpy(ies, res->pub.proberesp_ies,
451                                                ielen);
452                                         found->proberesp_ies_allocated = true;
453                                         found->pub.proberesp_ies = ies;
454                                         found->pub.len_proberesp_ies = ielen;
455                                 }
456                         }
457
458                         /* Override possible earlier Beacon frame IEs */
459                         found->pub.information_elements =
460                                 found->pub.proberesp_ies;
461                         found->pub.len_information_elements =
462                                 found->pub.len_proberesp_ies;
463                 }
464                 if (res->pub.beacon_ies) {
465                         size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
466                         size_t ielen = res->pub.len_beacon_ies;
467
468                         if (found->pub.beacon_ies &&
469                             !found->beacon_ies_allocated &&
470                             ksize(found) >= used + ielen) {
471                                 memcpy(found->pub.beacon_ies,
472                                        res->pub.beacon_ies, ielen);
473                                 found->pub.len_beacon_ies = ielen;
474                         } else {
475                                 u8 *ies = found->pub.beacon_ies;
476
477                                 if (found->beacon_ies_allocated)
478                                         ies = krealloc(ies, ielen, GFP_ATOMIC);
479                                 else
480                                         ies = kmalloc(ielen, GFP_ATOMIC);
481
482                                 if (ies) {
483                                         memcpy(ies, res->pub.beacon_ies,
484                                                ielen);
485                                         found->beacon_ies_allocated = true;
486                                         found->pub.beacon_ies = ies;
487                                         found->pub.len_beacon_ies = ielen;
488                                 }
489                         }
490                 }
491
492                 kref_put(&res->ref, bss_release);
493         } else {
494                 /* this "consumes" the reference */
495                 list_add_tail(&res->list, &dev->bss_list);
496                 rb_insert_bss(dev, res);
497                 found = res;
498         }
499
500         dev->bss_generation++;
501         spin_unlock_bh(&dev->bss_lock);
502
503         kref_get(&found->ref);
504         return found;
505 }
506
507 struct cfg80211_bss*
508 cfg80211_inform_bss(struct wiphy *wiphy,
509                     struct ieee80211_channel *channel,
510                     const u8 *bssid,
511                     u64 timestamp, u16 capability, u16 beacon_interval,
512                     const u8 *ie, size_t ielen,
513                     s32 signal, gfp_t gfp)
514 {
515         struct cfg80211_internal_bss *res;
516         size_t privsz;
517
518         if (WARN_ON(!wiphy))
519                 return NULL;
520
521         privsz = wiphy->bss_priv_size;
522
523         if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
524                         (signal < 0 || signal > 100)))
525                 return NULL;
526
527         res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
528         if (!res)
529                 return NULL;
530
531         memcpy(res->pub.bssid, bssid, ETH_ALEN);
532         res->pub.channel = channel;
533         res->pub.signal = signal;
534         res->pub.tsf = timestamp;
535         res->pub.beacon_interval = beacon_interval;
536         res->pub.capability = capability;
537         /*
538          * Since we do not know here whether the IEs are from a Beacon or Probe
539          * Response frame, we need to pick one of the options and only use it
540          * with the driver that does not provide the full Beacon/Probe Response
541          * frame. Use Beacon frame pointer to avoid indicating that this should
542          * override the information_elements pointer should we have received an
543          * earlier indication of Probe Response data.
544          *
545          * The initial buffer for the IEs is allocated with the BSS entry and
546          * is located after the private area.
547          */
548         res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz;
549         memcpy(res->pub.beacon_ies, ie, ielen);
550         res->pub.len_beacon_ies = ielen;
551         res->pub.information_elements = res->pub.beacon_ies;
552         res->pub.len_information_elements = res->pub.len_beacon_ies;
553
554         kref_init(&res->ref);
555
556         res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
557         if (!res)
558                 return NULL;
559
560         if (res->pub.capability & WLAN_CAPABILITY_ESS)
561                 regulatory_hint_found_beacon(wiphy, channel, gfp);
562
563         /* cfg80211_bss_update gives us a referenced result */
564         return &res->pub;
565 }
566 EXPORT_SYMBOL(cfg80211_inform_bss);
567
568 struct cfg80211_bss *
569 cfg80211_inform_bss_frame(struct wiphy *wiphy,
570                           struct ieee80211_channel *channel,
571                           struct ieee80211_mgmt *mgmt, size_t len,
572                           s32 signal, gfp_t gfp)
573 {
574         struct cfg80211_internal_bss *res;
575         size_t ielen = len - offsetof(struct ieee80211_mgmt,
576                                       u.probe_resp.variable);
577         size_t privsz = wiphy->bss_priv_size;
578
579         if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
580                     (signal < 0 || signal > 100)))
581                 return NULL;
582
583         if (WARN_ON(!mgmt || !wiphy ||
584                     len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
585                 return NULL;
586
587         res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
588         if (!res)
589                 return NULL;
590
591         memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
592         res->pub.channel = channel;
593         res->pub.signal = signal;
594         res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
595         res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
596         res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
597         /*
598          * The initial buffer for the IEs is allocated with the BSS entry and
599          * is located after the private area.
600          */
601         if (ieee80211_is_probe_resp(mgmt->frame_control)) {
602                 res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz;
603                 memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable,
604                        ielen);
605                 res->pub.len_proberesp_ies = ielen;
606                 res->pub.information_elements = res->pub.proberesp_ies;
607                 res->pub.len_information_elements = res->pub.len_proberesp_ies;
608         } else {
609                 res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz;
610                 memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen);
611                 res->pub.len_beacon_ies = ielen;
612                 res->pub.information_elements = res->pub.beacon_ies;
613                 res->pub.len_information_elements = res->pub.len_beacon_ies;
614         }
615
616         kref_init(&res->ref);
617
618         res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
619         if (!res)
620                 return NULL;
621
622         if (res->pub.capability & WLAN_CAPABILITY_ESS)
623                 regulatory_hint_found_beacon(wiphy, channel, gfp);
624
625         /* cfg80211_bss_update gives us a referenced result */
626         return &res->pub;
627 }
628 EXPORT_SYMBOL(cfg80211_inform_bss_frame);
629
630 void cfg80211_put_bss(struct cfg80211_bss *pub)
631 {
632         struct cfg80211_internal_bss *bss;
633
634         if (!pub)
635                 return;
636
637         bss = container_of(pub, struct cfg80211_internal_bss, pub);
638         kref_put(&bss->ref, bss_release);
639 }
640 EXPORT_SYMBOL(cfg80211_put_bss);
641
642 void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
643 {
644         struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
645         struct cfg80211_internal_bss *bss;
646
647         if (WARN_ON(!pub))
648                 return;
649
650         bss = container_of(pub, struct cfg80211_internal_bss, pub);
651
652         spin_lock_bh(&dev->bss_lock);
653         if (!list_empty(&bss->list)) {
654                 list_del_init(&bss->list);
655                 dev->bss_generation++;
656                 rb_erase(&bss->rbn, &dev->bss_tree);
657
658                 kref_put(&bss->ref, bss_release);
659         }
660         spin_unlock_bh(&dev->bss_lock);
661 }
662 EXPORT_SYMBOL(cfg80211_unlink_bss);
663
664 #ifdef CONFIG_CFG80211_WEXT
665 int cfg80211_wext_siwscan(struct net_device *dev,
666                           struct iw_request_info *info,
667                           union iwreq_data *wrqu, char *extra)
668 {
669         struct cfg80211_registered_device *rdev;
670         struct wiphy *wiphy;
671         struct iw_scan_req *wreq = NULL;
672         struct cfg80211_scan_request *creq = NULL;
673         int i, err, n_channels = 0;
674         enum ieee80211_band band;
675
676         if (!netif_running(dev))
677                 return -ENETDOWN;
678
679         if (wrqu->data.length == sizeof(struct iw_scan_req))
680                 wreq = (struct iw_scan_req *)extra;
681
682         rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
683
684         if (IS_ERR(rdev))
685                 return PTR_ERR(rdev);
686
687         if (rdev->scan_req) {
688                 err = -EBUSY;
689                 goto out;
690         }
691
692         wiphy = &rdev->wiphy;
693
694         /* Determine number of channels, needed to allocate creq */
695         if (wreq && wreq->num_channels)
696                 n_channels = wreq->num_channels;
697         else {
698                 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
699                         if (wiphy->bands[band])
700                                 n_channels += wiphy->bands[band]->n_channels;
701         }
702
703         creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
704                        n_channels * sizeof(void *),
705                        GFP_ATOMIC);
706         if (!creq) {
707                 err = -ENOMEM;
708                 goto out;
709         }
710
711         creq->wiphy = wiphy;
712         creq->dev = dev;
713         /* SSIDs come after channels */
714         creq->ssids = (void *)&creq->channels[n_channels];
715         creq->n_channels = n_channels;
716         creq->n_ssids = 1;
717
718         /* translate "Scan on frequencies" request */
719         i = 0;
720         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
721                 int j;
722
723                 if (!wiphy->bands[band])
724                         continue;
725
726                 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
727                         /* ignore disabled channels */
728                         if (wiphy->bands[band]->channels[j].flags &
729                                                 IEEE80211_CHAN_DISABLED)
730                                 continue;
731
732                         /* If we have a wireless request structure and the
733                          * wireless request specifies frequencies, then search
734                          * for the matching hardware channel.
735                          */
736                         if (wreq && wreq->num_channels) {
737                                 int k;
738                                 int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
739                                 for (k = 0; k < wreq->num_channels; k++) {
740                                         int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]);
741                                         if (wext_freq == wiphy_freq)
742                                                 goto wext_freq_found;
743                                 }
744                                 goto wext_freq_not_found;
745                         }
746
747                 wext_freq_found:
748                         creq->channels[i] = &wiphy->bands[band]->channels[j];
749                         i++;
750                 wext_freq_not_found: ;
751                 }
752         }
753         /* No channels found? */
754         if (!i) {
755                 err = -EINVAL;
756                 goto out;
757         }
758
759         /* Set real number of channels specified in creq->channels[] */
760         creq->n_channels = i;
761
762         /* translate "Scan for SSID" request */
763         if (wreq) {
764                 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
765                         if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
766                                 err = -EINVAL;
767                                 goto out;
768                         }
769                         memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
770                         creq->ssids[0].ssid_len = wreq->essid_len;
771                 }
772                 if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
773                         creq->n_ssids = 0;
774         }
775
776         rdev->scan_req = creq;
777         err = rdev->ops->scan(wiphy, dev, creq);
778         if (err) {
779                 rdev->scan_req = NULL;
780                 /* creq will be freed below */
781         } else {
782                 nl80211_send_scan_start(rdev, dev);
783                 /* creq now owned by driver */
784                 creq = NULL;
785                 dev_hold(dev);
786         }
787  out:
788         kfree(creq);
789         cfg80211_unlock_rdev(rdev);
790         return err;
791 }
792 EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
793
794 static void ieee80211_scan_add_ies(struct iw_request_info *info,
795                                    struct cfg80211_bss *bss,
796                                    char **current_ev, char *end_buf)
797 {
798         u8 *pos, *end, *next;
799         struct iw_event iwe;
800
801         if (!bss->information_elements ||
802             !bss->len_information_elements)
803                 return;
804
805         /*
806          * If needed, fragment the IEs buffer (at IE boundaries) into short
807          * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
808          */
809         pos = bss->information_elements;
810         end = pos + bss->len_information_elements;
811
812         while (end - pos > IW_GENERIC_IE_MAX) {
813                 next = pos + 2 + pos[1];
814                 while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
815                         next = next + 2 + next[1];
816
817                 memset(&iwe, 0, sizeof(iwe));
818                 iwe.cmd = IWEVGENIE;
819                 iwe.u.data.length = next - pos;
820                 *current_ev = iwe_stream_add_point(info, *current_ev,
821                                                    end_buf, &iwe, pos);
822
823                 pos = next;
824         }
825
826         if (end > pos) {
827                 memset(&iwe, 0, sizeof(iwe));
828                 iwe.cmd = IWEVGENIE;
829                 iwe.u.data.length = end - pos;
830                 *current_ev = iwe_stream_add_point(info, *current_ev,
831                                                    end_buf, &iwe, pos);
832         }
833 }
834
835 static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
836 {
837         unsigned long end = jiffies;
838
839         if (end >= start)
840                 return jiffies_to_msecs(end - start);
841
842         return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
843 }
844
845 static char *
846 ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
847               struct cfg80211_internal_bss *bss, char *current_ev,
848               char *end_buf)
849 {
850         struct iw_event iwe;
851         u8 *buf, *cfg, *p;
852         u8 *ie = bss->pub.information_elements;
853         int rem = bss->pub.len_information_elements, i, sig;
854         bool ismesh = false;
855
856         memset(&iwe, 0, sizeof(iwe));
857         iwe.cmd = SIOCGIWAP;
858         iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
859         memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
860         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
861                                           IW_EV_ADDR_LEN);
862
863         memset(&iwe, 0, sizeof(iwe));
864         iwe.cmd = SIOCGIWFREQ;
865         iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
866         iwe.u.freq.e = 0;
867         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
868                                           IW_EV_FREQ_LEN);
869
870         memset(&iwe, 0, sizeof(iwe));
871         iwe.cmd = SIOCGIWFREQ;
872         iwe.u.freq.m = bss->pub.channel->center_freq;
873         iwe.u.freq.e = 6;
874         current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
875                                           IW_EV_FREQ_LEN);
876
877         if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
878                 memset(&iwe, 0, sizeof(iwe));
879                 iwe.cmd = IWEVQUAL;
880                 iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
881                                      IW_QUAL_NOISE_INVALID |
882                                      IW_QUAL_QUAL_UPDATED;
883                 switch (wiphy->signal_type) {
884                 case CFG80211_SIGNAL_TYPE_MBM:
885                         sig = bss->pub.signal / 100;
886                         iwe.u.qual.level = sig;
887                         iwe.u.qual.updated |= IW_QUAL_DBM;
888                         if (sig < -110)         /* rather bad */
889                                 sig = -110;
890                         else if (sig > -40)     /* perfect */
891                                 sig = -40;
892                         /* will give a range of 0 .. 70 */
893                         iwe.u.qual.qual = sig + 110;
894                         break;
895                 case CFG80211_SIGNAL_TYPE_UNSPEC:
896                         iwe.u.qual.level = bss->pub.signal;
897                         /* will give range 0 .. 100 */
898                         iwe.u.qual.qual = bss->pub.signal;
899                         break;
900                 default:
901                         /* not reached */
902                         break;
903                 }
904                 current_ev = iwe_stream_add_event(info, current_ev, end_buf,
905                                                   &iwe, IW_EV_QUAL_LEN);
906         }
907
908         memset(&iwe, 0, sizeof(iwe));
909         iwe.cmd = SIOCGIWENCODE;
910         if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
911                 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
912         else
913                 iwe.u.data.flags = IW_ENCODE_DISABLED;
914         iwe.u.data.length = 0;
915         current_ev = iwe_stream_add_point(info, current_ev, end_buf,
916                                           &iwe, "");
917
918         while (rem >= 2) {
919                 /* invalid data */
920                 if (ie[1] > rem - 2)
921                         break;
922
923                 switch (ie[0]) {
924                 case WLAN_EID_SSID:
925                         memset(&iwe, 0, sizeof(iwe));
926                         iwe.cmd = SIOCGIWESSID;
927                         iwe.u.data.length = ie[1];
928                         iwe.u.data.flags = 1;
929                         current_ev = iwe_stream_add_point(info, current_ev, end_buf,
930                                                           &iwe, ie + 2);
931                         break;
932                 case WLAN_EID_MESH_ID:
933                         memset(&iwe, 0, sizeof(iwe));
934                         iwe.cmd = SIOCGIWESSID;
935                         iwe.u.data.length = ie[1];
936                         iwe.u.data.flags = 1;
937                         current_ev = iwe_stream_add_point(info, current_ev, end_buf,
938                                                           &iwe, ie + 2);
939                         break;
940                 case WLAN_EID_MESH_CONFIG:
941                         ismesh = true;
942                         if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
943                                 break;
944                         buf = kmalloc(50, GFP_ATOMIC);
945                         if (!buf)
946                                 break;
947                         cfg = ie + 2;
948                         memset(&iwe, 0, sizeof(iwe));
949                         iwe.cmd = IWEVCUSTOM;
950                         sprintf(buf, "Mesh Network Path Selection Protocol ID: "
951                                 "0x%02X", cfg[0]);
952                         iwe.u.data.length = strlen(buf);
953                         current_ev = iwe_stream_add_point(info, current_ev,
954                                                           end_buf,
955                                                           &iwe, buf);
956                         sprintf(buf, "Path Selection Metric ID: 0x%02X",
957                                 cfg[1]);
958                         iwe.u.data.length = strlen(buf);
959                         current_ev = iwe_stream_add_point(info, current_ev,
960                                                           end_buf,
961                                                           &iwe, buf);
962                         sprintf(buf, "Congestion Control Mode ID: 0x%02X",
963                                 cfg[2]);
964                         iwe.u.data.length = strlen(buf);
965                         current_ev = iwe_stream_add_point(info, current_ev,
966                                                           end_buf,
967                                                           &iwe, buf);
968                         sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
969                         iwe.u.data.length = strlen(buf);
970                         current_ev = iwe_stream_add_point(info, current_ev,
971                                                           end_buf,
972                                                           &iwe, buf);
973                         sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
974                         iwe.u.data.length = strlen(buf);
975                         current_ev = iwe_stream_add_point(info, current_ev,
976                                                           end_buf,
977                                                           &iwe, buf);
978                         sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
979                         iwe.u.data.length = strlen(buf);
980                         current_ev = iwe_stream_add_point(info, current_ev,
981                                                           end_buf,
982                                                           &iwe, buf);
983                         sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
984                         iwe.u.data.length = strlen(buf);
985                         current_ev = iwe_stream_add_point(info, current_ev,
986                                                           end_buf,
987                                                           &iwe, buf);
988                         kfree(buf);
989                         break;
990                 case WLAN_EID_SUPP_RATES:
991                 case WLAN_EID_EXT_SUPP_RATES:
992                         /* display all supported rates in readable format */
993                         p = current_ev + iwe_stream_lcp_len(info);
994
995                         memset(&iwe, 0, sizeof(iwe));
996                         iwe.cmd = SIOCGIWRATE;
997                         /* Those two flags are ignored... */
998                         iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
999
1000                         for (i = 0; i < ie[1]; i++) {
1001                                 iwe.u.bitrate.value =
1002                                         ((ie[i + 2] & 0x7f) * 500000);
1003                                 p = iwe_stream_add_value(info, current_ev, p,
1004                                                 end_buf, &iwe, IW_EV_PARAM_LEN);
1005                         }
1006                         current_ev = p;
1007                         break;
1008                 }
1009                 rem -= ie[1] + 2;
1010                 ie += ie[1] + 2;
1011         }
1012
1013         if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) ||
1014             ismesh) {
1015                 memset(&iwe, 0, sizeof(iwe));
1016                 iwe.cmd = SIOCGIWMODE;
1017                 if (ismesh)
1018                         iwe.u.mode = IW_MODE_MESH;
1019                 else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
1020                         iwe.u.mode = IW_MODE_MASTER;
1021                 else
1022                         iwe.u.mode = IW_MODE_ADHOC;
1023                 current_ev = iwe_stream_add_event(info, current_ev, end_buf,
1024                                                   &iwe, IW_EV_UINT_LEN);
1025         }
1026
1027         buf = kmalloc(30, GFP_ATOMIC);
1028         if (buf) {
1029                 memset(&iwe, 0, sizeof(iwe));
1030                 iwe.cmd = IWEVCUSTOM;
1031                 sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
1032                 iwe.u.data.length = strlen(buf);
1033                 current_ev = iwe_stream_add_point(info, current_ev, end_buf,
1034                                                   &iwe, buf);
1035                 memset(&iwe, 0, sizeof(iwe));
1036                 iwe.cmd = IWEVCUSTOM;
1037                 sprintf(buf, " Last beacon: %ums ago",
1038                         elapsed_jiffies_msecs(bss->ts));
1039                 iwe.u.data.length = strlen(buf);
1040                 current_ev = iwe_stream_add_point(info, current_ev,
1041                                                   end_buf, &iwe, buf);
1042                 kfree(buf);
1043         }
1044
1045         ieee80211_scan_add_ies(info, &bss->pub, &current_ev, end_buf);
1046
1047         return current_ev;
1048 }
1049
1050
1051 static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
1052                                   struct iw_request_info *info,
1053                                   char *buf, size_t len)
1054 {
1055         char *current_ev = buf;
1056         char *end_buf = buf + len;
1057         struct cfg80211_internal_bss *bss;
1058
1059         spin_lock_bh(&dev->bss_lock);
1060         cfg80211_bss_expire(dev);
1061
1062         list_for_each_entry(bss, &dev->bss_list, list) {
1063                 if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
1064                         spin_unlock_bh(&dev->bss_lock);
1065                         return -E2BIG;
1066                 }
1067                 current_ev = ieee80211_bss(&dev->wiphy, info, bss,
1068                                            current_ev, end_buf);
1069         }
1070         spin_unlock_bh(&dev->bss_lock);
1071         return current_ev - buf;
1072 }
1073
1074
1075 int cfg80211_wext_giwscan(struct net_device *dev,
1076                           struct iw_request_info *info,
1077                           struct iw_point *data, char *extra)
1078 {
1079         struct cfg80211_registered_device *rdev;
1080         int res;
1081
1082         if (!netif_running(dev))
1083                 return -ENETDOWN;
1084
1085         rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
1086
1087         if (IS_ERR(rdev))
1088                 return PTR_ERR(rdev);
1089
1090         if (rdev->scan_req) {
1091                 res = -EAGAIN;
1092                 goto out;
1093         }
1094
1095         res = ieee80211_scan_results(rdev, info, extra, data->length);
1096         data->length = 0;
1097         if (res >= 0) {
1098                 data->length = res;
1099                 res = 0;
1100         }
1101
1102  out:
1103         cfg80211_unlock_rdev(rdev);
1104         return res;
1105 }
1106 EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
1107 #endif