]> git.ipfire.org Git - thirdparty/iw.git/blob - scan.c
iw: add randomise option for sched_scan
[thirdparty/iw.git] / scan.c
1 #include <net/if.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <stdbool.h>
6
7 #include <netlink/genl/genl.h>
8 #include <netlink/genl/family.h>
9 #include <netlink/genl/ctrl.h>
10 #include <netlink/msg.h>
11 #include <netlink/attr.h>
12
13 #include "nl80211.h"
14 #include "iw.h"
15
16 #define WLAN_CAPABILITY_ESS (1<<0)
17 #define WLAN_CAPABILITY_IBSS (1<<1)
18 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
19 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
20 #define WLAN_CAPABILITY_PRIVACY (1<<4)
21 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
22 #define WLAN_CAPABILITY_PBCC (1<<6)
23 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
24 #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
25 #define WLAN_CAPABILITY_QOS (1<<9)
26 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
27 #define WLAN_CAPABILITY_APSD (1<<11)
28 #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
29 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
30 #define WLAN_CAPABILITY_DEL_BACK (1<<14)
31 #define WLAN_CAPABILITY_IMM_BACK (1<<15)
32 /* DMG (60gHz) 802.11ad */
33 /* type - bits 0..1 */
34 #define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
35
36 #define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
37 #define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
38 #define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
39
40 #define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
41 #define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
42 #define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
43 #define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
44
45 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
46 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
47
48 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
49 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
50 static unsigned char wfa_oui[3] = { 0x50, 0x6f, 0x9a };
51
52 struct scan_params {
53 bool unknown;
54 enum print_ie_type type;
55 bool show_both_ie_sets;
56 };
57
58 #define IEEE80211_COUNTRY_EXTENSION_ID 201
59
60 union ieee80211_country_ie_triplet {
61 struct {
62 __u8 first_channel;
63 __u8 num_channels;
64 __s8 max_power;
65 } __attribute__ ((packed)) chans;
66 struct {
67 __u8 reg_extension_id;
68 __u8 reg_class;
69 __u8 coverage_class;
70 } __attribute__ ((packed)) ext;
71 } __attribute__ ((packed));
72
73 static int parse_random_mac_addr(struct nl_msg *msg, char *arg)
74 {
75 char *a_addr, *a_mask, *sep;
76 unsigned char addr[ETH_ALEN], mask[ETH_ALEN];
77 char *addrs = arg + 9;
78
79 if (*addrs != '=')
80 return 0;
81
82 addrs++;
83 sep = strchr(addrs, '/');
84 a_addr = addrs;
85
86 if (!sep)
87 return 1;
88
89 *sep = 0;
90 a_mask = sep + 1;
91 if (mac_addr_a2n(addr, a_addr) || mac_addr_a2n(mask, a_mask))
92 return 1;
93
94 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
95 NLA_PUT(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN, mask);
96
97 return 0;
98 nla_put_failure:
99 return -ENOBUFS;
100 }
101
102 int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
103 {
104 struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL;
105 struct nlattr *match = NULL;
106 enum {
107 ND_TOPLEVEL,
108 ND_MATCH,
109 ND_FREQS,
110 ND_ACTIVE,
111 } parse_state = ND_TOPLEVEL;
112 int c = *argc;
113 char *end, **v = *argv;
114 int err = 0, i = 0;
115 unsigned int freq, interval = 0, delay = 0;
116 bool have_matchset = false, have_freqs = false, have_ssids = false;
117 bool have_active = false, have_passive = false;
118 uint32_t flags = 0;
119
120 matchset = nlmsg_alloc();
121 if (!matchset) {
122 err = -ENOBUFS;
123 goto out;
124 }
125
126 freqs = nlmsg_alloc();
127 if (!freqs) {
128 err = -ENOBUFS;
129 goto out;
130 }
131
132 ssids = nlmsg_alloc();
133 if (!ssids) {
134 err = -ENOMEM;
135 goto out;
136 }
137
138 while (c) {
139 switch (parse_state) {
140 case ND_TOPLEVEL:
141 if (!strcmp(v[0], "interval")) {
142 c--; v++;
143 if (c == 0) {
144 err = -EINVAL;
145 goto nla_put_failure;
146 }
147
148 if (interval) {
149 err = -EINVAL;
150 goto nla_put_failure;
151 }
152 interval = strtoul(v[0], &end, 10);
153 if (*end || !interval) {
154 err = -EINVAL;
155 goto nla_put_failure;
156 }
157 NLA_PUT_U32(msg,
158 NL80211_ATTR_SCHED_SCAN_INTERVAL,
159 interval);
160 } else if (!strcmp(v[0], "delay")) {
161 c--; v++;
162 if (c == 0) {
163 err = -EINVAL;
164 goto nla_put_failure;
165 }
166
167 if (delay) {
168 err = -EINVAL;
169 goto nla_put_failure;
170 }
171 delay = strtoul(v[0], &end, 10);
172 if (*end) {
173 err = -EINVAL;
174 goto nla_put_failure;
175 }
176 NLA_PUT_U32(msg,
177 NL80211_ATTR_SCHED_SCAN_DELAY,
178 delay);
179 } else if (!strcmp(v[0], "matches")) {
180 parse_state = ND_MATCH;
181 if (have_matchset) {
182 err = -EINVAL;
183 goto nla_put_failure;
184 }
185
186 i = 0;
187 } else if (!strcmp(v[0], "freqs")) {
188 parse_state = ND_FREQS;
189 if (have_freqs) {
190 err = -EINVAL;
191 goto nla_put_failure;
192 }
193
194 have_freqs = true;
195 i = 0;
196 } else if (!strcmp(v[0], "active")) {
197 parse_state = ND_ACTIVE;
198 if (have_active || have_passive) {
199 err = -EINVAL;
200 goto nla_put_failure;
201 }
202
203 have_active = true;
204 i = 0;
205 } else if (!strcmp(v[0], "passive")) {
206 if (have_active || have_passive) {
207 err = -EINVAL;
208 goto nla_put_failure;
209 }
210
211 have_passive = true;
212 } else if (!strncmp(v[0], "randomise", 9) ||
213 !strncmp(v[0], "randomize", 9)) {
214 flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
215 if (c > 0) {
216 err = parse_random_mac_addr(msg, v[0]);
217 if (err)
218 goto nla_put_failure;
219 }
220 } else {
221 /* this element is not for us, so
222 * return to continue parsing.
223 */
224 goto nla_put_failure;
225 }
226 c--; v++;
227
228 break;
229 case ND_MATCH:
230 if (!strcmp(v[0], "ssid")) {
231 c--; v++;
232 if (c == 0) {
233 err = -EINVAL;
234 goto nla_put_failure;
235 }
236
237 /* TODO: for now we can only have an
238 * SSID in the match, so we can start
239 * the match nest here.
240 */
241 match = nla_nest_start(matchset, i);
242 if (!match) {
243 err = -ENOBUFS;
244 goto nla_put_failure;
245 }
246
247 NLA_PUT(matchset,
248 NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
249 strlen(v[0]), v[0]);
250 nla_nest_end(matchset, match);
251 match = NULL;
252
253 have_matchset = true;
254 i++;
255 c--; v++;
256 } else {
257 /* other element that cannot be part
258 * of a match indicates the end of the
259 * match. */
260 /* need at least one match in the matchset */
261 if (i == 0) {
262 err = -EINVAL;
263 goto nla_put_failure;
264 }
265
266 parse_state = ND_TOPLEVEL;
267 }
268
269 break;
270 case ND_FREQS:
271 freq = strtoul(v[0], &end, 10);
272 if (*end) {
273 if (i == 0) {
274 err = -EINVAL;
275 goto nla_put_failure;
276 }
277
278 parse_state = ND_TOPLEVEL;
279 } else {
280 NLA_PUT_U32(freqs, i, freq);
281 i++;
282 c--; v++;
283 }
284 break;
285 case ND_ACTIVE:
286 if (!strcmp(v[0], "ssid")) {
287 c--; v++;
288 if (c == 0) {
289 err = -EINVAL;
290 goto nla_put_failure;
291 }
292
293 NLA_PUT(ssids,
294 NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
295 strlen(v[0]), v[0]);
296
297 have_ssids = true;
298 i++;
299 c--; v++;
300 } else {
301 /* other element that cannot be part
302 * of a match indicates the end of the
303 * active set. */
304 /* need at least one item in the set */
305 if (i == 0) {
306 err = -EINVAL;
307 goto nla_put_failure;
308 }
309
310 parse_state = ND_TOPLEVEL;
311 }
312 break;
313 }
314 }
315
316 if (!have_ssids)
317 NLA_PUT(ssids, 1, 0, "");
318 if (!have_passive)
319 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
320 if (have_freqs)
321 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
322 if (have_matchset)
323 nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, matchset);
324 if (flags)
325 NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
326
327 nla_put_failure:
328 if (match)
329 nla_nest_end(msg, match);
330 nlmsg_free(freqs);
331 nlmsg_free(matchset);
332
333 out:
334 *argc = c;
335 *argv = v;
336 return err;
337 }
338
339 static int handle_scan(struct nl80211_state *state,
340 struct nl_cb *cb,
341 struct nl_msg *msg,
342 int argc, char **argv,
343 enum id_input id)
344 {
345 struct nl_msg *ssids = NULL, *freqs = NULL;
346 char *eptr;
347 int err = -ENOBUFS;
348 int i;
349 enum {
350 NONE,
351 FREQ,
352 IES,
353 SSID,
354 MESHID,
355 DONE,
356 } parse = NONE;
357 int freq;
358 bool passive = false, have_ssids = false, have_freqs = false;
359 size_t ies_len = 0, meshid_len = 0;
360 unsigned char *ies = NULL, *meshid = NULL, *tmpies;
361 unsigned int flags = 0;
362
363 ssids = nlmsg_alloc();
364 if (!ssids)
365 return -ENOMEM;
366
367 freqs = nlmsg_alloc();
368 if (!freqs) {
369 nlmsg_free(ssids);
370 return -ENOMEM;
371 }
372
373 for (i = 0; i < argc; i++) {
374 switch (parse) {
375 case NONE:
376 if (strcmp(argv[i], "freq") == 0) {
377 parse = FREQ;
378 have_freqs = true;
379 break;
380 } else if (strcmp(argv[i], "ies") == 0) {
381 parse = IES;
382 break;
383 } else if (strcmp(argv[i], "lowpri") == 0) {
384 flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
385 break;
386 } else if (strcmp(argv[i], "flush") == 0) {
387 flags |= NL80211_SCAN_FLAG_FLUSH;
388 break;
389 } else if (strcmp(argv[i], "ap-force") == 0) {
390 flags |= NL80211_SCAN_FLAG_AP;
391 break;
392 } else if (strncmp(argv[i], "randomise", 9) == 0 ||
393 strncmp(argv[i], "randomize", 9) == 0) {
394 flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
395 err = parse_random_mac_addr(msg, argv[i]);
396 if (err)
397 goto nla_put_failure;
398 break;
399 } else if (strcmp(argv[i], "ssid") == 0) {
400 parse = SSID;
401 have_ssids = true;
402 break;
403 } else if (strcmp(argv[i], "passive") == 0) {
404 parse = DONE;
405 passive = true;
406 break;
407 } else if (strcmp(argv[i], "meshid") == 0) {
408 parse = MESHID;
409 break;
410 }
411 case DONE:
412 return 1;
413 case FREQ:
414 freq = strtoul(argv[i], &eptr, 10);
415 if (eptr != argv[i] + strlen(argv[i])) {
416 /* failed to parse as number -- maybe a tag? */
417 i--;
418 parse = NONE;
419 continue;
420 }
421 NLA_PUT_U32(freqs, i, freq);
422 break;
423 case IES:
424 ies = parse_hex(argv[i], &ies_len);
425 if (!ies)
426 goto nla_put_failure;
427 parse = NONE;
428 break;
429 case SSID:
430 NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
431 break;
432 case MESHID:
433 meshid_len = strlen(argv[i]);
434 meshid = (unsigned char *) malloc(meshid_len + 2);
435 if (!meshid)
436 goto nla_put_failure;
437 meshid[0] = 114; /* mesh element id */
438 meshid[1] = meshid_len;
439 memcpy(&meshid[2], argv[i], meshid_len);
440 meshid_len += 2;
441 parse = NONE;
442 break;
443 }
444 }
445
446 if (ies || meshid) {
447 tmpies = (unsigned char *) malloc(ies_len + meshid_len);
448 if (!tmpies)
449 goto nla_put_failure;
450 if (ies) {
451 memcpy(tmpies, ies, ies_len);
452 free(ies);
453 }
454 if (meshid) {
455 memcpy(&tmpies[ies_len], meshid, meshid_len);
456 free(meshid);
457 }
458 NLA_PUT(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies);
459 free(tmpies);
460 }
461
462 if (!have_ssids)
463 NLA_PUT(ssids, 1, 0, "");
464 if (!passive)
465 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
466
467 if (have_freqs)
468 nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
469 if (flags)
470 NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
471
472 err = 0;
473 nla_put_failure:
474 nlmsg_free(ssids);
475 nlmsg_free(freqs);
476 return err;
477 }
478
479 static void tab_on_first(bool *first)
480 {
481 if (!*first)
482 printf("\t");
483 else
484 *first = false;
485 }
486
487 static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
488 {
489 printf(" ");
490 print_ssid_escaped(len, data);
491 printf("\n");
492 }
493
494 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
495 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
496
497 static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
498 {
499 int i;
500
501 printf(" ");
502
503 for (i = 0; i < len; i++) {
504 int r = data[i] & 0x7f;
505
506 if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
507 printf("VHT");
508 else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
509 printf("HT");
510 else
511 printf("%d.%d", r/2, 5*(r&1));
512
513 printf("%s ", data[i] & 0x80 ? "*" : "");
514 }
515 printf("\n");
516 }
517
518 static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data)
519 {
520 printf(" channel %d\n", data[0]);
521 }
522
523 static const char *country_env_str(char environment)
524 {
525 switch (environment) {
526 case 'I':
527 return "Indoor only";
528 case 'O':
529 return "Outdoor only";
530 case ' ':
531 return "Indoor/Outdoor";
532 default:
533 return "bogus";
534 }
535 }
536
537 static void print_country(const uint8_t type, uint8_t len, const uint8_t *data)
538 {
539 printf(" %.*s", 2, data);
540
541 printf("\tEnvironment: %s\n", country_env_str(data[2]));
542
543 data += 3;
544 len -= 3;
545
546 if (len < 3) {
547 printf("\t\tNo country IE triplets present\n");
548 return;
549 }
550
551 while (len >= 3) {
552 int end_channel;
553 union ieee80211_country_ie_triplet *triplet = (void *) data;
554
555 if (triplet->ext.reg_extension_id >= IEEE80211_COUNTRY_EXTENSION_ID) {
556 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
557 triplet->ext.reg_extension_id,
558 triplet->ext.reg_class,
559 triplet->ext.coverage_class,
560 triplet->ext.coverage_class * 450);
561
562 data += 3;
563 len -= 3;
564 continue;
565 }
566
567 /* 2 GHz */
568 if (triplet->chans.first_channel <= 14)
569 end_channel = triplet->chans.first_channel + (triplet->chans.num_channels - 1);
570 else
571 end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1));
572
573 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
574
575 data += 3;
576 len -= 3;
577 }
578
579 return;
580 }
581
582 static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t *data)
583 {
584 printf(" %d dB\n", data[0]);
585 }
586
587 static void print_tpcreport(const uint8_t type, uint8_t len, const uint8_t *data)
588 {
589 printf(" TX power: %d dBm\n", data[0]);
590 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
591 }
592
593 static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data)
594 {
595 if (data[0] == 0x00)
596 printf(" <no flags>");
597 if (data[0] & 0x01)
598 printf(" NonERP_Present");
599 if (data[0] & 0x02)
600 printf(" Use_Protection");
601 if (data[0] & 0x04)
602 printf(" Barker_Preamble_Mode");
603 printf("\n");
604 }
605
606 static void print_cipher(const uint8_t *data)
607 {
608 if (memcmp(data, ms_oui, 3) == 0) {
609 switch (data[3]) {
610 case 0:
611 printf("Use group cipher suite");
612 break;
613 case 1:
614 printf("WEP-40");
615 break;
616 case 2:
617 printf("TKIP");
618 break;
619 case 4:
620 printf("CCMP");
621 break;
622 case 5:
623 printf("WEP-104");
624 break;
625 default:
626 printf("%.02x-%.02x-%.02x:%d",
627 data[0], data[1] ,data[2], data[3]);
628 break;
629 }
630 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
631 switch (data[3]) {
632 case 0:
633 printf("Use group cipher suite");
634 break;
635 case 1:
636 printf("WEP-40");
637 break;
638 case 2:
639 printf("TKIP");
640 break;
641 case 4:
642 printf("CCMP");
643 break;
644 case 5:
645 printf("WEP-104");
646 break;
647 case 6:
648 printf("AES-128-CMAC");
649 break;
650 case 8:
651 printf("GCMP");
652 break;
653 default:
654 printf("%.02x-%.02x-%.02x:%d",
655 data[0], data[1] ,data[2], data[3]);
656 break;
657 }
658 } else
659 printf("%.02x-%.02x-%.02x:%d",
660 data[0], data[1] ,data[2], data[3]);
661 }
662
663 static void print_auth(const uint8_t *data)
664 {
665 if (memcmp(data, ms_oui, 3) == 0) {
666 switch (data[3]) {
667 case 1:
668 printf("IEEE 802.1X");
669 break;
670 case 2:
671 printf("PSK");
672 break;
673 default:
674 printf("%.02x-%.02x-%.02x:%d",
675 data[0], data[1] ,data[2], data[3]);
676 break;
677 }
678 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
679 switch (data[3]) {
680 case 1:
681 printf("IEEE 802.1X");
682 break;
683 case 2:
684 printf("PSK");
685 break;
686 case 3:
687 printf("FT/IEEE 802.1X");
688 break;
689 case 4:
690 printf("FT/PSK");
691 break;
692 case 5:
693 printf("IEEE 802.1X/SHA-256");
694 break;
695 case 6:
696 printf("PSK/SHA-256");
697 break;
698 case 7:
699 printf("TDLS/TPK");
700 break;
701 default:
702 printf("%.02x-%.02x-%.02x:%d",
703 data[0], data[1] ,data[2], data[3]);
704 break;
705 }
706 } else
707 printf("%.02x-%.02x-%.02x:%d",
708 data[0], data[1] ,data[2], data[3]);
709 }
710
711 static void print_rsn_ie(const char *defcipher, const char *defauth,
712 uint8_t len, const uint8_t *data)
713 {
714 bool first = true;
715 __u16 version, count, capa;
716 int i;
717
718 version = data[0] + (data[1] << 8);
719 tab_on_first(&first);
720 printf("\t * Version: %d\n", version);
721
722 data += 2;
723 len -= 2;
724
725 if (len < 4) {
726 tab_on_first(&first);
727 printf("\t * Group cipher: %s\n", defcipher);
728 printf("\t * Pairwise ciphers: %s\n", defcipher);
729 return;
730 }
731
732 tab_on_first(&first);
733 printf("\t * Group cipher: ");
734 print_cipher(data);
735 printf("\n");
736
737 data += 4;
738 len -= 4;
739
740 if (len < 2) {
741 tab_on_first(&first);
742 printf("\t * Pairwise ciphers: %s\n", defcipher);
743 return;
744 }
745
746 count = data[0] | (data[1] << 8);
747 if (2 + (count * 4) > len)
748 goto invalid;
749
750 tab_on_first(&first);
751 printf("\t * Pairwise ciphers:");
752 for (i = 0; i < count; i++) {
753 printf(" ");
754 print_cipher(data + 2 + (i * 4));
755 }
756 printf("\n");
757
758 data += 2 + (count * 4);
759 len -= 2 + (count * 4);
760
761 if (len < 2) {
762 tab_on_first(&first);
763 printf("\t * Authentication suites: %s\n", defauth);
764 return;
765 }
766
767 count = data[0] | (data[1] << 8);
768 if (2 + (count * 4) > len)
769 goto invalid;
770
771 tab_on_first(&first);
772 printf("\t * Authentication suites:");
773 for (i = 0; i < count; i++) {
774 printf(" ");
775 print_auth(data + 2 + (i * 4));
776 }
777 printf("\n");
778
779 data += 2 + (count * 4);
780 len -= 2 + (count * 4);
781
782 if (len >= 2) {
783 capa = data[0] | (data[1] << 8);
784 tab_on_first(&first);
785 printf("\t * Capabilities:");
786 if (capa & 0x0001)
787 printf(" PreAuth");
788 if (capa & 0x0002)
789 printf(" NoPairwise");
790 switch ((capa & 0x000c) >> 2) {
791 case 0:
792 printf(" 1-PTKSA-RC");
793 break;
794 case 1:
795 printf(" 2-PTKSA-RC");
796 break;
797 case 2:
798 printf(" 4-PTKSA-RC");
799 break;
800 case 3:
801 printf(" 16-PTKSA-RC");
802 break;
803 }
804 switch ((capa & 0x0030) >> 4) {
805 case 0:
806 printf(" 1-GTKSA-RC");
807 break;
808 case 1:
809 printf(" 2-GTKSA-RC");
810 break;
811 case 2:
812 printf(" 4-GTKSA-RC");
813 break;
814 case 3:
815 printf(" 16-GTKSA-RC");
816 break;
817 }
818 if (capa & 0x0040)
819 printf(" MFP-required");
820 if (capa & 0x0080)
821 printf(" MFP-capable");
822 if (capa & 0x0200)
823 printf(" Peerkey-enabled");
824 if (capa & 0x0400)
825 printf(" SPP-AMSDU-capable");
826 if (capa & 0x0800)
827 printf(" SPP-AMSDU-required");
828 printf(" (0x%.4x)\n", capa);
829 data += 2;
830 len -= 2;
831 }
832
833 if (len >= 2) {
834 int pmkid_count = data[0] | (data[1] << 8);
835
836 if (len >= 2 + 16 * pmkid_count) {
837 tab_on_first(&first);
838 printf("\t * %d PMKIDs\n", pmkid_count);
839 /* not printing PMKID values */
840 data += 2 + 16 * pmkid_count;
841 len -= 2 + 16 * pmkid_count;
842 } else
843 goto invalid;
844 }
845
846 if (len >= 4) {
847 tab_on_first(&first);
848 printf("\t * Group mgmt cipher suite: ");
849 print_cipher(data);
850 printf("\n");
851 data += 4;
852 len -= 4;
853 }
854
855 invalid:
856 if (len != 0) {
857 printf("\t\t * bogus tail data (%d):", len);
858 while (len) {
859 printf(" %.2x", *data);
860 data++;
861 len--;
862 }
863 printf("\n");
864 }
865 }
866
867 static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data)
868 {
869 print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
870 }
871
872 static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
873 {
874 printf("\n");
875 print_ht_capability(data[0] | (data[1] << 8));
876 print_ampdu_length(data[2] & 3);
877 print_ampdu_spacing((data[2] >> 2) & 7);
878 print_ht_mcs(data + 3);
879 }
880
881 static const char* ntype_11u(uint8_t t)
882 {
883 switch (t) {
884 case 0: return "Private";
885 case 1: return "Private with Guest";
886 case 2: return "Chargeable Public";
887 case 3: return "Free Public";
888 case 4: return "Personal Device";
889 case 5: return "Emergency Services Only";
890 case 14: return "Test or Experimental";
891 case 15: return "Wildcard";
892 default: return "Reserved";
893 }
894 }
895
896 static const char* vgroup_11u(uint8_t t)
897 {
898 switch (t) {
899 case 0: return "Unspecified";
900 case 1: return "Assembly";
901 case 2: return "Business";
902 case 3: return "Educational";
903 case 4: return "Factory and Industrial";
904 case 5: return "Institutional";
905 case 6: return "Mercantile";
906 case 7: return "Residential";
907 case 8: return "Storage";
908 case 9: return "Utility and Miscellaneous";
909 case 10: return "Vehicular";
910 case 11: return "Outdoor";
911 default: return "Reserved";
912 }
913 }
914
915 static void print_interworking(const uint8_t type, uint8_t len, const uint8_t *data)
916 {
917 /* See Section 7.3.2.92 in the 802.11u spec. */
918 printf("\n");
919 if (len >= 1) {
920 uint8_t ano = data[0];
921 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano));
922 printf("\t\t\tNetwork Type: %i (%s)\n",
923 (int)(ano & 0xf), ntype_11u(ano & 0xf));
924 if (ano & (1<<4))
925 printf("\t\t\tInternet\n");
926 if (ano & (1<<5))
927 printf("\t\t\tASRA\n");
928 if (ano & (1<<6))
929 printf("\t\t\tESR\n");
930 if (ano & (1<<7))
931 printf("\t\t\tUESA\n");
932 }
933 if ((len == 3) || (len == 9)) {
934 printf("\t\tVenue Group: %i (%s)\n",
935 (int)(data[1]), vgroup_11u(data[1]));
936 printf("\t\tVenue Type: %i\n", (int)(data[2]));
937 }
938 if (len == 9)
939 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
940 data[3], data[4], data[5], data[6], data[7], data[8]);
941 else if (len == 7)
942 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
943 data[1], data[2], data[3], data[4], data[5], data[6]);
944 }
945
946 static void print_11u_advert(const uint8_t type, uint8_t len, const uint8_t *data)
947 {
948 /* See Section 7.3.2.93 in the 802.11u spec. */
949 /* TODO: This code below does not decode private protocol IDs */
950 int idx = 0;
951 printf("\n");
952 while (idx < (len - 1)) {
953 uint8_t qri = data[idx];
954 uint8_t proto_id = data[idx + 1];
955 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri));
956 printf("\t\t\tQuery Response Length Limit: %i\n",
957 (qri & 0x7f));
958 if (qri & (1<<7))
959 printf("\t\t\tPAME-BI\n");
960 switch(proto_id) {
961 case 0:
962 printf("\t\t\tANQP\n"); break;
963 case 1:
964 printf("\t\t\tMIH Information Service\n"); break;
965 case 2:
966 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
967 case 3:
968 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
969 case 221:
970 printf("\t\t\tVendor Specific\n"); break;
971 default:
972 printf("\t\t\tReserved: %i\n", proto_id); break;
973 }
974 idx += 2;
975 }
976 }
977
978 static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data)
979 {
980 /* See Section 7.3.2.96 in the 802.11u spec. */
981 int idx = 0;
982 int ln0 = data[1] & 0xf;
983 int ln1 = ((data[1] & 0xf0) >> 4);
984 int ln2 = 0;
985 printf("\n");
986
987 if (ln1)
988 ln2 = len - 2 - ln0 - ln1;
989
990 printf("\t\tANQP OIs: %i\n", data[0]);
991
992 if (ln0 > 0) {
993 printf("\t\tOI 1: ");
994 if (2 + ln0 > len) {
995 printf("Invalid IE length.\n");
996 } else {
997 for (idx = 0; idx < ln0; idx++) {
998 printf("%02hx", data[2 + idx]);
999 }
1000 printf("\n");
1001 }
1002 }
1003
1004 if (ln1 > 0) {
1005 printf("\t\tOI 2: ");
1006 if (2 + ln0 + ln1 > len) {
1007 printf("Invalid IE length.\n");
1008 } else {
1009 for (idx = 0; idx < ln1; idx++) {
1010 printf("%02hx", data[2 + ln0 + idx]);
1011 }
1012 printf("\n");
1013 }
1014 }
1015
1016 if (ln2 > 0) {
1017 printf("\t\tOI 3: ");
1018 if (2 + ln0 + ln1 + ln2 > len) {
1019 printf("Invalid IE length.\n");
1020 } else {
1021 for (idx = 0; idx < ln2; idx++) {
1022 printf("%02hx", data[2 + ln0 + ln1 + idx]);
1023 }
1024 printf("\n");
1025 }
1026 }
1027 }
1028
1029 static const char *ht_secondary_offset[4] = {
1030 "no secondary",
1031 "above",
1032 "[reserved!]",
1033 "below",
1034 };
1035
1036 static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
1037 {
1038 static const char *protection[4] = {
1039 "no",
1040 "nonmember",
1041 "20 MHz",
1042 "non-HT mixed",
1043 };
1044 static const char *sta_chan_width[2] = {
1045 "20 MHz",
1046 "any",
1047 };
1048
1049 printf("\n");
1050 printf("\t\t * primary channel: %d\n", data[0]);
1051 printf("\t\t * secondary channel offset: %s\n",
1052 ht_secondary_offset[data[1] & 0x3]);
1053 printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
1054 printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
1055 printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
1056 printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
1057 printf("\t\t * OBSS non-GF present: %d\n", (data[2] & 0x10) >> 4);
1058 printf("\t\t * dual beacon: %d\n", (data[4] & 0x40) >> 6);
1059 printf("\t\t * dual CTS protection: %d\n", (data[4] & 0x80) >> 7);
1060 printf("\t\t * STBC beacon: %d\n", data[5] & 0x1);
1061 printf("\t\t * L-SIG TXOP Prot: %d\n", (data[5] & 0x2) >> 1);
1062 printf("\t\t * PCO active: %d\n", (data[5] & 0x4) >> 2);
1063 printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3);
1064 }
1065
1066 static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data)
1067 {
1068 int i, base, bit;
1069 bool first = true;
1070
1071
1072 for (i = 0; i < len; i++) {
1073 base = i * 8;
1074
1075 for (bit = 0; bit < 8; bit++) {
1076 if (!(data[i] & (1 << bit)))
1077 continue;
1078
1079 if (!first)
1080 printf(",");
1081 else
1082 first = false;
1083
1084 #define CAPA(bit, name) case bit: printf(" " name); break
1085
1086 switch (bit + base) {
1087 CAPA(0, "HT Information Exchange Supported");
1088 CAPA(1, "reserved (On-demand Beacon)");
1089 CAPA(2, "Extended Channel Switching");
1090 CAPA(3, "reserved (Wave Indication)");
1091 CAPA(4, "PSMP Capability");
1092 CAPA(5, "reserved (Service Interval Granularity)");
1093 CAPA(6, "S-PSMP Capability");
1094 CAPA(7, "Event");
1095 CAPA(8, "Diagnostics");
1096 CAPA(9, "Multicast Diagnostics");
1097 CAPA(10, "Location Tracking");
1098 CAPA(11, "FMS");
1099 CAPA(12, "Proxy ARP Service");
1100 CAPA(13, "Collocated Interference Reporting");
1101 CAPA(14, "Civic Location");
1102 CAPA(15, "Geospatial Location");
1103 CAPA(16, "TFS");
1104 CAPA(17, "WNM-Sleep Mode");
1105 CAPA(18, "TIM Broadcast");
1106 CAPA(19, "BSS Transition");
1107 CAPA(20, "QoS Traffic Capability");
1108 CAPA(21, "AC Station Count");
1109 CAPA(22, "Multiple BSSID");
1110 CAPA(23, "Timing Measurement");
1111 CAPA(24, "Channel Usage");
1112 CAPA(25, "SSID List");
1113 CAPA(26, "DMS");
1114 CAPA(27, "UTC TSF Offset");
1115 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1116 CAPA(29, "TDLS Peer PSM Support");
1117 CAPA(30, "TDLS channel switching");
1118 CAPA(31, "Interworking");
1119 CAPA(32, "QoS Map");
1120 CAPA(33, "EBR");
1121 CAPA(34, "SSPN Interface");
1122 CAPA(35, "Reserved");
1123 CAPA(36, "MSGCF Capability");
1124 CAPA(37, "TDLS Support");
1125 CAPA(38, "TDLS Prohibited");
1126 CAPA(39, "TDLS Channel Switching Prohibited");
1127 CAPA(40, "Reject Unadmitted Frame");
1128 CAPA(44, "Identifier Location");
1129 CAPA(45, "U-APSD Coexistence");
1130 CAPA(46, "WNM-Notification");
1131 CAPA(47, "Reserved");
1132 CAPA(48, "UTF-8 SSID");
1133 default:
1134 printf(" %d", bit);
1135 break;
1136 }
1137 #undef CAPA
1138 }
1139 }
1140
1141 printf("\n");
1142 }
1143
1144 static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data)
1145 {
1146 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1147 "Bitmap[0] 0x%x",
1148 data[0], data[1], data[2], data[3]);
1149 if (len - 4)
1150 printf(" (+ %u octet%s)", len - 4, len - 4 == 1 ? "" : "s");
1151 printf("\n");
1152 }
1153
1154 static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data)
1155 {
1156 printf(" %d TUs", (data[1] << 8) + data[0]);
1157 }
1158
1159 static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
1160 {
1161 printf("\n");
1162 print_vht_info(data[0] | (data[1] << 8) |
1163 (data[2] << 16) | (data[3] << 24),
1164 data + 4);
1165 }
1166
1167 static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data)
1168 {
1169 const char *chandwidths[] = {
1170 [0] = "20 or 40 MHz",
1171 [1] = "80 MHz",
1172 [3] = "80+80 MHz",
1173 [2] = "160 MHz",
1174 };
1175
1176 printf("\n");
1177 printf("\t\t * channel width: %d (%s)\n", data[0],
1178 data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
1179 printf("\t\t * center freq segment 1: %d\n", data[1]);
1180 printf("\t\t * center freq segment 2: %d\n", data[2]);
1181 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
1182 }
1183
1184 static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data)
1185 {
1186 printf("\n");
1187 printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
1188 printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
1189 printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
1190 printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
1191 printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
1192 printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
1193 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1194 ((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
1195 }
1196
1197 static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data)
1198 {
1199 if (data[0] < ARRAY_SIZE(ht_secondary_offset))
1200 printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
1201 else
1202 printf(" %d\n", data[0]);
1203 }
1204
1205 static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data)
1206 {
1207 printf("\n");
1208 printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
1209 printf("\t\t * channel utilisation: %d/255\n", data[2]);
1210 printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
1211 }
1212
1213 static void print_mesh_conf(const uint8_t type, uint8_t len, const uint8_t *data)
1214 {
1215 printf("\n");
1216 printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
1217 printf("\t\t * Active Path Selection Metric ID: %d\n", data[1]);
1218 printf("\t\t * Congestion Control Mode ID: %d\n", data[2]);
1219 printf("\t\t * Synchronization Method ID: %d\n", data[3]);
1220 printf("\t\t * Authentication Protocol ID: %d\n", data[4]);
1221 printf("\t\t * Mesh Formation Info:\n");
1222 printf("\t\t\t Number of Peerings: %d\n", (data[5] & 0x7E) >> 1);
1223 if (data[5] & 0x01)
1224 printf("\t\t\t Connected to Mesh Gate\n");
1225 if (data[5] & 0x80)
1226 printf("\t\t\t Connected to AS\n");
1227 printf("\t\t * Mesh Capability\n");
1228 if (data[6] & 0x01)
1229 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1230 if (data[6] & 0x02)
1231 printf("\t\t\t MCCA Supported\n");
1232 if (data[6] & 0x04)
1233 printf("\t\t\t MCCA Enabled\n");
1234 if (data[6] & 0x08)
1235 printf("\t\t\t Forwarding\n");
1236 if (data[6] & 0x10)
1237 printf("\t\t\t MBCA Supported\n");
1238 if (data[6] & 0x20)
1239 printf("\t\t\t TBTT Adjusting\n");
1240 if (data[6] & 0x40)
1241 printf("\t\t\t Mesh Power Save Level\n");
1242 }
1243
1244 struct ie_print {
1245 const char *name;
1246 void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
1247 uint8_t minlen, maxlen;
1248 uint8_t flags;
1249 };
1250
1251 static void print_ie(const struct ie_print *p, const uint8_t type,
1252 uint8_t len, const uint8_t *data)
1253 {
1254 int i;
1255
1256 if (!p->print)
1257 return;
1258
1259 printf("\t%s:", p->name);
1260 if (len < p->minlen || len > p->maxlen) {
1261 if (len > 1) {
1262 printf(" <invalid: %d bytes:", len);
1263 for (i = 0; i < len; i++)
1264 printf(" %.02x", data[i]);
1265 printf(">\n");
1266 } else if (len)
1267 printf(" <invalid: 1 byte: %.02x>\n", data[0]);
1268 else
1269 printf(" <invalid: no data>\n");
1270 return;
1271 }
1272
1273 p->print(type, len, data);
1274 }
1275
1276 #define PRINT_IGN { \
1277 .name = "IGNORE", \
1278 .print = NULL, \
1279 .minlen = 0, \
1280 .maxlen = 255, \
1281 }
1282
1283 static const struct ie_print ieprinters[] = {
1284 [0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1285 [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1286 [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
1287 [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
1288 [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
1289 [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
1290 [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
1291 [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
1292 [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
1293 [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
1294 [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
1295 [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
1296 [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
1297 [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
1298 [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
1299 [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
1300 [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
1301 [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
1302 [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1303 [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
1304 [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1305 [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
1306 [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
1307 [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
1308 [111] = { "802.11u Roaming Consortium", print_11u_rcon, 0, 255, BIT(PRINT_SCAN), },
1309 };
1310
1311 static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data)
1312 {
1313 print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
1314 }
1315
1316 static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len)
1317 {
1318 int i;
1319 static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" };
1320
1321 if (len < 19)
1322 goto invalid;
1323
1324 if (data[0] != 1) {
1325 printf("Parameter: not version 1: ");
1326 return false;
1327 }
1328
1329 printf("\t * Parameter version 1");
1330
1331 data++;
1332
1333 if (data[0] & 0x80)
1334 printf("\n\t\t * u-APSD");
1335
1336 data += 2;
1337
1338 for (i = 0; i < 4; i++) {
1339 printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
1340 if (data[0] & 0x10)
1341 printf(" acm");
1342 printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
1343 (1 << (data[1] >> 4)) - 1);
1344 printf(", AIFSN %d", data[0] & 0xf);
1345 if (data[2] | data[3])
1346 printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
1347 data += 4;
1348 }
1349
1350 printf("\n");
1351 return true;
1352
1353 invalid:
1354 printf("invalid: ");
1355 return false;
1356 }
1357
1358 static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data)
1359 {
1360 int i;
1361
1362 switch (data[0]) {
1363 case 0x00:
1364 printf(" information:");
1365 break;
1366 case 0x01:
1367 if (print_wifi_wmm_param(data + 1, len - 1))
1368 return;
1369 break;
1370 default:
1371 printf(" type %d:", data[0]);
1372 break;
1373 }
1374
1375 for(i = 1; i < len; i++)
1376 printf(" %.02x", data[i]);
1377 printf("\n");
1378 }
1379
1380 static const char * wifi_wps_dev_passwd_id(uint16_t id)
1381 {
1382 switch (id) {
1383 case 0:
1384 return "Default (PIN)";
1385 case 1:
1386 return "User-specified";
1387 case 2:
1388 return "Machine-specified";
1389 case 3:
1390 return "Rekey";
1391 case 4:
1392 return "PushButton";
1393 case 5:
1394 return "Registrar-specified";
1395 default:
1396 return "??";
1397 }
1398 }
1399
1400 static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data)
1401 {
1402 bool first = true;
1403 __u16 subtype, sublen;
1404
1405 while (len >= 4) {
1406 subtype = (data[0] << 8) + data[1];
1407 sublen = (data[2] << 8) + data[3];
1408 if (sublen > len)
1409 break;
1410
1411 switch (subtype) {
1412 case 0x104a:
1413 tab_on_first(&first);
1414 printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
1415 break;
1416 case 0x1011:
1417 tab_on_first(&first);
1418 printf("\t * Device name: %.*s\n", sublen, data + 4);
1419 break;
1420 case 0x1012: {
1421 uint16_t id;
1422 tab_on_first(&first);
1423 if (sublen != 2) {
1424 printf("\t * Device Password ID: (invalid "
1425 "length %d)\n", sublen);
1426 break;
1427 }
1428 id = data[4] << 8 | data[5];
1429 printf("\t * Device Password ID: %u (%s)\n",
1430 id, wifi_wps_dev_passwd_id(id));
1431 break;
1432 }
1433 case 0x1021:
1434 tab_on_first(&first);
1435 printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
1436 break;
1437 case 0x1023:
1438 tab_on_first(&first);
1439 printf("\t * Model: %.*s\n", sublen, data + 4);
1440 break;
1441 case 0x1024:
1442 tab_on_first(&first);
1443 printf("\t * Model Number: %.*s\n", sublen, data + 4);
1444 break;
1445 case 0x103b: {
1446 __u8 val = data[4];
1447 tab_on_first(&first);
1448 printf("\t * Response Type: %d%s\n",
1449 val, val == 3 ? " (AP)" : "");
1450 break;
1451 }
1452 case 0x103c: {
1453 __u8 val = data[4];
1454 tab_on_first(&first);
1455 printf("\t * RF Bands: 0x%x\n", val);
1456 break;
1457 }
1458 case 0x1041: {
1459 __u8 val = data[4];
1460 tab_on_first(&first);
1461 printf("\t * Selected Registrar: 0x%x\n", val);
1462 break;
1463 }
1464 case 0x1042:
1465 tab_on_first(&first);
1466 printf("\t * Serial Number: %.*s\n", sublen, data + 4);
1467 break;
1468 case 0x1044: {
1469 __u8 val = data[4];
1470 tab_on_first(&first);
1471 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1472 val,
1473 val == 1 ? " (Unconfigured)" : "",
1474 val == 2 ? " (Configured)" : "");
1475 break;
1476 }
1477 case 0x1047:
1478 tab_on_first(&first);
1479 printf("\t * UUID: ");
1480 if (sublen != 16) {
1481 printf("(invalid, length=%d)\n", sublen);
1482 break;
1483 }
1484 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1485 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1486 data[4], data[5], data[6], data[7],
1487 data[8], data[9], data[10], data[11],
1488 data[12], data[13], data[14], data[15],
1489 data[16], data[17], data[18], data[19]);
1490 break;
1491 case 0x1054: {
1492 tab_on_first(&first);
1493 if (sublen != 8) {
1494 printf("\t * Primary Device Type: (invalid "
1495 "length %d)\n", sublen);
1496 break;
1497 }
1498 printf("\t * Primary Device Type: "
1499 "%u-%02x%02x%02x%02x-%u\n",
1500 data[4] << 8 | data[5],
1501 data[6], data[7], data[8], data[9],
1502 data[10] << 8 | data[11]);
1503 break;
1504 }
1505 case 0x1057: {
1506 __u8 val = data[4];
1507 tab_on_first(&first);
1508 printf("\t * AP setup locked: 0x%.2x\n", val);
1509 break;
1510 }
1511 case 0x1008:
1512 case 0x1053: {
1513 __u16 meth = (data[4] << 8) + data[5];
1514 bool comma = false;
1515 tab_on_first(&first);
1516 printf("\t * %sConfig methods:",
1517 subtype == 0x1053 ? "Selected Registrar ": "");
1518 #define T(bit, name) do { \
1519 if (meth & (1<<bit)) { \
1520 if (comma) \
1521 printf(","); \
1522 comma = true; \
1523 printf(" " name); \
1524 } } while (0)
1525 T(0, "USB");
1526 T(1, "Ethernet");
1527 T(2, "Label");
1528 T(3, "Display");
1529 T(4, "Ext. NFC");
1530 T(5, "Int. NFC");
1531 T(6, "NFC Intf.");
1532 T(7, "PBC");
1533 T(8, "Keypad");
1534 printf("\n");
1535 break;
1536 #undef T
1537 }
1538 default: {
1539 const __u8 *subdata = data + 4;
1540 __u16 tmplen = sublen;
1541
1542 tab_on_first(&first);
1543 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1544 subtype, tmplen);
1545 while (tmplen) {
1546 printf(" %.2x", *subdata);
1547 subdata++;
1548 tmplen--;
1549 }
1550 printf("\n");
1551 break;
1552 }
1553 }
1554
1555 data += sublen + 4;
1556 len -= sublen + 4;
1557 }
1558
1559 if (len != 0) {
1560 printf("\t\t * bogus tail data (%d):", len);
1561 while (len) {
1562 printf(" %.2x", *data);
1563 data++;
1564 len--;
1565 }
1566 printf("\n");
1567 }
1568 }
1569
1570 static const struct ie_print wifiprinters[] = {
1571 [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
1572 [2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), },
1573 [4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), },
1574 };
1575
1576 static inline void print_p2p(const uint8_t type, uint8_t len, const uint8_t *data)
1577 {
1578 bool first = true;
1579 __u8 subtype;
1580 __u16 sublen;
1581
1582 while (len >= 3) {
1583 subtype = data[0];
1584 sublen = (data[2] << 8) + data[1];
1585
1586 if (sublen > len - 3)
1587 break;
1588
1589 switch (subtype) {
1590 case 0x02: /* capability */
1591 tab_on_first(&first);
1592 if (sublen < 2) {
1593 printf("\t * malformed capability\n");
1594 break;
1595 }
1596 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1597 data[3], data[4]);
1598 break;
1599 case 0x0d: /* device info */
1600 if (sublen < 6 + 2 + 8 + 1) {
1601 printf("\t * malformed device info\n");
1602 break;
1603 }
1604 /* fall through for now */
1605 case 0x00: /* status */
1606 case 0x01: /* minor reason */
1607 case 0x03: /* device ID */
1608 case 0x04: /* GO intent */
1609 case 0x05: /* configuration timeout */
1610 case 0x06: /* listen channel */
1611 case 0x07: /* group BSSID */
1612 case 0x08: /* ext listen timing */
1613 case 0x09: /* intended interface address */
1614 case 0x0a: /* manageability */
1615 case 0x0b: /* channel list */
1616 case 0x0c: /* NoA */
1617 case 0x0e: /* group info */
1618 case 0x0f: /* group ID */
1619 case 0x10: /* interface */
1620 case 0x11: /* operating channel */
1621 case 0x12: /* invitation flags */
1622 case 0xdd: /* vendor specific */
1623 default: {
1624 const __u8 *subdata = data + 4;
1625 __u16 tmplen = sublen;
1626
1627 tab_on_first(&first);
1628 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1629 subtype, tmplen);
1630 while (tmplen) {
1631 printf(" %.2x", *subdata);
1632 subdata++;
1633 tmplen--;
1634 }
1635 printf("\n");
1636 break;
1637 }
1638 }
1639
1640 data += sublen + 3;
1641 len -= sublen + 3;
1642 }
1643
1644 if (len != 0) {
1645 tab_on_first(&first);
1646 printf("\t * bogus tail data (%d):", len);
1647 while (len) {
1648 printf(" %.2x", *data);
1649 data++;
1650 len--;
1651 }
1652 printf("\n");
1653 }
1654 }
1655
1656 static inline void print_hs20_ind(const uint8_t type, uint8_t len, const uint8_t *data)
1657 {
1658 /* I can't find the spec for this...just going off what wireshark uses. */
1659 printf("\n");
1660 if (len > 0)
1661 printf("\t\tDGAF: %i\n", (int)(data[0] & 0x1));
1662 else
1663 printf("\t\tUnexpected length: %i\n", len);
1664 }
1665
1666 static const struct ie_print wfa_printers[] = {
1667 [9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), },
1668 [16] = { "HotSpot 2.0 Indication", print_hs20_ind, 1, 255, BIT(PRINT_SCAN), },
1669 };
1670
1671 static void print_vendor(unsigned char len, unsigned char *data,
1672 bool unknown, enum print_ie_type ptype)
1673 {
1674 int i;
1675
1676 if (len < 3) {
1677 printf("\tVendor specific: <too short> data:");
1678 for(i = 0; i < len; i++)
1679 printf(" %.02x", data[i]);
1680 printf("\n");
1681 return;
1682 }
1683
1684 if (len >= 4 && memcmp(data, ms_oui, 3) == 0) {
1685 if (data[3] < ARRAY_SIZE(wifiprinters) &&
1686 wifiprinters[data[3]].name &&
1687 wifiprinters[data[3]].flags & BIT(ptype)) {
1688 print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
1689 return;
1690 }
1691 if (!unknown)
1692 return;
1693 printf("\tMS/WiFi %#.2x, data:", data[3]);
1694 for(i = 0; i < len - 4; i++)
1695 printf(" %.02x", data[i + 4]);
1696 printf("\n");
1697 return;
1698 }
1699
1700 if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
1701 if (data[3] < ARRAY_SIZE(wfa_printers) &&
1702 wfa_printers[data[3]].name &&
1703 wfa_printers[data[3]].flags & BIT(ptype)) {
1704 print_ie(&wfa_printers[data[3]], data[3], len - 4, data + 4);
1705 return;
1706 }
1707 if (!unknown)
1708 return;
1709 printf("\tWFA %#.2x, data:", data[3]);
1710 for(i = 0; i < len - 4; i++)
1711 printf(" %.02x", data[i + 4]);
1712 printf("\n");
1713 return;
1714 }
1715
1716 if (!unknown)
1717 return;
1718
1719 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1720 data[0], data[1], data[2]);
1721 for (i = 3; i < len; i++)
1722 printf(" %.2x", data[i]);
1723 printf("\n");
1724 }
1725
1726 void print_ies(unsigned char *ie, int ielen, bool unknown,
1727 enum print_ie_type ptype)
1728 {
1729 while (ielen >= 2 && ielen >= ie[1]) {
1730 if (ie[0] < ARRAY_SIZE(ieprinters) &&
1731 ieprinters[ie[0]].name &&
1732 ieprinters[ie[0]].flags & BIT(ptype)) {
1733 print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
1734 } else if (ie[0] == 221 /* vendor */) {
1735 print_vendor(ie[1], ie + 2, unknown, ptype);
1736 } else if (unknown) {
1737 int i;
1738
1739 printf("\tUnknown IE (%d):", ie[0]);
1740 for (i=0; i<ie[1]; i++)
1741 printf(" %.2x", ie[2+i]);
1742 printf("\n");
1743 }
1744 ielen -= ie[1] + 2;
1745 ie += ie[1] + 2;
1746 }
1747 }
1748
1749 static void print_capa_dmg(__u16 capa)
1750 {
1751 switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
1752 case WLAN_CAPABILITY_DMG_TYPE_AP:
1753 printf(" DMG_ESS");
1754 break;
1755 case WLAN_CAPABILITY_DMG_TYPE_PBSS:
1756 printf(" DMG_PCP");
1757 break;
1758 case WLAN_CAPABILITY_DMG_TYPE_IBSS:
1759 printf(" DMG_IBSS");
1760 break;
1761 }
1762
1763 if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
1764 printf(" CBAP_Only");
1765 if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
1766 printf(" CBAP_Src");
1767 if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
1768 printf(" Privacy");
1769 if (capa & WLAN_CAPABILITY_DMG_ECPAC)
1770 printf(" ECPAC");
1771 if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
1772 printf(" SpectrumMgmt");
1773 if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
1774 printf(" RadioMeasure");
1775 }
1776
1777 static void print_capa_non_dmg(__u16 capa)
1778 {
1779 if (capa & WLAN_CAPABILITY_ESS)
1780 printf(" ESS");
1781 if (capa & WLAN_CAPABILITY_IBSS)
1782 printf(" IBSS");
1783 if (capa & WLAN_CAPABILITY_CF_POLLABLE)
1784 printf(" CfPollable");
1785 if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
1786 printf(" CfPollReq");
1787 if (capa & WLAN_CAPABILITY_PRIVACY)
1788 printf(" Privacy");
1789 if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
1790 printf(" ShortPreamble");
1791 if (capa & WLAN_CAPABILITY_PBCC)
1792 printf(" PBCC");
1793 if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
1794 printf(" ChannelAgility");
1795 if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
1796 printf(" SpectrumMgmt");
1797 if (capa & WLAN_CAPABILITY_QOS)
1798 printf(" QoS");
1799 if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
1800 printf(" ShortSlotTime");
1801 if (capa & WLAN_CAPABILITY_APSD)
1802 printf(" APSD");
1803 if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
1804 printf(" RadioMeasure");
1805 if (capa & WLAN_CAPABILITY_DSSS_OFDM)
1806 printf(" DSSS-OFDM");
1807 if (capa & WLAN_CAPABILITY_DEL_BACK)
1808 printf(" DelayedBACK");
1809 if (capa & WLAN_CAPABILITY_IMM_BACK)
1810 printf(" ImmediateBACK");
1811 }
1812
1813 static int print_bss_handler(struct nl_msg *msg, void *arg)
1814 {
1815 struct nlattr *tb[NL80211_ATTR_MAX + 1];
1816 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1817 struct nlattr *bss[NL80211_BSS_MAX + 1];
1818 char mac_addr[20], dev[20];
1819 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1820 [NL80211_BSS_TSF] = { .type = NLA_U64 },
1821 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1822 [NL80211_BSS_BSSID] = { },
1823 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1824 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1825 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
1826 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
1827 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1828 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
1829 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
1830 [NL80211_BSS_BEACON_IES] = { },
1831 };
1832 struct scan_params *params = arg;
1833 int show = params->show_both_ie_sets ? 2 : 1;
1834 bool is_dmg = false;
1835
1836 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1837 genlmsg_attrlen(gnlh, 0), NULL);
1838
1839 if (!tb[NL80211_ATTR_BSS]) {
1840 fprintf(stderr, "bss info missing!\n");
1841 return NL_SKIP;
1842 }
1843 if (nla_parse_nested(bss, NL80211_BSS_MAX,
1844 tb[NL80211_ATTR_BSS],
1845 bss_policy)) {
1846 fprintf(stderr, "failed to parse nested attributes!\n");
1847 return NL_SKIP;
1848 }
1849
1850 if (!bss[NL80211_BSS_BSSID])
1851 return NL_SKIP;
1852
1853 mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
1854 printf("BSS %s", mac_addr);
1855 if (tb[NL80211_ATTR_IFINDEX]) {
1856 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1857 printf("(on %s)", dev);
1858 }
1859
1860 if (bss[NL80211_BSS_STATUS]) {
1861 switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
1862 case NL80211_BSS_STATUS_AUTHENTICATED:
1863 printf(" -- authenticated");
1864 break;
1865 case NL80211_BSS_STATUS_ASSOCIATED:
1866 printf(" -- associated");
1867 break;
1868 case NL80211_BSS_STATUS_IBSS_JOINED:
1869 printf(" -- joined");
1870 break;
1871 default:
1872 printf(" -- unknown status: %d",
1873 nla_get_u32(bss[NL80211_BSS_STATUS]));
1874 break;
1875 }
1876 }
1877 printf("\n");
1878
1879 if (bss[NL80211_BSS_TSF]) {
1880 unsigned long long tsf;
1881 tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
1882 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1883 tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
1884 (tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
1885 }
1886 if (bss[NL80211_BSS_FREQUENCY]) {
1887 int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
1888 printf("\tfreq: %d\n", freq);
1889 if (freq > 45000)
1890 is_dmg = true;
1891 }
1892 if (bss[NL80211_BSS_BEACON_INTERVAL])
1893 printf("\tbeacon interval: %d TUs\n",
1894 nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
1895 if (bss[NL80211_BSS_CAPABILITY]) {
1896 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
1897 printf("\tcapability:");
1898 if (is_dmg)
1899 print_capa_dmg(capa);
1900 else
1901 print_capa_non_dmg(capa);
1902 printf(" (0x%.4x)\n", capa);
1903 }
1904 if (bss[NL80211_BSS_SIGNAL_MBM]) {
1905 int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
1906 printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
1907 }
1908 if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
1909 unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
1910 printf("\tsignal: %d/100\n", s);
1911 }
1912 if (bss[NL80211_BSS_SEEN_MS_AGO]) {
1913 int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
1914 printf("\tlast seen: %d ms ago\n", age);
1915 }
1916
1917 if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
1918 if (bss[NL80211_BSS_BEACON_IES])
1919 printf("\tInformation elements from Probe Response "
1920 "frame:\n");
1921 print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1922 nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
1923 params->unknown, params->type);
1924 }
1925 if (bss[NL80211_BSS_BEACON_IES] && show--) {
1926 printf("\tInformation elements from Beacon frame:\n");
1927 print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
1928 nla_len(bss[NL80211_BSS_BEACON_IES]),
1929 params->unknown, params->type);
1930 }
1931
1932 return NL_SKIP;
1933 }
1934
1935 static struct scan_params scan_params;
1936
1937 static int handle_scan_dump(struct nl80211_state *state,
1938 struct nl_cb *cb,
1939 struct nl_msg *msg,
1940 int argc, char **argv,
1941 enum id_input id)
1942 {
1943 if (argc > 1)
1944 return 1;
1945
1946 memset(&scan_params, 0, sizeof(scan_params));
1947
1948 if (argc == 1 && !strcmp(argv[0], "-u"))
1949 scan_params.unknown = true;
1950 else if (argc == 1 && !strcmp(argv[0], "-b"))
1951 scan_params.show_both_ie_sets = true;
1952
1953 scan_params.type = PRINT_SCAN;
1954
1955 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
1956 &scan_params);
1957 return 0;
1958 }
1959
1960 static int handle_scan_combined(struct nl80211_state *state,
1961 struct nl_cb *cb,
1962 struct nl_msg *msg,
1963 int argc, char **argv,
1964 enum id_input id)
1965 {
1966 char **trig_argv;
1967 static char *dump_argv[] = {
1968 NULL,
1969 "scan",
1970 "dump",
1971 NULL,
1972 };
1973 static const __u32 cmds[] = {
1974 NL80211_CMD_NEW_SCAN_RESULTS,
1975 NL80211_CMD_SCAN_ABORTED,
1976 };
1977 int trig_argc, dump_argc, err;
1978
1979 if (argc >= 3 && !strcmp(argv[2], "-u")) {
1980 dump_argc = 4;
1981 dump_argv[3] = "-u";
1982 } else if (argc >= 3 && !strcmp(argv[2], "-b")) {
1983 dump_argc = 4;
1984 dump_argv[3] = "-b";
1985 } else
1986 dump_argc = 3;
1987
1988 trig_argc = 3 + (argc - 2) + (3 - dump_argc);
1989 trig_argv = calloc(trig_argc, sizeof(*trig_argv));
1990 if (!trig_argv)
1991 return -ENOMEM;
1992 trig_argv[0] = argv[0];
1993 trig_argv[1] = "scan";
1994 trig_argv[2] = "trigger";
1995 int i;
1996 for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
1997 trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
1998 err = handle_cmd(state, id, trig_argc, trig_argv);
1999 free(trig_argv);
2000 if (err)
2001 return err;
2002
2003 /*
2004 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2005 *
2006 * This code has a bug, which requires creating a separate
2007 * nl80211 socket to fix:
2008 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2009 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2010 * before (!) we listen to it, because we only start listening
2011 * after we send our scan request.
2012 *
2013 * Doing it the other way around has a race condition as well,
2014 * if you first open the events socket you may get a notification
2015 * for a previous scan.
2016 *
2017 * The only proper way to fix this would be to listen to events
2018 * before sending the command, and for the kernel to send the
2019 * scan request along with the event, so that you can match up
2020 * whether the scan you requested was finished or aborted (this
2021 * may result in processing a scan that another application
2022 * requested, but that doesn't seem to be a problem).
2023 *
2024 * Alas, the kernel doesn't do that (yet).
2025 */
2026
2027 if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
2028 NL80211_CMD_SCAN_ABORTED) {
2029 printf("scan aborted!\n");
2030 return 0;
2031 }
2032
2033 dump_argv[0] = argv[0];
2034 return handle_cmd(state, id, dump_argc, dump_argv);
2035 }
2036 TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2037 CIB_NETDEV, handle_scan_combined,
2038 "Scan on the given frequencies and probe for the given SSIDs\n"
2039 "(or wildcard if not given) unless passive scanning is requested.\n"
2040 "If -u is specified print unknown data in the scan results.\n"
2041 "Specified (vendor) IEs must be well-formed.");
2042 COMMAND(scan, dump, "[-u]",
2043 NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
2044 "Dump the current scan results. If -u is specified, print unknown\n"
2045 "data in scan results.");
2046 COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2047 NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
2048 "Trigger a scan on the given frequencies with probing for the given\n"
2049 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2050
2051
2052 static int handle_start_sched_scan(struct nl80211_state *state,
2053 struct nl_cb *cb, struct nl_msg *msg,
2054 int argc, char **argv, enum id_input id)
2055 {
2056 return parse_sched_scan(msg, &argc, &argv);
2057 }
2058
2059 static int handle_stop_sched_scan(struct nl80211_state *state, struct nl_cb *cb,
2060 struct nl_msg *msg, int argc, char **argv,
2061 enum id_input id)
2062 {
2063 if (argc != 0)
2064 return 1;
2065
2066 return 0;
2067 }
2068
2069 COMMAND(scan, sched_start,
2070 SCHED_SCAN_OPTIONS,
2071 NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
2072 "Start a scheduled scan at the specified interval on the given frequencies\n"
2073 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2074 "scanning is requested. If matches are specified, only matching results\n"
2075 "will be returned.");
2076 COMMAND(scan, sched_stop, "",
2077 NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
2078 "Stop an ongoing scheduled scan.");