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