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