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