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