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>
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)
27 #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
28 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
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)
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 */
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)
44 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
45 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
47 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
48 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
49 static unsigned char wfa_oui
[3] = { 0x50, 0x6f, 0x9a };
53 enum print_ie_type type
;
54 bool show_both_ie_sets
;
57 #define IEEE80211_COUNTRY_EXTENSION_ID 201
59 union ieee80211_country_ie_triplet
{
64 } __attribute__ ((packed
)) chans
;
66 __u8 reg_extension_id
;
69 } __attribute__ ((packed
)) ext
;
70 } __attribute__ ((packed
));
72 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
74 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
, *ssids
= NULL
;
75 struct nl_msg
*scan_plans
= NULL
;
76 struct nlattr
*match
= NULL
, *plan
= NULL
;
83 } parse_state
= ND_TOPLEVEL
;
85 char *end
, **v
= *argv
;
87 unsigned int freq
, interval
= 0, delay
= 0, iterations
= 0;
88 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
89 bool have_active
= false, have_passive
= false, have_plans
= false;
92 matchset
= nlmsg_alloc();
98 freqs
= nlmsg_alloc();
104 ssids
= nlmsg_alloc();
110 scan_plans
= nlmsg_alloc();
117 switch (parse_state
) {
119 if (!strcmp(v
[0], "interval")) {
123 goto nla_put_failure
;
126 if (interval
|| have_plans
) {
128 goto nla_put_failure
;
130 interval
= strtoul(v
[0], &end
, 10);
131 if (*end
|| !interval
) {
133 goto nla_put_failure
;
136 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
138 } else if (!strcmp(v
[0], "scan_plans")) {
139 parse_state
= ND_PLANS
;
140 if (have_plans
|| interval
) {
142 goto nla_put_failure
;
147 } else if (!strcmp(v
[0], "delay")) {
151 goto nla_put_failure
;
156 goto nla_put_failure
;
158 delay
= strtoul(v
[0], &end
, 10);
161 goto nla_put_failure
;
164 NL80211_ATTR_SCHED_SCAN_DELAY
,
166 } else if (!strcmp(v
[0], "matches")) {
167 parse_state
= ND_MATCH
;
170 goto nla_put_failure
;
174 } else if (!strcmp(v
[0], "freqs")) {
175 parse_state
= ND_FREQS
;
178 goto nla_put_failure
;
183 } else if (!strcmp(v
[0], "active")) {
184 parse_state
= ND_ACTIVE
;
185 if (have_active
|| have_passive
) {
187 goto nla_put_failure
;
192 } else if (!strcmp(v
[0], "passive")) {
193 if (have_active
|| have_passive
) {
195 goto nla_put_failure
;
199 } else if (!strncmp(v
[0], "randomise", 9) ||
200 !strncmp(v
[0], "randomize", 9)) {
201 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
202 err
= parse_random_mac_addr(msg
, v
[0] + 9);
204 goto nla_put_failure
;
205 } else if (!strncmp(v
[0], "coloc", 5)) {
206 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
207 } else if (!strncmp(v
[0], "flush", 5)) {
208 flags
|= NL80211_SCAN_FLAG_FLUSH
;
210 /* this element is not for us, so
211 * return to continue parsing.
213 goto nla_put_failure
;
219 if (!strcmp(v
[0], "ssid")) {
223 goto nla_put_failure
;
226 /* TODO: for now we can only have an
227 * SSID in the match, so we can start
228 * the match nest here.
230 match
= nla_nest_start(matchset
, i
);
233 goto nla_put_failure
;
237 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
239 nla_nest_end(matchset
, match
);
242 have_matchset
= true;
246 /* other element that cannot be part
247 * of a match indicates the end of the
249 /* need at least one match in the matchset */
252 goto nla_put_failure
;
255 parse_state
= ND_TOPLEVEL
;
260 freq
= strtoul(v
[0], &end
, 10);
264 goto nla_put_failure
;
267 parse_state
= ND_TOPLEVEL
;
269 NLA_PUT_U32(freqs
, i
, freq
);
275 if (!strcmp(v
[0], "ssid")) {
279 goto nla_put_failure
;
283 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
290 /* other element that cannot be part
291 * of a match indicates the end of the
293 /* need at least one item in the set */
296 goto nla_put_failure
;
299 parse_state
= ND_TOPLEVEL
;
304 interval
= strtoul(v
[0], &end
, 10);
310 goto nla_put_failure
;
314 iterations
= strtoul(iter
, &end
, 10);
315 if (*end
|| !iterations
) {
317 goto nla_put_failure
;
321 plan
= nla_nest_start(scan_plans
, i
+ 1);
324 goto nla_put_failure
;
327 NLA_PUT_U32(scan_plans
,
328 NL80211_SCHED_SCAN_PLAN_INTERVAL
,
332 NLA_PUT_U32(scan_plans
,
333 NL80211_SCHED_SCAN_PLAN_ITERATIONS
,
336 parse_state
= ND_TOPLEVEL
;
338 nla_nest_end(scan_plans
, plan
);
347 NLA_PUT(ssids
, 1, 0, "");
349 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
351 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
353 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
355 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
357 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
359 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
363 nla_nest_end(msg
, match
);
366 nlmsg_free(matchset
);
367 nlmsg_free(scan_plans
);
375 static int handle_scan(struct nl80211_state
*state
,
377 int argc
, char **argv
,
380 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
394 unsigned int duration
= 0;
395 bool passive
= false, have_ssids
= false, have_freqs
= false;
396 bool duration_mandatory
= false;
397 size_t ies_len
= 0, meshid_len
= 0;
398 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
= NULL
;
399 unsigned int flags
= 0;
401 ssids
= nlmsg_alloc();
405 freqs
= nlmsg_alloc();
411 for (i
= 0; i
< argc
; i
++) {
414 if (strcmp(argv
[i
], "freq") == 0) {
418 } else if (strcmp(argv
[i
], "ies") == 0) {
421 } else if (strcmp(argv
[i
], "lowpri") == 0) {
422 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
424 } else if (strcmp(argv
[i
], "flush") == 0) {
425 flags
|= NL80211_SCAN_FLAG_FLUSH
;
427 } else if (strcmp(argv
[i
], "ap-force") == 0) {
428 flags
|= NL80211_SCAN_FLAG_AP
;
430 } else if (strcmp(argv
[i
], "coloc") == 0) {
431 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
433 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
434 duration_mandatory
= true;
436 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
437 strncmp(argv
[i
], "randomize", 9) == 0) {
438 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
439 err
= parse_random_mac_addr(msg
, argv
[i
] + 9);
441 goto nla_put_failure
;
443 } else if (strcmp(argv
[i
], "ssid") == 0) {
447 } else if (strcmp(argv
[i
], "passive") == 0) {
451 } else if (strcmp(argv
[i
], "meshid") == 0) {
454 } else if (strcmp(argv
[i
], "duration") == 0) {
458 /* fall through - this is an error */
461 goto nla_put_failure
;
463 freq
= strtoul(argv
[i
], &eptr
, 10);
464 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
465 /* failed to parse as number -- maybe a tag? */
470 NLA_PUT_U32(freqs
, i
, freq
);
475 ies
= parse_hex(argv
[i
], &ies_len
);
477 goto nla_put_failure
;
481 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
484 meshid_len
= strlen(argv
[i
]);
485 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
487 goto nla_put_failure
;
488 meshid
[0] = 114; /* mesh element id */
489 meshid
[1] = meshid_len
;
490 memcpy(&meshid
[2], argv
[i
], meshid_len
);
495 duration
= strtoul(argv
[i
], &eptr
, 10);
502 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
504 goto nla_put_failure
;
506 memcpy(tmpies
, ies
, ies_len
);
508 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
509 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0)
510 goto nla_put_failure
;
514 NLA_PUT(ssids
, 1, 0, "");
516 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
519 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
521 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
523 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
525 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
526 if (duration_mandatory
) {
529 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
532 goto nla_put_failure
;
549 static void tab_on_first(bool *first
)
557 struct print_ies_data
{
562 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
563 const struct print_ies_data
*ie_buffer
)
566 print_ssid_escaped(len
, data
);
570 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
571 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
573 static void print_supprates(const uint8_t type
, uint8_t len
,
575 const struct print_ies_data
*ie_buffer
)
581 for (i
= 0; i
< len
; i
++) {
582 int r
= data
[i
] & 0x7f;
584 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
586 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
589 printf("%d.%d", r
/2, 5*(r
&1));
591 printf("%s ", data
[i
] & 0x80 ? "*" : "");
596 static void print_rm_enabled_capabilities(const uint8_t type
, uint8_t len
,
598 const struct print_ies_data
*ie_buffer
)
600 __u64 capa
= ((__u64
) data
[0]) |
601 ((__u64
) data
[1]) << 8 |
602 ((__u64
) data
[2]) << 16 |
603 ((__u64
) data
[3]) << 24 |
604 ((__u64
) data
[4]) << 32;
607 printf("\t\tCapabilities: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
612 #define PRINT_RM_CAPA(_bit, _str) \
614 if (capa & BIT(_bit)) \
615 printf("\t\t\t" _str "\n"); \
618 PRINT_RM_CAPA(0, "Link Measurement");
619 PRINT_RM_CAPA(1, "Neighbor Report");
620 PRINT_RM_CAPA(2, "Parallel Measurements");
621 PRINT_RM_CAPA(3, "Repeated Measurements");
622 PRINT_RM_CAPA(4, "Beacon Passive Measurement");
623 PRINT_RM_CAPA(5, "Beacon Active Measurement");
624 PRINT_RM_CAPA(6, "Beacon Table Measurement");
625 PRINT_RM_CAPA(7, "Beacon Measurement Reporting Conditions");
626 PRINT_RM_CAPA(8, "Frame Measurement");
627 PRINT_RM_CAPA(9, "Channel Load");
628 PRINT_RM_CAPA(10, "Noise Histogram Measurement");
629 PRINT_RM_CAPA(11, "Statistics Measurement");
630 PRINT_RM_CAPA(12, "LCI Measurement");
631 PRINT_RM_CAPA(13, "LCI Azimuth");
632 PRINT_RM_CAPA(14, "Transmit Stream/Category Measurement");
633 PRINT_RM_CAPA(15, "Triggered Transmit Stream/Category");
634 PRINT_RM_CAPA(16, "AP Channel Report");
635 PRINT_RM_CAPA(17, "RM MIB Capability");
637 PRINT_RM_CAPA(27, "Measurement Pilot Transmission Information");
638 PRINT_RM_CAPA(28, "Neighbor Report TSF Offset");
639 PRINT_RM_CAPA(29, "RCPI Measurement");
640 PRINT_RM_CAPA(30, "RSNI Measurement");
641 PRINT_RM_CAPA(31, "BSS Average Access Delay");
642 PRINT_RM_CAPA(32, "BSS Available Admission");
643 PRINT_RM_CAPA(33, "Antenna");
644 PRINT_RM_CAPA(34, "FTM Range Report");
645 PRINT_RM_CAPA(35, "Civic Location Measurement");
647 printf("\t\tNonoperating Channel Max Measurement Duration: %i\n", data
[3] >> 5);
648 printf("\t\tMeasurement Pilot Capability: %i\n", data
[4] & 7);
651 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
652 const struct print_ies_data
*ie_buffer
)
654 printf(" channel %d\n", data
[0]);
657 static const char *country_env_str(char environment
)
659 switch (environment
) {
661 return "Indoor only";
663 return "Outdoor only";
665 return "Indoor/Outdoor";
671 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
672 const struct print_ies_data
*ie_buffer
)
674 printf(" %.*s", 2, data
);
676 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
682 printf("\t\tNo country IE triplets present\n");
688 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
690 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
691 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
692 triplet
->ext
.reg_extension_id
,
693 triplet
->ext
.reg_class
,
694 triplet
->ext
.coverage_class
,
695 triplet
->ext
.coverage_class
* 450);
703 if (triplet
->chans
.first_channel
<= 14)
704 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
706 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
708 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
717 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
719 const struct print_ies_data
*ie_buffer
)
721 printf(" %d dB\n", data
[0]);
724 static void print_tpcreport(const uint8_t type
, uint8_t len
,
726 const struct print_ies_data
*ie_buffer
)
728 printf(" TX power: %d dBm\n", data
[0]);
729 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
732 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
733 const struct print_ies_data
*ie_buffer
)
736 printf(" <no flags>");
738 printf(" NonERP_Present");
740 printf(" Use_Protection");
742 printf(" Barker_Preamble_Mode");
746 static void print_ap_channel_report(const uint8_t type
, uint8_t len
, const uint8_t *data
,
747 const struct print_ies_data
*ie_buffer
)
749 uint8_t oper_class
= data
[0];
753 printf("\t\t * operating class: %d\n", oper_class
);
754 printf("\t\t * channel(s):");
755 for (i
= 1; i
< len
; ++i
) {
756 printf(" %d", data
[i
]);
761 static void print_cipher(const uint8_t *data
)
763 if (memcmp(data
, ms_oui
, 3) == 0) {
766 printf("Use group cipher suite");
781 printf("%.02x-%.02x-%.02x:%d",
782 data
[0], data
[1] ,data
[2], data
[3]);
785 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
788 printf("Use group cipher suite");
803 printf("AES-128-CMAC");
812 printf("%.02x-%.02x-%.02x:%d",
813 data
[0], data
[1] ,data
[2], data
[3]);
817 printf("%.02x-%.02x-%.02x:%d",
818 data
[0], data
[1] ,data
[2], data
[3]);
821 static void print_auth(const uint8_t *data
)
823 if (memcmp(data
, ms_oui
, 3) == 0) {
826 printf("IEEE 802.1X");
832 printf("%.02x-%.02x-%.02x:%d",
833 data
[0], data
[1] ,data
[2], data
[3]);
836 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
839 printf("IEEE 802.1X");
845 printf("FT/IEEE 802.1X");
851 printf("IEEE 802.1X/SHA-256");
854 printf("PSK/SHA-256");
866 printf("IEEE 802.1X/SUITE-B");
869 printf("IEEE 802.1X/SUITE-B-192");
872 printf("FT/IEEE 802.1X/SHA-384");
875 printf("FILS/SHA-256");
878 printf("FILS/SHA-384");
881 printf("FT/FILS/SHA-256");
884 printf("FT/FILS/SHA-384");
890 printf("%.02x-%.02x-%.02x:%d",
891 data
[0], data
[1] ,data
[2], data
[3]);
894 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
903 printf("%.02x-%.02x-%.02x:%d",
904 data
[0], data
[1] ,data
[2], data
[3]);
908 printf("%.02x-%.02x-%.02x:%d",
909 data
[0], data
[1] ,data
[2], data
[3]);
912 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
913 uint8_t len
, const uint8_t *data
, int is_osen
)
921 version
= data
[0] + (data
[1] << 8);
922 tab_on_first(&first
);
923 printf("\t * Version: %d\n", version
);
930 tab_on_first(&first
);
931 printf("\t * Group cipher: %s\n", defcipher
);
932 printf("\t * Pairwise ciphers: %s\n", defcipher
);
936 tab_on_first(&first
);
937 printf("\t * Group cipher: ");
945 tab_on_first(&first
);
946 printf("\t * Pairwise ciphers: %s\n", defcipher
);
950 count
= data
[0] | (data
[1] << 8);
951 if (2 + (count
* 4) > len
)
954 tab_on_first(&first
);
955 printf("\t * Pairwise ciphers:");
956 for (i
= 0; i
< count
; i
++) {
958 print_cipher(data
+ 2 + (i
* 4));
962 data
+= 2 + (count
* 4);
963 len
-= 2 + (count
* 4);
966 tab_on_first(&first
);
967 printf("\t * Authentication suites: %s\n", defauth
);
971 count
= data
[0] | (data
[1] << 8);
972 if (2 + (count
* 4) > len
)
975 tab_on_first(&first
);
976 printf("\t * Authentication suites:");
977 for (i
= 0; i
< count
; i
++) {
979 print_auth(data
+ 2 + (i
* 4));
983 data
+= 2 + (count
* 4);
984 len
-= 2 + (count
* 4);
987 capa
= data
[0] | (data
[1] << 8);
988 tab_on_first(&first
);
989 printf("\t * Capabilities:");
993 printf(" NoPairwise");
994 switch ((capa
& 0x000c) >> 2) {
996 printf(" 1-PTKSA-RC");
999 printf(" 2-PTKSA-RC");
1002 printf(" 4-PTKSA-RC");
1005 printf(" 16-PTKSA-RC");
1008 switch ((capa
& 0x0030) >> 4) {
1010 printf(" 1-GTKSA-RC");
1013 printf(" 2-GTKSA-RC");
1016 printf(" 4-GTKSA-RC");
1019 printf(" 16-GTKSA-RC");
1023 printf(" MFP-required");
1025 printf(" MFP-capable");
1027 printf(" Peerkey-enabled");
1029 printf(" SPP-AMSDU-capable");
1031 printf(" SPP-AMSDU-required");
1033 printf(" Extended-Key-ID");
1034 printf(" (0x%.4x)\n", capa
);
1040 int pmkid_count
= data
[0] | (data
[1] << 8);
1042 if (len
>= 2 + 16 * pmkid_count
) {
1043 tab_on_first(&first
);
1044 printf("\t * %d PMKIDs\n", pmkid_count
);
1045 /* not printing PMKID values */
1046 data
+= 2 + 16 * pmkid_count
;
1047 len
-= 2 + 16 * pmkid_count
;
1053 tab_on_first(&first
);
1054 printf("\t * Group mgmt cipher suite: ");
1063 printf("\t\t * bogus tail data (%d):", len
);
1065 printf(" %.2x", *data
);
1073 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1074 uint8_t len
, const uint8_t *data
)
1076 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1079 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1080 uint8_t len
, const uint8_t *data
)
1083 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1086 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1087 const struct print_ies_data
*ie_buffer
)
1089 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1092 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1093 const struct print_ies_data
*ie_buffer
)
1096 print_ht_capability(data
[0] | (data
[1] << 8));
1097 print_ampdu_length(data
[2] & 3);
1098 print_ampdu_spacing((data
[2] >> 2) & 7);
1099 print_ht_mcs(data
+ 3);
1102 static const char* ntype_11u(uint8_t t
)
1105 case 0: return "Private";
1106 case 1: return "Private with Guest";
1107 case 2: return "Chargeable Public";
1108 case 3: return "Free Public";
1109 case 4: return "Personal Device";
1110 case 5: return "Emergency Services Only";
1111 case 14: return "Test or Experimental";
1112 case 15: return "Wildcard";
1113 default: return "Reserved";
1117 static const char* vgroup_11u(uint8_t t
)
1120 case 0: return "Unspecified";
1121 case 1: return "Assembly";
1122 case 2: return "Business";
1123 case 3: return "Educational";
1124 case 4: return "Factory and Industrial";
1125 case 5: return "Institutional";
1126 case 6: return "Mercantile";
1127 case 7: return "Residential";
1128 case 8: return "Storage";
1129 case 9: return "Utility and Miscellaneous";
1130 case 10: return "Vehicular";
1131 case 11: return "Outdoor";
1132 default: return "Reserved";
1136 static void print_interworking(const uint8_t type
, uint8_t len
,
1137 const uint8_t *data
,
1138 const struct print_ies_data
*ie_buffer
)
1140 /* See Section 7.3.2.92 in the 802.11u spec. */
1143 uint8_t ano
= data
[0];
1144 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1145 printf("\t\t\tNetwork Type: %i (%s)\n",
1146 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1148 printf("\t\t\tInternet\n");
1150 printf("\t\t\tASRA\n");
1152 printf("\t\t\tESR\n");
1154 printf("\t\t\tUESA\n");
1156 if ((len
== 3) || (len
== 9)) {
1157 printf("\t\tVenue Group: %i (%s)\n",
1158 (int)(data
[1]), vgroup_11u(data
[1]));
1159 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1162 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1163 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1165 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1166 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1169 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1170 const uint8_t *data
,
1171 const struct print_ies_data
*ie_buffer
)
1173 /* See Section 7.3.2.93 in the 802.11u spec. */
1174 /* TODO: This code below does not decode private protocol IDs */
1177 while (idx
< (len
- 1)) {
1178 uint8_t qri
= data
[idx
];
1179 uint8_t proto_id
= data
[idx
+ 1];
1180 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1181 printf("\t\t\tQuery Response Length Limit: %i\n",
1184 printf("\t\t\tPAME-BI\n");
1187 printf("\t\t\tANQP\n"); break;
1189 printf("\t\t\tMIH Information Service\n"); break;
1191 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1193 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1195 printf("\t\t\tVendor Specific\n"); break;
1197 printf("\t\t\tReserved: %i\n", proto_id
); break;
1203 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1204 const struct print_ies_data
*ie_buffer
)
1206 /* See Section 7.3.2.96 in the 802.11u spec. */
1208 int ln0
= data
[1] & 0xf;
1209 int ln1
= ((data
[1] & 0xf0) >> 4);
1214 ln2
= len
- 2 - ln0
- ln1
;
1216 printf("\t\tANQP OIs: %i\n", data
[0]);
1219 printf("\t\tOI 1: ");
1220 if (2 + ln0
> len
) {
1221 printf("Invalid IE length.\n");
1223 for (idx
= 0; idx
< ln0
; idx
++) {
1224 printf("%02hhx", data
[2 + idx
]);
1231 printf("\t\tOI 2: ");
1232 if (2 + ln0
+ ln1
> len
) {
1233 printf("Invalid IE length.\n");
1235 for (idx
= 0; idx
< ln1
; idx
++) {
1236 printf("%02hhx", data
[2 + ln0
+ idx
]);
1243 printf("\t\tOI 3: ");
1244 if (2 + ln0
+ ln1
+ ln2
> len
) {
1245 printf("Invalid IE length.\n");
1247 for (idx
= 0; idx
< ln2
; idx
++) {
1248 printf("%02hhx", data
[2 + ln0
+ ln1
+ idx
]);
1255 static void print_tx_power_envelope(const uint8_t type
, uint8_t len
,
1256 const uint8_t *data
,
1257 const struct print_ies_data
*ie_buffer
)
1259 const uint8_t local_max_tx_power_count
= data
[0] & 7;
1260 const uint8_t local_max_tx_power_unit_interp
= (data
[0] >> 3) & 7;
1262 static const char *power_names
[] = {
1263 "Local Maximum Transmit Power For 20 MHz",
1264 "Local Maximum Transmit Power For 40 MHz",
1265 "Local Maximum Transmit Power For 80 MHz",
1266 "Local Maximum Transmit Power For 160/80+80 MHz",
1271 if (local_max_tx_power_count
+ 2 != len
)
1273 if (local_max_tx_power_unit_interp
!= 0)
1275 for (i
= 0; i
< local_max_tx_power_count
+ 1; ++i
) {
1276 int8_t power_val
= ((int8_t)data
[1 + i
]) >> 1;
1277 int8_t point5
= data
[1 + i
] & 1;
1279 printf("\t\t * %s: %i.5 dBm\n", power_names
[i
], power_val
);
1281 printf("\t\t * %s: %i dBm\n", power_names
[i
], power_val
);
1285 static const char *ht_secondary_offset
[4] = {
1292 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1293 const struct print_ies_data
*ie_buffer
)
1295 static const char *protection
[4] = {
1301 static const char *sta_chan_width
[2] = {
1307 printf("\t\t * primary channel: %d\n", data
[0]);
1308 printf("\t\t * secondary channel offset: %s\n",
1309 ht_secondary_offset
[data
[1] & 0x3]);
1310 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1311 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1312 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1313 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1314 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1315 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1316 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1317 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1318 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1319 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1320 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1323 static void print_capabilities(const uint8_t type
, uint8_t len
,
1324 const uint8_t *data
,
1325 const struct print_ies_data
*ie_buffer
)
1327 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1328 bool s_psmp_support
= false, is_vht_cap
= false;
1329 unsigned char *ie
= ie_buffer
->ie
;
1330 int ielen
= ie_buffer
->ielen
;
1332 while (ielen
>= 2 && ielen
>= ie
[1]) {
1341 for (i
= 0; i
< len
; i
++) {
1344 for (bit
= 0; bit
< 8; bit
++) {
1345 if (!(data
[i
] & (1 << bit
)))
1350 #define CAPA(bit, name) case bit: printf(" " name); break
1352 /* if the capability 'cap' exists add 'val' to 'sum'
1353 * otherwise print 'Reserved' */
1354 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1356 printf(" Reserved"); \
1363 switch (bit
+ base
) {
1364 CAPA(0, "HT Information Exchange Supported");
1365 CAPA(1, "reserved (On-demand Beacon)");
1366 CAPA(2, "Extended Channel Switching");
1367 CAPA(3, "reserved (Wave Indication)");
1368 CAPA(4, "PSMP Capability");
1369 CAPA(5, "reserved (Service Interval Granularity)");
1372 s_psmp_support
= true;
1373 printf(" S-PSMP Capability");
1377 CAPA(8, "Diagnostics");
1378 CAPA(9, "Multicast Diagnostics");
1379 CAPA(10, "Location Tracking");
1381 CAPA(12, "Proxy ARP Service");
1382 CAPA(13, "Collocated Interference Reporting");
1383 CAPA(14, "Civic Location");
1384 CAPA(15, "Geospatial Location");
1386 CAPA(17, "WNM-Sleep Mode");
1387 CAPA(18, "TIM Broadcast");
1388 CAPA(19, "BSS Transition");
1389 CAPA(20, "QoS Traffic Capability");
1390 CAPA(21, "AC Station Count");
1391 CAPA(22, "Multiple BSSID");
1392 CAPA(23, "Timing Measurement");
1393 CAPA(24, "Channel Usage");
1394 CAPA(25, "SSID List");
1396 CAPA(27, "UTC TSF Offset");
1397 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1398 CAPA(29, "TDLS Peer PSM Support");
1399 CAPA(30, "TDLS channel switching");
1400 CAPA(31, "Interworking");
1401 CAPA(32, "QoS Map");
1403 CAPA(34, "SSPN Interface");
1404 CAPA(35, "Reserved");
1405 CAPA(36, "MSGCF Capability");
1406 CAPA(37, "TDLS Support");
1407 CAPA(38, "TDLS Prohibited");
1408 CAPA(39, "TDLS Channel Switching Prohibited");
1409 CAPA(40, "Reject Unadmitted Frame");
1411 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1412 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1413 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1415 CAPA(44, "Identifier Location");
1416 CAPA(45, "U-APSD Coexistence");
1417 CAPA(46, "WNM-Notification");
1418 CAPA(47, "Reserved");
1419 CAPA(48, "UTF-8 SSID");
1420 CAPA(49, "QMFActivated");
1421 CAPA(50, "QMFReconfigurationActivated");
1422 CAPA(51, "Robust AV Streaming");
1423 CAPA(52, "Advanced GCR");
1424 CAPA(53, "Mesh GCR");
1426 CAPA(55, "QLoad Report");
1427 CAPA(56, "Alternate EDCA");
1428 CAPA(57, "Unprotected TXOP Negotiation");
1429 CAPA(58, "Protected TXOP egotiation");
1430 CAPA(59, "Reserved");
1431 CAPA(60, "Protected QLoad Report");
1432 CAPA(61, "TDLS Wider Bandwidth");
1433 CAPA(62, "Operating Mode Notification");
1435 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1436 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1438 CAPA(65, "Channel Schedule Management");
1439 CAPA(66, "Geodatabase Inband Enabling Signal");
1440 CAPA(67, "Network Channel Control");
1441 CAPA(68, "White Space Map");
1442 CAPA(69, "Channel Availability Query");
1443 CAPA(70, "FTM Responder");
1444 CAPA(71, "FTM Initiator");
1445 CAPA(72, "Reserved");
1446 CAPA(73, "Extended Spectrum Management Capable");
1447 CAPA(74, "Reserved");
1448 CAPA(77, "TWT Requester Support");
1449 CAPA(78, "TWT Responder Support");
1450 CAPA(79, "OBSS Narrow Bandwith RU in UL OFDMA Tolerance Support");
1453 printf(" %d", bit
+ base
);
1462 printf("\n\t\t * Service Interval Granularity is %d ms",
1463 (si_duration
+ 1) * 5);
1466 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1467 switch (max_amsdu
) {
1469 printf("unlimited");
1488 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1489 const struct print_ies_data
*ie_buffer
)
1491 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1493 data
[0], data
[1], data
[2], data
[3]);
1495 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1499 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1500 const struct print_ies_data
*ie_buffer
)
1502 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1505 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1506 const struct print_ies_data
*ie_buffer
)
1509 print_vht_info((__u32
) data
[0] | ((__u32
)data
[1] << 8) |
1510 ((__u32
)data
[2] << 16) | ((__u32
)data
[3] << 24),
1514 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1515 const struct print_ies_data
*ie_buffer
)
1517 const char *chandwidths
[] = {
1518 [0] = "20 or 40 MHz",
1525 printf("\t\t * channel width: %d (%s)\n", data
[0],
1526 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1527 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1528 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1529 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1532 static void print_supp_op_classes(const uint8_t type
, uint8_t len
,
1533 const uint8_t *data
,
1534 const struct print_ies_data
*ie_buffer
)
1536 uint8_t *p
= (uint8_t*) data
;
1537 const uint8_t *next_data
= p
+ len
;
1538 int zero_delimiter
= 0;
1539 int one_hundred_thirty_delimiter
= 0;
1542 printf("\t\t * current operating class: %d\n", *p
);
1543 while (++p
< next_data
) {
1545 one_hundred_thirty_delimiter
= 1;
1552 printf("\t\t * operating class: %d\n", *p
);
1554 if (one_hundred_thirty_delimiter
)
1555 while (++p
< next_data
) {
1556 printf("\t\t * current operating class extension: %d\n", *p
);
1559 while (++p
< next_data
- 1) {
1560 printf("\t\t * operating class tuple: %d %d\n", p
[0], p
[1]);
1566 static void print_measurement_pilot_tx(const uint8_t type
, uint8_t len
,
1567 const uint8_t *data
,
1568 const struct print_ies_data
*ie_buffer
)
1570 uint8_t *p
, len_remaining
;
1573 printf("\t\t * interval: %d TUs\n", data
[0]);
1578 p
= (uint8_t *) data
+ 1;
1579 len_remaining
= len
- 1;
1581 while (len_remaining
>=5) {
1582 uint8_t subelement_id
= *p
, len
, *end
;
1591 /* 802.11-2016 only allows vendor specific elements */
1592 if (subelement_id
!= 221) {
1593 printf("\t\t * <Invalid subelement ID %d>\n", subelement_id
);
1597 if (len
< 3 || len
> len_remaining
) {
1598 printf(" <Parse error, element too short>\n");
1602 printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1604 /* add only two here and use ++p in while loop */
1608 printf(" %.2x", *p
);
1611 len_remaining
-= len
;
1615 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1616 const uint8_t *data
,
1617 const struct print_ies_data
*ie_buffer
)
1620 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1621 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1622 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1623 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1624 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1625 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1626 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1627 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1630 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1631 const uint8_t *data
,
1632 const struct print_ies_data
*ie_buffer
)
1634 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1635 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1637 printf(" %d\n", data
[0]);
1640 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1641 const struct print_ies_data
*ie_buffer
)
1644 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1645 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1646 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1649 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1650 const uint8_t *data
,
1651 const struct print_ies_data
*ie_buffer
)
1654 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1655 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1656 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1657 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1658 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1659 printf("\t\t * Mesh Formation Info:\n");
1660 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1662 printf("\t\t\t Connected to Mesh Gate\n");
1664 printf("\t\t\t Connected to AS\n");
1665 printf("\t\t * Mesh Capability\n");
1667 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1669 printf("\t\t\t MCCA Supported\n");
1671 printf("\t\t\t MCCA Enabled\n");
1673 printf("\t\t\t Forwarding\n");
1675 printf("\t\t\t MBCA Supported\n");
1677 printf("\t\t\t TBTT Adjusting\n");
1679 printf("\t\t\t Mesh Power Save Level\n");
1682 static void print_s1g_capa(const uint8_t type
, uint8_t len
,
1683 const uint8_t *data
,
1684 const struct print_ies_data
*ie_buffer
)
1687 print_s1g_capability(data
);
1690 static void print_short_beacon_int(const uint8_t type
, uint8_t len
,
1691 const uint8_t *data
,
1692 const struct print_ies_data
*ie_buffer
)
1694 printf(" %d\n", (data
[1] << 8) | data
[0]);
1697 static void print_s1g_oper(const uint8_t type
, uint8_t len
,
1698 const uint8_t *data
,
1699 const struct print_ies_data
*ie_buffer
)
1701 int oper_ch_width
, prim_ch_width
;
1702 int prim_ch_width_subfield
= data
[0] & 0x1;
1706 /* B1-B4 BSS channel width subfield */
1707 switch ((data
[0] >> 1) & 0xf) {
1711 if (!prim_ch_width_subfield
) {
1718 if (prim_ch_width_subfield
)
1723 if (prim_ch_width_subfield
)
1728 if (prim_ch_width_subfield
)
1733 if (prim_ch_width_subfield
)
1743 printf("\t\tChannel width:\n");
1744 if (oper_ch_width
== -1 || prim_ch_width
== -1) {
1745 printf("\t\t\tBSS primary channel width: invalid\n");
1746 printf("\t\t\tBSS operating channel width: invalid\n");
1748 printf("\t\t\tBSS primary channel width: %d MHz\n", prim_ch_width
);
1749 printf("\t\t\tBSS operating channel width: %d MHz\n", oper_ch_width
);
1751 if (data
[0] & BIT(5))
1752 printf("\t\t\t1 MHz primary channel located at the lower side of 2 MHz\n");
1754 printf("\t\t\t1 MHz primary channel located at the upper side of 2 MHz\n");
1756 if (data
[0] & BIT(7))
1757 printf("\t\t\tMCS 10 not recommended\n");
1759 printf("\t\t* operating class: %d\n", data
[1]);
1760 printf("\t\t* primary channel number: %d\n", data
[2]);
1762 printf("\t\t* channel index: %d\n", data
[3]);
1764 printf("\t\tMax S1G MCS Map:\n");
1765 printf("\t\t\tFor 1 SS: %s\n", s1g_ss_max_support((data
[4] >> 2) & 0x3));
1766 printf("\t\t\tFor 2 SS: %s\n", s1g_ss_max_support((data
[4] >> 6) & 0x3));
1767 printf("\t\t\tFor 3 SS: %s\n", s1g_ss_max_support((data
[5] >> 2) & 0x3));
1768 printf("\t\t\tFor 4 SS: %s\n", s1g_ss_max_support((data
[5] >> 6) & 0x3));
1770 printf("\t\tMin S1G MCS Map:\n");
1771 printf("\t\t\tFor 1 SS: %s\n", s1g_ss_min_support(data
[4] & 0x3));
1772 printf("\t\t\tFor 2 SS: %s\n", s1g_ss_min_support((data
[4] >> 4) & 0x3));
1773 printf("\t\t\tFor 3 SS: %s\n", s1g_ss_min_support(data
[5] & 0x3));
1774 printf("\t\t\tFor 4 SS: %s\n", s1g_ss_min_support((data
[5] >> 4) & 0x3));
1779 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1780 const struct print_ies_data
*ie_buffer
);
1781 uint8_t minlen
, maxlen
;
1785 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1786 const uint8_t *data
,
1787 const struct print_ies_data
*ie_buffer
)
1794 printf("\t%s:", p
->name
);
1795 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1797 printf(" <invalid: %d bytes:", len
);
1798 for (i
= 0; i
< len
; i
++)
1799 printf(" %.02x", data
[i
]);
1802 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1804 printf(" <invalid: no data>\n");
1808 p
->print(type
, len
, data
, ie_buffer
);
1811 #define PRINT_IGN { \
1818 static const struct ie_print ieprinters
[] = {
1819 [0] = { "SSID", print_ssid
, 0, 32,
1820 BIT(PRINT_SCAN
) | BIT(PRINT_LINK
) | BIT(PRINT_LINK_MLO_MLD
), },
1821 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1822 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1823 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1824 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1825 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1826 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1827 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1828 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1829 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1830 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1831 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1832 [51] = { "AP Channel Report", print_ap_channel_report
, 1, 255, BIT(PRINT_SCAN
), },
1833 [59] = { "Supported operating classes", print_supp_op_classes
, 1, 255, BIT(PRINT_SCAN
), },
1834 [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx
, 1, 255, BIT(PRINT_SCAN
), },
1835 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1836 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1837 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1838 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1839 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1840 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1841 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1842 [70] = { "RM enabled capabilities", print_rm_enabled_capabilities
, 5, 5, BIT(PRINT_SCAN
), },
1843 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1844 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1845 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1846 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1847 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1848 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 2, 255, BIT(PRINT_SCAN
), },
1849 [195] = { "Transmit Power Envelope", print_tx_power_envelope
, 2, 5, BIT(PRINT_SCAN
), },
1850 [214] = { "Short beacon interval", print_short_beacon_int
, 2, 2, BIT(PRINT_SCAN
), },
1851 [217] = { "S1G capabilities", print_s1g_capa
, 15, 15, BIT(PRINT_SCAN
), },
1852 [232] = { "S1G operation", print_s1g_oper
, 6, 6, BIT(PRINT_SCAN
), },
1855 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1856 const struct print_ies_data
*ie_buffer
)
1858 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1861 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1862 const uint8_t *data
,
1863 const struct print_ies_data
*ie_buffer
)
1865 print_osen_ie("OSEN", "OSEN", len
, data
);
1868 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1871 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1877 printf("Parameter: not version 1: ");
1881 printf("\t * Parameter version 1");
1886 printf("\n\t\t * u-APSD");
1890 for (i
= 0; i
< 4; i
++) {
1891 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1894 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1895 (1 << (data
[1] >> 4)) - 1);
1896 printf(", AIFSN %d", data
[0] & 0xf);
1897 if (data
[2] | data
[3])
1898 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1906 printf("invalid: ");
1910 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1911 const struct print_ies_data
*ie_buffer
)
1917 printf(" information:");
1920 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1924 printf(" type %d:", data
[0]);
1928 for(i
= 1; i
< len
; i
++)
1929 printf(" %.02x", data
[i
]);
1933 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1937 return "Default (PIN)";
1939 return "User-specified";
1941 return "Machine-specified";
1945 return "PushButton";
1947 return "Registrar-specified";
1953 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1954 const struct print_ies_data
*ie_buffer
)
1957 __u16 subtype
, sublen
;
1960 subtype
= (data
[0] << 8) + data
[1];
1961 sublen
= (data
[2] << 8) + data
[3];
1962 if (sublen
> len
- 4)
1967 tab_on_first(&first
);
1969 printf("\t * Version: (invalid "
1970 "length %d)\n", sublen
);
1973 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1976 tab_on_first(&first
);
1977 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1981 tab_on_first(&first
);
1983 printf("\t * Device Password ID: (invalid length %d)\n",
1987 id
= data
[4] << 8 | data
[5];
1988 printf("\t * Device Password ID: %u (%s)\n",
1989 id
, wifi_wps_dev_passwd_id(id
));
1993 tab_on_first(&first
);
1994 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1997 tab_on_first(&first
);
1998 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
2001 tab_on_first(&first
);
2002 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
2008 printf("\t * Response Type: (invalid length %d)\n",
2013 tab_on_first(&first
);
2014 printf("\t * Response Type: %d%s\n",
2015 val
, val
== 3 ? " (AP)" : "");
2022 printf("\t * RF Bands: (invalid length %d)\n",
2027 tab_on_first(&first
);
2028 printf("\t * RF Bands: 0x%x\n", val
);
2035 printf("\t * Selected Registrar: (invalid length %d)\n",
2040 tab_on_first(&first
);
2041 printf("\t * Selected Registrar: 0x%x\n", val
);
2045 tab_on_first(&first
);
2046 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
2052 printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
2057 tab_on_first(&first
);
2058 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
2060 val
== 1 ? " (Unconfigured)" : "",
2061 val
== 2 ? " (Configured)" : "");
2065 tab_on_first(&first
);
2066 printf("\t * UUID: ");
2068 printf("(invalid, length=%d)\n", sublen
);
2071 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
2072 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
2073 data
[4], data
[5], data
[6], data
[7],
2074 data
[8], data
[9], data
[10], data
[11],
2075 data
[12], data
[13], data
[14], data
[15],
2076 data
[16], data
[17], data
[18], data
[19]);
2079 tab_on_first(&first
);
2086 uint8_t v2
= data
[9];
2087 printf("\t * Version2: %d.%d\n", v2
>> 4, v2
& 0xf);
2089 printf("\t * Unknown vendor extension. len=%u\n",
2094 tab_on_first(&first
);
2096 printf("\t * Primary Device Type: (invalid length %d)\n",
2100 printf("\t * Primary Device Type: "
2101 "%u-%02x%02x%02x%02x-%u\n",
2102 data
[4] << 8 | data
[5],
2103 data
[6], data
[7], data
[8], data
[9],
2104 data
[10] << 8 | data
[11]);
2109 tab_on_first(&first
);
2111 printf("\t * AP setup locked: (invalid length %d)\n",
2116 printf("\t * AP setup locked: 0x%.2x\n", val
);
2125 printf("\t * Config methods: (invalid length %d)\n",
2129 meth
= (data
[4] << 8) + data
[5];
2131 tab_on_first(&first
);
2132 printf("\t * %sConfig methods:",
2133 subtype
== 0x1053 ? "Selected Registrar ": "");
2134 #define T(bit, name) do { \
2135 if (meth & (1<<bit)) { \
2155 const __u8
*subdata
= data
+ 4;
2156 __u16 tmplen
= sublen
;
2158 tab_on_first(&first
);
2159 printf("\t * Unknown TLV (%#.4x, %d bytes):",
2162 printf(" %.2x", *subdata
);
2176 printf("\t\t * bogus tail data (%d):", len
);
2178 printf(" %.2x", *data
);
2186 static const struct ie_print wifiprinters
[] = {
2187 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
2188 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
2189 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
2192 static inline void print_p2p(const uint8_t type
, uint8_t len
,
2193 const uint8_t *data
,
2194 const struct print_ies_data
*ie_buffer
)
2202 sublen
= (data
[2] << 8) + data
[1];
2204 if (sublen
> len
- 3)
2208 case 0x02: /* capability */
2209 tab_on_first(&first
);
2211 printf("\t * malformed capability\n");
2214 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2217 case 0x0d: /* device info */
2218 if (sublen
< 6 + 2 + 8 + 1) {
2219 printf("\t * malformed device info\n");
2223 case 0x00: /* status */
2224 case 0x01: /* minor reason */
2225 case 0x03: /* device ID */
2226 case 0x04: /* GO intent */
2227 case 0x05: /* configuration timeout */
2228 case 0x06: /* listen channel */
2229 case 0x07: /* group BSSID */
2230 case 0x08: /* ext listen timing */
2231 case 0x09: /* intended interface address */
2232 case 0x0a: /* manageability */
2233 case 0x0b: /* channel list */
2234 case 0x0c: /* NoA */
2235 case 0x0e: /* group info */
2236 case 0x0f: /* group ID */
2237 case 0x10: /* interface */
2238 case 0x11: /* operating channel */
2239 case 0x12: /* invitation flags */
2240 case 0xdd: /* vendor specific */
2242 const __u8
*subdata
= data
+ 3;
2243 __u16 tmplen
= sublen
;
2245 tab_on_first(&first
);
2246 printf("\t * Unknown TLV (%#.2x, %d bytes):",
2249 printf(" %.2x", *subdata
);
2263 tab_on_first(&first
);
2264 printf("\t * bogus tail data (%d):", len
);
2266 printf(" %.2x", *data
);
2274 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
2275 const uint8_t *data
,
2276 const struct print_ies_data
*ie_buffer
)
2278 /* I can't find the spec for this...just going off what wireshark uses. */
2281 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
2283 printf("\t\tUnexpected length: %i\n", len
);
2286 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
2287 const uint8_t *data
,
2288 const struct print_ies_data
*ie_buffer
)
2297 mac_addr_n2a(mac_addr
, data
);
2298 printf("\t\tBSSID: %s\n", mac_addr
);
2301 if (ssid_len
> len
- 7)
2303 printf("\t\tSSID: ");
2304 print_ssid_escaped(ssid_len
, data
+ 7);
2307 /* optional elements */
2308 if (len
>= ssid_len
+ 9) {
2309 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
2310 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
2314 static const struct ie_print wfa_printers
[] = {
2315 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
2316 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
2317 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
2318 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
2321 static void print_vendor(unsigned char len
, unsigned char *data
,
2322 bool unknown
, enum print_ie_type ptype
)
2327 printf("\tVendor specific: <too short> data:");
2328 for(i
= 0; i
< len
; i
++)
2329 printf(" %.02x", data
[i
]);
2334 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2335 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2336 wifiprinters
[data
[3]].name
&&
2337 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2338 print_ie(&wifiprinters
[data
[3]],
2339 data
[3], len
- 4, data
+ 4,
2345 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2346 for(i
= 0; i
< len
- 4; i
++)
2347 printf(" %.02x", data
[i
+ 4]);
2352 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2353 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2354 wfa_printers
[data
[3]].name
&&
2355 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2356 print_ie(&wfa_printers
[data
[3]],
2357 data
[3], len
- 4, data
+ 4,
2363 printf("\tWFA %#.2x, data:", data
[3]);
2364 for(i
= 0; i
< len
- 4; i
++)
2365 printf(" %.02x", data
[i
+ 4]);
2373 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2374 data
[0], data
[1], data
[2]);
2375 for (i
= 3; i
< len
; i
++)
2376 printf(" %.2x", data
[i
]);
2380 static void print_he_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
2381 const struct print_ies_data
*ie_buffer
)
2384 print_he_capability(data
, len
);
2387 static const struct ie_print ext_printers
[] = {
2388 [35] = { "HE capabilities", print_he_capa
, 21, 54, BIT(PRINT_SCAN
), },
2391 static void print_extension(unsigned char len
, unsigned char *ie
,
2392 bool unknown
, enum print_ie_type ptype
)
2397 printf("\tExtension IE: <empty>\n");
2402 if (tag
< ARRAY_SIZE(ext_printers
) && ext_printers
[tag
].name
&&
2403 ext_printers
[tag
].flags
& BIT(ptype
)) {
2404 print_ie(&ext_printers
[tag
], tag
, len
- 1, ie
+ 1, NULL
);
2411 printf("\tUnknown Extension ID (%d):", ie
[0]);
2412 for (i
= 1; i
< len
; i
++)
2413 printf(" %.2x", ie
[i
]);
2418 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2419 enum print_ie_type ptype
)
2421 struct print_ies_data ie_buffer
= {
2425 if (ie
== NULL
|| ielen
< 0)
2428 while (ielen
>= 2 && ielen
- 2 >= ie
[1]) {
2429 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2430 ieprinters
[ie
[0]].name
&&
2431 ieprinters
[ie
[0]].flags
& BIT(ptype
) &&
2433 print_ie(&ieprinters
[ie
[0]],
2434 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2435 } else if (ie
[0] == 221 /* vendor */) {
2436 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2437 } else if (ie
[0] == 255 /* extension */) {
2438 print_extension(ie
[1], ie
+ 2, unknown
, ptype
);
2439 } else if (unknown
) {
2442 printf("\tUnknown IE (%d):", ie
[0]);
2443 for (i
=0; i
<ie
[1]; i
++)
2444 printf(" %.2x", ie
[2+i
]);
2452 static void print_capa_dmg(__u16 capa
)
2454 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2455 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2458 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2461 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2462 printf(" DMG_IBSS");
2466 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2467 printf(" CBAP_Only");
2468 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2469 printf(" CBAP_Src");
2470 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2472 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2474 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2475 printf(" SpectrumMgmt");
2476 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2477 printf(" RadioMeasure");
2480 static void print_capa_non_dmg(__u16 capa
)
2482 if (capa
& WLAN_CAPABILITY_ESS
)
2484 if (capa
& WLAN_CAPABILITY_IBSS
)
2486 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2487 printf(" CfPollable");
2488 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2489 printf(" CfPollReq");
2490 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2492 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2493 printf(" ShortPreamble");
2494 if (capa
& WLAN_CAPABILITY_PBCC
)
2496 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2497 printf(" ChannelAgility");
2498 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2499 printf(" SpectrumMgmt");
2500 if (capa
& WLAN_CAPABILITY_QOS
)
2502 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2503 printf(" ShortSlotTime");
2504 if (capa
& WLAN_CAPABILITY_APSD
)
2506 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2507 printf(" RadioMeasure");
2508 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2509 printf(" DSSS-OFDM");
2510 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2511 printf(" DelayedBACK");
2512 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2513 printf(" ImmediateBACK");
2516 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2518 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2519 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2520 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2521 char mac_addr
[20], dev
[20];
2522 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2523 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2524 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2525 [NL80211_BSS_FREQUENCY_OFFSET
] = { .type
= NLA_U32
},
2526 [NL80211_BSS_BSSID
] = { },
2527 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2528 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2529 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2530 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2531 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2532 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2533 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2534 [NL80211_BSS_BEACON_IES
] = { },
2536 struct scan_params
*params
= arg
;
2537 int show
= params
->show_both_ie_sets
? 2 : 1;
2538 bool is_dmg
= false;
2540 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2541 genlmsg_attrlen(gnlh
, 0), NULL
);
2543 if (!tb
[NL80211_ATTR_BSS
]) {
2544 fprintf(stderr
, "bss info missing!\n");
2547 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2548 tb
[NL80211_ATTR_BSS
],
2550 fprintf(stderr
, "failed to parse nested attributes!\n");
2554 if (!bss
[NL80211_BSS_BSSID
])
2557 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2558 printf("BSS %s", mac_addr
);
2559 if (tb
[NL80211_ATTR_IFINDEX
]) {
2560 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2561 printf("(on %s)", dev
);
2564 if (bss
[NL80211_BSS_STATUS
]) {
2565 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2566 case NL80211_BSS_STATUS_AUTHENTICATED
:
2567 printf(" -- authenticated");
2569 case NL80211_BSS_STATUS_ASSOCIATED
:
2570 printf(" -- associated");
2572 case NL80211_BSS_STATUS_IBSS_JOINED
:
2573 printf(" -- joined");
2576 printf(" -- unknown status: %d",
2577 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2583 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2584 unsigned long long bt
;
2585 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2586 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2589 if (bss
[NL80211_BSS_TSF
]) {
2590 unsigned long long tsf
;
2591 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2592 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2593 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2594 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2596 if (bss
[NL80211_BSS_FREQUENCY
]) {
2597 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2598 if (bss
[NL80211_BSS_FREQUENCY_OFFSET
])
2599 printf("\tfreq: %d.%d\n", freq
,
2600 nla_get_u32(bss
[NL80211_BSS_FREQUENCY_OFFSET
]));
2602 printf("\tfreq: %d\n", freq
);
2607 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2608 printf("\tbeacon interval: %d TUs\n",
2609 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2610 if (bss
[NL80211_BSS_CAPABILITY
]) {
2611 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2612 printf("\tcapability:");
2614 print_capa_dmg(capa
);
2616 print_capa_non_dmg(capa
);
2617 printf(" (0x%.4x)\n", capa
);
2619 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2620 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2621 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2623 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2624 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2625 printf("\tsignal: %d/100\n", s
);
2627 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2628 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2629 printf("\tlast seen: %d ms ago\n", age
);
2632 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2633 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2634 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2636 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2637 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2638 memcmp(nla_data(ies
), nla_data(bcnies
),
2640 printf("\tInformation elements from Probe Response "
2642 print_ies(nla_data(ies
), nla_len(ies
),
2643 params
->unknown
, params
->type
);
2645 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2646 printf("\tInformation elements from Beacon frame:\n");
2647 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2648 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2649 params
->unknown
, params
->type
);
2655 static struct scan_params scan_params
;
2657 static int handle_scan_dump(struct nl80211_state
*state
,
2659 int argc
, char **argv
,
2665 memset(&scan_params
, 0, sizeof(scan_params
));
2667 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2668 scan_params
.unknown
= true;
2669 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2670 scan_params
.show_both_ie_sets
= true;
2672 scan_params
.type
= PRINT_SCAN
;
2674 register_handler(print_bss_handler
, &scan_params
);
2678 static int handle_scan_combined(struct nl80211_state
*state
,
2680 int argc
, char **argv
,
2684 static char *dump_argv
[] = {
2690 static const __u32 cmds
[] = {
2691 NL80211_CMD_NEW_SCAN_RESULTS
,
2692 NL80211_CMD_SCAN_ABORTED
,
2694 int trig_argc
, dump_argc
, err
;
2697 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2699 dump_argv
[3] = "-u";
2700 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2702 dump_argv
[3] = "-b";
2706 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2707 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2710 trig_argv
[0] = argv
[0];
2711 trig_argv
[1] = "scan";
2712 trig_argv
[2] = "trigger";
2714 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2715 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2716 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2722 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2724 * This code has a bug, which requires creating a separate
2725 * nl80211 socket to fix:
2726 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2727 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2728 * before (!) we listen to it, because we only start listening
2729 * after we send our scan request.
2731 * Doing it the other way around has a race condition as well,
2732 * if you first open the events socket you may get a notification
2733 * for a previous scan.
2735 * The only proper way to fix this would be to listen to events
2736 * before sending the command, and for the kernel to send the
2737 * scan request along with the event, so that you can match up
2738 * whether the scan you requested was finished or aborted (this
2739 * may result in processing a scan that another application
2740 * requested, but that doesn't seem to be a problem).
2742 * Alas, the kernel doesn't do that (yet).
2745 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2746 NL80211_CMD_SCAN_ABORTED
) {
2747 printf("scan aborted!\n");
2751 dump_argv
[0] = argv
[0];
2752 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2754 TOPLEVEL(scan
, "[-u] [freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2755 CIB_NETDEV
, handle_scan_combined
,
2756 "Scan on the given frequencies and probe for the given SSIDs\n"
2757 "(or wildcard if not given) unless passive scanning is requested.\n"
2758 "If -u is specified print unknown data in the scan results.\n"
2759 "Specified (vendor) IEs must be well-formed.");
2760 COMMAND(scan
, dump
, "[-u]",
2761 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2762 "Dump the current scan results. If -u is specified, print unknown\n"
2763 "data in scan results.");
2764 COMMAND(scan
, trigger
, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory,coloc] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2765 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2766 "Trigger a scan on the given frequencies with probing for the given\n"
2767 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2768 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2771 static int handle_scan_abort(struct nl80211_state
*state
,
2773 int argc
, char **argv
,
2778 COMMAND(scan
, abort
, "",
2779 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2780 "Abort ongoing scan");
2782 static int handle_start_sched_scan(struct nl80211_state
*state
,
2784 int argc
, char **argv
, enum id_input id
)
2786 return parse_sched_scan(msg
, &argc
, &argv
);
2789 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2790 struct nl_msg
*msg
, int argc
, char **argv
,
2799 COMMAND(scan
, sched_start
,
2801 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2802 "Start a scheduled scan at the specified interval on the given frequencies\n"
2803 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2804 "scanning is requested. If matches are specified, only matching results\n"
2805 "will be returned.");
2806 COMMAND(scan
, sched_stop
, "",
2807 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2808 "Stop an ongoing scheduled scan.");