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