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