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
);
360 nlmsg_free(matchset
);
361 nlmsg_free(scan_plans
);
369 static int handle_scan(struct nl80211_state
*state
,
371 int argc
, char **argv
,
374 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
388 unsigned int duration
= 0;
389 bool passive
= false, have_ssids
= false, have_freqs
= false;
390 bool duration_mandatory
= false;
391 size_t ies_len
= 0, meshid_len
= 0;
392 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
393 unsigned int flags
= 0;
395 ssids
= nlmsg_alloc();
399 freqs
= nlmsg_alloc();
405 for (i
= 0; i
< argc
; i
++) {
408 if (strcmp(argv
[i
], "freq") == 0) {
412 } else if (strcmp(argv
[i
], "ies") == 0) {
415 } else if (strcmp(argv
[i
], "lowpri") == 0) {
416 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
418 } else if (strcmp(argv
[i
], "flush") == 0) {
419 flags
|= NL80211_SCAN_FLAG_FLUSH
;
421 } else if (strcmp(argv
[i
], "ap-force") == 0) {
422 flags
|= NL80211_SCAN_FLAG_AP
;
424 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
425 duration_mandatory
= true;
427 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
428 strncmp(argv
[i
], "randomize", 9) == 0) {
429 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
430 err
= parse_random_mac_addr(msg
, argv
[i
] + 9);
432 goto nla_put_failure
;
434 } else if (strcmp(argv
[i
], "ssid") == 0) {
438 } else if (strcmp(argv
[i
], "passive") == 0) {
442 } else if (strcmp(argv
[i
], "meshid") == 0) {
445 } else if (strcmp(argv
[i
], "duration") == 0) {
449 /* fall through - this is an error */
455 freq
= strtoul(argv
[i
], &eptr
, 10);
456 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
457 /* failed to parse as number -- maybe a tag? */
462 NLA_PUT_U32(freqs
, i
, freq
);
465 ies
= parse_hex(argv
[i
], &ies_len
);
467 goto nla_put_failure
;
471 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
474 meshid_len
= strlen(argv
[i
]);
475 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
477 goto nla_put_failure
;
478 meshid
[0] = 114; /* mesh element id */
479 meshid
[1] = meshid_len
;
480 memcpy(&meshid
[2], argv
[i
], meshid_len
);
485 duration
= strtoul(argv
[i
], &eptr
, 10);
492 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
496 goto nla_put_failure
;
499 memcpy(tmpies
, ies
, ies_len
);
503 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
506 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
508 goto nla_put_failure
;
514 NLA_PUT(ssids
, 1, 0, "");
516 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
519 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
521 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
;
541 static void tab_on_first(bool *first
)
549 struct print_ies_data
{
554 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
555 const struct print_ies_data
*ie_buffer
)
558 print_ssid_escaped(len
, data
);
562 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
563 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
565 static void print_supprates(const uint8_t type
, uint8_t len
,
567 const struct print_ies_data
*ie_buffer
)
573 for (i
= 0; i
< len
; i
++) {
574 int r
= data
[i
] & 0x7f;
576 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
578 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
581 printf("%d.%d", r
/2, 5*(r
&1));
583 printf("%s ", data
[i
] & 0x80 ? "*" : "");
588 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
589 const struct print_ies_data
*ie_buffer
)
591 printf(" channel %d\n", data
[0]);
594 static const char *country_env_str(char environment
)
596 switch (environment
) {
598 return "Indoor only";
600 return "Outdoor only";
602 return "Indoor/Outdoor";
608 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
609 const struct print_ies_data
*ie_buffer
)
611 printf(" %.*s", 2, data
);
613 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
619 printf("\t\tNo country IE triplets present\n");
625 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
627 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
628 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
629 triplet
->ext
.reg_extension_id
,
630 triplet
->ext
.reg_class
,
631 triplet
->ext
.coverage_class
,
632 triplet
->ext
.coverage_class
* 450);
640 if (triplet
->chans
.first_channel
<= 14)
641 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
643 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
645 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
654 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
656 const struct print_ies_data
*ie_buffer
)
658 printf(" %d dB\n", data
[0]);
661 static void print_tpcreport(const uint8_t type
, uint8_t len
,
663 const struct print_ies_data
*ie_buffer
)
665 printf(" TX power: %d dBm\n", data
[0]);
666 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
669 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
670 const struct print_ies_data
*ie_buffer
)
673 printf(" <no flags>");
675 printf(" NonERP_Present");
677 printf(" Use_Protection");
679 printf(" Barker_Preamble_Mode");
683 static void print_cipher(const uint8_t *data
)
685 if (memcmp(data
, ms_oui
, 3) == 0) {
688 printf("Use group cipher suite");
703 printf("%.02x-%.02x-%.02x:%d",
704 data
[0], data
[1] ,data
[2], data
[3]);
707 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
710 printf("Use group cipher suite");
725 printf("AES-128-CMAC");
734 printf("%.02x-%.02x-%.02x:%d",
735 data
[0], data
[1] ,data
[2], data
[3]);
739 printf("%.02x-%.02x-%.02x:%d",
740 data
[0], data
[1] ,data
[2], data
[3]);
743 static void print_auth(const uint8_t *data
)
745 if (memcmp(data
, ms_oui
, 3) == 0) {
748 printf("IEEE 802.1X");
754 printf("%.02x-%.02x-%.02x:%d",
755 data
[0], data
[1] ,data
[2], data
[3]);
758 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
761 printf("IEEE 802.1X");
767 printf("FT/IEEE 802.1X");
773 printf("IEEE 802.1X/SHA-256");
776 printf("PSK/SHA-256");
788 printf("IEEE 802.1X/SUITE-B");
791 printf("IEEE 802.1X/SUITE-B-192");
794 printf("FT/IEEE 802.1X/SHA-384");
797 printf("FILS/SHA-256");
800 printf("FILS/SHA-384");
803 printf("FT/FILS/SHA-256");
806 printf("FT/FILS/SHA-384");
812 printf("%.02x-%.02x-%.02x:%d",
813 data
[0], data
[1] ,data
[2], data
[3]);
816 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
825 printf("%.02x-%.02x-%.02x:%d",
826 data
[0], data
[1] ,data
[2], data
[3]);
830 printf("%.02x-%.02x-%.02x:%d",
831 data
[0], data
[1] ,data
[2], data
[3]);
834 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
835 uint8_t len
, const uint8_t *data
, int is_osen
)
843 version
= data
[0] + (data
[1] << 8);
844 tab_on_first(&first
);
845 printf("\t * Version: %d\n", version
);
852 tab_on_first(&first
);
853 printf("\t * Group cipher: %s\n", defcipher
);
854 printf("\t * Pairwise ciphers: %s\n", defcipher
);
858 tab_on_first(&first
);
859 printf("\t * Group cipher: ");
867 tab_on_first(&first
);
868 printf("\t * Pairwise ciphers: %s\n", defcipher
);
872 count
= data
[0] | (data
[1] << 8);
873 if (2 + (count
* 4) > len
)
876 tab_on_first(&first
);
877 printf("\t * Pairwise ciphers:");
878 for (i
= 0; i
< count
; i
++) {
880 print_cipher(data
+ 2 + (i
* 4));
884 data
+= 2 + (count
* 4);
885 len
-= 2 + (count
* 4);
888 tab_on_first(&first
);
889 printf("\t * Authentication suites: %s\n", defauth
);
893 count
= data
[0] | (data
[1] << 8);
894 if (2 + (count
* 4) > len
)
897 tab_on_first(&first
);
898 printf("\t * Authentication suites:");
899 for (i
= 0; i
< count
; i
++) {
901 print_auth(data
+ 2 + (i
* 4));
905 data
+= 2 + (count
* 4);
906 len
-= 2 + (count
* 4);
909 capa
= data
[0] | (data
[1] << 8);
910 tab_on_first(&first
);
911 printf("\t * Capabilities:");
915 printf(" NoPairwise");
916 switch ((capa
& 0x000c) >> 2) {
918 printf(" 1-PTKSA-RC");
921 printf(" 2-PTKSA-RC");
924 printf(" 4-PTKSA-RC");
927 printf(" 16-PTKSA-RC");
930 switch ((capa
& 0x0030) >> 4) {
932 printf(" 1-GTKSA-RC");
935 printf(" 2-GTKSA-RC");
938 printf(" 4-GTKSA-RC");
941 printf(" 16-GTKSA-RC");
945 printf(" MFP-required");
947 printf(" MFP-capable");
949 printf(" Peerkey-enabled");
951 printf(" SPP-AMSDU-capable");
953 printf(" SPP-AMSDU-required");
954 printf(" (0x%.4x)\n", capa
);
960 int pmkid_count
= data
[0] | (data
[1] << 8);
962 if (len
>= 2 + 16 * pmkid_count
) {
963 tab_on_first(&first
);
964 printf("\t * %d PMKIDs\n", pmkid_count
);
965 /* not printing PMKID values */
966 data
+= 2 + 16 * pmkid_count
;
967 len
-= 2 + 16 * pmkid_count
;
973 tab_on_first(&first
);
974 printf("\t * Group mgmt cipher suite: ");
983 printf("\t\t * bogus tail data (%d):", len
);
985 printf(" %.2x", *data
);
993 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
994 uint8_t len
, const uint8_t *data
)
996 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
999 static void print_osen_ie(const char *defcipher
, const char *defauth
,
1000 uint8_t len
, const uint8_t *data
)
1003 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1006 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1007 const struct print_ies_data
*ie_buffer
)
1009 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1012 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1013 const struct print_ies_data
*ie_buffer
)
1016 print_ht_capability(data
[0] | (data
[1] << 8));
1017 print_ampdu_length(data
[2] & 3);
1018 print_ampdu_spacing((data
[2] >> 2) & 7);
1019 print_ht_mcs(data
+ 3);
1022 static const char* ntype_11u(uint8_t t
)
1025 case 0: return "Private";
1026 case 1: return "Private with Guest";
1027 case 2: return "Chargeable Public";
1028 case 3: return "Free Public";
1029 case 4: return "Personal Device";
1030 case 5: return "Emergency Services Only";
1031 case 14: return "Test or Experimental";
1032 case 15: return "Wildcard";
1033 default: return "Reserved";
1037 static const char* vgroup_11u(uint8_t t
)
1040 case 0: return "Unspecified";
1041 case 1: return "Assembly";
1042 case 2: return "Business";
1043 case 3: return "Educational";
1044 case 4: return "Factory and Industrial";
1045 case 5: return "Institutional";
1046 case 6: return "Mercantile";
1047 case 7: return "Residential";
1048 case 8: return "Storage";
1049 case 9: return "Utility and Miscellaneous";
1050 case 10: return "Vehicular";
1051 case 11: return "Outdoor";
1052 default: return "Reserved";
1056 static void print_interworking(const uint8_t type
, uint8_t len
,
1057 const uint8_t *data
,
1058 const struct print_ies_data
*ie_buffer
)
1060 /* See Section 7.3.2.92 in the 802.11u spec. */
1063 uint8_t ano
= data
[0];
1064 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1065 printf("\t\t\tNetwork Type: %i (%s)\n",
1066 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1068 printf("\t\t\tInternet\n");
1070 printf("\t\t\tASRA\n");
1072 printf("\t\t\tESR\n");
1074 printf("\t\t\tUESA\n");
1076 if ((len
== 3) || (len
== 9)) {
1077 printf("\t\tVenue Group: %i (%s)\n",
1078 (int)(data
[1]), vgroup_11u(data
[1]));
1079 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1082 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1083 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1085 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1086 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1089 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1090 const uint8_t *data
,
1091 const struct print_ies_data
*ie_buffer
)
1093 /* See Section 7.3.2.93 in the 802.11u spec. */
1094 /* TODO: This code below does not decode private protocol IDs */
1097 while (idx
< (len
- 1)) {
1098 uint8_t qri
= data
[idx
];
1099 uint8_t proto_id
= data
[idx
+ 1];
1100 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1101 printf("\t\t\tQuery Response Length Limit: %i\n",
1104 printf("\t\t\tPAME-BI\n");
1107 printf("\t\t\tANQP\n"); break;
1109 printf("\t\t\tMIH Information Service\n"); break;
1111 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1113 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1115 printf("\t\t\tVendor Specific\n"); break;
1117 printf("\t\t\tReserved: %i\n", proto_id
); break;
1123 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1124 const struct print_ies_data
*ie_buffer
)
1126 /* See Section 7.3.2.96 in the 802.11u spec. */
1128 int ln0
= data
[1] & 0xf;
1129 int ln1
= ((data
[1] & 0xf0) >> 4);
1134 ln2
= len
- 2 - ln0
- ln1
;
1136 printf("\t\tANQP OIs: %i\n", data
[0]);
1139 printf("\t\tOI 1: ");
1140 if (2 + ln0
> len
) {
1141 printf("Invalid IE length.\n");
1143 for (idx
= 0; idx
< ln0
; idx
++) {
1144 printf("%02hx", data
[2 + idx
]);
1151 printf("\t\tOI 2: ");
1152 if (2 + ln0
+ ln1
> len
) {
1153 printf("Invalid IE length.\n");
1155 for (idx
= 0; idx
< ln1
; idx
++) {
1156 printf("%02hx", data
[2 + ln0
+ idx
]);
1163 printf("\t\tOI 3: ");
1164 if (2 + ln0
+ ln1
+ ln2
> len
) {
1165 printf("Invalid IE length.\n");
1167 for (idx
= 0; idx
< ln2
; idx
++) {
1168 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1175 static const char *ht_secondary_offset
[4] = {
1182 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1183 const struct print_ies_data
*ie_buffer
)
1185 static const char *protection
[4] = {
1191 static const char *sta_chan_width
[2] = {
1197 printf("\t\t * primary channel: %d\n", data
[0]);
1198 printf("\t\t * secondary channel offset: %s\n",
1199 ht_secondary_offset
[data
[1] & 0x3]);
1200 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1201 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1202 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1203 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1204 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1205 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1206 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1207 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1208 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1209 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1210 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1213 static void print_capabilities(const uint8_t type
, uint8_t len
,
1214 const uint8_t *data
,
1215 const struct print_ies_data
*ie_buffer
)
1217 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1218 bool s_psmp_support
= false, is_vht_cap
= false;
1219 unsigned char *ie
= ie_buffer
->ie
;
1220 int ielen
= ie_buffer
->ielen
;
1222 while (ielen
>= 2 && ielen
>= ie
[1]) {
1231 for (i
= 0; i
< len
; i
++) {
1234 for (bit
= 0; bit
< 8; bit
++) {
1235 if (!(data
[i
] & (1 << bit
)))
1240 #define CAPA(bit, name) case bit: printf(" " name); break
1242 /* if the capability 'cap' exists add 'val' to 'sum'
1243 * otherwise print 'Reserved' */
1244 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1246 printf(" Reserved"); \
1253 switch (bit
+ base
) {
1254 CAPA(0, "HT Information Exchange Supported");
1255 CAPA(1, "reserved (On-demand Beacon)");
1256 CAPA(2, "Extended Channel Switching");
1257 CAPA(3, "reserved (Wave Indication)");
1258 CAPA(4, "PSMP Capability");
1259 CAPA(5, "reserved (Service Interval Granularity)");
1262 s_psmp_support
= true;
1263 printf(" S-PSMP Capability");
1267 CAPA(8, "Diagnostics");
1268 CAPA(9, "Multicast Diagnostics");
1269 CAPA(10, "Location Tracking");
1271 CAPA(12, "Proxy ARP Service");
1272 CAPA(13, "Collocated Interference Reporting");
1273 CAPA(14, "Civic Location");
1274 CAPA(15, "Geospatial Location");
1276 CAPA(17, "WNM-Sleep Mode");
1277 CAPA(18, "TIM Broadcast");
1278 CAPA(19, "BSS Transition");
1279 CAPA(20, "QoS Traffic Capability");
1280 CAPA(21, "AC Station Count");
1281 CAPA(22, "Multiple BSSID");
1282 CAPA(23, "Timing Measurement");
1283 CAPA(24, "Channel Usage");
1284 CAPA(25, "SSID List");
1286 CAPA(27, "UTC TSF Offset");
1287 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1288 CAPA(29, "TDLS Peer PSM Support");
1289 CAPA(30, "TDLS channel switching");
1290 CAPA(31, "Interworking");
1291 CAPA(32, "QoS Map");
1293 CAPA(34, "SSPN Interface");
1294 CAPA(35, "Reserved");
1295 CAPA(36, "MSGCF Capability");
1296 CAPA(37, "TDLS Support");
1297 CAPA(38, "TDLS Prohibited");
1298 CAPA(39, "TDLS Channel Switching Prohibited");
1299 CAPA(40, "Reject Unadmitted Frame");
1301 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1302 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1303 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1305 CAPA(44, "Identifier Location");
1306 CAPA(45, "U-APSD Coexistence");
1307 CAPA(46, "WNM-Notification");
1308 CAPA(47, "Reserved");
1309 CAPA(48, "UTF-8 SSID");
1310 CAPA(49, "QMFActivated");
1311 CAPA(50, "QMFReconfigurationActivated");
1312 CAPA(51, "Robust AV Streaming");
1313 CAPA(52, "Advanced GCR");
1314 CAPA(53, "Mesh GCR");
1316 CAPA(55, "QLoad Report");
1317 CAPA(56, "Alternate EDCA");
1318 CAPA(57, "Unprotected TXOP Negotiation");
1319 CAPA(58, "Protected TXOP egotiation");
1320 CAPA(59, "Reserved");
1321 CAPA(60, "Protected QLoad Report");
1322 CAPA(61, "TDLS Wider Bandwidth");
1323 CAPA(62, "Operating Mode Notification");
1325 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1326 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1328 CAPA(65, "Channel Schedule Management");
1329 CAPA(66, "Geodatabase Inband Enabling Signal");
1330 CAPA(67, "Network Channel Control");
1331 CAPA(68, "White Space Map");
1332 CAPA(69, "Channel Availability Query");
1333 CAPA(70, "FTM Responder");
1334 CAPA(71, "FTM Initiator");
1335 CAPA(72, "Reserved");
1336 CAPA(73, "Extended Spectrum Management Capable");
1337 CAPA(74, "Reserved");
1348 printf("\n\t\t * Service Interval Granularity is %d ms",
1349 (si_duration
+ 1) * 5);
1352 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1353 switch (max_amsdu
) {
1355 printf("unlimited");
1374 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1375 const struct print_ies_data
*ie_buffer
)
1377 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1379 data
[0], data
[1], data
[2], data
[3]);
1381 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1385 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1386 const struct print_ies_data
*ie_buffer
)
1388 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1391 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1392 const struct print_ies_data
*ie_buffer
)
1395 print_vht_info(data
[0] | (data
[1] << 8) |
1396 (data
[2] << 16) | (data
[3] << 24),
1400 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1401 const struct print_ies_data
*ie_buffer
)
1403 const char *chandwidths
[] = {
1404 [0] = "20 or 40 MHz",
1411 printf("\t\t * channel width: %d (%s)\n", data
[0],
1412 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1413 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1414 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1415 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1418 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1419 const uint8_t *data
,
1420 const struct print_ies_data
*ie_buffer
)
1423 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1424 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1425 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1426 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1427 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1428 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1429 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1430 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1433 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1434 const uint8_t *data
,
1435 const struct print_ies_data
*ie_buffer
)
1437 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1438 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1440 printf(" %d\n", data
[0]);
1443 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1444 const struct print_ies_data
*ie_buffer
)
1447 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1448 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1449 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1452 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1453 const uint8_t *data
,
1454 const struct print_ies_data
*ie_buffer
)
1457 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1458 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1459 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1460 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1461 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1462 printf("\t\t * Mesh Formation Info:\n");
1463 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1465 printf("\t\t\t Connected to Mesh Gate\n");
1467 printf("\t\t\t Connected to AS\n");
1468 printf("\t\t * Mesh Capability\n");
1470 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1472 printf("\t\t\t MCCA Supported\n");
1474 printf("\t\t\t MCCA Enabled\n");
1476 printf("\t\t\t Forwarding\n");
1478 printf("\t\t\t MBCA Supported\n");
1480 printf("\t\t\t TBTT Adjusting\n");
1482 printf("\t\t\t Mesh Power Save Level\n");
1487 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1488 const struct print_ies_data
*ie_buffer
);
1489 uint8_t minlen
, maxlen
;
1493 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1494 const uint8_t *data
,
1495 const struct print_ies_data
*ie_buffer
)
1502 printf("\t%s:", p
->name
);
1503 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1505 printf(" <invalid: %d bytes:", len
);
1506 for (i
= 0; i
< len
; i
++)
1507 printf(" %.02x", data
[i
]);
1510 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1512 printf(" <invalid: no data>\n");
1516 p
->print(type
, len
, data
, ie_buffer
);
1519 #define PRINT_IGN { \
1526 static const struct ie_print ieprinters
[] = {
1527 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1528 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1529 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1530 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1531 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1532 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1533 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1534 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1535 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1536 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1537 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1538 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1539 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1540 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1541 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1542 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1543 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1544 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1545 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1546 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1547 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1548 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1549 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1550 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1551 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1554 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1555 const struct print_ies_data
*ie_buffer
)
1557 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1560 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1561 const uint8_t *data
,
1562 const struct print_ies_data
*ie_buffer
)
1564 print_osen_ie("OSEN", "OSEN", len
, data
);
1567 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1570 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1576 printf("Parameter: not version 1: ");
1580 printf("\t * Parameter version 1");
1585 printf("\n\t\t * u-APSD");
1589 for (i
= 0; i
< 4; i
++) {
1590 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1593 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1594 (1 << (data
[1] >> 4)) - 1);
1595 printf(", AIFSN %d", data
[0] & 0xf);
1596 if (data
[2] | data
[3])
1597 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1605 printf("invalid: ");
1609 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1610 const struct print_ies_data
*ie_buffer
)
1616 printf(" information:");
1619 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1623 printf(" type %d:", data
[0]);
1627 for(i
= 1; i
< len
; i
++)
1628 printf(" %.02x", data
[i
]);
1632 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1636 return "Default (PIN)";
1638 return "User-specified";
1640 return "Machine-specified";
1644 return "PushButton";
1646 return "Registrar-specified";
1652 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1653 const struct print_ies_data
*ie_buffer
)
1656 __u16 subtype
, sublen
;
1659 subtype
= (data
[0] << 8) + data
[1];
1660 sublen
= (data
[2] << 8) + data
[3];
1666 tab_on_first(&first
);
1667 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1670 tab_on_first(&first
);
1671 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1675 tab_on_first(&first
);
1677 printf("\t * Device Password ID: (invalid "
1678 "length %d)\n", sublen
);
1681 id
= data
[4] << 8 | data
[5];
1682 printf("\t * Device Password ID: %u (%s)\n",
1683 id
, wifi_wps_dev_passwd_id(id
));
1687 tab_on_first(&first
);
1688 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1691 tab_on_first(&first
);
1692 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1695 tab_on_first(&first
);
1696 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1700 tab_on_first(&first
);
1701 printf("\t * Response Type: %d%s\n",
1702 val
, val
== 3 ? " (AP)" : "");
1707 tab_on_first(&first
);
1708 printf("\t * RF Bands: 0x%x\n", val
);
1713 tab_on_first(&first
);
1714 printf("\t * Selected Registrar: 0x%x\n", val
);
1718 tab_on_first(&first
);
1719 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1723 tab_on_first(&first
);
1724 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1726 val
== 1 ? " (Unconfigured)" : "",
1727 val
== 2 ? " (Configured)" : "");
1731 tab_on_first(&first
);
1732 printf("\t * UUID: ");
1734 printf("(invalid, length=%d)\n", sublen
);
1737 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1738 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1739 data
[4], data
[5], data
[6], data
[7],
1740 data
[8], data
[9], data
[10], data
[11],
1741 data
[12], data
[13], data
[14], data
[15],
1742 data
[16], data
[17], data
[18], data
[19]);
1745 tab_on_first(&first
);
1747 printf("\t * Primary Device Type: (invalid "
1748 "length %d)\n", sublen
);
1751 printf("\t * Primary Device Type: "
1752 "%u-%02x%02x%02x%02x-%u\n",
1753 data
[4] << 8 | data
[5],
1754 data
[6], data
[7], data
[8], data
[9],
1755 data
[10] << 8 | data
[11]);
1760 tab_on_first(&first
);
1761 printf("\t * AP setup locked: 0x%.2x\n", val
);
1766 __u16 meth
= (data
[4] << 8) + data
[5];
1768 tab_on_first(&first
);
1769 printf("\t * %sConfig methods:",
1770 subtype
== 0x1053 ? "Selected Registrar ": "");
1771 #define T(bit, name) do { \
1772 if (meth & (1<<bit)) { \
1792 const __u8
*subdata
= data
+ 4;
1793 __u16 tmplen
= sublen
;
1795 tab_on_first(&first
);
1796 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1799 printf(" %.2x", *subdata
);
1813 printf("\t\t * bogus tail data (%d):", len
);
1815 printf(" %.2x", *data
);
1823 static const struct ie_print wifiprinters
[] = {
1824 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1825 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1826 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1829 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1830 const uint8_t *data
,
1831 const struct print_ies_data
*ie_buffer
)
1839 sublen
= (data
[2] << 8) + data
[1];
1841 if (sublen
> len
- 3)
1845 case 0x02: /* capability */
1846 tab_on_first(&first
);
1848 printf("\t * malformed capability\n");
1851 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1854 case 0x0d: /* device info */
1855 if (sublen
< 6 + 2 + 8 + 1) {
1856 printf("\t * malformed device info\n");
1860 case 0x00: /* status */
1861 case 0x01: /* minor reason */
1862 case 0x03: /* device ID */
1863 case 0x04: /* GO intent */
1864 case 0x05: /* configuration timeout */
1865 case 0x06: /* listen channel */
1866 case 0x07: /* group BSSID */
1867 case 0x08: /* ext listen timing */
1868 case 0x09: /* intended interface address */
1869 case 0x0a: /* manageability */
1870 case 0x0b: /* channel list */
1871 case 0x0c: /* NoA */
1872 case 0x0e: /* group info */
1873 case 0x0f: /* group ID */
1874 case 0x10: /* interface */
1875 case 0x11: /* operating channel */
1876 case 0x12: /* invitation flags */
1877 case 0xdd: /* vendor specific */
1879 const __u8
*subdata
= data
+ 4;
1880 __u16 tmplen
= sublen
;
1882 tab_on_first(&first
);
1883 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1886 printf(" %.2x", *subdata
);
1900 tab_on_first(&first
);
1901 printf("\t * bogus tail data (%d):", len
);
1903 printf(" %.2x", *data
);
1911 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1912 const uint8_t *data
,
1913 const struct print_ies_data
*ie_buffer
)
1915 /* I can't find the spec for this...just going off what wireshark uses. */
1918 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1920 printf("\t\tUnexpected length: %i\n", len
);
1923 static void print_wifi_owe_tarns(const uint8_t type
, uint8_t len
,
1924 const uint8_t *data
,
1925 const struct print_ies_data
*ie_buffer
)
1934 mac_addr_n2a(mac_addr
, data
);
1935 printf("\t\tBSSID: %s\n", mac_addr
);
1938 if (ssid_len
> len
- 7)
1940 printf("\t\tSSID: ");
1941 print_ssid_escaped(ssid_len
, data
+ 7);
1944 /* optional elements */
1945 if (len
>= ssid_len
+ 9) {
1946 printf("\t\tBand Info: %u\n", data
[ssid_len
+ 7]);
1947 printf("\t\tChannel Info: %u\n", data
[ssid_len
+ 8]);
1951 static const struct ie_print wfa_printers
[] = {
1952 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1953 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1954 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1955 [28] = { "OWE Transition Mode", print_wifi_owe_tarns
, 7, 255, BIT(PRINT_SCAN
), },
1958 static void print_vendor(unsigned char len
, unsigned char *data
,
1959 bool unknown
, enum print_ie_type ptype
)
1964 printf("\tVendor specific: <too short> data:");
1965 for(i
= 0; i
< len
; i
++)
1966 printf(" %.02x", data
[i
]);
1971 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1972 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1973 wifiprinters
[data
[3]].name
&&
1974 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1975 print_ie(&wifiprinters
[data
[3]],
1976 data
[3], len
- 4, data
+ 4,
1982 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1983 for(i
= 0; i
< len
- 4; i
++)
1984 printf(" %.02x", data
[i
+ 4]);
1989 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1990 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1991 wfa_printers
[data
[3]].name
&&
1992 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1993 print_ie(&wfa_printers
[data
[3]],
1994 data
[3], len
- 4, data
+ 4,
2000 printf("\tWFA %#.2x, data:", data
[3]);
2001 for(i
= 0; i
< len
- 4; i
++)
2002 printf(" %.02x", data
[i
+ 4]);
2010 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2011 data
[0], data
[1], data
[2]);
2012 for (i
= 3; i
< len
; i
++)
2013 printf(" %.2x", data
[i
]);
2017 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
2018 enum print_ie_type ptype
)
2020 struct print_ies_data ie_buffer
= {
2024 while (ielen
>= 2 && ielen
>= ie
[1]) {
2025 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
2026 ieprinters
[ie
[0]].name
&&
2027 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
2028 print_ie(&ieprinters
[ie
[0]],
2029 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
2030 } else if (ie
[0] == 221 /* vendor */) {
2031 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
2032 } else if (unknown
) {
2035 printf("\tUnknown IE (%d):", ie
[0]);
2036 for (i
=0; i
<ie
[1]; i
++)
2037 printf(" %.2x", ie
[2+i
]);
2045 static void print_capa_dmg(__u16 capa
)
2047 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2048 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2051 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2054 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2055 printf(" DMG_IBSS");
2059 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2060 printf(" CBAP_Only");
2061 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2062 printf(" CBAP_Src");
2063 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2065 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2067 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2068 printf(" SpectrumMgmt");
2069 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2070 printf(" RadioMeasure");
2073 static void print_capa_non_dmg(__u16 capa
)
2075 if (capa
& WLAN_CAPABILITY_ESS
)
2077 if (capa
& WLAN_CAPABILITY_IBSS
)
2079 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2080 printf(" CfPollable");
2081 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2082 printf(" CfPollReq");
2083 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2085 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2086 printf(" ShortPreamble");
2087 if (capa
& WLAN_CAPABILITY_PBCC
)
2089 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2090 printf(" ChannelAgility");
2091 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2092 printf(" SpectrumMgmt");
2093 if (capa
& WLAN_CAPABILITY_QOS
)
2095 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2096 printf(" ShortSlotTime");
2097 if (capa
& WLAN_CAPABILITY_APSD
)
2099 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2100 printf(" RadioMeasure");
2101 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2102 printf(" DSSS-OFDM");
2103 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2104 printf(" DelayedBACK");
2105 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2106 printf(" ImmediateBACK");
2109 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2111 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2112 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2113 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2114 char mac_addr
[20], dev
[20];
2115 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2116 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2117 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2118 [NL80211_BSS_BSSID
] = { },
2119 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2120 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2121 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2122 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2123 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2124 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2125 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2126 [NL80211_BSS_BEACON_IES
] = { },
2128 struct scan_params
*params
= arg
;
2129 int show
= params
->show_both_ie_sets
? 2 : 1;
2130 bool is_dmg
= false;
2132 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2133 genlmsg_attrlen(gnlh
, 0), NULL
);
2135 if (!tb
[NL80211_ATTR_BSS
]) {
2136 fprintf(stderr
, "bss info missing!\n");
2139 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2140 tb
[NL80211_ATTR_BSS
],
2142 fprintf(stderr
, "failed to parse nested attributes!\n");
2146 if (!bss
[NL80211_BSS_BSSID
])
2149 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2150 printf("BSS %s", mac_addr
);
2151 if (tb
[NL80211_ATTR_IFINDEX
]) {
2152 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2153 printf("(on %s)", dev
);
2156 if (bss
[NL80211_BSS_STATUS
]) {
2157 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2158 case NL80211_BSS_STATUS_AUTHENTICATED
:
2159 printf(" -- authenticated");
2161 case NL80211_BSS_STATUS_ASSOCIATED
:
2162 printf(" -- associated");
2164 case NL80211_BSS_STATUS_IBSS_JOINED
:
2165 printf(" -- joined");
2168 printf(" -- unknown status: %d",
2169 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2175 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2176 unsigned long long bt
;
2177 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2178 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2181 if (bss
[NL80211_BSS_TSF
]) {
2182 unsigned long long tsf
;
2183 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2184 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2185 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2186 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2188 if (bss
[NL80211_BSS_FREQUENCY
]) {
2189 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2190 printf("\tfreq: %d\n", freq
);
2194 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2195 printf("\tbeacon interval: %d TUs\n",
2196 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2197 if (bss
[NL80211_BSS_CAPABILITY
]) {
2198 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2199 printf("\tcapability:");
2201 print_capa_dmg(capa
);
2203 print_capa_non_dmg(capa
);
2204 printf(" (0x%.4x)\n", capa
);
2206 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2207 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2208 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2210 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2211 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2212 printf("\tsignal: %d/100\n", s
);
2214 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2215 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2216 printf("\tlast seen: %d ms ago\n", age
);
2219 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2220 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2221 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2223 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2224 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2225 memcmp(nla_data(ies
), nla_data(bcnies
),
2227 printf("\tInformation elements from Probe Response "
2229 print_ies(nla_data(ies
), nla_len(ies
),
2230 params
->unknown
, params
->type
);
2232 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2233 printf("\tInformation elements from Beacon frame:\n");
2234 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2235 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2236 params
->unknown
, params
->type
);
2242 static struct scan_params scan_params
;
2244 static int handle_scan_dump(struct nl80211_state
*state
,
2246 int argc
, char **argv
,
2252 memset(&scan_params
, 0, sizeof(scan_params
));
2254 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2255 scan_params
.unknown
= true;
2256 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2257 scan_params
.show_both_ie_sets
= true;
2259 scan_params
.type
= PRINT_SCAN
;
2261 register_handler(print_bss_handler
, &scan_params
);
2265 static int handle_scan_combined(struct nl80211_state
*state
,
2267 int argc
, char **argv
,
2271 static char *dump_argv
[] = {
2277 static const __u32 cmds
[] = {
2278 NL80211_CMD_NEW_SCAN_RESULTS
,
2279 NL80211_CMD_SCAN_ABORTED
,
2281 int trig_argc
, dump_argc
, err
;
2284 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2286 dump_argv
[3] = "-u";
2287 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2289 dump_argv
[3] = "-b";
2293 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2294 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2297 trig_argv
[0] = argv
[0];
2298 trig_argv
[1] = "scan";
2299 trig_argv
[2] = "trigger";
2301 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2302 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2303 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2309 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2311 * This code has a bug, which requires creating a separate
2312 * nl80211 socket to fix:
2313 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2314 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2315 * before (!) we listen to it, because we only start listening
2316 * after we send our scan request.
2318 * Doing it the other way around has a race condition as well,
2319 * if you first open the events socket you may get a notification
2320 * for a previous scan.
2322 * The only proper way to fix this would be to listen to events
2323 * before sending the command, and for the kernel to send the
2324 * scan request along with the event, so that you can match up
2325 * whether the scan you requested was finished or aborted (this
2326 * may result in processing a scan that another application
2327 * requested, but that doesn't seem to be a problem).
2329 * Alas, the kernel doesn't do that (yet).
2332 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2333 NL80211_CMD_SCAN_ABORTED
) {
2334 printf("scan aborted!\n");
2338 dump_argv
[0] = argv
[0];
2339 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2341 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,
2342 CIB_NETDEV
, handle_scan_combined
,
2343 "Scan on the given frequencies and probe for the given SSIDs\n"
2344 "(or wildcard if not given) unless passive scanning is requested.\n"
2345 "If -u is specified print unknown data in the scan results.\n"
2346 "Specified (vendor) IEs must be well-formed.");
2347 COMMAND(scan
, dump
, "[-u]",
2348 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2349 "Dump the current scan results. If -u is specified, print unknown\n"
2350 "data in scan results.");
2351 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]",
2352 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2353 "Trigger a scan on the given frequencies with probing for the given\n"
2354 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2355 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2358 static int handle_scan_abort(struct nl80211_state
*state
,
2360 int argc
, char **argv
,
2365 COMMAND(scan
, abort
, "",
2366 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2367 "Abort ongoing scan");
2369 static int handle_start_sched_scan(struct nl80211_state
*state
,
2371 int argc
, char **argv
, enum id_input id
)
2373 return parse_sched_scan(msg
, &argc
, &argv
);
2376 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2377 struct nl_msg
*msg
, int argc
, char **argv
,
2386 COMMAND(scan
, sched_start
,
2388 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2389 "Start a scheduled scan at the specified interval on the given frequencies\n"
2390 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2391 "scanning is requested. If matches are specified, only matching results\n"
2392 "will be returned.");
2393 COMMAND(scan
, sched_stop
, "",
2394 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2395 "Stop an ongoing scheduled scan.");