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