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