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