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