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