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