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