1
2
3
4
5
6
7#include <linux/types.h>
8#include <linux/kernel.h>
9#include <linux/etherdevice.h>
10#include <linux/if_arp.h>
11#include <asm/unaligned.h>
12#include <net/lib80211.h>
13
14#include "host.h"
15#include "decl.h"
16#include "dev.h"
17#include "scan.h"
18#include "cmd.h"
19
20
21#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
22 + IW_ESSID_MAX_SIZE \
23 + IW_EV_UINT_LEN \
24 + IW_EV_FREQ_LEN \
25 + IW_EV_QUAL_LEN \
26 + IW_ESSID_MAX_SIZE \
27 + IW_EV_PARAM_LEN \
28 + 40)
29
30
31#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \
32 + (MRVDRV_MAX_CHANNELS_PER_SCAN \
33 * sizeof(struct chanscanparamset)))
34
35
36#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set))
37
38
39#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
40 + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)
41
42
43#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
44
45
46
47
48
49
50
51#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
52
53
54#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
55
56
57#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
58
59#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
60
61static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
62 struct cmd_header *resp);
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
79{
80 int i;
81
82 for (i = 0; i < len; i++)
83 rates[i] &= 0x7f;
84}
85
86
87static inline void clear_bss_descriptor(struct bss_descriptor *bss)
88{
89
90 memset(bss, 0, offsetof(struct bss_descriptor, list));
91}
92
93
94
95
96
97
98
99
100
101int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,
102 uint8_t ssid2_len)
103{
104 if (ssid1_len != ssid2_len)
105 return -1;
106
107 return memcmp(ssid1, ssid2, ssid1_len);
108}
109
110static inline int is_same_network(struct bss_descriptor *src,
111 struct bss_descriptor *dst)
112{
113
114
115
116 return ((src->ssid_len == dst->ssid_len) &&
117 (src->channel == dst->channel) &&
118 !compare_ether_addr(src->bssid, dst->bssid) &&
119 !memcmp(src->ssid, dst->ssid, src->ssid_len));
120}
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145static int lbs_scan_create_channel_list(struct lbs_private *priv,
146 struct chanscanparamset *scanchanlist)
147{
148 struct region_channel *scanregion;
149 struct chan_freq_power *cfp;
150 int rgnidx;
151 int chanidx;
152 int nextchan;
153 uint8_t scantype;
154
155 chanidx = 0;
156
157
158
159
160
161 scantype = CMD_SCAN_TYPE_ACTIVE;
162
163 for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
164 if (priv->enable11d && (priv->connect_status != LBS_CONNECTED)
165 && (priv->mesh_connect_status != LBS_CONNECTED)) {
166
167 if (!priv->universal_channel[rgnidx].valid)
168 continue;
169 scanregion = &priv->universal_channel[rgnidx];
170
171
172 memset(&priv->parsed_region_chan, 0x00,
173 sizeof(priv->parsed_region_chan));
174 } else {
175 if (!priv->region_channel[rgnidx].valid)
176 continue;
177 scanregion = &priv->region_channel[rgnidx];
178 }
179
180 for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
181 struct chanscanparamset *chan = &scanchanlist[chanidx];
182
183 cfp = scanregion->CFP + nextchan;
184
185 if (priv->enable11d)
186 scantype = lbs_get_scan_type_11d(cfp->channel,
187 &priv->parsed_region_chan);
188
189 if (scanregion->band == BAND_B || scanregion->band == BAND_G)
190 chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;
191
192 if (scantype == CMD_SCAN_TYPE_PASSIVE) {
193 chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
194 chan->chanscanmode.passivescan = 1;
195 } else {
196 chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);
197 chan->chanscanmode.passivescan = 0;
198 }
199
200 chan->channumber = cfp->channel;
201 }
202 }
203 return chanidx;
204}
205
206
207
208
209
210
211
212
213static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
214{
215 struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
216
217 ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
218 ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
219 memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);
220 return sizeof(ssid_tlv->header) + priv->scan_ssid_len;
221}
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
249 struct chanscanparamset *chan_list,
250 int chan_count)
251{
252 size_t size = sizeof(struct chanscanparamset) *chan_count;
253 struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
254
255 chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
256 memcpy(chan_tlv->chanscanparam, chan_list, size);
257 chan_tlv->header.len = cpu_to_le16(size);
258 return sizeof(chan_tlv->header) + size;
259}
260
261
262
263
264
265
266
267
268
269
270
271static int lbs_scan_add_rates_tlv(uint8_t *tlv)
272{
273 int i;
274 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
275
276 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
277 tlv += sizeof(rate_tlv->header);
278 for (i = 0; i < MAX_RATES; i++) {
279 *tlv = lbs_bg_rates[i];
280 if (*tlv == 0)
281 break;
282
283
284
285
286 if (*tlv == 0x02 || *tlv == 0x04 ||
287 *tlv == 0x0b || *tlv == 0x16)
288 *tlv |= 0x80;
289 tlv++;
290 }
291 rate_tlv->header.len = cpu_to_le16(i);
292 return sizeof(rate_tlv->header) + i;
293}
294
295
296
297
298
299static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,
300 struct chanscanparamset *chan_list, int chan_count)
301{
302 int ret = -ENOMEM;
303 struct cmd_ds_802_11_scan *scan_cmd;
304 uint8_t *tlv;
305
306 lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",
307 bsstype, chan_list ? chan_list[0].channumber : -1,
308 chan_count);
309
310
311 scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
312 if (scan_cmd == NULL)
313 goto out;
314
315 tlv = scan_cmd->tlvbuffer;
316
317
318 scan_cmd->bsstype = bsstype;
319
320
321 if (priv->scan_ssid_len)
322 tlv += lbs_scan_add_ssid_tlv(priv, tlv);
323 if (chan_list && chan_count)
324 tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
325 tlv += lbs_scan_add_rates_tlv(tlv);
326
327
328 scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);
329 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,
330 sizeof(*scan_cmd));
331 lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
332 tlv - scan_cmd->tlvbuffer);
333
334 ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,
335 le16_to_cpu(scan_cmd->hdr.size),
336 lbs_ret_80211_scan, 0);
337
338out:
339 kfree(scan_cmd);
340 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
341 return ret;
342}
343
344
345
346
347
348
349
350
351
352
353
354
355
356int lbs_scan_networks(struct lbs_private *priv, int full_scan)
357{
358 int ret = -ENOMEM;
359 struct chanscanparamset *chan_list;
360 struct chanscanparamset *curr_chans;
361 int chan_count;
362 uint8_t bsstype = CMD_BSS_TYPE_ANY;
363 int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
364 union iwreq_data wrqu;
365#ifdef CONFIG_LIBERTAS_DEBUG
366 struct bss_descriptor *iter;
367 int i = 0;
368 DECLARE_SSID_BUF(ssid);
369#endif
370
371 lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
372
373
374
375
376 if (full_scan && delayed_work_pending(&priv->scan_work))
377 cancel_delayed_work(&priv->scan_work);
378
379
380
381
382
383
384
385
386
387
388 lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);
389
390
391 chan_list = kzalloc(sizeof(struct chanscanparamset) *
392 LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
393 if (!chan_list) {
394 lbs_pr_alert("SCAN: chan_list empty\n");
395 goto out;
396 }
397
398
399 chan_count = lbs_scan_create_channel_list(priv, chan_list);
400
401 netif_stop_queue(priv->dev);
402 netif_carrier_off(priv->dev);
403 if (priv->mesh_dev) {
404 netif_stop_queue(priv->mesh_dev);
405 netif_carrier_off(priv->mesh_dev);
406 }
407
408
409 lbs_deb_scan("chan_count %d, scan_channel %d\n",
410 chan_count, priv->scan_channel);
411 curr_chans = chan_list;
412
413 if (priv->scan_channel > 0) {
414 curr_chans += priv->scan_channel;
415 chan_count -= priv->scan_channel;
416 }
417
418
419
420
421
422
423 while (chan_count) {
424 int to_scan = min(numchannels, chan_count);
425 lbs_deb_scan("scanning %d of %d channels\n",
426 to_scan, chan_count);
427 ret = lbs_do_scan(priv, bsstype, curr_chans,
428 to_scan);
429 if (ret) {
430 lbs_pr_err("SCAN_CMD failed\n");
431 goto out2;
432 }
433 curr_chans += to_scan;
434 chan_count -= to_scan;
435
436
437 if (chan_count && !full_scan &&
438 !priv->surpriseremoved) {
439
440 if (priv->scan_channel < 0)
441 priv->scan_channel = to_scan;
442 else
443 priv->scan_channel += to_scan;
444 cancel_delayed_work(&priv->scan_work);
445 queue_delayed_work(priv->work_thread, &priv->scan_work,
446 msecs_to_jiffies(300));
447
448 goto out;
449 }
450
451 }
452 memset(&wrqu, 0, sizeof(union iwreq_data));
453 wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
454
455#ifdef CONFIG_LIBERTAS_DEBUG
456
457 mutex_lock(&priv->lock);
458 lbs_deb_scan("scan table:\n");
459 list_for_each_entry(iter, &priv->network_list, list)
460 lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",
461 i++, iter->bssid, iter->rssi,
462 print_ssid(ssid, iter->ssid, iter->ssid_len));
463 mutex_unlock(&priv->lock);
464#endif
465
466out2:
467 priv->scan_channel = 0;
468
469out:
470 if (priv->connect_status == LBS_CONNECTED) {
471 netif_carrier_on(priv->dev);
472 if (!priv->tx_pending_len)
473 netif_wake_queue(priv->dev);
474 }
475 if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
476 netif_carrier_on(priv->mesh_dev);
477 if (!priv->tx_pending_len)
478 netif_wake_queue(priv->mesh_dev);
479 }
480 kfree(chan_list);
481
482 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
483 return ret;
484}
485
486void lbs_scan_worker(struct work_struct *work)
487{
488 struct lbs_private *priv =
489 container_of(work, struct lbs_private, scan_work.work);
490
491 lbs_deb_enter(LBS_DEB_SCAN);
492 lbs_scan_networks(priv, 0);
493 lbs_deb_leave(LBS_DEB_SCAN);
494}
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514static int lbs_process_bss(struct bss_descriptor *bss,
515 uint8_t **pbeaconinfo, int *bytesleft)
516{
517 struct ieee_ie_fh_param_set *fh;
518 struct ieee_ie_ds_param_set *ds;
519 struct ieee_ie_cf_param_set *cf;
520 struct ieee_ie_ibss_param_set *ibss;
521 DECLARE_SSID_BUF(ssid);
522 struct ieee_ie_country_info_set *pcountryinfo;
523 uint8_t *pos, *end, *p;
524 uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
525 uint16_t beaconsize = 0;
526 int ret;
527
528 lbs_deb_enter(LBS_DEB_SCAN);
529
530 if (*bytesleft >= sizeof(beaconsize)) {
531
532 beaconsize = get_unaligned_le16(*pbeaconinfo);
533 *bytesleft -= sizeof(beaconsize);
534 *pbeaconinfo += sizeof(beaconsize);
535 }
536
537 if (beaconsize == 0 || beaconsize > *bytesleft) {
538 *pbeaconinfo += *bytesleft;
539 *bytesleft = 0;
540 ret = -1;
541 goto done;
542 }
543
544
545 pos = *pbeaconinfo;
546 end = pos + beaconsize;
547
548
549 *pbeaconinfo += beaconsize;
550 *bytesleft -= beaconsize;
551
552 memcpy(bss->bssid, pos, ETH_ALEN);
553 lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);
554 pos += ETH_ALEN;
555
556 if ((end - pos) < 12) {
557 lbs_deb_scan("process_bss: Not enough bytes left\n");
558 ret = -1;
559 goto done;
560 }
561
562
563
564
565
566
567
568 bss->rssi = *pos;
569 lbs_deb_scan("process_bss: RSSI %d\n", *pos);
570 pos++;
571
572
573 pos += 8;
574
575
576 bss->beaconperiod = get_unaligned_le16(pos);
577 pos += 2;
578
579
580 bss->capability = get_unaligned_le16(pos);
581 lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
582 pos += 2;
583
584 if (bss->capability & WLAN_CAPABILITY_PRIVACY)
585 lbs_deb_scan("process_bss: WEP enabled\n");
586 if (bss->capability & WLAN_CAPABILITY_IBSS)
587 bss->mode = IW_MODE_ADHOC;
588 else
589 bss->mode = IW_MODE_INFRA;
590
591
592 lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
593 lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
594
595
596 while (pos <= end - 2) {
597 if (pos + pos[1] > end) {
598 lbs_deb_scan("process_bss: error in processing IE, "
599 "bytes left < IE length\n");
600 break;
601 }
602
603 switch (pos[0]) {
604 case WLAN_EID_SSID:
605 bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
606 memcpy(bss->ssid, pos + 2, bss->ssid_len);
607 lbs_deb_scan("got SSID IE: '%s', len %u\n",
608 print_ssid(ssid, bss->ssid, bss->ssid_len),
609 bss->ssid_len);
610 break;
611
612 case WLAN_EID_SUPP_RATES:
613 n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
614 memcpy(bss->rates, pos + 2, n_basic_rates);
615 got_basic_rates = 1;
616 lbs_deb_scan("got RATES IE\n");
617 break;
618
619 case WLAN_EID_FH_PARAMS:
620 fh = (struct ieee_ie_fh_param_set *) pos;
621 memcpy(&bss->phy.fh, fh, sizeof(*fh));
622 lbs_deb_scan("got FH IE\n");
623 break;
624
625 case WLAN_EID_DS_PARAMS:
626 ds = (struct ieee_ie_ds_param_set *) pos;
627 bss->channel = ds->channel;
628 memcpy(&bss->phy.ds, ds, sizeof(*ds));
629 lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
630 break;
631
632 case WLAN_EID_CF_PARAMS:
633 cf = (struct ieee_ie_cf_param_set *) pos;
634 memcpy(&bss->ss.cf, cf, sizeof(*cf));
635 lbs_deb_scan("got CF IE\n");
636 break;
637
638 case WLAN_EID_IBSS_PARAMS:
639 ibss = (struct ieee_ie_ibss_param_set *) pos;
640 bss->atimwindow = ibss->atimwindow;
641 memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
642 lbs_deb_scan("got IBSS IE\n");
643 break;
644
645 case WLAN_EID_COUNTRY:
646 pcountryinfo = (struct ieee_ie_country_info_set *) pos;
647 lbs_deb_scan("got COUNTRY IE\n");
648 if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
649 || pcountryinfo->header.len > 254) {
650 lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
651 __func__,
652 pcountryinfo->header.len,
653 sizeof(pcountryinfo->countrycode));
654 ret = -1;
655 goto done;
656 }
657
658 memcpy(&bss->countryinfo, pcountryinfo,
659 pcountryinfo->header.len + 2);
660 lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
661 (uint8_t *) pcountryinfo,
662 (int) (pcountryinfo->header.len + 2));
663 break;
664
665 case WLAN_EID_EXT_SUPP_RATES:
666
667
668
669
670 lbs_deb_scan("got RATESEX IE\n");
671 if (!got_basic_rates) {
672 lbs_deb_scan("... but ignoring it\n");
673 break;
674 }
675
676 n_ex_rates = pos[1];
677 if (n_basic_rates + n_ex_rates > MAX_RATES)
678 n_ex_rates = MAX_RATES - n_basic_rates;
679
680 p = bss->rates + n_basic_rates;
681 memcpy(p, pos + 2, n_ex_rates);
682 break;
683
684 case WLAN_EID_GENERIC:
685 if (pos[1] >= 4 &&
686 pos[2] == 0x00 && pos[3] == 0x50 &&
687 pos[4] == 0xf2 && pos[5] == 0x01) {
688 bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
689 memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
690 lbs_deb_scan("got WPA IE\n");
691 lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
692 bss->wpa_ie_len);
693 } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
694 pos[2] == 0x00 && pos[3] == 0x50 &&
695 pos[4] == 0x43 && pos[5] == 0x04) {
696 lbs_deb_scan("got mesh IE\n");
697 bss->mesh = 1;
698 } else {
699 lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
700 pos[2], pos[3],
701 pos[4], pos[5],
702 pos[1]);
703 }
704 break;
705
706 case WLAN_EID_RSN:
707 lbs_deb_scan("got RSN IE\n");
708 bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
709 memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
710 lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
711 bss->rsn_ie, bss->rsn_ie_len);
712 break;
713
714 default:
715 lbs_deb_scan("got IE 0x%04x, len %d\n",
716 pos[0], pos[1]);
717 break;
718 }
719
720 pos += pos[1] + 2;
721 }
722
723
724 bss->last_scanned = jiffies;
725 lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
726
727 ret = 0;
728
729done:
730 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
731 return ret;
732}
733
734
735
736
737
738
739
740
741
742
743
744
745int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,
746 uint8_t ssid_len)
747{
748 DECLARE_SSID_BUF(ssid_buf);
749 int ret = 0;
750
751 lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",
752 print_ssid(ssid_buf, ssid, ssid_len));
753
754 if (!ssid_len)
755 goto out;
756
757 memcpy(priv->scan_ssid, ssid, ssid_len);
758 priv->scan_ssid_len = ssid_len;
759
760 lbs_scan_networks(priv, 1);
761 if (priv->surpriseremoved) {
762 ret = -1;
763 goto out;
764 }
765
766out:
767 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
768 return ret;
769}
770
771
772
773
774
775
776
777
778
779
780
781#define MAX_CUSTOM_LEN 64
782
783static inline char *lbs_translate_scan(struct lbs_private *priv,
784 struct iw_request_info *info,
785 char *start, char *stop,
786 struct bss_descriptor *bss)
787{
788 struct chan_freq_power *cfp;
789 char *current_val;
790 struct iw_event iwe;
791 int j;
792#define PERFECT_RSSI ((uint8_t)50)
793#define WORST_RSSI ((uint8_t)0)
794#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI))
795 uint8_t rssi;
796
797 lbs_deb_enter(LBS_DEB_SCAN);
798
799 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
800 if (!cfp) {
801 lbs_deb_scan("Invalid channel number %d\n", bss->channel);
802 start = NULL;
803 goto out;
804 }
805
806
807 iwe.cmd = SIOCGIWAP;
808 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
809 memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
810 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
811
812
813 iwe.cmd = SIOCGIWESSID;
814 iwe.u.data.flags = 1;
815 iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE);
816 start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
817
818
819 iwe.cmd = SIOCGIWMODE;
820 iwe.u.mode = bss->mode;
821 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
822
823
824 iwe.cmd = SIOCGIWFREQ;
825 iwe.u.freq.m = (long)cfp->freq * 100000;
826 iwe.u.freq.e = 1;
827 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
828
829
830 iwe.cmd = IWEVQUAL;
831 iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
832 iwe.u.qual.level = SCAN_RSSI(bss->rssi);
833
834 rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
835 iwe.u.qual.qual =
836 (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
837 (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
838 (RSSI_DIFF * RSSI_DIFF);
839 if (iwe.u.qual.qual > 100)
840 iwe.u.qual.qual = 100;
841
842 if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
843 iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
844 } else {
845 iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
846 }
847
848
849
850
851
852 if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate
853 && !lbs_ssid_cmp(priv->curbssparams.ssid,
854 priv->curbssparams.ssid_len,
855 bss->ssid, bss->ssid_len)) {
856 int snr, nf;
857 snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
858 nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
859 iwe.u.qual.level = CAL_RSSI(snr, nf);
860 }
861 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
862
863
864 iwe.cmd = SIOCGIWENCODE;
865 if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
866 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
867 } else {
868 iwe.u.data.flags = IW_ENCODE_DISABLED;
869 }
870 iwe.u.data.length = 0;
871 start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
872
873 current_val = start + iwe_stream_lcp_len(info);
874
875 iwe.cmd = SIOCGIWRATE;
876 iwe.u.bitrate.fixed = 0;
877 iwe.u.bitrate.disabled = 0;
878 iwe.u.bitrate.value = 0;
879
880 for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
881
882 iwe.u.bitrate.value = bss->rates[j] * 500000;
883 current_val = iwe_stream_add_value(info, start, current_val,
884 stop, &iwe, IW_EV_PARAM_LEN);
885 }
886 if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
887 && !lbs_ssid_cmp(priv->curbssparams.ssid,
888 priv->curbssparams.ssid_len,
889 bss->ssid, bss->ssid_len)) {
890 iwe.u.bitrate.value = 22 * 500000;
891 current_val = iwe_stream_add_value(info, start, current_val,
892 stop, &iwe, IW_EV_PARAM_LEN);
893 }
894
895 if ((current_val - start) > iwe_stream_lcp_len(info))
896 start = current_val;
897
898 memset(&iwe, 0, sizeof(iwe));
899 if (bss->wpa_ie_len) {
900 char buf[MAX_WPA_IE_LEN];
901 memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);
902 iwe.cmd = IWEVGENIE;
903 iwe.u.data.length = bss->wpa_ie_len;
904 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
905 }
906
907 memset(&iwe, 0, sizeof(iwe));
908 if (bss->rsn_ie_len) {
909 char buf[MAX_WPA_IE_LEN];
910 memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);
911 iwe.cmd = IWEVGENIE;
912 iwe.u.data.length = bss->rsn_ie_len;
913 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
914 }
915
916 if (bss->mesh) {
917 char custom[MAX_CUSTOM_LEN];
918 char *p = custom;
919
920 iwe.cmd = IWEVCUSTOM;
921 p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");
922 iwe.u.data.length = p - custom;
923 if (iwe.u.data.length)
924 start = iwe_stream_add_point(info, start, stop,
925 &iwe, custom);
926 }
927
928out:
929 lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
930 return start;
931}
932
933
934
935
936
937
938
939
940
941
942
943
944int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
945 union iwreq_data *wrqu, char *extra)
946{
947 DECLARE_SSID_BUF(ssid);
948 struct lbs_private *priv = dev->ml_priv;
949 int ret = 0;
950
951 lbs_deb_enter(LBS_DEB_WEXT);
952
953 if (!priv->radio_on) {
954 ret = -EINVAL;
955 goto out;
956 }
957
958 if (!netif_running(dev)) {
959 ret = -ENETDOWN;
960 goto out;
961 }
962
963
964
965
966
967
968
969
970
971 if (wrqu->data.length == sizeof(struct iw_scan_req) &&
972 wrqu->data.flags & IW_SCAN_THIS_ESSID) {
973 struct iw_scan_req *req = (struct iw_scan_req *)extra;
974 priv->scan_ssid_len = req->essid_len;
975 memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);
976 lbs_deb_wext("set_scan, essid '%s'\n",
977 print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));
978 } else {
979 priv->scan_ssid_len = 0;
980 }
981
982 if (!delayed_work_pending(&priv->scan_work))
983 queue_delayed_work(priv->work_thread, &priv->scan_work,
984 msecs_to_jiffies(50));
985
986 priv->scan_channel = -1;
987
988 if (priv->surpriseremoved)
989 ret = -EIO;
990
991out:
992 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
993 return ret;
994}
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
1008 struct iw_point *dwrq, char *extra)
1009{
1010#define SCAN_ITEM_SIZE 128
1011 struct lbs_private *priv = dev->ml_priv;
1012 int err = 0;
1013 char *ev = extra;
1014 char *stop = ev + dwrq->length;
1015 struct bss_descriptor *iter_bss;
1016 struct bss_descriptor *safe;
1017
1018 lbs_deb_enter(LBS_DEB_WEXT);
1019
1020
1021 if (priv->scan_channel)
1022 return -EAGAIN;
1023
1024
1025 if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate)
1026 lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
1027 CMD_OPTION_WAITFORRSP, 0, NULL);
1028
1029 mutex_lock(&priv->lock);
1030 list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
1031 char *next_ev;
1032 unsigned long stale_time;
1033
1034 if (stop - ev < SCAN_ITEM_SIZE) {
1035 err = -E2BIG;
1036 break;
1037 }
1038
1039
1040 if (dev == priv->mesh_dev && !iter_bss->mesh)
1041 continue;
1042
1043
1044 stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
1045 if (time_after(jiffies, stale_time)) {
1046 list_move_tail(&iter_bss->list, &priv->network_free_list);
1047 clear_bss_descriptor(iter_bss);
1048 continue;
1049 }
1050
1051
1052 next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);
1053 if (next_ev == NULL)
1054 continue;
1055 ev = next_ev;
1056 }
1057 mutex_unlock(&priv->lock);
1058
1059 dwrq->length = (ev - extra);
1060 dwrq->flags = 0;
1061
1062 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
1063 return err;
1064}
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
1103 struct cmd_header *resp)
1104{
1105 struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
1106 struct bss_descriptor *iter_bss;
1107 struct bss_descriptor *safe;
1108 uint8_t *bssinfo;
1109 uint16_t scanrespsize;
1110 int bytesleft;
1111 int idx;
1112 int tlvbufsize;
1113 int ret;
1114
1115 lbs_deb_enter(LBS_DEB_SCAN);
1116
1117
1118 list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
1119 unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
1120 if (time_before(jiffies, stale_time))
1121 continue;
1122 list_move_tail (&iter_bss->list, &priv->network_free_list);
1123 clear_bss_descriptor(iter_bss);
1124 }
1125
1126 if (scanresp->nr_sets > MAX_NETWORK_COUNT) {
1127 lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",
1128 scanresp->nr_sets, MAX_NETWORK_COUNT);
1129 ret = -1;
1130 goto done;
1131 }
1132
1133 bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
1134 lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
1135
1136 scanrespsize = le16_to_cpu(resp->size);
1137 lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);
1138
1139 bssinfo = scanresp->bssdesc_and_tlvbuffer;
1140
1141
1142
1143
1144
1145
1146 tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)
1147 + sizeof(scanresp->nr_sets)
1148 + S_DS_GEN);
1149
1150
1151
1152
1153
1154
1155
1156 for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {
1157 struct bss_descriptor new;
1158 struct bss_descriptor *found = NULL;
1159 struct bss_descriptor *oldest = NULL;
1160
1161
1162 memset(&new, 0, sizeof (struct bss_descriptor));
1163 if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {
1164
1165 lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
1166 continue;
1167 }
1168
1169
1170 list_for_each_entry (iter_bss, &priv->network_list, list) {
1171 if (is_same_network(iter_bss, &new)) {
1172 found = iter_bss;
1173 break;
1174 }
1175
1176 if ((oldest == NULL) ||
1177 (iter_bss->last_scanned < oldest->last_scanned))
1178 oldest = iter_bss;
1179 }
1180
1181 if (found) {
1182
1183 clear_bss_descriptor(found);
1184 } else if (!list_empty(&priv->network_free_list)) {
1185
1186 found = list_entry(priv->network_free_list.next,
1187 struct bss_descriptor, list);
1188 list_move_tail(&found->list, &priv->network_list);
1189 } else if (oldest) {
1190
1191 found = oldest;
1192 clear_bss_descriptor(found);
1193 list_move_tail(&found->list, &priv->network_list);
1194 } else {
1195 continue;
1196 }
1197
1198 lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);
1199
1200
1201 memcpy(found, &new, offsetof(struct bss_descriptor, list));
1202 }
1203
1204 ret = 0;
1205
1206done:
1207 lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
1208 return ret;
1209}
1210