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