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