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
;
206 /* this element is not for us, so
207 * return to continue parsing.
209 goto nla_put_failure
;
215 if (!strcmp(v
[0], "ssid")) {
219 goto nla_put_failure
;
222 /* TODO: for now we can only have an
223 * SSID in the match, so we can start
224 * the match nest here.
226 match
= nla_nest_start(matchset
, i
);
229 goto nla_put_failure
;
233 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
235 nla_nest_end(matchset
, match
);
238 have_matchset
= true;
242 /* other element that cannot be part
243 * of a match indicates the end of the
245 /* need at least one match in the matchset */
248 goto nla_put_failure
;
251 parse_state
= ND_TOPLEVEL
;
256 freq
= strtoul(v
[0], &end
, 10);
260 goto nla_put_failure
;
263 parse_state
= ND_TOPLEVEL
;
265 NLA_PUT_U32(freqs
, i
, freq
);
271 if (!strcmp(v
[0], "ssid")) {
275 goto nla_put_failure
;
279 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
286 /* other element that cannot be part
287 * of a match indicates the end of the
289 /* need at least one item in the set */
292 goto nla_put_failure
;
295 parse_state
= ND_TOPLEVEL
;
300 interval
= strtoul(v
[0], &end
, 10);
306 goto nla_put_failure
;
310 iterations
= strtoul(iter
, &end
, 10);
311 if (*end
|| !iterations
) {
313 goto nla_put_failure
;
317 plan
= nla_nest_start(scan_plans
, i
+ 1);
320 goto nla_put_failure
;
323 NLA_PUT_U32(scan_plans
,
324 NL80211_SCHED_SCAN_PLAN_INTERVAL
,
328 NLA_PUT_U32(scan_plans
,
329 NL80211_SCHED_SCAN_PLAN_ITERATIONS
,
332 parse_state
= ND_TOPLEVEL
;
334 nla_nest_end(scan_plans
, plan
);
343 NLA_PUT(ssids
, 1, 0, "");
345 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
347 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
349 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
351 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
353 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
357 nla_nest_end(msg
, match
);
359 nlmsg_free(matchset
);
360 nlmsg_free(scan_plans
);
368 static int handle_scan(struct nl80211_state
*state
,
370 int argc
, char **argv
,
373 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
387 unsigned int duration
= 0;
388 bool passive
= false, have_ssids
= false, have_freqs
= false;
389 bool duration_mandatory
= false;
390 size_t ies_len
= 0, meshid_len
= 0;
391 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
392 unsigned int flags
= 0;
394 ssids
= nlmsg_alloc();
398 freqs
= nlmsg_alloc();
404 for (i
= 0; i
< argc
; i
++) {
407 if (strcmp(argv
[i
], "freq") == 0) {
411 } else if (strcmp(argv
[i
], "ies") == 0) {
414 } else if (strcmp(argv
[i
], "lowpri") == 0) {
415 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
417 } else if (strcmp(argv
[i
], "flush") == 0) {
418 flags
|= NL80211_SCAN_FLAG_FLUSH
;
420 } else if (strcmp(argv
[i
], "ap-force") == 0) {
421 flags
|= NL80211_SCAN_FLAG_AP
;
423 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
424 duration_mandatory
= true;
426 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
427 strncmp(argv
[i
], "randomize", 9) == 0) {
428 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
429 err
= parse_random_mac_addr(msg
, argv
[i
] + 9);
431 goto nla_put_failure
;
433 } else if (strcmp(argv
[i
], "ssid") == 0) {
437 } else if (strcmp(argv
[i
], "passive") == 0) {
441 } else if (strcmp(argv
[i
], "meshid") == 0) {
444 } else if (strcmp(argv
[i
], "duration") == 0) {
448 /* fall through - this is an error */
454 freq
= strtoul(argv
[i
], &eptr
, 10);
455 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
456 /* failed to parse as number -- maybe a tag? */
461 NLA_PUT_U32(freqs
, i
, freq
);
464 ies
= parse_hex(argv
[i
], &ies_len
);
466 goto nla_put_failure
;
470 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
473 meshid_len
= strlen(argv
[i
]);
474 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
476 goto nla_put_failure
;
477 meshid
[0] = 114; /* mesh element id */
478 meshid
[1] = meshid_len
;
479 memcpy(&meshid
[2], argv
[i
], meshid_len
);
484 duration
= strtoul(argv
[i
], &eptr
, 10);
491 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
495 goto nla_put_failure
;
498 memcpy(tmpies
, ies
, ies_len
);
502 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
505 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
507 goto nla_put_failure
;
513 NLA_PUT(ssids
, 1, 0, "");
515 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
518 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
520 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
522 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
523 if (duration_mandatory
) {
526 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
529 goto nla_put_failure
;
540 static void tab_on_first(bool *first
)
548 struct print_ies_data
{
553 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
554 const struct print_ies_data
*ie_buffer
)
557 print_ssid_escaped(len
, data
);
561 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
562 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
564 static void print_supprates(const uint8_t type
, uint8_t len
,
566 const struct print_ies_data
*ie_buffer
)
572 for (i
= 0; i
< len
; i
++) {
573 int r
= data
[i
] & 0x7f;
575 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
577 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
580 printf("%d.%d", r
/2, 5*(r
&1));
582 printf("%s ", data
[i
] & 0x80 ? "*" : "");
587 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
588 const struct print_ies_data
*ie_buffer
)
590 printf(" channel %d\n", data
[0]);
593 static const char *country_env_str(char environment
)
595 switch (environment
) {
597 return "Indoor only";
599 return "Outdoor only";
601 return "Indoor/Outdoor";
607 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
608 const struct print_ies_data
*ie_buffer
)
610 printf(" %.*s", 2, data
);
612 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
618 printf("\t\tNo country IE triplets present\n");
624 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
626 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
627 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
628 triplet
->ext
.reg_extension_id
,
629 triplet
->ext
.reg_class
,
630 triplet
->ext
.coverage_class
,
631 triplet
->ext
.coverage_class
* 450);
639 if (triplet
->chans
.first_channel
<= 14)
640 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
642 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
644 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
653 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
655 const struct print_ies_data
*ie_buffer
)
657 printf(" %d dB\n", data
[0]);
660 static void print_tpcreport(const uint8_t type
, uint8_t len
,
662 const struct print_ies_data
*ie_buffer
)
664 printf(" TX power: %d dBm\n", data
[0]);
665 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
668 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
669 const struct print_ies_data
*ie_buffer
)
672 printf(" <no flags>");
674 printf(" NonERP_Present");
676 printf(" Use_Protection");
678 printf(" Barker_Preamble_Mode");
682 static void print_cipher(const uint8_t *data
)
684 if (memcmp(data
, ms_oui
, 3) == 0) {
687 printf("Use group cipher suite");
702 printf("%.02x-%.02x-%.02x:%d",
703 data
[0], data
[1] ,data
[2], data
[3]);
706 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
709 printf("Use group cipher suite");
724 printf("AES-128-CMAC");
733 printf("%.02x-%.02x-%.02x:%d",
734 data
[0], data
[1] ,data
[2], data
[3]);
738 printf("%.02x-%.02x-%.02x:%d",
739 data
[0], data
[1] ,data
[2], data
[3]);
742 static void print_auth(const uint8_t *data
)
744 if (memcmp(data
, ms_oui
, 3) == 0) {
747 printf("IEEE 802.1X");
753 printf("%.02x-%.02x-%.02x:%d",
754 data
[0], data
[1] ,data
[2], data
[3]);
757 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
760 printf("IEEE 802.1X");
766 printf("FT/IEEE 802.1X");
772 printf("IEEE 802.1X/SHA-256");
775 printf("PSK/SHA-256");
787 printf("IEEE 802.1X/SUITE-B");
790 printf("IEEE 802.1X/SUITE-B-192");
793 printf("FT/IEEE 802.1X/SHA-384");
796 printf("FILS/SHA-256");
799 printf("FILS/SHA-384");
802 printf("FT/FILS/SHA-256");
805 printf("FT/FILS/SHA-384");
811 printf("%.02x-%.02x-%.02x:%d",
812 data
[0], data
[1] ,data
[2], data
[3]);
815 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
824 printf("%.02x-%.02x-%.02x:%d",
825 data
[0], data
[1] ,data
[2], data
[3]);
829 printf("%.02x-%.02x-%.02x:%d",
830 data
[0], data
[1] ,data
[2], data
[3]);
833 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
834 uint8_t len
, const uint8_t *data
, int is_osen
)
842 version
= data
[0] + (data
[1] << 8);
843 tab_on_first(&first
);
844 printf("\t * Version: %d\n", version
);
851 tab_on_first(&first
);
852 printf("\t * Group cipher: %s\n", defcipher
);
853 printf("\t * Pairwise ciphers: %s\n", defcipher
);
857 tab_on_first(&first
);
858 printf("\t * Group cipher: ");
866 tab_on_first(&first
);
867 printf("\t * Pairwise ciphers: %s\n", defcipher
);
871 count
= data
[0] | (data
[1] << 8);
872 if (2 + (count
* 4) > len
)
875 tab_on_first(&first
);
876 printf("\t * Pairwise ciphers:");
877 for (i
= 0; i
< count
; i
++) {
879 print_cipher(data
+ 2 + (i
* 4));
883 data
+= 2 + (count
* 4);
884 len
-= 2 + (count
* 4);
887 tab_on_first(&first
);
888 printf("\t * Authentication suites: %s\n", defauth
);
892 count
= data
[0] | (data
[1] << 8);
893 if (2 + (count
* 4) > len
)
896 tab_on_first(&first
);
897 printf("\t * Authentication suites:");
898 for (i
= 0; i
< count
; i
++) {
900 print_auth(data
+ 2 + (i
* 4));
904 data
+= 2 + (count
* 4);
905 len
-= 2 + (count
* 4);
908 capa
= data
[0] | (data
[1] << 8);
909 tab_on_first(&first
);
910 printf("\t * Capabilities:");
914 printf(" NoPairwise");
915 switch ((capa
& 0x000c) >> 2) {
917 printf(" 1-PTKSA-RC");
920 printf(" 2-PTKSA-RC");
923 printf(" 4-PTKSA-RC");
926 printf(" 16-PTKSA-RC");
929 switch ((capa
& 0x0030) >> 4) {
931 printf(" 1-GTKSA-RC");
934 printf(" 2-GTKSA-RC");
937 printf(" 4-GTKSA-RC");
940 printf(" 16-GTKSA-RC");
944 printf(" MFP-required");
946 printf(" MFP-capable");
948 printf(" Peerkey-enabled");
950 printf(" SPP-AMSDU-capable");
952 printf(" SPP-AMSDU-required");
953 printf(" (0x%.4x)\n", capa
);
959 int pmkid_count
= data
[0] | (data
[1] << 8);
961 if (len
>= 2 + 16 * pmkid_count
) {
962 tab_on_first(&first
);
963 printf("\t * %d PMKIDs\n", pmkid_count
);
964 /* not printing PMKID values */
965 data
+= 2 + 16 * pmkid_count
;
966 len
-= 2 + 16 * pmkid_count
;
972 tab_on_first(&first
);
973 printf("\t * Group mgmt cipher suite: ");
982 printf("\t\t * bogus tail data (%d):", len
);
984 printf(" %.2x", *data
);
992 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
993 uint8_t len
, const uint8_t *data
)
995 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
998 static void print_osen_ie(const char *defcipher
, const char *defauth
,
999 uint8_t len
, const uint8_t *data
)
1002 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1005 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1006 const struct print_ies_data
*ie_buffer
)
1008 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1011 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1012 const struct print_ies_data
*ie_buffer
)
1015 print_ht_capability(data
[0] | (data
[1] << 8));
1016 print_ampdu_length(data
[2] & 3);
1017 print_ampdu_spacing((data
[2] >> 2) & 7);
1018 print_ht_mcs(data
+ 3);
1021 static const char* ntype_11u(uint8_t t
)
1024 case 0: return "Private";
1025 case 1: return "Private with Guest";
1026 case 2: return "Chargeable Public";
1027 case 3: return "Free Public";
1028 case 4: return "Personal Device";
1029 case 5: return "Emergency Services Only";
1030 case 14: return "Test or Experimental";
1031 case 15: return "Wildcard";
1032 default: return "Reserved";
1036 static const char* vgroup_11u(uint8_t t
)
1039 case 0: return "Unspecified";
1040 case 1: return "Assembly";
1041 case 2: return "Business";
1042 case 3: return "Educational";
1043 case 4: return "Factory and Industrial";
1044 case 5: return "Institutional";
1045 case 6: return "Mercantile";
1046 case 7: return "Residential";
1047 case 8: return "Storage";
1048 case 9: return "Utility and Miscellaneous";
1049 case 10: return "Vehicular";
1050 case 11: return "Outdoor";
1051 default: return "Reserved";
1055 static void print_interworking(const uint8_t type
, uint8_t len
,
1056 const uint8_t *data
,
1057 const struct print_ies_data
*ie_buffer
)
1059 /* See Section 7.3.2.92 in the 802.11u spec. */
1062 uint8_t ano
= data
[0];
1063 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1064 printf("\t\t\tNetwork Type: %i (%s)\n",
1065 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1067 printf("\t\t\tInternet\n");
1069 printf("\t\t\tASRA\n");
1071 printf("\t\t\tESR\n");
1073 printf("\t\t\tUESA\n");
1075 if ((len
== 3) || (len
== 9)) {
1076 printf("\t\tVenue Group: %i (%s)\n",
1077 (int)(data
[1]), vgroup_11u(data
[1]));
1078 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1081 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1082 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1084 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1085 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1088 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1089 const uint8_t *data
,
1090 const struct print_ies_data
*ie_buffer
)
1092 /* See Section 7.3.2.93 in the 802.11u spec. */
1093 /* TODO: This code below does not decode private protocol IDs */
1096 while (idx
< (len
- 1)) {
1097 uint8_t qri
= data
[idx
];
1098 uint8_t proto_id
= data
[idx
+ 1];
1099 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1100 printf("\t\t\tQuery Response Length Limit: %i\n",
1103 printf("\t\t\tPAME-BI\n");
1106 printf("\t\t\tANQP\n"); break;
1108 printf("\t\t\tMIH Information Service\n"); break;
1110 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1112 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1114 printf("\t\t\tVendor Specific\n"); break;
1116 printf("\t\t\tReserved: %i\n", proto_id
); break;
1122 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1123 const struct print_ies_data
*ie_buffer
)
1125 /* See Section 7.3.2.96 in the 802.11u spec. */
1127 int ln0
= data
[1] & 0xf;
1128 int ln1
= ((data
[1] & 0xf0) >> 4);
1133 ln2
= len
- 2 - ln0
- ln1
;
1135 printf("\t\tANQP OIs: %i\n", data
[0]);
1138 printf("\t\tOI 1: ");
1139 if (2 + ln0
> len
) {
1140 printf("Invalid IE length.\n");
1142 for (idx
= 0; idx
< ln0
; idx
++) {
1143 printf("%02hx", data
[2 + idx
]);
1150 printf("\t\tOI 2: ");
1151 if (2 + ln0
+ ln1
> len
) {
1152 printf("Invalid IE length.\n");
1154 for (idx
= 0; idx
< ln1
; idx
++) {
1155 printf("%02hx", data
[2 + ln0
+ idx
]);
1162 printf("\t\tOI 3: ");
1163 if (2 + ln0
+ ln1
+ ln2
> len
) {
1164 printf("Invalid IE length.\n");
1166 for (idx
= 0; idx
< ln2
; idx
++) {
1167 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1174 static const char *ht_secondary_offset
[4] = {
1181 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1182 const struct print_ies_data
*ie_buffer
)
1184 static const char *protection
[4] = {
1190 static const char *sta_chan_width
[2] = {
1196 printf("\t\t * primary channel: %d\n", data
[0]);
1197 printf("\t\t * secondary channel offset: %s\n",
1198 ht_secondary_offset
[data
[1] & 0x3]);
1199 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1200 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1201 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1202 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1203 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1204 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1205 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1206 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1207 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1208 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1209 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1212 static void print_capabilities(const uint8_t type
, uint8_t len
,
1213 const uint8_t *data
,
1214 const struct print_ies_data
*ie_buffer
)
1216 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1217 bool s_psmp_support
= false, is_vht_cap
= false;
1218 unsigned char *ie
= ie_buffer
->ie
;
1219 int ielen
= ie_buffer
->ielen
;
1221 while (ielen
>= 2 && ielen
>= ie
[1]) {
1230 for (i
= 0; i
< len
; i
++) {
1233 for (bit
= 0; bit
< 8; bit
++) {
1234 if (!(data
[i
] & (1 << bit
)))
1239 #define CAPA(bit, name) case bit: printf(" " name); break
1241 /* if the capability 'cap' exists add 'val' to 'sum'
1242 * otherwise print 'Reserved' */
1243 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1245 printf(" Reserved"); \
1252 switch (bit
+ base
) {
1253 CAPA(0, "HT Information Exchange Supported");
1254 CAPA(1, "reserved (On-demand Beacon)");
1255 CAPA(2, "Extended Channel Switching");
1256 CAPA(3, "reserved (Wave Indication)");
1257 CAPA(4, "PSMP Capability");
1258 CAPA(5, "reserved (Service Interval Granularity)");
1261 s_psmp_support
= true;
1262 printf(" S-PSMP Capability");
1266 CAPA(8, "Diagnostics");
1267 CAPA(9, "Multicast Diagnostics");
1268 CAPA(10, "Location Tracking");
1270 CAPA(12, "Proxy ARP Service");
1271 CAPA(13, "Collocated Interference Reporting");
1272 CAPA(14, "Civic Location");
1273 CAPA(15, "Geospatial Location");
1275 CAPA(17, "WNM-Sleep Mode");
1276 CAPA(18, "TIM Broadcast");
1277 CAPA(19, "BSS Transition");
1278 CAPA(20, "QoS Traffic Capability");
1279 CAPA(21, "AC Station Count");
1280 CAPA(22, "Multiple BSSID");
1281 CAPA(23, "Timing Measurement");
1282 CAPA(24, "Channel Usage");
1283 CAPA(25, "SSID List");
1285 CAPA(27, "UTC TSF Offset");
1286 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1287 CAPA(29, "TDLS Peer PSM Support");
1288 CAPA(30, "TDLS channel switching");
1289 CAPA(31, "Interworking");
1290 CAPA(32, "QoS Map");
1292 CAPA(34, "SSPN Interface");
1293 CAPA(35, "Reserved");
1294 CAPA(36, "MSGCF Capability");
1295 CAPA(37, "TDLS Support");
1296 CAPA(38, "TDLS Prohibited");
1297 CAPA(39, "TDLS Channel Switching Prohibited");
1298 CAPA(40, "Reject Unadmitted Frame");
1300 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1301 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1302 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1304 CAPA(44, "Identifier Location");
1305 CAPA(45, "U-APSD Coexistence");
1306 CAPA(46, "WNM-Notification");
1307 CAPA(47, "Reserved");
1308 CAPA(48, "UTF-8 SSID");
1309 CAPA(49, "QMFActivated");
1310 CAPA(50, "QMFReconfigurationActivated");
1311 CAPA(51, "Robust AV Streaming");
1312 CAPA(52, "Advanced GCR");
1313 CAPA(53, "Mesh GCR");
1315 CAPA(55, "QLoad Report");
1316 CAPA(56, "Alternate EDCA");
1317 CAPA(57, "Unprotected TXOP Negotiation");
1318 CAPA(58, "Protected TXOP egotiation");
1319 CAPA(59, "Reserved");
1320 CAPA(60, "Protected QLoad Report");
1321 CAPA(61, "TDLS Wider Bandwidth");
1322 CAPA(62, "Operating Mode Notification");
1324 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1325 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1327 CAPA(65, "Channel Schedule Management");
1328 CAPA(66, "Geodatabase Inband Enabling Signal");
1329 CAPA(67, "Network Channel Control");
1330 CAPA(68, "White Space Map");
1331 CAPA(69, "Channel Availability Query");
1332 CAPA(70, "FTM Responder");
1333 CAPA(71, "FTM Initiator");
1334 CAPA(72, "Reserved");
1335 CAPA(73, "Extended Spectrum Management Capable");
1336 CAPA(74, "Reserved");
1347 printf("\n\t\t * Service Interval Granularity is %d ms",
1348 (si_duration
+ 1) * 5);
1351 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1352 switch (max_amsdu
) {
1354 printf("unlimited");
1373 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1374 const struct print_ies_data
*ie_buffer
)
1376 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1378 data
[0], data
[1], data
[2], data
[3]);
1380 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1384 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1385 const struct print_ies_data
*ie_buffer
)
1387 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1390 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1391 const struct print_ies_data
*ie_buffer
)
1394 print_vht_info(data
[0] | (data
[1] << 8) |
1395 (data
[2] << 16) | (data
[3] << 24),
1399 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1400 const struct print_ies_data
*ie_buffer
)
1402 const char *chandwidths
[] = {
1403 [0] = "20 or 40 MHz",
1410 printf("\t\t * channel width: %d (%s)\n", data
[0],
1411 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1412 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1413 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1414 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1417 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1418 const uint8_t *data
,
1419 const struct print_ies_data
*ie_buffer
)
1422 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1423 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1424 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1425 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1426 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1427 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1428 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1429 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1432 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1433 const uint8_t *data
,
1434 const struct print_ies_data
*ie_buffer
)
1436 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1437 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1439 printf(" %d\n", data
[0]);
1442 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1443 const struct print_ies_data
*ie_buffer
)
1446 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1447 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1448 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1451 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1452 const uint8_t *data
,
1453 const struct print_ies_data
*ie_buffer
)
1456 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1457 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1458 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1459 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1460 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1461 printf("\t\t * Mesh Formation Info:\n");
1462 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1464 printf("\t\t\t Connected to Mesh Gate\n");
1466 printf("\t\t\t Connected to AS\n");
1467 printf("\t\t * Mesh Capability\n");
1469 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1471 printf("\t\t\t MCCA Supported\n");
1473 printf("\t\t\t MCCA Enabled\n");
1475 printf("\t\t\t Forwarding\n");
1477 printf("\t\t\t MBCA Supported\n");
1479 printf("\t\t\t TBTT Adjusting\n");
1481 printf("\t\t\t Mesh Power Save Level\n");
1486 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1487 const struct print_ies_data
*ie_buffer
);
1488 uint8_t minlen
, maxlen
;
1492 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1493 const uint8_t *data
,
1494 const struct print_ies_data
*ie_buffer
)
1501 printf("\t%s:", p
->name
);
1502 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1504 printf(" <invalid: %d bytes:", len
);
1505 for (i
= 0; i
< len
; i
++)
1506 printf(" %.02x", data
[i
]);
1509 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1511 printf(" <invalid: no data>\n");
1515 p
->print(type
, len
, data
, ie_buffer
);
1518 #define PRINT_IGN { \
1525 static const struct ie_print ieprinters
[] = {
1526 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1527 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1528 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1529 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1530 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1531 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1532 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1533 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1534 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1535 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1536 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1537 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1538 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1539 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1540 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1541 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1542 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1543 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1544 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1545 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1546 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1547 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1548 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1549 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1550 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1553 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1554 const struct print_ies_data
*ie_buffer
)
1556 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1559 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1560 const uint8_t *data
,
1561 const struct print_ies_data
*ie_buffer
)
1563 print_osen_ie("OSEN", "OSEN", len
, data
);
1566 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1569 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1575 printf("Parameter: not version 1: ");
1579 printf("\t * Parameter version 1");
1584 printf("\n\t\t * u-APSD");
1588 for (i
= 0; i
< 4; i
++) {
1589 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1592 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1593 (1 << (data
[1] >> 4)) - 1);
1594 printf(", AIFSN %d", data
[0] & 0xf);
1595 if (data
[2] | data
[3])
1596 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1604 printf("invalid: ");
1608 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1609 const struct print_ies_data
*ie_buffer
)
1615 printf(" information:");
1618 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1622 printf(" type %d:", data
[0]);
1626 for(i
= 1; i
< len
; i
++)
1627 printf(" %.02x", data
[i
]);
1631 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1635 return "Default (PIN)";
1637 return "User-specified";
1639 return "Machine-specified";
1643 return "PushButton";
1645 return "Registrar-specified";
1651 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1652 const struct print_ies_data
*ie_buffer
)
1655 __u16 subtype
, sublen
;
1658 subtype
= (data
[0] << 8) + data
[1];
1659 sublen
= (data
[2] << 8) + data
[3];
1665 tab_on_first(&first
);
1666 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1669 tab_on_first(&first
);
1670 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1674 tab_on_first(&first
);
1676 printf("\t * Device Password ID: (invalid "
1677 "length %d)\n", sublen
);
1680 id
= data
[4] << 8 | data
[5];
1681 printf("\t * Device Password ID: %u (%s)\n",
1682 id
, wifi_wps_dev_passwd_id(id
));
1686 tab_on_first(&first
);
1687 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1690 tab_on_first(&first
);
1691 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1694 tab_on_first(&first
);
1695 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1699 tab_on_first(&first
);
1700 printf("\t * Response Type: %d%s\n",
1701 val
, val
== 3 ? " (AP)" : "");
1706 tab_on_first(&first
);
1707 printf("\t * RF Bands: 0x%x\n", val
);
1712 tab_on_first(&first
);
1713 printf("\t * Selected Registrar: 0x%x\n", val
);
1717 tab_on_first(&first
);
1718 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1722 tab_on_first(&first
);
1723 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1725 val
== 1 ? " (Unconfigured)" : "",
1726 val
== 2 ? " (Configured)" : "");
1730 tab_on_first(&first
);
1731 printf("\t * UUID: ");
1733 printf("(invalid, length=%d)\n", sublen
);
1736 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1737 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1738 data
[4], data
[5], data
[6], data
[7],
1739 data
[8], data
[9], data
[10], data
[11],
1740 data
[12], data
[13], data
[14], data
[15],
1741 data
[16], data
[17], data
[18], data
[19]);
1744 tab_on_first(&first
);
1746 printf("\t * Primary Device Type: (invalid "
1747 "length %d)\n", sublen
);
1750 printf("\t * Primary Device Type: "
1751 "%u-%02x%02x%02x%02x-%u\n",
1752 data
[4] << 8 | data
[5],
1753 data
[6], data
[7], data
[8], data
[9],
1754 data
[10] << 8 | data
[11]);
1759 tab_on_first(&first
);
1760 printf("\t * AP setup locked: 0x%.2x\n", val
);
1765 __u16 meth
= (data
[4] << 8) + data
[5];
1767 tab_on_first(&first
);
1768 printf("\t * %sConfig methods:",
1769 subtype
== 0x1053 ? "Selected Registrar ": "");
1770 #define T(bit, name) do { \
1771 if (meth & (1<<bit)) { \
1791 const __u8
*subdata
= data
+ 4;
1792 __u16 tmplen
= sublen
;
1794 tab_on_first(&first
);
1795 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1798 printf(" %.2x", *subdata
);
1812 printf("\t\t * bogus tail data (%d):", len
);
1814 printf(" %.2x", *data
);
1822 static const struct ie_print wifiprinters
[] = {
1823 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1824 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1825 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1828 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1829 const uint8_t *data
,
1830 const struct print_ies_data
*ie_buffer
)
1838 sublen
= (data
[2] << 8) + data
[1];
1840 if (sublen
> len
- 3)
1844 case 0x02: /* capability */
1845 tab_on_first(&first
);
1847 printf("\t * malformed capability\n");
1850 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1853 case 0x0d: /* device info */
1854 if (sublen
< 6 + 2 + 8 + 1) {
1855 printf("\t * malformed device info\n");
1859 case 0x00: /* status */
1860 case 0x01: /* minor reason */
1861 case 0x03: /* device ID */
1862 case 0x04: /* GO intent */
1863 case 0x05: /* configuration timeout */
1864 case 0x06: /* listen channel */
1865 case 0x07: /* group BSSID */
1866 case 0x08: /* ext listen timing */
1867 case 0x09: /* intended interface address */
1868 case 0x0a: /* manageability */
1869 case 0x0b: /* channel list */
1870 case 0x0c: /* NoA */
1871 case 0x0e: /* group info */
1872 case 0x0f: /* group ID */
1873 case 0x10: /* interface */
1874 case 0x11: /* operating channel */
1875 case 0x12: /* invitation flags */
1876 case 0xdd: /* vendor specific */
1878 const __u8
*subdata
= data
+ 4;
1879 __u16 tmplen
= sublen
;
1881 tab_on_first(&first
);
1882 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1885 printf(" %.2x", *subdata
);
1899 tab_on_first(&first
);
1900 printf("\t * bogus tail data (%d):", len
);
1902 printf(" %.2x", *data
);
1910 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1911 const uint8_t *data
,
1912 const struct print_ies_data
*ie_buffer
)
1914 /* I can't find the spec for this...just going off what wireshark uses. */
1917 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1919 printf("\t\tUnexpected length: %i\n", len
);
1922 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
1923 const uint8_t *data
,
1924 const struct print_ies_data
*ie_buffer
)
1933 mac_addr_n2a(mac_addr
, data
);
1934 printf("\t\tBSSID: %s\n", mac_addr
);
1937 if (ssid_len
> len
- 7)
1939 printf("\t\tSSID: ");
1940 print_ssid_escaped(ssid_len
, data
+ 7);
1943 /* optional elements */
1944 if (len
>= ssid_len
+ 9) {
1945 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
1946 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
1950 static const struct ie_print wfa_printers
[] = {
1951 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1952 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1953 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1954 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
1957 static void print_vendor(unsigned char len
, unsigned char *data
,
1958 bool unknown
, enum print_ie_type ptype
)
1963 printf("\tVendor specific: <too short> data:");
1964 for(i
= 0; i
< len
; i
++)
1965 printf(" %.02x", data
[i
]);
1970 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1971 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1972 wifiprinters
[data
[3]].name
&&
1973 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1974 print_ie(&wifiprinters
[data
[3]],
1975 data
[3], len
- 4, data
+ 4,
1981 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1982 for(i
= 0; i
< len
- 4; i
++)
1983 printf(" %.02x", data
[i
+ 4]);
1988 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1989 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1990 wfa_printers
[data
[3]].name
&&
1991 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1992 print_ie(&wfa_printers
[data
[3]],
1993 data
[3], len
- 4, data
+ 4,
1999 printf("\tWFA %#.2x, data:", data
[3]);
2000 for(i
= 0; i
< len
- 4; i
++)
2001 printf(" %.02x", data
[i
+ 4]);
2009 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2010 data
[0], data
[1], data
[2]);
2011 for (i
= 3; i
< len
; i
++)
2012 printf(" %.2x", data
[i
]);
2016 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2017 enum print_ie_type ptype
)
2019 struct print_ies_data ie_buffer
= {
2023 while (ielen
>= 2 && ielen
>= ie
[1]) {
2024 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2025 ieprinters
[ie
[0]].name
&&
2026 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2027 print_ie(&ieprinters
[ie
[0]],
2028 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2029 } else if (ie
[0] == 221 /* vendor */) {
2030 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2031 } else if (unknown
) {
2034 printf("\tUnknown IE (%d):", ie
[0]);
2035 for (i
=0; i
<ie
[1]; i
++)
2036 printf(" %.2x", ie
[2+i
]);
2044 static void print_capa_dmg(__u16 capa
)
2046 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2047 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2050 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2053 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2054 printf(" DMG_IBSS");
2058 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2059 printf(" CBAP_Only");
2060 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2061 printf(" CBAP_Src");
2062 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2064 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2066 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2067 printf(" SpectrumMgmt");
2068 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2069 printf(" RadioMeasure");
2072 static void print_capa_non_dmg(__u16 capa
)
2074 if (capa
& WLAN_CAPABILITY_ESS
)
2076 if (capa
& WLAN_CAPABILITY_IBSS
)
2078 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2079 printf(" CfPollable");
2080 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2081 printf(" CfPollReq");
2082 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2084 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2085 printf(" ShortPreamble");
2086 if (capa
& WLAN_CAPABILITY_PBCC
)
2088 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2089 printf(" ChannelAgility");
2090 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2091 printf(" SpectrumMgmt");
2092 if (capa
& WLAN_CAPABILITY_QOS
)
2094 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2095 printf(" ShortSlotTime");
2096 if (capa
& WLAN_CAPABILITY_APSD
)
2098 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2099 printf(" RadioMeasure");
2100 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2101 printf(" DSSS-OFDM");
2102 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2103 printf(" DelayedBACK");
2104 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2105 printf(" ImmediateBACK");
2108 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2110 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2111 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2112 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2113 char mac_addr
[20], dev
[20];
2114 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2115 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2116 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2117 [NL80211_BSS_BSSID
] = { },
2118 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2119 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2120 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2121 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2122 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2123 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2124 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2125 [NL80211_BSS_BEACON_IES
] = { },
2127 struct scan_params
*params
= arg
;
2128 int show
= params
->show_both_ie_sets
? 2 : 1;
2129 bool is_dmg
= false;
2131 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2132 genlmsg_attrlen(gnlh
, 0), NULL
);
2134 if (!tb
[NL80211_ATTR_BSS
]) {
2135 fprintf(stderr
, "bss info missing!\n");
2138 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2139 tb
[NL80211_ATTR_BSS
],
2141 fprintf(stderr
, "failed to parse nested attributes!\n");
2145 if (!bss
[NL80211_BSS_BSSID
])
2148 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2149 printf("BSS %s", mac_addr
);
2150 if (tb
[NL80211_ATTR_IFINDEX
]) {
2151 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2152 printf("(on %s)", dev
);
2155 if (bss
[NL80211_BSS_STATUS
]) {
2156 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2157 case NL80211_BSS_STATUS_AUTHENTICATED
:
2158 printf(" -- authenticated");
2160 case NL80211_BSS_STATUS_ASSOCIATED
:
2161 printf(" -- associated");
2163 case NL80211_BSS_STATUS_IBSS_JOINED
:
2164 printf(" -- joined");
2167 printf(" -- unknown status: %d",
2168 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2174 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2175 unsigned long long bt
;
2176 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2177 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2180 if (bss
[NL80211_BSS_TSF
]) {
2181 unsigned long long tsf
;
2182 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2183 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2184 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2185 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2187 if (bss
[NL80211_BSS_FREQUENCY
]) {
2188 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2189 printf("\tfreq: %d\n", freq
);
2193 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2194 printf("\tbeacon interval: %d TUs\n",
2195 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2196 if (bss
[NL80211_BSS_CAPABILITY
]) {
2197 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2198 printf("\tcapability:");
2200 print_capa_dmg(capa
);
2202 print_capa_non_dmg(capa
);
2203 printf(" (0x%.4x)\n", capa
);
2205 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2206 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2207 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2209 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2210 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2211 printf("\tsignal: %d/100\n", s
);
2213 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2214 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2215 printf("\tlast seen: %d ms ago\n", age
);
2218 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2219 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2220 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2222 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2223 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2224 memcmp(nla_data(ies
), nla_data(bcnies
),
2226 printf("\tInformation elements from Probe Response "
2228 print_ies(nla_data(ies
), nla_len(ies
),
2229 params
->unknown
, params
->type
);
2231 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2232 printf("\tInformation elements from Beacon frame:\n");
2233 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2234 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2235 params
->unknown
, params
->type
);
2241 static struct scan_params scan_params
;
2243 static int handle_scan_dump(struct nl80211_state
*state
,
2245 int argc
, char **argv
,
2251 memset(&scan_params
, 0, sizeof(scan_params
));
2253 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2254 scan_params
.unknown
= true;
2255 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2256 scan_params
.show_both_ie_sets
= true;
2258 scan_params
.type
= PRINT_SCAN
;
2260 register_handler(print_bss_handler
, &scan_params
);
2264 static int handle_scan_combined(struct nl80211_state
*state
,
2266 int argc
, char **argv
,
2270 static char *dump_argv
[] = {
2276 static const __u32 cmds
[] = {
2277 NL80211_CMD_NEW_SCAN_RESULTS
,
2278 NL80211_CMD_SCAN_ABORTED
,
2280 int trig_argc
, dump_argc
, err
;
2283 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2285 dump_argv
[3] = "-u";
2286 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2288 dump_argv
[3] = "-b";
2292 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2293 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2296 trig_argv
[0] = argv
[0];
2297 trig_argv
[1] = "scan";
2298 trig_argv
[2] = "trigger";
2300 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2301 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2302 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2308 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2310 * This code has a bug, which requires creating a separate
2311 * nl80211 socket to fix:
2312 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2313 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2314 * before (!) we listen to it, because we only start listening
2315 * after we send our scan request.
2317 * Doing it the other way around has a race condition as well,
2318 * if you first open the events socket you may get a notification
2319 * for a previous scan.
2321 * The only proper way to fix this would be to listen to events
2322 * before sending the command, and for the kernel to send the
2323 * scan request along with the event, so that you can match up
2324 * whether the scan you requested was finished or aborted (this
2325 * may result in processing a scan that another application
2326 * requested, but that doesn't seem to be a problem).
2328 * Alas, the kernel doesn't do that (yet).
2331 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2332 NL80211_CMD_SCAN_ABORTED
) {
2333 printf("scan aborted!\n");
2337 dump_argv
[0] = argv
[0];
2338 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2340 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,
2341 CIB_NETDEV
, handle_scan_combined
,
2342 "Scan on the given frequencies and probe for the given SSIDs\n"
2343 "(or wildcard if not given) unless passive scanning is requested.\n"
2344 "If -u is specified print unknown data in the scan results.\n"
2345 "Specified (vendor) IEs must be well-formed.");
2346 COMMAND(scan
, dump
, "[-u]",
2347 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2348 "Dump the current scan results. If -u is specified, print unknown\n"
2349 "data in scan results.");
2350 COMMAND(scan
, trigger
, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2351 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2352 "Trigger a scan on the given frequencies with probing for the given\n"
2353 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2354 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2357 static int handle_scan_abort(struct nl80211_state
*state
,
2359 int argc
, char **argv
,
2364 COMMAND(scan
, abort
, "",
2365 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2366 "Abort ongoing scan");
2368 static int handle_start_sched_scan(struct nl80211_state
*state
,
2370 int argc
, char **argv
, enum id_input id
)
2372 return parse_sched_scan(msg
, &argc
, &argv
);
2375 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2376 struct nl_msg
*msg
, int argc
, char **argv
,
2385 COMMAND(scan
, sched_start
,
2387 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2388 "Start a scheduled scan at the specified interval on the given frequencies\n"
2389 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2390 "scanning is requested. If matches are specified, only matching results\n"
2391 "will be returned.");
2392 COMMAND(scan
, sched_stop
, "",
2393 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2394 "Stop an ongoing scheduled scan.");