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