]> git.ipfire.org Git - thirdparty/iw.git/blame - scan.c
iw: 'idby' might be used uninitialized in main function
[thirdparty/iw.git] / scan.c
CommitLineData
3563f4c5
JB
1#include <net/if.h>
2#include <errno.h>
3#include <string.h>
764fe753 4#include <stdbool.h>
3563f4c5
JB
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
92a04ecd
MH
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)
2e8b82c1 27#define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
92a04ecd 28#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
2e8b82c1
VK
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)
92a04ecd 46
3bd60ef1
JB
47static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
48static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
9a22374a 49static unsigned char wfa_oui[3] = { 0x50, 0x6f, 0x9a };
857d966e 50
764fe753
JB
51struct scan_params {
52 bool unknown;
febeb0c0 53 enum print_ie_type type;
575280cc 54 bool show_both_ie_sets;
764fe753
JB
55};
56
2b690f0a
LR
57#define IEEE80211_COUNTRY_EXTENSION_ID 201
58
72725719
JB
59union 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;
2b690f0a
LR
70} __attribute__ ((packed));
71
5085aa2b
JB
72static 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
b1622287
LC
101int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
102{
302a378a 103 struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL;
9ae0d103
AS
104 struct nl_msg *scan_plans = NULL;
105 struct nlattr *match = NULL, *plan = NULL;
b1622287
LC
106 enum {
107 ND_TOPLEVEL,
108 ND_MATCH,
109 ND_FREQS,
302a378a 110 ND_ACTIVE,
9ae0d103 111 ND_PLANS,
b1622287
LC
112 } parse_state = ND_TOPLEVEL;
113 int c = *argc;
114 char *end, **v = *argv;
115 int err = 0, i = 0;
9ae0d103 116 unsigned int freq, interval = 0, delay = 0, iterations = 0;
302a378a 117 bool have_matchset = false, have_freqs = false, have_ssids = false;
9ae0d103 118 bool have_active = false, have_passive = false, have_plans = false;
5130bba0 119 uint32_t flags = 0;
b1622287
LC
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
302a378a
LC
133 ssids = nlmsg_alloc();
134 if (!ssids) {
135 err = -ENOMEM;
136 goto out;
137 }
138
9ae0d103
AS
139 scan_plans = nlmsg_alloc();
140 if (!scan_plans) {
141 err = -ENOBUFS;
142 goto out;
143 }
144
b1622287
LC
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
9ae0d103 155 if (interval || have_plans) {
b1622287
LC
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);
9ae0d103
AS
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;
b1622287
LC
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;
302a378a
LC
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;
5130bba0
LC
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 }
b1622287
LC
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;
302a378a
LC
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;
9ae0d103
AS
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;
b1622287
LC
370 }
371 }
372
302a378a
LC
373 if (!have_ssids)
374 NLA_PUT(ssids, 1, 0, "");
375 if (!have_passive)
376 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
b1622287
LC
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);
9ae0d103
AS
381 if (have_plans)
382 nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_PLANS, scan_plans);
5130bba0
LC
383 if (flags)
384 NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
b1622287
LC
385
386nla_put_failure:
387 if (match)
388 nla_nest_end(msg, match);
389 nlmsg_free(freqs);
390 nlmsg_free(matchset);
9ae0d103 391 nlmsg_free(scan_plans);
b1622287
LC
392
393out:
394 *argc = c;
395 *argv = v;
396 return err;
397}
398
7c37a24d 399static int handle_scan(struct nl80211_state *state,
3563f4c5 400 struct nl_msg *msg,
05514f95
JB
401 int argc, char **argv,
402 enum id_input id)
3563f4c5 403{
559a1713
JB
404 struct nl_msg *ssids = NULL, *freqs = NULL;
405 char *eptr;
3563f4c5 406 int err = -ENOBUFS;
559a1713
JB
407 int i;
408 enum {
409 NONE,
410 FREQ,
64797a7f 411 IES,
559a1713 412 SSID,
851d35c2 413 MESHID,
3a99ff6d 414 DURATION,
559a1713
JB
415 DONE,
416 } parse = NONE;
417 int freq;
3a99ff6d 418 unsigned int duration = 0;
559a1713 419 bool passive = false, have_ssids = false, have_freqs = false;
3a99ff6d 420 bool duration_mandatory = false;
851d35c2 421 size_t ies_len = 0, meshid_len = 0;
422 unsigned char *ies = NULL, *meshid = NULL, *tmpies;
5085aa2b 423 unsigned int flags = 0;
3563f4c5
JB
424
425 ssids = nlmsg_alloc();
426 if (!ssids)
427 return -ENOMEM;
559a1713
JB
428
429 freqs = nlmsg_alloc();
430 if (!freqs) {
431 nlmsg_free(ssids);
432 return -ENOMEM;
433 }
434
435 for (i = 0; i < argc; i++) {
559a1713
JB
436 switch (parse) {
437 case NONE:
64797a7f
JB
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;
fe862239 445 } else if (strcmp(argv[i], "lowpri") == 0) {
fe862239
SL
446 flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
447 break;
448 } else if (strcmp(argv[i], "flush") == 0) {
fe862239
SL
449 flags |= NL80211_SCAN_FLAG_FLUSH;
450 break;
ced94d5f 451 } else if (strcmp(argv[i], "ap-force") == 0) {
ced94d5f
AQ
452 flags |= NL80211_SCAN_FLAG_AP;
453 break;
3a99ff6d
PKC
454 } else if (strcmp(argv[i], "duration-mandatory") == 0) {
455 duration_mandatory = true;
456 break;
5085aa2b
JB
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;
64797a7f
JB
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;
851d35c2 472 } else if (strcmp(argv[i], "meshid") == 0) {
473 parse = MESHID;
474 break;
3a99ff6d
PKC
475 } else if (strcmp(argv[i], "duration") == 0) {
476 parse = DURATION;
477 break;
64797a7f 478 }
6ab936f0 479 /* fall through - this is an error */
559a1713 480 case DONE:
367e7dd3
AK
481 nlmsg_free(ssids);
482 nlmsg_free(freqs);
559a1713
JB
483 return 1;
484 case FREQ:
485 freq = strtoul(argv[i], &eptr, 10);
cc12e895
JB
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 }
559a1713 492 NLA_PUT_U32(freqs, i, freq);
64797a7f
JB
493 break;
494 case IES:
851d35c2 495 ies = parse_hex(argv[i], &ies_len);
64797a7f
JB
496 if (!ies)
497 goto nla_put_failure;
64797a7f 498 parse = NONE;
559a1713
JB
499 break;
500 case SSID:
501 NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
502 break;
851d35c2 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;
3a99ff6d
PKC
514 case DURATION:
515 duration = strtoul(argv[i], &eptr, 10);
516 parse = NONE;
517 break;
851d35c2 518 }
519 }
520
521 if (ies || meshid) {
522 tmpies = (unsigned char *) malloc(ies_len + meshid_len);
24cc1cf4
OO
523 if (!tmpies) {
524 free(ies);
525 free(meshid);
851d35c2 526 goto nla_put_failure;
24cc1cf4 527 }
851d35c2 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);
559a1713 535 }
ab65a092
OO
536 if (nla_put(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies) < 0) {
537 free(tmpies);
538 goto nla_put_failure;
539 }
851d35c2 540 free(tmpies);
559a1713
JB
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);
fe862239
SL
550 if (flags)
551 NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
3a99ff6d
PKC
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 }
3563f4c5
JB
563
564 err = 0;
565 nla_put_failure:
566 nlmsg_free(ssids);
559a1713 567 nlmsg_free(freqs);
3563f4c5
JB
568 return err;
569}
3563f4c5 570
857d966e
MH
571static void tab_on_first(bool *first)
572{
573 if (!*first)
574 printf("\t");
575 else
576 *first = false;
577}
578
5f310d83
SM
579struct print_ies_data {
580 unsigned char *ie;
581 int ielen;
582};
583
584static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
585 const struct print_ies_data *ie_buffer)
3563f4c5 586{
83b4934c 587 printf(" ");
748f8489 588 print_ssid_escaped(len, data);
3563f4c5
JB
589 printf("\n");
590}
591
ca159934 592#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
1fd19c39
CL
593#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
594
5f310d83
SM
595static void print_supprates(const uint8_t type, uint8_t len,
596 const uint8_t *data,
597 const struct print_ies_data *ie_buffer)
3563f4c5
JB
598{
599 int i;
600
83b4934c 601 printf(" ");
3563f4c5 602
83b4934c 603 for (i = 0; i < len; i++) {
3563f4c5 604 int r = data[i] & 0x7f;
1fd19c39 605
ca159934
JB
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)
1fd19c39
CL
609 printf("HT");
610 else
611 printf("%d.%d", r/2, 5*(r&1));
612
613 printf("%s ", data[i] & 0x80 ? "*" : "");
3563f4c5
JB
614 }
615 printf("\n");
616}
617
5f310d83
SM
618static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data,
619 const struct print_ies_data *ie_buffer)
3563f4c5 620{
83b4934c 621 printf(" channel %d\n", data[0]);
3563f4c5
JB
622}
623
2b690f0a 624static const char *country_env_str(char environment)
b7e8fa37 625{
2b690f0a 626 switch (environment) {
b7e8fa37 627 case 'I':
2b690f0a 628 return "Indoor only";
b7e8fa37 629 case 'O':
2b690f0a 630 return "Outdoor only";
b6c0d634 631 case ' ':
2b690f0a 632 return "Indoor/Outdoor";
b6c0d634 633 default:
2b690f0a 634 return "bogus";
b7e8fa37 635 }
2b690f0a
LR
636}
637
5f310d83
SM
638static void print_country(const uint8_t type, uint8_t len, const uint8_t *data,
639 const struct print_ies_data *ie_buffer)
2b690f0a
LR
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;
72725719 655 union ieee80211_country_ie_triplet *triplet = (void *) data;
2b690f0a
LR
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
a9859d30 675 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
2b690f0a
LR
676
677 data += 3;
678 len -= 3;
679 }
680
681 return;
b7e8fa37
MH
682}
683
5f310d83
SM
684static void print_powerconstraint(const uint8_t type, uint8_t len,
685 const uint8_t *data,
686 const struct print_ies_data *ie_buffer)
d1563a1b
MH
687{
688 printf(" %d dB\n", data[0]);
689}
690
5f310d83
SM
691static void print_tpcreport(const uint8_t type, uint8_t len,
692 const uint8_t *data,
693 const struct print_ies_data *ie_buffer)
792172b0
JM
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
5f310d83
SM
699static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data,
700 const struct print_ies_data *ie_buffer)
fc4d1484
MH
701{
702 if (data[0] == 0x00)
83b4934c 703 printf(" <no flags>");
fc4d1484
MH
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
83b4934c 713static void print_cipher(const uint8_t *data)
857d966e 714{
3bd60ef1 715 if (memcmp(data, ms_oui, 3) == 0) {
857d966e 716 switch (data[3]) {
510e0e2f 717 case 0:
857d966e
MH
718 printf("Use group cipher suite");
719 break;
510e0e2f 720 case 1:
857d966e
MH
721 printf("WEP-40");
722 break;
510e0e2f 723 case 2:
857d966e
MH
724 printf("TKIP");
725 break;
510e0e2f 726 case 4:
857d966e
MH
727 printf("CCMP");
728 break;
510e0e2f 729 case 5:
857d966e
MH
730 printf("WEP-104");
731 break;
732 default:
332769c6 733 printf("%.02x-%.02x-%.02x:%d",
5594fd23 734 data[0], data[1] ,data[2], data[3]);
857d966e
MH
735 break;
736 }
737 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
738 switch (data[3]) {
510e0e2f 739 case 0:
857d966e
MH
740 printf("Use group cipher suite");
741 break;
510e0e2f 742 case 1:
857d966e
MH
743 printf("WEP-40");
744 break;
510e0e2f 745 case 2:
857d966e
MH
746 printf("TKIP");
747 break;
510e0e2f 748 case 4:
857d966e
MH
749 printf("CCMP");
750 break;
510e0e2f 751 case 5:
857d966e
MH
752 printf("WEP-104");
753 break;
510e0e2f 754 case 6:
857d966e
MH
755 printf("AES-128-CMAC");
756 break;
f188ab67
BG
757 case 7:
758 printf("NO-GROUP");
759 break;
a8b3da9d
VK
760 case 8:
761 printf("GCMP");
762 break;
857d966e 763 default:
332769c6 764 printf("%.02x-%.02x-%.02x:%d",
5594fd23 765 data[0], data[1] ,data[2], data[3]);
857d966e
MH
766 break;
767 }
768 } else
332769c6 769 printf("%.02x-%.02x-%.02x:%d",
5594fd23 770 data[0], data[1] ,data[2], data[3]);
857d966e
MH
771}
772
83b4934c 773static void print_auth(const uint8_t *data)
857d966e 774{
3bd60ef1 775 if (memcmp(data, ms_oui, 3) == 0) {
857d966e 776 switch (data[3]) {
510e0e2f 777 case 1:
857d966e
MH
778 printf("IEEE 802.1X");
779 break;
510e0e2f 780 case 2:
857d966e
MH
781 printf("PSK");
782 break;
783 default:
332769c6 784 printf("%.02x-%.02x-%.02x:%d",
5594fd23 785 data[0], data[1] ,data[2], data[3]);
857d966e
MH
786 break;
787 }
788 } else if (memcmp(data, ieee80211_oui, 3) == 0) {
789 switch (data[3]) {
510e0e2f 790 case 1:
857d966e
MH
791 printf("IEEE 802.1X");
792 break;
510e0e2f 793 case 2:
857d966e
MH
794 printf("PSK");
795 break;
0fe1c415
JB
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;
4361eef3
JM
808 case 7:
809 printf("TDLS/TPK");
810 break;
857d966e 811 default:
332769c6 812 printf("%.02x-%.02x-%.02x:%d",
5594fd23 813 data[0], data[1] ,data[2], data[3]);
857d966e
MH
814 break;
815 }
f188ab67
BG
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 }
857d966e 826 } else
332769c6 827 printf("%.02x-%.02x-%.02x:%d",
5594fd23 828 data[0], data[1] ,data[2], data[3]);
857d966e
MH
829}
830
f188ab67
BG
831static void _print_rsn_ie(const char *defcipher, const char *defauth,
832 uint8_t len, const uint8_t *data, int is_osen)
857d966e
MH
833{
834 bool first = true;
f188ab67 835 __u16 count, capa;
857d966e
MH
836 int i;
837
f188ab67
BG
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);
857d966e 843
f188ab67
BG
844 data += 2;
845 len -= 2;
846 }
857d966e
MH
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);
31d477fb
MH
870 if (2 + (count * 4) > len)
871 goto invalid;
872
857d966e
MH
873 tab_on_first(&first);
874 printf("\t * Pairwise ciphers:");
31d477fb 875 for (i = 0; i < count; i++) {
857d966e
MH
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);
31d477fb
MH
891 if (2 + (count * 4) > len)
892 goto invalid;
893
857d966e
MH
894 tab_on_first(&first);
895 printf("\t * Authentication suites:");
83b4934c 896 for (i = 0; i < count; i++) {
857d966e
MH
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
6a4f24e8
JB
905 if (len >= 2) {
906 capa = data[0] | (data[1] << 8);
907 tab_on_first(&first);
cadbe89a
JB
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:
4361eef3 915 printf(" 1-PTKSA-RC");
cadbe89a
JB
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:
4361eef3 929 printf(" 1-GTKSA-RC");
cadbe89a
JB
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);
6a4f24e8
JB
952 data += 2;
953 len -= 2;
954 }
31d477fb 955
5ba3f523
JB
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
cadbe89a 978 invalid:
31d477fb
MH
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 }
857d966e
MH
988}
989
f188ab67
BG
990static 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
996static 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
5f310d83
SM
1003static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data,
1004 const struct print_ies_data *ie_buffer)
857d966e 1005{
83b4934c 1006 print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
857d966e
MH
1007}
1008
5f310d83
SM
1009static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
1010 const struct print_ies_data *ie_buffer)
0c445c24 1011{
357c1a5d 1012 printf("\n");
7ddfb679
JB
1013 print_ht_capability(data[0] | (data[1] << 8));
1014 print_ampdu_length(data[2] & 3);
c79c7464 1015 print_ampdu_spacing((data[2] >> 2) & 7);
7ddfb679 1016 print_ht_mcs(data + 3);
0c445c24
LR
1017}
1018
489f0ea9
BG
1019static 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
1034static 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
5f310d83
SM
1053static void print_interworking(const uint8_t type, uint8_t len,
1054 const uint8_t *data,
1055 const struct print_ies_data *ie_buffer)
489f0ea9
BG
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
5f310d83
SM
1086static void print_11u_advert(const uint8_t type, uint8_t len,
1087 const uint8_t *data,
1088 const struct print_ies_data *ie_buffer)
3f818f6d
BG
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
5f310d83
SM
1120static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data,
1121 const struct print_ies_data *ie_buffer)
bc9e14f1
BG
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
29f7579e
JB
1172static const char *ht_secondary_offset[4] = {
1173 "no secondary",
1174 "above",
1175 "[reserved!]",
1176 "below",
1177};
1178
5f310d83
SM
1179static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data,
1180 const struct print_ies_data *ie_buffer)
be7602fb 1181{
be7602fb
JB
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",
29f7579e 1196 ht_secondary_offset[data[1] & 0x3]);
be7602fb
JB
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
5f310d83
SM
1210static void print_capabilities(const uint8_t type, uint8_t len,
1211 const uint8_t *data,
1212 const struct print_ies_data *ie_buffer)
9b880b00 1213{
5f310d83
SM
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;
31d2d259 1218
5f310d83
SM
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 }
31d2d259
JB
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
5f310d83 1235 printf("\n\t\t *");
31d2d259 1236
70c649d2
JB
1237#define CAPA(bit, name) case bit: printf(" " name); break
1238
5f310d83
SM
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
31d2d259 1250 switch (bit + base) {
70c649d2
JB
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)");
5f310d83
SM
1257
1258 case 6:
1259 s_psmp_support = true;
1260 printf(" S-PSMP Capability");
1261 break;
1262
70c649d2
JB
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");
5f310d83
SM
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
70c649d2
JB
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");
5f310d83
SM
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");
d06cda9e
AK
1330 CAPA(70, "FTM Responder");
1331 CAPA(71, "FTM Initiator");
5f310d83
SM
1332 CAPA(72, "Reserved");
1333 CAPA(73, "Extended Spectrum Management Capable");
1334 CAPA(74, "Reserved");
31d2d259
JB
1335 default:
1336 printf(" %d", bit);
1337 break;
1338 }
5f310d83 1339#undef ADD_BIT_VAL
70c649d2 1340#undef CAPA
31d2d259
JB
1341 }
1342 }
9b880b00 1343
5f310d83
SM
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
9b880b00
MH
1368 printf("\n");
1369}
1370
5f310d83
SM
1371static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data,
1372 const struct print_ies_data *ie_buffer)
575280cc
JM
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
5f310d83
SM
1382static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data,
1383 const struct print_ies_data *ie_buffer)
792172b0
JM
1384{
1385 printf(" %d TUs", (data[1] << 8) + data[0]);
1386}
1387
5f310d83
SM
1388static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
1389 const struct print_ies_data *ie_buffer)
54eb1613
JB
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
5f310d83
SM
1397static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data,
1398 const struct print_ies_data *ie_buffer)
ca159934
JB
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
5f310d83
SM
1415static 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)
29f7579e
JB
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
5f310d83
SM
1430static void print_secchan_offs(const uint8_t type, uint8_t len,
1431 const uint8_t *data,
1432 const struct print_ies_data *ie_buffer)
29f7579e
JB
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
5f310d83
SM
1440static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data,
1441 const struct print_ies_data *ie_buffer)
29f7579e
JB
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
5f310d83
SM
1449static void print_mesh_conf(const uint8_t type, uint8_t len,
1450 const uint8_t *data,
1451 const struct print_ies_data *ie_buffer)
2d86b0f3
CYY
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
83b4934c
JB
1482struct ie_print {
1483 const char *name;
5f310d83
SM
1484 void (*print)(const uint8_t type, uint8_t len, const uint8_t *data,
1485 const struct print_ies_data *ie_buffer);
83b4934c 1486 uint8_t minlen, maxlen;
febeb0c0 1487 uint8_t flags;
764fe753
JB
1488};
1489
5f310d83
SM
1490static 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)
4673a894 1493{
83b4934c
JB
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
5f310d83 1513 p->print(type, len, data, ie_buffer);
83b4934c
JB
1514}
1515
1516#define PRINT_IGN { \
1517 .name = "IGNORE", \
1518 .print = NULL, \
1519 .minlen = 0, \
1520 .maxlen = 255, \
4673a894
JB
1521}
1522
83b4934c 1523static const struct ie_print ieprinters[] = {
febeb0c0
JB
1524 [0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1525 [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
014d581a 1526 [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
575280cc 1527 [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
792172b0 1528 [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
febeb0c0 1529 [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
29f7579e 1530 [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
febeb0c0 1531 [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
792172b0 1532 [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
febeb0c0 1533 [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
a2e61861 1534 [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
792172b0 1535 [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
29f7579e 1536 [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
be7602fb 1537 [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
29f7579e 1538 [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
54eb1613 1539 [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
ca159934 1540 [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
febeb0c0
JB
1541 [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
1542 [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
2d86b0f3 1543 [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
720583e9 1544 [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
febeb0c0 1545 [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
489f0ea9 1546 [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
3f818f6d 1547 [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
bc9e14f1 1548 [111] = { "802.11u Roaming Consortium", print_11u_rcon, 0, 255, BIT(PRINT_SCAN), },
83b4934c
JB
1549};
1550
5f310d83
SM
1551static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
1552 const struct print_ies_data *ie_buffer)
83b4934c
JB
1553{
1554 print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
1555}
1556
5f310d83
SM
1557static void print_wifi_osen(const uint8_t type, uint8_t len,
1558 const uint8_t *data,
1559 const struct print_ies_data *ie_buffer)
f188ab67
BG
1560{
1561 print_osen_ie("OSEN", "OSEN", len, data);
1562}
1563
1cab57eb
JB
1564static 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) {
cee4fe20 1573 printf("Parameter: not version 1: ");
1cab57eb
JB
1574 return false;
1575 }
1576
89ea706f 1577 printf("\t * Parameter version 1");
1cab57eb
JB
1578
1579 data++;
1580
1581 if (data[0] & 0x80)
89ea706f 1582 printf("\n\t\t * u-APSD");
1cab57eb
JB
1583
1584 data += 2;
1585
1586 for (i = 0; i < 4; i++) {
89ea706f 1587 printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
87181516 1588 if (data[0] & 0x10)
1cab57eb
JB
1589 printf(" acm");
1590 printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
1591 (1 << (data[1] >> 4)) - 1);
a2a4c265 1592 printf(", AIFSN %d", data[0] & 0xf);
1cab57eb 1593 if (data[2] | data[3])
cee4fe20 1594 printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
1cab57eb
JB
1595 data += 4;
1596 }
1597
1598 printf("\n");
1599 return true;
1600
1601 invalid:
1602 printf("invalid: ");
1603 return false;
1604}
1605
5f310d83
SM
1606static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data,
1607 const struct print_ies_data *ie_buffer)
6ff0c93a
MH
1608{
1609 int i;
1610
6ff0c93a
MH
1611 switch (data[0]) {
1612 case 0x00:
83b4934c 1613 printf(" information:");
6ff0c93a
MH
1614 break;
1615 case 0x01:
1cab57eb
JB
1616 if (print_wifi_wmm_param(data + 1, len - 1))
1617 return;
6ff0c93a
MH
1618 break;
1619 default:
83b4934c 1620 printf(" type %d:", data[0]);
6ff0c93a
MH
1621 break;
1622 }
1623
1cab57eb
JB
1624 for(i = 1; i < len; i++)
1625 printf(" %.02x", data[i]);
6ff0c93a
MH
1626 printf("\n");
1627}
1628
a6816965
JM
1629static 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
5f310d83
SM
1649static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data,
1650 const struct print_ies_data *ie_buffer)
4673a894
JB
1651{
1652 bool first = true;
1653 __u16 subtype, sublen;
1654
4673a894
JB
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);
dffc6750 1664 printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
4673a894
JB
1665 break;
1666 case 0x1011:
1667 tab_on_first(&first);
1668 printf("\t * Device name: %.*s\n", sublen, data + 4);
1669 break;
a6816965
JM
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 }
4673a894
JB
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;
a6816965
JM
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 }
09fe09dc
JB
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;
a6816965
JM
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 }
7ee5a865 1755 case 0x1057: {
fe31a22e 1756 __u8 val = data[4];
7ee5a865 1757 tab_on_first(&first);
fe31a22e 1758 printf("\t * AP setup locked: 0x%.2x\n", val);
7ee5a865
JB
1759 break;
1760 }
a6816965
JM
1761 case 0x1008:
1762 case 0x1053: {
4673a894
JB
1763 __u16 meth = (data[4] << 8) + data[5];
1764 bool comma = false;
1765 tab_on_first(&first);
a6816965
JM
1766 printf("\t * %sConfig methods:",
1767 subtype == 0x1053 ? "Selected Registrar ": "");
4673a894
JB
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 }
2650d46b
JB
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");
4673a894
JB
1801 break;
1802 }
2650d46b 1803 }
4673a894
JB
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
83b4934c 1820static const struct ie_print wifiprinters[] = {
febeb0c0
JB
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), },
4673a894
JB
1824};
1825
5f310d83
SM
1826static inline void print_p2p(const uint8_t type, uint8_t len,
1827 const uint8_t *data,
1828 const struct print_ies_data *ie_buffer)
9a22374a
JB
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 }
6ab936f0 1856
9a22374a
JB
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
5f310d83
SM
1909static 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)
7e10c4ab
BG
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
9a22374a
JB
1921static const struct ie_print wfa_printers[] = {
1922 [9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), },
7e10c4ab 1923 [16] = { "HotSpot 2.0 Indication", print_hs20_ind, 1, 255, BIT(PRINT_SCAN), },
f188ab67 1924 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen, 1, 255, BIT(PRINT_SCAN), },
9a22374a
JB
1925};
1926
764fe753 1927static void print_vendor(unsigned char len, unsigned char *data,
febeb0c0 1928 bool unknown, enum print_ie_type ptype)
3563f4c5
JB
1929{
1930 int i;
1931
fbf80af5 1932 if (len < 3) {
4673a894 1933 printf("\tVendor specific: <too short> data:");
fbf80af5
JB
1934 for(i = 0; i < len; i++)
1935 printf(" %.02x", data[i]);
1936 printf("\n");
1937 return;
1938 }
1939
3bd60ef1 1940 if (len >= 4 && memcmp(data, ms_oui, 3) == 0) {
febeb0c0
JB
1941 if (data[3] < ARRAY_SIZE(wifiprinters) &&
1942 wifiprinters[data[3]].name &&
1943 wifiprinters[data[3]].flags & BIT(ptype)) {
5f310d83
SM
1944 print_ie(&wifiprinters[data[3]],
1945 data[3], len - 4, data + 4, 0);
83b4934c
JB
1946 return;
1947 }
febeb0c0 1948 if (!unknown)
4673a894 1949 return;
3bd60ef1 1950 printf("\tMS/WiFi %#.2x, data:", data[3]);
4673a894
JB
1951 for(i = 0; i < len - 4; i++)
1952 printf(" %.02x", data[i + 4]);
1953 printf("\n");
1954 return;
1955 }
1956
9a22374a
JB
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)) {
5f310d83
SM
1961 print_ie(&wfa_printers[data[3]],
1962 data[3], len - 4, data + 4, 0);
9a22374a
JB
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
febeb0c0 1974 if (!unknown)
764fe753
JB
1975 return;
1976
fbf80af5 1977 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
3563f4c5 1978 data[0], data[1], data[2]);
fbf80af5
JB
1979 for (i = 3; i < len; i++)
1980 printf(" %.2x", data[i]);
3563f4c5
JB
1981 printf("\n");
1982}
1983
febeb0c0
JB
1984void print_ies(unsigned char *ie, int ielen, bool unknown,
1985 enum print_ie_type ptype)
3563f4c5 1986{
5f310d83
SM
1987 struct print_ies_data ie_buffer = {
1988 .ie = ie,
1989 .ielen = ielen };
1990
3563f4c5 1991 while (ielen >= 2 && ielen >= ie[1]) {
febeb0c0
JB
1992 if (ie[0] < ARRAY_SIZE(ieprinters) &&
1993 ieprinters[ie[0]].name &&
1994 ieprinters[ie[0]].flags & BIT(ptype)) {
5f310d83
SM
1995 print_ie(&ieprinters[ie[0]],
1996 ie[0], ie[1], ie + 2, &ie_buffer);
764fe753 1997 } else if (ie[0] == 221 /* vendor */) {
febeb0c0
JB
1998 print_vendor(ie[1], ie + 2, unknown, ptype);
1999 } else if (unknown) {
3563f4c5
JB
2000 int i;
2001
8086b700 2002 printf("\tUnknown IE (%d):", ie[0]);
3563f4c5 2003 for (i=0; i<ie[1]; i++)
8086b700 2004 printf(" %.2x", ie[2+i]);
3563f4c5
JB
2005 printf("\n");
2006 }
2007 ielen -= ie[1] + 2;
2008 ie += ie[1] + 2;
2009 }
2010}
2011
2e8b82c1
VK
2012static 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
2040static 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
3563f4c5
JB
2076static 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] = { },
f2e17e1f
JB
2089 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
2090 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
a56117a6 2091 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
c04a78df 2092 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
575280cc 2093 [NL80211_BSS_BEACON_IES] = { },
3563f4c5 2094 };
febeb0c0 2095 struct scan_params *params = arg;
1c5bcd9c 2096 int show = params->show_both_ie_sets ? 2 : 1;
2e8b82c1 2097 bool is_dmg = false;
3563f4c5
JB
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]) {
5fe70c0e 2103 fprintf(stderr, "bss info missing!\n");
3563f4c5
JB
2104 return NL_SKIP;
2105 }
2106 if (nla_parse_nested(bss, NL80211_BSS_MAX,
2107 tb[NL80211_ATTR_BSS],
2108 bss_policy)) {
5fe70c0e 2109 fprintf(stderr, "failed to parse nested attributes!\n");
3563f4c5
JB
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]));
00889fb2
JB
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 }
a56117a6
JB
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");
3563f4c5 2141
f6fca12c
JB
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
e7109a8a
JB
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 }
2e8b82c1
VK
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 }
3563f4c5 2161 if (bss[NL80211_BSS_BEACON_INTERVAL])
792172b0 2162 printf("\tbeacon interval: %d TUs\n",
3563f4c5 2163 nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
92a04ecd
MH
2164 if (bss[NL80211_BSS_CAPABILITY]) {
2165 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
2166 printf("\tcapability:");
2e8b82c1
VK
2167 if (is_dmg)
2168 print_capa_dmg(capa);
2169 else
2170 print_capa_non_dmg(capa);
92a04ecd
MH
2171 printf(" (0x%.4x)\n", capa);
2172 }
f2e17e1f
JB
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 }
c04a78df
HS
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 }
c551449a 2185
1c5bcd9c 2186 if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
b50d1456
JB
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 nla_len(ies) != nla_len(bcnies) ||
2192 memcmp(nla_data(ies), nla_data(bcnies), nla_len(ies)))
575280cc
JM
2193 printf("\tInformation elements from Probe Response "
2194 "frame:\n");
b50d1456 2195 print_ies(nla_data(ies), nla_len(ies),
febeb0c0 2196 params->unknown, params->type);
575280cc 2197 }
1c5bcd9c 2198 if (bss[NL80211_BSS_BEACON_IES] && show--) {
575280cc
JM
2199 printf("\tInformation elements from Beacon frame:\n");
2200 print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
2201 nla_len(bss[NL80211_BSS_BEACON_IES]),
2202 params->unknown, params->type);
2203 }
3563f4c5
JB
2204
2205 return NL_SKIP;
2206}
2207
764fe753 2208static struct scan_params scan_params;
3563f4c5 2209
7c37a24d 2210static int handle_scan_dump(struct nl80211_state *state,
3563f4c5 2211 struct nl_msg *msg,
05514f95
JB
2212 int argc, char **argv,
2213 enum id_input id)
3563f4c5 2214{
764fe753
JB
2215 if (argc > 1)
2216 return 1;
2217
1c5bcd9c
JB
2218 memset(&scan_params, 0, sizeof(scan_params));
2219
764fe753
JB
2220 if (argc == 1 && !strcmp(argv[0], "-u"))
2221 scan_params.unknown = true;
575280cc
JM
2222 else if (argc == 1 && !strcmp(argv[0], "-b"))
2223 scan_params.show_both_ie_sets = true;
764fe753 2224
febeb0c0
JB
2225 scan_params.type = PRINT_SCAN;
2226
f3c96669 2227 register_handler(print_bss_handler, &scan_params);
3563f4c5
JB
2228 return 0;
2229}
a5fe4ef2
JB
2230
2231static int handle_scan_combined(struct nl80211_state *state,
a5fe4ef2 2232 struct nl_msg *msg,
05514f95
JB
2233 int argc, char **argv,
2234 enum id_input id)
a5fe4ef2 2235{
559a1713 2236 char **trig_argv;
a5fe4ef2
JB
2237 static char *dump_argv[] = {
2238 NULL,
2239 "scan",
2240 "dump",
92649eab 2241 NULL,
a5fe4ef2
JB
2242 };
2243 static const __u32 cmds[] = {
2244 NL80211_CMD_NEW_SCAN_RESULTS,
2245 NL80211_CMD_SCAN_ABORTED,
2246 };
559a1713 2247 int trig_argc, dump_argc, err;
7d19e35d 2248 int i;
a5fe4ef2 2249
559a1713
JB
2250 if (argc >= 3 && !strcmp(argv[2], "-u")) {
2251 dump_argc = 4;
2252 dump_argv[3] = "-u";
575280cc
JM
2253 } else if (argc >= 3 && !strcmp(argv[2], "-b")) {
2254 dump_argc = 4;
2255 dump_argv[3] = "-b";
559a1713
JB
2256 } else
2257 dump_argc = 3;
2258
2259 trig_argc = 3 + (argc - 2) + (3 - dump_argc);
2260 trig_argv = calloc(trig_argc, sizeof(*trig_argv));
2261 if (!trig_argv)
2262 return -ENOMEM;
a5fe4ef2 2263 trig_argv[0] = argv[0];
559a1713
JB
2264 trig_argv[1] = "scan";
2265 trig_argv[2] = "trigger";
7d19e35d 2266
559a1713
JB
2267 for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
2268 trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
75f4204c 2269 err = handle_cmd(state, id, trig_argc, trig_argv);
559a1713 2270 free(trig_argv);
a5fe4ef2
JB
2271 if (err)
2272 return err;
2273
61725dbe
JB
2274 /*
2275 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2276 *
2277 * This code has a bug, which requires creating a separate
2278 * nl80211 socket to fix:
2279 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2280 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2281 * before (!) we listen to it, because we only start listening
2282 * after we send our scan request.
2283 *
2284 * Doing it the other way around has a race condition as well,
2285 * if you first open the events socket you may get a notification
2286 * for a previous scan.
2287 *
2288 * The only proper way to fix this would be to listen to events
2289 * before sending the command, and for the kernel to send the
2290 * scan request along with the event, so that you can match up
2291 * whether the scan you requested was finished or aborted (this
2292 * may result in processing a scan that another application
2293 * requested, but that doesn't seem to be a problem).
2294 *
2295 * Alas, the kernel doesn't do that (yet).
2296 */
2297
a5fe4ef2
JB
2298 if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
2299 NL80211_CMD_SCAN_ABORTED) {
2300 printf("scan aborted!\n");
2301 return 0;
2302 }
2303
2304 dump_argv[0] = argv[0];
75f4204c 2305 return handle_cmd(state, id, dump_argc, dump_argv);
a5fe4ef2 2306}
3a99ff6d 2307TOPLEVEL(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,
6ca98d28
JB
2308 CIB_NETDEV, handle_scan_combined,
2309 "Scan on the given frequencies and probe for the given SSIDs\n"
2310 "(or wildcard if not given) unless passive scanning is requested.\n"
64797a7f
JB
2311 "If -u is specified print unknown data in the scan results.\n"
2312 "Specified (vendor) IEs must be well-formed.");
4698bfc2
JB
2313COMMAND(scan, dump, "[-u]",
2314 NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
2315 "Dump the current scan results. If -u is specified, print unknown\n"
2316 "data in scan results.");
3a99ff6d 2317COMMAND(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]",
4698bfc2
JB
2318 NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
2319 "Trigger a scan on the given frequencies with probing for the given\n"
3a99ff6d
PKC
2320 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2321 "Duration(in TUs), if specified, will be used to set dwell times.\n");
3fce58aa
LC
2322
2323
0a12cf8d
EP
2324static int handle_scan_abort(struct nl80211_state *state,
2325 struct nl_msg *msg,
2326 int argc, char **argv,
2327 enum id_input id)
2328{
2329 return 0;
2330}
2331COMMAND(scan, abort, "",
2332 NL80211_CMD_ABORT_SCAN, 0, CIB_NETDEV, handle_scan_abort,
2333 "Abort ongoing scan");
2334
3fce58aa 2335static int handle_start_sched_scan(struct nl80211_state *state,
34b23014 2336 struct nl_msg *msg,
3fce58aa
LC
2337 int argc, char **argv, enum id_input id)
2338{
2339 return parse_sched_scan(msg, &argc, &argv);
2340}
2341
34b23014 2342static int handle_stop_sched_scan(struct nl80211_state *state,
3fce58aa
LC
2343 struct nl_msg *msg, int argc, char **argv,
2344 enum id_input id)
2345{
2346 if (argc != 0)
2347 return 1;
2348
2349 return 0;
2350}
2351
2352COMMAND(scan, sched_start,
2353 SCHED_SCAN_OPTIONS,
2354 NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
2355 "Start a scheduled scan at the specified interval on the given frequencies\n"
2356 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2357 "scanning is requested. If matches are specified, only matching results\n"
2358 "will be returned.");
2359COMMAND(scan, sched_stop, "",
2360 NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
2361 "Stop an ongoing scheduled scan.");