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