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