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