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