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 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
355 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
357 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
361 nla_nest_end(msg
, match
);
364 nlmsg_free(matchset
);
365 nlmsg_free(scan_plans
);
373 static int handle_scan(struct nl80211_state
*state
,
375 int argc
, char **argv
,
378 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
392 unsigned int duration
= 0;
393 bool passive
= false, have_ssids
= false, have_freqs
= false;
394 bool duration_mandatory
= false;
395 size_t ies_len
= 0, meshid_len
= 0;
396 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
= NULL
;
397 unsigned int flags
= 0;
399 ssids
= nlmsg_alloc();
403 freqs
= nlmsg_alloc();
409 for (i
= 0; i
< argc
; i
++) {
412 if (strcmp(argv
[i
], "freq") == 0) {
416 } else if (strcmp(argv
[i
], "ies") == 0) {
419 } else if (strcmp(argv
[i
], "lowpri") == 0) {
420 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
422 } else if (strcmp(argv
[i
], "flush") == 0) {
423 flags
|= NL80211_SCAN_FLAG_FLUSH
;
425 } else if (strcmp(argv
[i
], "ap-force") == 0) {
426 flags
|= NL80211_SCAN_FLAG_AP
;
428 } else if (strcmp(argv
[i
], "coloc") == 0) {
429 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
431 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
432 duration_mandatory
= true;
434 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
435 strncmp(argv
[i
], "randomize", 9) == 0) {
436 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
437 err
= parse_random_mac_addr(msg
, argv
[i
] + 9);
439 goto nla_put_failure
;
441 } else if (strcmp(argv
[i
], "ssid") == 0) {
445 } else if (strcmp(argv
[i
], "passive") == 0) {
449 } else if (strcmp(argv
[i
], "meshid") == 0) {
452 } else if (strcmp(argv
[i
], "duration") == 0) {
456 /* fall through - this is an error */
459 goto nla_put_failure
;
461 freq
= strtoul(argv
[i
], &eptr
, 10);
462 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
463 /* failed to parse as number -- maybe a tag? */
468 NLA_PUT_U32(freqs
, i
, freq
);
473 ies
= parse_hex(argv
[i
], &ies_len
);
475 goto nla_put_failure
;
479 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
482 meshid_len
= strlen(argv
[i
]);
483 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
485 goto nla_put_failure
;
486 meshid
[0] = 114; /* mesh element id */
487 meshid
[1] = meshid_len
;
488 memcpy(&meshid
[2], argv
[i
], meshid_len
);
493 duration
= strtoul(argv
[i
], &eptr
, 10);
500 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
502 goto nla_put_failure
;
504 memcpy(tmpies
, ies
, ies_len
);
506 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
507 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0)
508 goto nla_put_failure
;
512 NLA_PUT(ssids
, 1, 0, "");
514 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
517 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
519 flags
|= NL80211_SCAN_FLAG_COLOCATED_6GHZ
;
521 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
523 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
524 if (duration_mandatory
) {
527 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
530 goto nla_put_failure
;
547 static void tab_on_first(bool *first
)
555 struct print_ies_data
{
560 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
561 const struct print_ies_data
*ie_buffer
)
564 print_ssid_escaped(len
, data
);
568 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
569 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
571 static void print_supprates(const uint8_t type
, uint8_t len
,
573 const struct print_ies_data
*ie_buffer
)
579 for (i
= 0; i
< len
; i
++) {
580 int r
= data
[i
] & 0x7f;
582 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
584 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
587 printf("%d.%d", r
/2, 5*(r
&1));
589 printf("%s ", data
[i
] & 0x80 ? "*" : "");
594 static void print_rm_enabled_capabilities(const uint8_t type
, uint8_t len
,
596 const struct print_ies_data
*ie_buffer
)
598 __u64 capa
= ((__u64
) data
[0]) |
599 ((__u64
) data
[1]) << 8 |
600 ((__u64
) data
[2]) << 16 |
601 ((__u64
) data
[3]) << 24 |
602 ((__u64
) data
[4]) << 32;
605 printf("\t\tCapabilities: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
610 #define PRINT_RM_CAPA(_bit, _str) \
612 if (capa & BIT(_bit)) \
613 printf("\t\t\t" _str "\n"); \
616 PRINT_RM_CAPA(0, "Link Measurement");
617 PRINT_RM_CAPA(1, "Neighbor Report");
618 PRINT_RM_CAPA(2, "Parallel Measurements");
619 PRINT_RM_CAPA(3, "Repeated Measurements");
620 PRINT_RM_CAPA(4, "Beacon Passive Measurement");
621 PRINT_RM_CAPA(5, "Beacon Active Measurement");
622 PRINT_RM_CAPA(6, "Beacon Table Measurement");
623 PRINT_RM_CAPA(7, "Beacon Measurement Reporting Conditions");
624 PRINT_RM_CAPA(8, "Frame Measurement");
625 PRINT_RM_CAPA(9, "Channel Load");
626 PRINT_RM_CAPA(10, "Noise Histogram Measurement");
627 PRINT_RM_CAPA(11, "Statistics Measurement");
628 PRINT_RM_CAPA(12, "LCI Measurement");
629 PRINT_RM_CAPA(13, "LCI Azimuth");
630 PRINT_RM_CAPA(14, "Transmit Stream/Category Measurement");
631 PRINT_RM_CAPA(15, "Triggered Transmit Stream/Category");
632 PRINT_RM_CAPA(16, "AP Channel Report");
633 PRINT_RM_CAPA(17, "RM MIB Capability");
635 PRINT_RM_CAPA(27, "Measurement Pilot Transmission Information");
636 PRINT_RM_CAPA(28, "Neighbor Report TSF Offset");
637 PRINT_RM_CAPA(29, "RCPI Measurement");
638 PRINT_RM_CAPA(30, "RSNI Measurement");
639 PRINT_RM_CAPA(31, "BSS Average Access Delay");
640 PRINT_RM_CAPA(32, "BSS Available Admission");
641 PRINT_RM_CAPA(33, "Antenna");
642 PRINT_RM_CAPA(34, "FTM Range Report");
643 PRINT_RM_CAPA(35, "Civic Location Measurement");
645 printf("\t\tNonoperating Channel Max Measurement Duration: %i\n", data
[3] >> 5);
646 printf("\t\tMeasurement Pilot Capability: %i\n", data
[4] & 7);
649 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
650 const struct print_ies_data
*ie_buffer
)
652 printf(" channel %d\n", data
[0]);
655 static const char *country_env_str(char environment
)
657 switch (environment
) {
659 return "Indoor only";
661 return "Outdoor only";
663 return "Indoor/Outdoor";
669 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
670 const struct print_ies_data
*ie_buffer
)
672 printf(" %.*s", 2, data
);
674 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
680 printf("\t\tNo country IE triplets present\n");
686 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
688 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
689 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
690 triplet
->ext
.reg_extension_id
,
691 triplet
->ext
.reg_class
,
692 triplet
->ext
.coverage_class
,
693 triplet
->ext
.coverage_class
* 450);
701 if (triplet
->chans
.first_channel
<= 14)
702 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
704 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
706 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
715 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
717 const struct print_ies_data
*ie_buffer
)
719 printf(" %d dB\n", data
[0]);
722 static void print_tpcreport(const uint8_t type
, uint8_t len
,
724 const struct print_ies_data
*ie_buffer
)
726 printf(" TX power: %d dBm\n", data
[0]);
727 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
730 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
731 const struct print_ies_data
*ie_buffer
)
734 printf(" <no flags>");
736 printf(" NonERP_Present");
738 printf(" Use_Protection");
740 printf(" Barker_Preamble_Mode");
744 static void print_ap_channel_report(const uint8_t type
, uint8_t len
, const uint8_t *data
,
745 const struct print_ies_data
*ie_buffer
)
747 uint8_t oper_class
= data
[0];
751 printf("\t\t * operating class: %d\n", oper_class
);
752 printf("\t\t * channel(s):");
753 for (i
= 1; i
< len
; ++i
) {
754 printf(" %d", data
[i
]);
759 static void print_cipher(const uint8_t *data
)
761 if (memcmp(data
, ms_oui
, 3) == 0) {
764 printf("Use group cipher suite");
779 printf("%.02x-%.02x-%.02x:%d",
780 data
[0], data
[1] ,data
[2], data
[3]);
783 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
786 printf("Use group cipher suite");
801 printf("AES-128-CMAC");
810 printf("%.02x-%.02x-%.02x:%d",
811 data
[0], data
[1] ,data
[2], data
[3]);
815 printf("%.02x-%.02x-%.02x:%d",
816 data
[0], data
[1] ,data
[2], data
[3]);
819 static void print_auth(const uint8_t *data
)
821 if (memcmp(data
, ms_oui
, 3) == 0) {
824 printf("IEEE 802.1X");
830 printf("%.02x-%.02x-%.02x:%d",
831 data
[0], data
[1] ,data
[2], data
[3]);
834 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
837 printf("IEEE 802.1X");
843 printf("FT/IEEE 802.1X");
849 printf("IEEE 802.1X/SHA-256");
852 printf("PSK/SHA-256");
864 printf("IEEE 802.1X/SUITE-B");
867 printf("IEEE 802.1X/SUITE-B-192");
870 printf("FT/IEEE 802.1X/SHA-384");
873 printf("FILS/SHA-256");
876 printf("FILS/SHA-384");
879 printf("FT/FILS/SHA-256");
882 printf("FT/FILS/SHA-384");
888 printf("%.02x-%.02x-%.02x:%d",
889 data
[0], data
[1] ,data
[2], data
[3]);
892 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
901 printf("%.02x-%.02x-%.02x:%d",
902 data
[0], data
[1] ,data
[2], data
[3]);
906 printf("%.02x-%.02x-%.02x:%d",
907 data
[0], data
[1] ,data
[2], data
[3]);
910 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
911 uint8_t len
, const uint8_t *data
, int is_osen
)
919 version
= data
[0] + (data
[1] << 8);
920 tab_on_first(&first
);
921 printf("\t * Version: %d\n", version
);
928 tab_on_first(&first
);
929 printf("\t * Group cipher: %s\n", defcipher
);
930 printf("\t * Pairwise ciphers: %s\n", defcipher
);
934 tab_on_first(&first
);
935 printf("\t * Group cipher: ");
943 tab_on_first(&first
);
944 printf("\t * Pairwise ciphers: %s\n", defcipher
);
948 count
= data
[0] | (data
[1] << 8);
949 if (2 + (count
* 4) > len
)
952 tab_on_first(&first
);
953 printf("\t * Pairwise ciphers:");
954 for (i
= 0; i
< count
; i
++) {
956 print_cipher(data
+ 2 + (i
* 4));
960 data
+= 2 + (count
* 4);
961 len
-= 2 + (count
* 4);
964 tab_on_first(&first
);
965 printf("\t * Authentication suites: %s\n", defauth
);
969 count
= data
[0] | (data
[1] << 8);
970 if (2 + (count
* 4) > len
)
973 tab_on_first(&first
);
974 printf("\t * Authentication suites:");
975 for (i
= 0; i
< count
; i
++) {
977 print_auth(data
+ 2 + (i
* 4));
981 data
+= 2 + (count
* 4);
982 len
-= 2 + (count
* 4);
985 capa
= data
[0] | (data
[1] << 8);
986 tab_on_first(&first
);
987 printf("\t * Capabilities:");
991 printf(" NoPairwise");
992 switch ((capa
& 0x000c) >> 2) {
994 printf(" 1-PTKSA-RC");
997 printf(" 2-PTKSA-RC");
1000 printf(" 4-PTKSA-RC");
1003 printf(" 16-PTKSA-RC");
1006 switch ((capa
& 0x0030) >> 4) {
1008 printf(" 1-GTKSA-RC");
1011 printf(" 2-GTKSA-RC");
1014 printf(" 4-GTKSA-RC");
1017 printf(" 16-GTKSA-RC");
1021 printf(" MFP-required");
1023 printf(" MFP-capable");
1025 printf(" Peerkey-enabled");
1027 printf(" SPP-AMSDU-capable");
1029 printf(" SPP-AMSDU-required");
1031 printf(" Extended-Key-ID");
1032 printf(" (0x%.4x)\n", capa
);
1038 int pmkid_count
= data
[0] | (data
[1] << 8);
1040 if (len
>= 2 + 16 * pmkid_count
) {
1041 tab_on_first(&first
);
1042 printf("\t * %d PMKIDs\n", pmkid_count
);
1043 /* not printing PMKID values */
1044 data
+= 2 + 16 * pmkid_count
;
1045 len
-= 2 + 16 * pmkid_count
;
1051 tab_on_first(&first
);
1052 printf("\t * Group mgmt cipher suite: ");
1061 printf("\t\t * bogus tail data (%d):", len
);
1063 printf(" %.2x", *data
);
1071 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
1072 uint8_t len
, const uint8_t *data
)
1074 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
1077 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1078 uint8_t len
, const uint8_t *data
)
1081 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1084 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1085 const struct print_ies_data
*ie_buffer
)
1087 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1090 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1091 const struct print_ies_data
*ie_buffer
)
1094 print_ht_capability(data
[0] | (data
[1] << 8));
1095 print_ampdu_length(data
[2] & 3);
1096 print_ampdu_spacing((data
[2] >> 2) & 7);
1097 print_ht_mcs(data
+ 3);
1100 static const char* ntype_11u(uint8_t t
)
1103 case 0: return "Private";
1104 case 1: return "Private with Guest";
1105 case 2: return "Chargeable Public";
1106 case 3: return "Free Public";
1107 case 4: return "Personal Device";
1108 case 5: return "Emergency Services Only";
1109 case 14: return "Test or Experimental";
1110 case 15: return "Wildcard";
1111 default: return "Reserved";
1115 static const char* vgroup_11u(uint8_t t
)
1118 case 0: return "Unspecified";
1119 case 1: return "Assembly";
1120 case 2: return "Business";
1121 case 3: return "Educational";
1122 case 4: return "Factory and Industrial";
1123 case 5: return "Institutional";
1124 case 6: return "Mercantile";
1125 case 7: return "Residential";
1126 case 8: return "Storage";
1127 case 9: return "Utility and Miscellaneous";
1128 case 10: return "Vehicular";
1129 case 11: return "Outdoor";
1130 default: return "Reserved";
1134 static void print_interworking(const uint8_t type
, uint8_t len
,
1135 const uint8_t *data
,
1136 const struct print_ies_data
*ie_buffer
)
1138 /* See Section 7.3.2.92 in the 802.11u spec. */
1141 uint8_t ano
= data
[0];
1142 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1143 printf("\t\t\tNetwork Type: %i (%s)\n",
1144 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1146 printf("\t\t\tInternet\n");
1148 printf("\t\t\tASRA\n");
1150 printf("\t\t\tESR\n");
1152 printf("\t\t\tUESA\n");
1154 if ((len
== 3) || (len
== 9)) {
1155 printf("\t\tVenue Group: %i (%s)\n",
1156 (int)(data
[1]), vgroup_11u(data
[1]));
1157 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1160 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1161 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1163 printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1164 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1167 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1168 const uint8_t *data
,
1169 const struct print_ies_data
*ie_buffer
)
1171 /* See Section 7.3.2.93 in the 802.11u spec. */
1172 /* TODO: This code below does not decode private protocol IDs */
1175 while (idx
< (len
- 1)) {
1176 uint8_t qri
= data
[idx
];
1177 uint8_t proto_id
= data
[idx
+ 1];
1178 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1179 printf("\t\t\tQuery Response Length Limit: %i\n",
1182 printf("\t\t\tPAME-BI\n");
1185 printf("\t\t\tANQP\n"); break;
1187 printf("\t\t\tMIH Information Service\n"); break;
1189 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1191 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1193 printf("\t\t\tVendor Specific\n"); break;
1195 printf("\t\t\tReserved: %i\n", proto_id
); break;
1201 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1202 const struct print_ies_data
*ie_buffer
)
1204 /* See Section 7.3.2.96 in the 802.11u spec. */
1206 int ln0
= data
[1] & 0xf;
1207 int ln1
= ((data
[1] & 0xf0) >> 4);
1212 ln2
= len
- 2 - ln0
- ln1
;
1214 printf("\t\tANQP OIs: %i\n", data
[0]);
1217 printf("\t\tOI 1: ");
1218 if (2 + ln0
> len
) {
1219 printf("Invalid IE length.\n");
1221 for (idx
= 0; idx
< ln0
; idx
++) {
1222 printf("%02hhx", data
[2 + idx
]);
1229 printf("\t\tOI 2: ");
1230 if (2 + ln0
+ ln1
> len
) {
1231 printf("Invalid IE length.\n");
1233 for (idx
= 0; idx
< ln1
; idx
++) {
1234 printf("%02hhx", data
[2 + ln0
+ idx
]);
1241 printf("\t\tOI 3: ");
1242 if (2 + ln0
+ ln1
+ ln2
> len
) {
1243 printf("Invalid IE length.\n");
1245 for (idx
= 0; idx
< ln2
; idx
++) {
1246 printf("%02hhx", data
[2 + ln0
+ ln1
+ idx
]);
1253 static void print_tx_power_envelope(const uint8_t type
, uint8_t len
,
1254 const uint8_t *data
,
1255 const struct print_ies_data
*ie_buffer
)
1257 const uint8_t local_max_tx_power_count
= data
[0] & 7;
1258 const uint8_t local_max_tx_power_unit_interp
= (data
[0] >> 3) & 7;
1260 static const char *power_names
[] = {
1261 "Local Maximum Transmit Power For 20 MHz",
1262 "Local Maximum Transmit Power For 40 MHz",
1263 "Local Maximum Transmit Power For 80 MHz",
1264 "Local Maximum Transmit Power For 160/80+80 MHz",
1269 if (local_max_tx_power_count
+ 2 != len
)
1271 if (local_max_tx_power_unit_interp
!= 0)
1273 for (i
= 0; i
< local_max_tx_power_count
+ 1; ++i
) {
1274 int8_t power_val
= ((int8_t)data
[1 + i
]) >> 1;
1275 int8_t point5
= data
[1 + i
] & 1;
1277 printf("\t\t * %s: %i.5 dBm\n", power_names
[i
], power_val
);
1279 printf("\t\t * %s: %i dBm\n", power_names
[i
], power_val
);
1283 static const char *ht_secondary_offset
[4] = {
1290 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1291 const struct print_ies_data
*ie_buffer
)
1293 static const char *protection
[4] = {
1299 static const char *sta_chan_width
[2] = {
1305 printf("\t\t * primary channel: %d\n", data
[0]);
1306 printf("\t\t * secondary channel offset: %s\n",
1307 ht_secondary_offset
[data
[1] & 0x3]);
1308 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1309 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1310 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1311 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1312 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1313 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1314 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1315 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1316 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1317 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1318 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1321 static void print_capabilities(const uint8_t type
, uint8_t len
,
1322 const uint8_t *data
,
1323 const struct print_ies_data
*ie_buffer
)
1325 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1326 bool s_psmp_support
= false, is_vht_cap
= false;
1327 unsigned char *ie
= ie_buffer
->ie
;
1328 int ielen
= ie_buffer
->ielen
;
1330 while (ielen
>= 2 && ielen
>= ie
[1]) {
1339 for (i
= 0; i
< len
; i
++) {
1342 for (bit
= 0; bit
< 8; bit
++) {
1343 if (!(data
[i
] & (1 << bit
)))
1348 #define CAPA(bit, name) case bit: printf(" " name); break
1350 /* if the capability 'cap' exists add 'val' to 'sum'
1351 * otherwise print 'Reserved' */
1352 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1354 printf(" Reserved"); \
1361 switch (bit
+ base
) {
1362 CAPA(0, "HT Information Exchange Supported");
1363 CAPA(1, "reserved (On-demand Beacon)");
1364 CAPA(2, "Extended Channel Switching");
1365 CAPA(3, "reserved (Wave Indication)");
1366 CAPA(4, "PSMP Capability");
1367 CAPA(5, "reserved (Service Interval Granularity)");
1370 s_psmp_support
= true;
1371 printf(" S-PSMP Capability");
1375 CAPA(8, "Diagnostics");
1376 CAPA(9, "Multicast Diagnostics");
1377 CAPA(10, "Location Tracking");
1379 CAPA(12, "Proxy ARP Service");
1380 CAPA(13, "Collocated Interference Reporting");
1381 CAPA(14, "Civic Location");
1382 CAPA(15, "Geospatial Location");
1384 CAPA(17, "WNM-Sleep Mode");
1385 CAPA(18, "TIM Broadcast");
1386 CAPA(19, "BSS Transition");
1387 CAPA(20, "QoS Traffic Capability");
1388 CAPA(21, "AC Station Count");
1389 CAPA(22, "Multiple BSSID");
1390 CAPA(23, "Timing Measurement");
1391 CAPA(24, "Channel Usage");
1392 CAPA(25, "SSID List");
1394 CAPA(27, "UTC TSF Offset");
1395 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1396 CAPA(29, "TDLS Peer PSM Support");
1397 CAPA(30, "TDLS channel switching");
1398 CAPA(31, "Interworking");
1399 CAPA(32, "QoS Map");
1401 CAPA(34, "SSPN Interface");
1402 CAPA(35, "Reserved");
1403 CAPA(36, "MSGCF Capability");
1404 CAPA(37, "TDLS Support");
1405 CAPA(38, "TDLS Prohibited");
1406 CAPA(39, "TDLS Channel Switching Prohibited");
1407 CAPA(40, "Reject Unadmitted Frame");
1409 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1410 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1411 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1413 CAPA(44, "Identifier Location");
1414 CAPA(45, "U-APSD Coexistence");
1415 CAPA(46, "WNM-Notification");
1416 CAPA(47, "Reserved");
1417 CAPA(48, "UTF-8 SSID");
1418 CAPA(49, "QMFActivated");
1419 CAPA(50, "QMFReconfigurationActivated");
1420 CAPA(51, "Robust AV Streaming");
1421 CAPA(52, "Advanced GCR");
1422 CAPA(53, "Mesh GCR");
1424 CAPA(55, "QLoad Report");
1425 CAPA(56, "Alternate EDCA");
1426 CAPA(57, "Unprotected TXOP Negotiation");
1427 CAPA(58, "Protected TXOP egotiation");
1428 CAPA(59, "Reserved");
1429 CAPA(60, "Protected QLoad Report");
1430 CAPA(61, "TDLS Wider Bandwidth");
1431 CAPA(62, "Operating Mode Notification");
1433 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1434 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1436 CAPA(65, "Channel Schedule Management");
1437 CAPA(66, "Geodatabase Inband Enabling Signal");
1438 CAPA(67, "Network Channel Control");
1439 CAPA(68, "White Space Map");
1440 CAPA(69, "Channel Availability Query");
1441 CAPA(70, "FTM Responder");
1442 CAPA(71, "FTM Initiator");
1443 CAPA(72, "Reserved");
1444 CAPA(73, "Extended Spectrum Management Capable");
1445 CAPA(74, "Reserved");
1456 printf("\n\t\t * Service Interval Granularity is %d ms",
1457 (si_duration
+ 1) * 5);
1460 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1461 switch (max_amsdu
) {
1463 printf("unlimited");
1482 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1483 const struct print_ies_data
*ie_buffer
)
1485 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1487 data
[0], data
[1], data
[2], data
[3]);
1489 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1493 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1494 const struct print_ies_data
*ie_buffer
)
1496 printf(" %d TUs\n", (data
[1] << 8) + data
[0]);
1499 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1500 const struct print_ies_data
*ie_buffer
)
1503 print_vht_info((__u32
) data
[0] | ((__u32
)data
[1] << 8) |
1504 ((__u32
)data
[2] << 16) | ((__u32
)data
[3] << 24),
1508 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1509 const struct print_ies_data
*ie_buffer
)
1511 const char *chandwidths
[] = {
1512 [0] = "20 or 40 MHz",
1519 printf("\t\t * channel width: %d (%s)\n", data
[0],
1520 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1521 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1522 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1523 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1526 static void print_supp_op_classes(const uint8_t type
, uint8_t len
,
1527 const uint8_t *data
,
1528 const struct print_ies_data
*ie_buffer
)
1530 uint8_t *p
= (uint8_t*) data
;
1531 const uint8_t *next_data
= p
+ len
;
1532 int zero_delimiter
= 0;
1533 int one_hundred_thirty_delimiter
= 0;
1536 printf("\t\t * current operating class: %d\n", *p
);
1537 while (++p
< next_data
) {
1539 one_hundred_thirty_delimiter
= 1;
1546 printf("\t\t * operating class: %d\n", *p
);
1548 if (one_hundred_thirty_delimiter
)
1549 while (++p
< next_data
) {
1550 printf("\t\t * current operating class extension: %d\n", *p
);
1553 while (++p
< next_data
- 1) {
1554 printf("\t\t * operating class tuple: %d %d\n", p
[0], p
[1]);
1560 static void print_measurement_pilot_tx(const uint8_t type
, uint8_t len
,
1561 const uint8_t *data
,
1562 const struct print_ies_data
*ie_buffer
)
1564 uint8_t *p
, len_remaining
;
1567 printf("\t\t * interval: %d TUs\n", data
[0]);
1572 p
= (uint8_t *) data
+ 1;
1573 len_remaining
= len
- 1;
1575 while (len_remaining
>=5) {
1576 uint8_t subelement_id
= *p
, len
, *end
;
1585 /* 802.11-2016 only allows vendor specific elements */
1586 if (subelement_id
!= 221) {
1587 printf("\t\t * <Invalid subelement ID %d>\n", subelement_id
);
1591 if (len
< 3 || len
> len_remaining
) {
1592 printf(" <Parse error, element too short>\n");
1596 printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1598 /* add only two here and use ++p in while loop */
1602 printf(" %.2x", *p
);
1605 len_remaining
-= len
;
1609 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1610 const uint8_t *data
,
1611 const struct print_ies_data
*ie_buffer
)
1614 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1615 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1616 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1617 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1618 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1619 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1620 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1621 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1624 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1625 const uint8_t *data
,
1626 const struct print_ies_data
*ie_buffer
)
1628 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1629 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1631 printf(" %d\n", data
[0]);
1634 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1635 const struct print_ies_data
*ie_buffer
)
1638 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1639 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1640 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1643 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1644 const uint8_t *data
,
1645 const struct print_ies_data
*ie_buffer
)
1648 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1649 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1650 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1651 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1652 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1653 printf("\t\t * Mesh Formation Info:\n");
1654 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1656 printf("\t\t\t Connected to Mesh Gate\n");
1658 printf("\t\t\t Connected to AS\n");
1659 printf("\t\t * Mesh Capability\n");
1661 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1663 printf("\t\t\t MCCA Supported\n");
1665 printf("\t\t\t MCCA Enabled\n");
1667 printf("\t\t\t Forwarding\n");
1669 printf("\t\t\t MBCA Supported\n");
1671 printf("\t\t\t TBTT Adjusting\n");
1673 printf("\t\t\t Mesh Power Save Level\n");
1678 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1679 const struct print_ies_data
*ie_buffer
);
1680 uint8_t minlen
, maxlen
;
1684 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1685 const uint8_t *data
,
1686 const struct print_ies_data
*ie_buffer
)
1693 printf("\t%s:", p
->name
);
1694 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1696 printf(" <invalid: %d bytes:", len
);
1697 for (i
= 0; i
< len
; i
++)
1698 printf(" %.02x", data
[i
]);
1701 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1703 printf(" <invalid: no data>\n");
1707 p
->print(type
, len
, data
, ie_buffer
);
1710 #define PRINT_IGN { \
1717 static const struct ie_print ieprinters
[] = {
1718 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1719 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1720 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1721 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1722 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1723 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1724 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1725 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1726 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1727 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1728 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1729 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1730 [51] = { "AP Channel Report", print_ap_channel_report
, 1, 255, BIT(PRINT_SCAN
), },
1731 [59] = { "Supported operating classes", print_supp_op_classes
, 1, 255, BIT(PRINT_SCAN
), },
1732 [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx
, 1, 255, BIT(PRINT_SCAN
), },
1733 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1734 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1735 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1736 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1737 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1738 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1739 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1740 [70] = { "RM enabled capabilities", print_rm_enabled_capabilities
, 5, 5, BIT(PRINT_SCAN
), },
1741 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1742 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1743 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1744 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1745 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1746 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 2, 255, BIT(PRINT_SCAN
), },
1747 [195] = { "Transmit Power Envelope", print_tx_power_envelope
, 2, 5, BIT(PRINT_SCAN
), },
1750 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1751 const struct print_ies_data
*ie_buffer
)
1753 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1756 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1757 const uint8_t *data
,
1758 const struct print_ies_data
*ie_buffer
)
1760 print_osen_ie("OSEN", "OSEN", len
, data
);
1763 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1766 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1772 printf("Parameter: not version 1: ");
1776 printf("\t * Parameter version 1");
1781 printf("\n\t\t * u-APSD");
1785 for (i
= 0; i
< 4; i
++) {
1786 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1789 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1790 (1 << (data
[1] >> 4)) - 1);
1791 printf(", AIFSN %d", data
[0] & 0xf);
1792 if (data
[2] | data
[3])
1793 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1801 printf("invalid: ");
1805 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1806 const struct print_ies_data
*ie_buffer
)
1812 printf(" information:");
1815 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1819 printf(" type %d:", data
[0]);
1823 for(i
= 1; i
< len
; i
++)
1824 printf(" %.02x", data
[i
]);
1828 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1832 return "Default (PIN)";
1834 return "User-specified";
1836 return "Machine-specified";
1840 return "PushButton";
1842 return "Registrar-specified";
1848 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1849 const struct print_ies_data
*ie_buffer
)
1852 __u16 subtype
, sublen
;
1855 subtype
= (data
[0] << 8) + data
[1];
1856 sublen
= (data
[2] << 8) + data
[3];
1857 if (sublen
> len
- 4)
1862 tab_on_first(&first
);
1864 printf("\t * Version: (invalid "
1865 "length %d)\n", sublen
);
1868 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1871 tab_on_first(&first
);
1872 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1876 tab_on_first(&first
);
1878 printf("\t * Device Password ID: (invalid length %d)\n",
1882 id
= data
[4] << 8 | data
[5];
1883 printf("\t * Device Password ID: %u (%s)\n",
1884 id
, wifi_wps_dev_passwd_id(id
));
1888 tab_on_first(&first
);
1889 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1892 tab_on_first(&first
);
1893 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1896 tab_on_first(&first
);
1897 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1903 printf("\t * Response Type: (invalid length %d)\n",
1908 tab_on_first(&first
);
1909 printf("\t * Response Type: %d%s\n",
1910 val
, val
== 3 ? " (AP)" : "");
1917 printf("\t * RF Bands: (invalid length %d)\n",
1922 tab_on_first(&first
);
1923 printf("\t * RF Bands: 0x%x\n", val
);
1930 printf("\t * Selected Registrar: (invalid length %d)\n",
1935 tab_on_first(&first
);
1936 printf("\t * Selected Registrar: 0x%x\n", val
);
1940 tab_on_first(&first
);
1941 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1947 printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
1952 tab_on_first(&first
);
1953 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1955 val
== 1 ? " (Unconfigured)" : "",
1956 val
== 2 ? " (Configured)" : "");
1960 tab_on_first(&first
);
1961 printf("\t * UUID: ");
1963 printf("(invalid, length=%d)\n", sublen
);
1966 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1967 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1968 data
[4], data
[5], data
[6], data
[7],
1969 data
[8], data
[9], data
[10], data
[11],
1970 data
[12], data
[13], data
[14], data
[15],
1971 data
[16], data
[17], data
[18], data
[19]);
1974 tab_on_first(&first
);
1981 uint8_t v2
= data
[9];
1982 printf("\t * Version2: %d.%d\n", v2
>> 4, v2
& 0xf);
1984 printf("\t * Unknown vendor extension. len=%u\n",
1989 tab_on_first(&first
);
1991 printf("\t * Primary Device Type: (invalid length %d)\n",
1995 printf("\t * Primary Device Type: "
1996 "%u-%02x%02x%02x%02x-%u\n",
1997 data
[4] << 8 | data
[5],
1998 data
[6], data
[7], data
[8], data
[9],
1999 data
[10] << 8 | data
[11]);
2004 tab_on_first(&first
);
2006 printf("\t * AP setup locked: (invalid length %d)\n",
2011 printf("\t * AP setup locked: 0x%.2x\n", val
);
2020 printf("\t * Config methods: (invalid length %d)\n",
2024 meth
= (data
[4] << 8) + data
[5];
2026 tab_on_first(&first
);
2027 printf("\t * %sConfig methods:",
2028 subtype
== 0x1053 ? "Selected Registrar ": "");
2029 #define T(bit, name) do { \
2030 if (meth & (1<<bit)) { \
2050 const __u8
*subdata
= data
+ 4;
2051 __u16 tmplen
= sublen
;
2053 tab_on_first(&first
);
2054 printf("\t * Unknown TLV (%#.4x, %d bytes):",
2057 printf(" %.2x", *subdata
);
2071 printf("\t\t * bogus tail data (%d):", len
);
2073 printf(" %.2x", *data
);
2081 static const struct ie_print wifiprinters
[] = {
2082 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
2083 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
2084 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
2087 static inline void print_p2p(const uint8_t type
, uint8_t len
,
2088 const uint8_t *data
,
2089 const struct print_ies_data
*ie_buffer
)
2097 sublen
= (data
[2] << 8) + data
[1];
2099 if (sublen
> len
- 3)
2103 case 0x02: /* capability */
2104 tab_on_first(&first
);
2106 printf("\t * malformed capability\n");
2109 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2112 case 0x0d: /* device info */
2113 if (sublen
< 6 + 2 + 8 + 1) {
2114 printf("\t * malformed device info\n");
2118 case 0x00: /* status */
2119 case 0x01: /* minor reason */
2120 case 0x03: /* device ID */
2121 case 0x04: /* GO intent */
2122 case 0x05: /* configuration timeout */
2123 case 0x06: /* listen channel */
2124 case 0x07: /* group BSSID */
2125 case 0x08: /* ext listen timing */
2126 case 0x09: /* intended interface address */
2127 case 0x0a: /* manageability */
2128 case 0x0b: /* channel list */
2129 case 0x0c: /* NoA */
2130 case 0x0e: /* group info */
2131 case 0x0f: /* group ID */
2132 case 0x10: /* interface */
2133 case 0x11: /* operating channel */
2134 case 0x12: /* invitation flags */
2135 case 0xdd: /* vendor specific */
2137 const __u8
*subdata
= data
+ 3;
2138 __u16 tmplen
= sublen
;
2140 tab_on_first(&first
);
2141 printf("\t * Unknown TLV (%#.2x, %d bytes):",
2144 printf(" %.2x", *subdata
);
2158 tab_on_first(&first
);
2159 printf("\t * bogus tail data (%d):", len
);
2161 printf(" %.2x", *data
);
2169 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
2170 const uint8_t *data
,
2171 const struct print_ies_data
*ie_buffer
)
2173 /* I can't find the spec for this...just going off what wireshark uses. */
2176 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
2178 printf("\t\tUnexpected length: %i\n", len
);
2181 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
2182 const uint8_t *data
,
2183 const struct print_ies_data
*ie_buffer
)
2192 mac_addr_n2a(mac_addr
, data
);
2193 printf("\t\tBSSID: %s\n", mac_addr
);
2196 if (ssid_len
> len
- 7)
2198 printf("\t\tSSID: ");
2199 print_ssid_escaped(ssid_len
, data
+ 7);
2202 /* optional elements */
2203 if (len
>= ssid_len
+ 9) {
2204 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
2205 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
2209 static const struct ie_print wfa_printers
[] = {
2210 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
2211 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
2212 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
2213 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
2216 static void print_vendor(unsigned char len
, unsigned char *data
,
2217 bool unknown
, enum print_ie_type ptype
)
2222 printf("\tVendor specific: <too short> data:");
2223 for(i
= 0; i
< len
; i
++)
2224 printf(" %.02x", data
[i
]);
2229 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
2230 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
2231 wifiprinters
[data
[3]].name
&&
2232 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
2233 print_ie(&wifiprinters
[data
[3]],
2234 data
[3], len
- 4, data
+ 4,
2240 printf("\tMS/WiFi %#.2x, data:", data
[3]);
2241 for(i
= 0; i
< len
- 4; i
++)
2242 printf(" %.02x", data
[i
+ 4]);
2247 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
2248 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
2249 wfa_printers
[data
[3]].name
&&
2250 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
2251 print_ie(&wfa_printers
[data
[3]],
2252 data
[3], len
- 4, data
+ 4,
2258 printf("\tWFA %#.2x, data:", data
[3]);
2259 for(i
= 0; i
< len
- 4; i
++)
2260 printf(" %.02x", data
[i
+ 4]);
2268 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2269 data
[0], data
[1], data
[2]);
2270 for (i
= 3; i
< len
; i
++)
2271 printf(" %.2x", data
[i
]);
2275 static void print_he_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
2276 const struct print_ies_data
*ie_buffer
)
2279 print_he_capability(data
, len
);
2282 static const struct ie_print ext_printers
[] = {
2283 [35] = { "HE capabilities", print_he_capa
, 21, 54, BIT(PRINT_SCAN
), },
2286 static void print_extension(unsigned char len
, unsigned char *ie
,
2287 bool unknown
, enum print_ie_type ptype
)
2292 printf("\tExtension IE: <empty>\n");
2297 if (tag
< ARRAY_SIZE(ext_printers
) && ext_printers
[tag
].name
&&
2298 ext_printers
[tag
].flags
& BIT(ptype
)) {
2299 print_ie(&ext_printers
[tag
], tag
, len
- 1, ie
+ 1, NULL
);
2306 printf("\tUnknown Extension ID (%d):", ie
[0]);
2307 for (i
= 1; i
< len
; i
++)
2308 printf(" %.2x", ie
[i
]);
2313 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2314 enum print_ie_type ptype
)
2316 struct print_ies_data ie_buffer
= {
2320 if (ie
== NULL
|| ielen
< 0)
2323 while (ielen
>= 2 && ielen
- 2 >= ie
[1]) {
2324 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2325 ieprinters
[ie
[0]].name
&&
2326 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2327 print_ie(&ieprinters
[ie
[0]],
2328 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2329 } else if (ie
[0] == 221 /* vendor */) {
2330 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2331 } else if (ie
[0] == 255 /* extension */) {
2332 print_extension(ie
[1], ie
+ 2, unknown
, ptype
);
2333 } else if (unknown
) {
2336 printf("\tUnknown IE (%d):", ie
[0]);
2337 for (i
=0; i
<ie
[1]; i
++)
2338 printf(" %.2x", ie
[2+i
]);
2346 static void print_capa_dmg(__u16 capa
)
2348 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2349 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2352 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2355 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2356 printf(" DMG_IBSS");
2360 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2361 printf(" CBAP_Only");
2362 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2363 printf(" CBAP_Src");
2364 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2366 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2368 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2369 printf(" SpectrumMgmt");
2370 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2371 printf(" RadioMeasure");
2374 static void print_capa_non_dmg(__u16 capa
)
2376 if (capa
& WLAN_CAPABILITY_ESS
)
2378 if (capa
& WLAN_CAPABILITY_IBSS
)
2380 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2381 printf(" CfPollable");
2382 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2383 printf(" CfPollReq");
2384 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2386 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2387 printf(" ShortPreamble");
2388 if (capa
& WLAN_CAPABILITY_PBCC
)
2390 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2391 printf(" ChannelAgility");
2392 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2393 printf(" SpectrumMgmt");
2394 if (capa
& WLAN_CAPABILITY_QOS
)
2396 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2397 printf(" ShortSlotTime");
2398 if (capa
& WLAN_CAPABILITY_APSD
)
2400 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2401 printf(" RadioMeasure");
2402 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2403 printf(" DSSS-OFDM");
2404 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2405 printf(" DelayedBACK");
2406 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2407 printf(" ImmediateBACK");
2410 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2412 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2413 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2414 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2415 char mac_addr
[20], dev
[20];
2416 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2417 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2418 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2419 [NL80211_BSS_BSSID
] = { },
2420 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2421 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2422 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2423 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2424 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2425 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2426 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2427 [NL80211_BSS_BEACON_IES
] = { },
2429 struct scan_params
*params
= arg
;
2430 int show
= params
->show_both_ie_sets
? 2 : 1;
2431 bool is_dmg
= false;
2433 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2434 genlmsg_attrlen(gnlh
, 0), NULL
);
2436 if (!tb
[NL80211_ATTR_BSS
]) {
2437 fprintf(stderr
, "bss info missing!\n");
2440 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2441 tb
[NL80211_ATTR_BSS
],
2443 fprintf(stderr
, "failed to parse nested attributes!\n");
2447 if (!bss
[NL80211_BSS_BSSID
])
2450 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2451 printf("BSS %s", mac_addr
);
2452 if (tb
[NL80211_ATTR_IFINDEX
]) {
2453 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2454 printf("(on %s)", dev
);
2457 if (bss
[NL80211_BSS_STATUS
]) {
2458 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2459 case NL80211_BSS_STATUS_AUTHENTICATED
:
2460 printf(" -- authenticated");
2462 case NL80211_BSS_STATUS_ASSOCIATED
:
2463 printf(" -- associated");
2465 case NL80211_BSS_STATUS_IBSS_JOINED
:
2466 printf(" -- joined");
2469 printf(" -- unknown status: %d",
2470 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2476 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2477 unsigned long long bt
;
2478 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2479 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2482 if (bss
[NL80211_BSS_TSF
]) {
2483 unsigned long long tsf
;
2484 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2485 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2486 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2487 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2489 if (bss
[NL80211_BSS_FREQUENCY
]) {
2490 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2491 printf("\tfreq: %d\n", freq
);
2495 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2496 printf("\tbeacon interval: %d TUs\n",
2497 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2498 if (bss
[NL80211_BSS_CAPABILITY
]) {
2499 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2500 printf("\tcapability:");
2502 print_capa_dmg(capa
);
2504 print_capa_non_dmg(capa
);
2505 printf(" (0x%.4x)\n", capa
);
2507 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2508 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2509 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2511 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2512 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2513 printf("\tsignal: %d/100\n", s
);
2515 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2516 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2517 printf("\tlast seen: %d ms ago\n", age
);
2520 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2521 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2522 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2524 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2525 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2526 memcmp(nla_data(ies
), nla_data(bcnies
),
2528 printf("\tInformation elements from Probe Response "
2530 print_ies(nla_data(ies
), nla_len(ies
),
2531 params
->unknown
, params
->type
);
2533 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2534 printf("\tInformation elements from Beacon frame:\n");
2535 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2536 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2537 params
->unknown
, params
->type
);
2543 static struct scan_params scan_params
;
2545 static int handle_scan_dump(struct nl80211_state
*state
,
2547 int argc
, char **argv
,
2553 memset(&scan_params
, 0, sizeof(scan_params
));
2555 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2556 scan_params
.unknown
= true;
2557 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2558 scan_params
.show_both_ie_sets
= true;
2560 scan_params
.type
= PRINT_SCAN
;
2562 register_handler(print_bss_handler
, &scan_params
);
2566 static int handle_scan_combined(struct nl80211_state
*state
,
2568 int argc
, char **argv
,
2572 static char *dump_argv
[] = {
2578 static const __u32 cmds
[] = {
2579 NL80211_CMD_NEW_SCAN_RESULTS
,
2580 NL80211_CMD_SCAN_ABORTED
,
2582 int trig_argc
, dump_argc
, err
;
2585 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2587 dump_argv
[3] = "-u";
2588 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2590 dump_argv
[3] = "-b";
2594 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2595 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2598 trig_argv
[0] = argv
[0];
2599 trig_argv
[1] = "scan";
2600 trig_argv
[2] = "trigger";
2602 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2603 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2604 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2610 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2612 * This code has a bug, which requires creating a separate
2613 * nl80211 socket to fix:
2614 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2615 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2616 * before (!) we listen to it, because we only start listening
2617 * after we send our scan request.
2619 * Doing it the other way around has a race condition as well,
2620 * if you first open the events socket you may get a notification
2621 * for a previous scan.
2623 * The only proper way to fix this would be to listen to events
2624 * before sending the command, and for the kernel to send the
2625 * scan request along with the event, so that you can match up
2626 * whether the scan you requested was finished or aborted (this
2627 * may result in processing a scan that another application
2628 * requested, but that doesn't seem to be a problem).
2630 * Alas, the kernel doesn't do that (yet).
2633 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2634 NL80211_CMD_SCAN_ABORTED
) {
2635 printf("scan aborted!\n");
2639 dump_argv
[0] = argv
[0];
2640 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2642 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,
2643 CIB_NETDEV
, handle_scan_combined
,
2644 "Scan on the given frequencies and probe for the given SSIDs\n"
2645 "(or wildcard if not given) unless passive scanning is requested.\n"
2646 "If -u is specified print unknown data in the scan results.\n"
2647 "Specified (vendor) IEs must be well-formed.");
2648 COMMAND(scan
, dump
, "[-u]",
2649 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2650 "Dump the current scan results. If -u is specified, print unknown\n"
2651 "data in scan results.");
2652 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]",
2653 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2654 "Trigger a scan on the given frequencies with probing for the given\n"
2655 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2656 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2659 static int handle_scan_abort(struct nl80211_state
*state
,
2661 int argc
, char **argv
,
2666 COMMAND(scan
, abort
, "",
2667 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2668 "Abort ongoing scan");
2670 static int handle_start_sched_scan(struct nl80211_state
*state
,
2672 int argc
, char **argv
, enum id_input id
)
2674 return parse_sched_scan(msg
, &argc
, &argv
);
2677 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2678 struct nl_msg
*msg
, int argc
, char **argv
,
2687 COMMAND(scan
, sched_start
,
2689 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2690 "Start a scheduled scan at the specified interval on the given frequencies\n"
2691 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2692 "scanning is requested. If matches are specified, only matching results\n"
2693 "will be returned.");
2694 COMMAND(scan
, sched_stop
, "",
2695 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2696 "Stop an ongoing scheduled scan.");