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