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