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 static int parse_random_mac_addr(struct nl_msg
*msg
, char *arg
)
74 char *a_addr
, *a_mask
, *sep
;
75 unsigned char addr
[ETH_ALEN
], mask
[ETH_ALEN
];
76 char *addrs
= arg
+ 9;
82 sep
= strchr(addrs
, '/');
90 if (mac_addr_a2n(addr
, a_addr
) || mac_addr_a2n(mask
, a_mask
))
93 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, addr
);
94 NLA_PUT(msg
, NL80211_ATTR_MAC_MASK
, ETH_ALEN
, mask
);
101 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
103 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
, *ssids
= NULL
;
104 struct nl_msg
*scan_plans
= NULL
;
105 struct nlattr
*match
= NULL
, *plan
= NULL
;
112 } parse_state
= ND_TOPLEVEL
;
114 char *end
, **v
= *argv
;
116 unsigned int freq
, interval
= 0, delay
= 0, iterations
= 0;
117 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
118 bool have_active
= false, have_passive
= false, have_plans
= false;
121 matchset
= nlmsg_alloc();
127 freqs
= nlmsg_alloc();
133 ssids
= nlmsg_alloc();
139 scan_plans
= nlmsg_alloc();
146 switch (parse_state
) {
148 if (!strcmp(v
[0], "interval")) {
152 goto nla_put_failure
;
155 if (interval
|| have_plans
) {
157 goto nla_put_failure
;
159 interval
= strtoul(v
[0], &end
, 10);
160 if (*end
|| !interval
) {
162 goto nla_put_failure
;
165 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
167 } else if (!strcmp(v
[0], "scan_plans")) {
168 parse_state
= ND_PLANS
;
169 if (have_plans
|| interval
) {
171 goto nla_put_failure
;
176 } else if (!strcmp(v
[0], "delay")) {
180 goto nla_put_failure
;
185 goto nla_put_failure
;
187 delay
= strtoul(v
[0], &end
, 10);
190 goto nla_put_failure
;
193 NL80211_ATTR_SCHED_SCAN_DELAY
,
195 } else if (!strcmp(v
[0], "matches")) {
196 parse_state
= ND_MATCH
;
199 goto nla_put_failure
;
203 } else if (!strcmp(v
[0], "freqs")) {
204 parse_state
= ND_FREQS
;
207 goto nla_put_failure
;
212 } else if (!strcmp(v
[0], "active")) {
213 parse_state
= ND_ACTIVE
;
214 if (have_active
|| have_passive
) {
216 goto nla_put_failure
;
221 } else if (!strcmp(v
[0], "passive")) {
222 if (have_active
|| have_passive
) {
224 goto nla_put_failure
;
228 } else if (!strncmp(v
[0], "randomise", 9) ||
229 !strncmp(v
[0], "randomize", 9)) {
230 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
232 err
= parse_random_mac_addr(msg
, v
[0]);
234 goto nla_put_failure
;
237 /* this element is not for us, so
238 * return to continue parsing.
240 goto nla_put_failure
;
246 if (!strcmp(v
[0], "ssid")) {
250 goto nla_put_failure
;
253 /* TODO: for now we can only have an
254 * SSID in the match, so we can start
255 * the match nest here.
257 match
= nla_nest_start(matchset
, i
);
260 goto nla_put_failure
;
264 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
266 nla_nest_end(matchset
, match
);
269 have_matchset
= true;
273 /* other element that cannot be part
274 * of a match indicates the end of the
276 /* need at least one match in the matchset */
279 goto nla_put_failure
;
282 parse_state
= ND_TOPLEVEL
;
287 freq
= strtoul(v
[0], &end
, 10);
291 goto nla_put_failure
;
294 parse_state
= ND_TOPLEVEL
;
296 NLA_PUT_U32(freqs
, i
, freq
);
302 if (!strcmp(v
[0], "ssid")) {
306 goto nla_put_failure
;
310 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
317 /* other element that cannot be part
318 * of a match indicates the end of the
320 /* need at least one item in the set */
323 goto nla_put_failure
;
326 parse_state
= ND_TOPLEVEL
;
331 interval
= strtoul(v
[0], &end
, 10);
337 goto nla_put_failure
;
341 iterations
= strtoul(iter
, &end
, 10);
342 if (*end
|| !iterations
) {
344 goto nla_put_failure
;
348 plan
= nla_nest_start(scan_plans
, i
+ 1);
351 goto nla_put_failure
;
354 NLA_PUT_U32(scan_plans
,
355 NL80211_SCHED_SCAN_PLAN_INTERVAL
,
359 NLA_PUT_U32(scan_plans
,
360 NL80211_SCHED_SCAN_PLAN_ITERATIONS
,
363 parse_state
= ND_TOPLEVEL
;
365 nla_nest_end(scan_plans
, plan
);
374 NLA_PUT(ssids
, 1, 0, "");
376 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
378 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
380 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
382 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_PLANS
, scan_plans
);
384 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
388 nla_nest_end(msg
, match
);
390 nlmsg_free(matchset
);
391 nlmsg_free(scan_plans
);
399 static int handle_scan(struct nl80211_state
*state
,
401 int argc
, char **argv
,
404 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
418 unsigned int duration
= 0;
419 bool passive
= false, have_ssids
= false, have_freqs
= false;
420 bool duration_mandatory
= false;
421 size_t ies_len
= 0, meshid_len
= 0;
422 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
423 unsigned int flags
= 0;
425 ssids
= nlmsg_alloc();
429 freqs
= nlmsg_alloc();
435 for (i
= 0; i
< argc
; i
++) {
438 if (strcmp(argv
[i
], "freq") == 0) {
442 } else if (strcmp(argv
[i
], "ies") == 0) {
445 } else if (strcmp(argv
[i
], "lowpri") == 0) {
446 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
448 } else if (strcmp(argv
[i
], "flush") == 0) {
449 flags
|= NL80211_SCAN_FLAG_FLUSH
;
451 } else if (strcmp(argv
[i
], "ap-force") == 0) {
452 flags
|= NL80211_SCAN_FLAG_AP
;
454 } else if (strcmp(argv
[i
], "duration-mandatory") == 0) {
455 duration_mandatory
= true;
457 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
458 strncmp(argv
[i
], "randomize", 9) == 0) {
459 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
460 err
= parse_random_mac_addr(msg
, argv
[i
]);
462 goto nla_put_failure
;
464 } else if (strcmp(argv
[i
], "ssid") == 0) {
468 } else if (strcmp(argv
[i
], "passive") == 0) {
472 } else if (strcmp(argv
[i
], "meshid") == 0) {
475 } else if (strcmp(argv
[i
], "duration") == 0) {
479 /* fall through - this is an error */
485 freq
= strtoul(argv
[i
], &eptr
, 10);
486 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
487 /* failed to parse as number -- maybe a tag? */
492 NLA_PUT_U32(freqs
, i
, freq
);
495 ies
= parse_hex(argv
[i
], &ies_len
);
497 goto nla_put_failure
;
501 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
504 meshid_len
= strlen(argv
[i
]);
505 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
507 goto nla_put_failure
;
508 meshid
[0] = 114; /* mesh element id */
509 meshid
[1] = meshid_len
;
510 memcpy(&meshid
[2], argv
[i
], meshid_len
);
515 duration
= strtoul(argv
[i
], &eptr
, 10);
522 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
526 goto nla_put_failure
;
529 memcpy(tmpies
, ies
, ies_len
);
533 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
536 if (nla_put(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
) < 0) {
538 goto nla_put_failure
;
544 NLA_PUT(ssids
, 1, 0, "");
546 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
549 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
551 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
553 NLA_PUT_U16(msg
, NL80211_ATTR_MEASUREMENT_DURATION
, duration
);
554 if (duration_mandatory
) {
557 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY
);
560 goto nla_put_failure
;
571 static void tab_on_first(bool *first
)
579 struct print_ies_data
{
584 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
,
585 const struct print_ies_data
*ie_buffer
)
588 print_ssid_escaped(len
, data
);
592 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
593 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
595 static void print_supprates(const uint8_t type
, uint8_t len
,
597 const struct print_ies_data
*ie_buffer
)
603 for (i
= 0; i
< len
; i
++) {
604 int r
= data
[i
] & 0x7f;
606 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
608 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
611 printf("%d.%d", r
/2, 5*(r
&1));
613 printf("%s ", data
[i
] & 0x80 ? "*" : "");
618 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
,
619 const struct print_ies_data
*ie_buffer
)
621 printf(" channel %d\n", data
[0]);
624 static const char *country_env_str(char environment
)
626 switch (environment
) {
628 return "Indoor only";
630 return "Outdoor only";
632 return "Indoor/Outdoor";
638 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
,
639 const struct print_ies_data
*ie_buffer
)
641 printf(" %.*s", 2, data
);
643 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
649 printf("\t\tNo country IE triplets present\n");
655 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
657 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
658 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
659 triplet
->ext
.reg_extension_id
,
660 triplet
->ext
.reg_class
,
661 triplet
->ext
.coverage_class
,
662 triplet
->ext
.coverage_class
* 450);
670 if (triplet
->chans
.first_channel
<= 14)
671 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
673 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
675 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
684 static void print_powerconstraint(const uint8_t type
, uint8_t len
,
686 const struct print_ies_data
*ie_buffer
)
688 printf(" %d dB\n", data
[0]);
691 static void print_tpcreport(const uint8_t type
, uint8_t len
,
693 const struct print_ies_data
*ie_buffer
)
695 printf(" TX power: %d dBm\n", data
[0]);
696 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
699 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
,
700 const struct print_ies_data
*ie_buffer
)
703 printf(" <no flags>");
705 printf(" NonERP_Present");
707 printf(" Use_Protection");
709 printf(" Barker_Preamble_Mode");
713 static void print_cipher(const uint8_t *data
)
715 if (memcmp(data
, ms_oui
, 3) == 0) {
718 printf("Use group cipher suite");
733 printf("%.02x-%.02x-%.02x:%d",
734 data
[0], data
[1] ,data
[2], data
[3]);
737 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
740 printf("Use group cipher suite");
755 printf("AES-128-CMAC");
764 printf("%.02x-%.02x-%.02x:%d",
765 data
[0], data
[1] ,data
[2], data
[3]);
769 printf("%.02x-%.02x-%.02x:%d",
770 data
[0], data
[1] ,data
[2], data
[3]);
773 static void print_auth(const uint8_t *data
)
775 if (memcmp(data
, ms_oui
, 3) == 0) {
778 printf("IEEE 802.1X");
784 printf("%.02x-%.02x-%.02x:%d",
785 data
[0], data
[1] ,data
[2], data
[3]);
788 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
791 printf("IEEE 802.1X");
797 printf("FT/IEEE 802.1X");
803 printf("IEEE 802.1X/SHA-256");
806 printf("PSK/SHA-256");
812 printf("%.02x-%.02x-%.02x:%d",
813 data
[0], data
[1] ,data
[2], data
[3]);
816 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
822 printf("%.02x-%.02x-%.02x:%d",
823 data
[0], data
[1] ,data
[2], data
[3]);
827 printf("%.02x-%.02x-%.02x:%d",
828 data
[0], data
[1] ,data
[2], data
[3]);
831 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
832 uint8_t len
, const uint8_t *data
, int is_osen
)
840 version
= data
[0] + (data
[1] << 8);
841 tab_on_first(&first
);
842 printf("\t * Version: %d\n", version
);
849 tab_on_first(&first
);
850 printf("\t * Group cipher: %s\n", defcipher
);
851 printf("\t * Pairwise ciphers: %s\n", defcipher
);
855 tab_on_first(&first
);
856 printf("\t * Group cipher: ");
864 tab_on_first(&first
);
865 printf("\t * Pairwise ciphers: %s\n", defcipher
);
869 count
= data
[0] | (data
[1] << 8);
870 if (2 + (count
* 4) > len
)
873 tab_on_first(&first
);
874 printf("\t * Pairwise ciphers:");
875 for (i
= 0; i
< count
; i
++) {
877 print_cipher(data
+ 2 + (i
* 4));
881 data
+= 2 + (count
* 4);
882 len
-= 2 + (count
* 4);
885 tab_on_first(&first
);
886 printf("\t * Authentication suites: %s\n", defauth
);
890 count
= data
[0] | (data
[1] << 8);
891 if (2 + (count
* 4) > len
)
894 tab_on_first(&first
);
895 printf("\t * Authentication suites:");
896 for (i
= 0; i
< count
; i
++) {
898 print_auth(data
+ 2 + (i
* 4));
902 data
+= 2 + (count
* 4);
903 len
-= 2 + (count
* 4);
906 capa
= data
[0] | (data
[1] << 8);
907 tab_on_first(&first
);
908 printf("\t * Capabilities:");
912 printf(" NoPairwise");
913 switch ((capa
& 0x000c) >> 2) {
915 printf(" 1-PTKSA-RC");
918 printf(" 2-PTKSA-RC");
921 printf(" 4-PTKSA-RC");
924 printf(" 16-PTKSA-RC");
927 switch ((capa
& 0x0030) >> 4) {
929 printf(" 1-GTKSA-RC");
932 printf(" 2-GTKSA-RC");
935 printf(" 4-GTKSA-RC");
938 printf(" 16-GTKSA-RC");
942 printf(" MFP-required");
944 printf(" MFP-capable");
946 printf(" Peerkey-enabled");
948 printf(" SPP-AMSDU-capable");
950 printf(" SPP-AMSDU-required");
951 printf(" (0x%.4x)\n", capa
);
957 int pmkid_count
= data
[0] | (data
[1] << 8);
959 if (len
>= 2 + 16 * pmkid_count
) {
960 tab_on_first(&first
);
961 printf("\t * %d PMKIDs\n", pmkid_count
);
962 /* not printing PMKID values */
963 data
+= 2 + 16 * pmkid_count
;
964 len
-= 2 + 16 * pmkid_count
;
970 tab_on_first(&first
);
971 printf("\t * Group mgmt cipher suite: ");
980 printf("\t\t * bogus tail data (%d):", len
);
982 printf(" %.2x", *data
);
990 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
991 uint8_t len
, const uint8_t *data
)
993 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
996 static void print_osen_ie(const char *defcipher
, const char *defauth
,
997 uint8_t len
, const uint8_t *data
)
1000 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
1003 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1004 const struct print_ies_data
*ie_buffer
)
1006 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
1009 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1010 const struct print_ies_data
*ie_buffer
)
1013 print_ht_capability(data
[0] | (data
[1] << 8));
1014 print_ampdu_length(data
[2] & 3);
1015 print_ampdu_spacing((data
[2] >> 2) & 7);
1016 print_ht_mcs(data
+ 3);
1019 static const char* ntype_11u(uint8_t t
)
1022 case 0: return "Private";
1023 case 1: return "Private with Guest";
1024 case 2: return "Chargeable Public";
1025 case 3: return "Free Public";
1026 case 4: return "Personal Device";
1027 case 5: return "Emergency Services Only";
1028 case 14: return "Test or Experimental";
1029 case 15: return "Wildcard";
1030 default: return "Reserved";
1034 static const char* vgroup_11u(uint8_t t
)
1037 case 0: return "Unspecified";
1038 case 1: return "Assembly";
1039 case 2: return "Business";
1040 case 3: return "Educational";
1041 case 4: return "Factory and Industrial";
1042 case 5: return "Institutional";
1043 case 6: return "Mercantile";
1044 case 7: return "Residential";
1045 case 8: return "Storage";
1046 case 9: return "Utility and Miscellaneous";
1047 case 10: return "Vehicular";
1048 case 11: return "Outdoor";
1049 default: return "Reserved";
1053 static void print_interworking(const uint8_t type
, uint8_t len
,
1054 const uint8_t *data
,
1055 const struct print_ies_data
*ie_buffer
)
1057 /* See Section 7.3.2.92 in the 802.11u spec. */
1060 uint8_t ano
= data
[0];
1061 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
1062 printf("\t\t\tNetwork Type: %i (%s)\n",
1063 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
1065 printf("\t\t\tInternet\n");
1067 printf("\t\t\tASRA\n");
1069 printf("\t\t\tESR\n");
1071 printf("\t\t\tUESA\n");
1073 if ((len
== 3) || (len
== 9)) {
1074 printf("\t\tVenue Group: %i (%s)\n",
1075 (int)(data
[1]), vgroup_11u(data
[1]));
1076 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
1079 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1080 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
1082 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
1083 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
1086 static void print_11u_advert(const uint8_t type
, uint8_t len
,
1087 const uint8_t *data
,
1088 const struct print_ies_data
*ie_buffer
)
1090 /* See Section 7.3.2.93 in the 802.11u spec. */
1091 /* TODO: This code below does not decode private protocol IDs */
1094 while (idx
< (len
- 1)) {
1095 uint8_t qri
= data
[idx
];
1096 uint8_t proto_id
= data
[idx
+ 1];
1097 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
1098 printf("\t\t\tQuery Response Length Limit: %i\n",
1101 printf("\t\t\tPAME-BI\n");
1104 printf("\t\t\tANQP\n"); break;
1106 printf("\t\t\tMIH Information Service\n"); break;
1108 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1110 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1112 printf("\t\t\tVendor Specific\n"); break;
1114 printf("\t\t\tReserved: %i\n", proto_id
); break;
1120 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1121 const struct print_ies_data
*ie_buffer
)
1123 /* See Section 7.3.2.96 in the 802.11u spec. */
1125 int ln0
= data
[1] & 0xf;
1126 int ln1
= ((data
[1] & 0xf0) >> 4);
1131 ln2
= len
- 2 - ln0
- ln1
;
1133 printf("\t\tANQP OIs: %i\n", data
[0]);
1136 printf("\t\tOI 1: ");
1137 if (2 + ln0
> len
) {
1138 printf("Invalid IE length.\n");
1140 for (idx
= 0; idx
< ln0
; idx
++) {
1141 printf("%02hx", data
[2 + idx
]);
1148 printf("\t\tOI 2: ");
1149 if (2 + ln0
+ ln1
> len
) {
1150 printf("Invalid IE length.\n");
1152 for (idx
= 0; idx
< ln1
; idx
++) {
1153 printf("%02hx", data
[2 + ln0
+ idx
]);
1160 printf("\t\tOI 3: ");
1161 if (2 + ln0
+ ln1
+ ln2
> len
) {
1162 printf("Invalid IE length.\n");
1164 for (idx
= 0; idx
< ln2
; idx
++) {
1165 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1172 static const char *ht_secondary_offset
[4] = {
1179 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1180 const struct print_ies_data
*ie_buffer
)
1182 static const char *protection
[4] = {
1188 static const char *sta_chan_width
[2] = {
1194 printf("\t\t * primary channel: %d\n", data
[0]);
1195 printf("\t\t * secondary channel offset: %s\n",
1196 ht_secondary_offset
[data
[1] & 0x3]);
1197 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1198 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1199 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1200 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1201 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1202 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1203 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1204 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1205 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1206 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1207 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1210 static void print_capabilities(const uint8_t type
, uint8_t len
,
1211 const uint8_t *data
,
1212 const struct print_ies_data
*ie_buffer
)
1214 int i
, base
, bit
, si_duration
= 0, max_amsdu
= 0;
1215 bool s_psmp_support
= false, is_vht_cap
= false;
1216 unsigned char *ie
= ie_buffer
->ie
;
1217 int ielen
= ie_buffer
->ielen
;
1219 while (ielen
>= 2 && ielen
>= ie
[1]) {
1228 for (i
= 0; i
< len
; i
++) {
1231 for (bit
= 0; bit
< 8; bit
++) {
1232 if (!(data
[i
] & (1 << bit
)))
1237 #define CAPA(bit, name) case bit: printf(" " name); break
1239 /* if the capability 'cap' exists add 'val' to 'sum'
1240 * otherwise print 'Reserved' */
1241 #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1243 printf(" Reserved"); \
1250 switch (bit
+ base
) {
1251 CAPA(0, "HT Information Exchange Supported");
1252 CAPA(1, "reserved (On-demand Beacon)");
1253 CAPA(2, "Extended Channel Switching");
1254 CAPA(3, "reserved (Wave Indication)");
1255 CAPA(4, "PSMP Capability");
1256 CAPA(5, "reserved (Service Interval Granularity)");
1259 s_psmp_support
= true;
1260 printf(" S-PSMP Capability");
1264 CAPA(8, "Diagnostics");
1265 CAPA(9, "Multicast Diagnostics");
1266 CAPA(10, "Location Tracking");
1268 CAPA(12, "Proxy ARP Service");
1269 CAPA(13, "Collocated Interference Reporting");
1270 CAPA(14, "Civic Location");
1271 CAPA(15, "Geospatial Location");
1273 CAPA(17, "WNM-Sleep Mode");
1274 CAPA(18, "TIM Broadcast");
1275 CAPA(19, "BSS Transition");
1276 CAPA(20, "QoS Traffic Capability");
1277 CAPA(21, "AC Station Count");
1278 CAPA(22, "Multiple BSSID");
1279 CAPA(23, "Timing Measurement");
1280 CAPA(24, "Channel Usage");
1281 CAPA(25, "SSID List");
1283 CAPA(27, "UTC TSF Offset");
1284 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1285 CAPA(29, "TDLS Peer PSM Support");
1286 CAPA(30, "TDLS channel switching");
1287 CAPA(31, "Interworking");
1288 CAPA(32, "QoS Map");
1290 CAPA(34, "SSPN Interface");
1291 CAPA(35, "Reserved");
1292 CAPA(36, "MSGCF Capability");
1293 CAPA(37, "TDLS Support");
1294 CAPA(38, "TDLS Prohibited");
1295 CAPA(39, "TDLS Channel Switching Prohibited");
1296 CAPA(40, "Reject Unadmitted Frame");
1298 ADD_BIT_VAL(41, s_psmp_support
, si_duration
, 1);
1299 ADD_BIT_VAL(42, s_psmp_support
, si_duration
, 2);
1300 ADD_BIT_VAL(43, s_psmp_support
, si_duration
, 4);
1302 CAPA(44, "Identifier Location");
1303 CAPA(45, "U-APSD Coexistence");
1304 CAPA(46, "WNM-Notification");
1305 CAPA(47, "Reserved");
1306 CAPA(48, "UTF-8 SSID");
1307 CAPA(49, "QMFActivated");
1308 CAPA(50, "QMFReconfigurationActivated");
1309 CAPA(51, "Robust AV Streaming");
1310 CAPA(52, "Advanced GCR");
1311 CAPA(53, "Mesh GCR");
1313 CAPA(55, "QLoad Report");
1314 CAPA(56, "Alternate EDCA");
1315 CAPA(57, "Unprotected TXOP Negotiation");
1316 CAPA(58, "Protected TXOP egotiation");
1317 CAPA(59, "Reserved");
1318 CAPA(60, "Protected QLoad Report");
1319 CAPA(61, "TDLS Wider Bandwidth");
1320 CAPA(62, "Operating Mode Notification");
1322 ADD_BIT_VAL(63, is_vht_cap
, max_amsdu
, 1);
1323 ADD_BIT_VAL(64, is_vht_cap
, max_amsdu
, 2);
1325 CAPA(65, "Channel Schedule Management");
1326 CAPA(66, "Geodatabase Inband Enabling Signal");
1327 CAPA(67, "Network Channel Control");
1328 CAPA(68, "White Space Map");
1329 CAPA(69, "Channel Availability Query");
1330 CAPA(70, "FTM Responder");
1331 CAPA(71, "FTM Initiator");
1332 CAPA(72, "Reserved");
1333 CAPA(73, "Extended Spectrum Management Capable");
1334 CAPA(74, "Reserved");
1345 printf("\n\t\t * Service Interval Granularity is %d ms",
1346 (si_duration
+ 1) * 5);
1349 printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1350 switch (max_amsdu
) {
1352 printf("unlimited");
1371 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1372 const struct print_ies_data
*ie_buffer
)
1374 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1376 data
[0], data
[1], data
[2], data
[3]);
1378 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1382 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1383 const struct print_ies_data
*ie_buffer
)
1385 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1388 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1389 const struct print_ies_data
*ie_buffer
)
1392 print_vht_info(data
[0] | (data
[1] << 8) |
1393 (data
[2] << 16) | (data
[3] << 24),
1397 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1398 const struct print_ies_data
*ie_buffer
)
1400 const char *chandwidths
[] = {
1401 [0] = "20 or 40 MHz",
1408 printf("\t\t * channel width: %d (%s)\n", data
[0],
1409 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1410 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1411 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1412 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1415 static void print_obss_scan_params(const uint8_t type
, uint8_t len
,
1416 const uint8_t *data
,
1417 const struct print_ies_data
*ie_buffer
)
1420 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1421 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1422 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1423 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1424 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1425 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1426 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1427 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1430 static void print_secchan_offs(const uint8_t type
, uint8_t len
,
1431 const uint8_t *data
,
1432 const struct print_ies_data
*ie_buffer
)
1434 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1435 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1437 printf(" %d\n", data
[0]);
1440 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1441 const struct print_ies_data
*ie_buffer
)
1444 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1445 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1446 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1449 static void print_mesh_conf(const uint8_t type
, uint8_t len
,
1450 const uint8_t *data
,
1451 const struct print_ies_data
*ie_buffer
)
1454 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1455 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1456 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1457 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1458 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1459 printf("\t\t * Mesh Formation Info:\n");
1460 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1462 printf("\t\t\t Connected to Mesh Gate\n");
1464 printf("\t\t\t Connected to AS\n");
1465 printf("\t\t * Mesh Capability\n");
1467 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1469 printf("\t\t\t MCCA Supported\n");
1471 printf("\t\t\t MCCA Enabled\n");
1473 printf("\t\t\t Forwarding\n");
1475 printf("\t\t\t MBCA Supported\n");
1477 printf("\t\t\t TBTT Adjusting\n");
1479 printf("\t\t\t Mesh Power Save Level\n");
1484 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1485 const struct print_ies_data
*ie_buffer
);
1486 uint8_t minlen
, maxlen
;
1490 static void print_ie(const struct ie_print
*p
, const uint8_t type
, uint8_t len
,
1491 const uint8_t *data
,
1492 const struct print_ies_data
*ie_buffer
)
1499 printf("\t%s:", p
->name
);
1500 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1502 printf(" <invalid: %d bytes:", len
);
1503 for (i
= 0; i
< len
; i
++)
1504 printf(" %.02x", data
[i
]);
1507 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1509 printf(" <invalid: no data>\n");
1513 p
->print(type
, len
, data
, ie_buffer
);
1516 #define PRINT_IGN { \
1523 static const struct ie_print ieprinters
[] = {
1524 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1525 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1526 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1527 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1528 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1529 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1530 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1531 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1532 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1533 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1534 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1535 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1536 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1537 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1538 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1539 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1540 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1541 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1542 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1543 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1544 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1545 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1546 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1547 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1548 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1551 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1552 const struct print_ies_data
*ie_buffer
)
1554 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1557 static void print_wifi_osen(const uint8_t type
, uint8_t len
,
1558 const uint8_t *data
,
1559 const struct print_ies_data
*ie_buffer
)
1561 print_osen_ie("OSEN", "OSEN", len
, data
);
1564 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1567 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1573 printf("Parameter: not version 1: ");
1577 printf("\t * Parameter version 1");
1582 printf("\n\t\t * u-APSD");
1586 for (i
= 0; i
< 4; i
++) {
1587 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1590 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1591 (1 << (data
[1] >> 4)) - 1);
1592 printf(", AIFSN %d", data
[0] & 0xf);
1593 if (data
[2] | data
[3])
1594 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1602 printf("invalid: ");
1606 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1607 const struct print_ies_data
*ie_buffer
)
1613 printf(" information:");
1616 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1620 printf(" type %d:", data
[0]);
1624 for(i
= 1; i
< len
; i
++)
1625 printf(" %.02x", data
[i
]);
1629 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1633 return "Default (PIN)";
1635 return "User-specified";
1637 return "Machine-specified";
1641 return "PushButton";
1643 return "Registrar-specified";
1649 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
,
1650 const struct print_ies_data
*ie_buffer
)
1653 __u16 subtype
, sublen
;
1656 subtype
= (data
[0] << 8) + data
[1];
1657 sublen
= (data
[2] << 8) + data
[3];
1663 tab_on_first(&first
);
1664 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1667 tab_on_first(&first
);
1668 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1672 tab_on_first(&first
);
1674 printf("\t * Device Password ID: (invalid "
1675 "length %d)\n", sublen
);
1678 id
= data
[4] << 8 | data
[5];
1679 printf("\t * Device Password ID: %u (%s)\n",
1680 id
, wifi_wps_dev_passwd_id(id
));
1684 tab_on_first(&first
);
1685 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1688 tab_on_first(&first
);
1689 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1692 tab_on_first(&first
);
1693 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1697 tab_on_first(&first
);
1698 printf("\t * Response Type: %d%s\n",
1699 val
, val
== 3 ? " (AP)" : "");
1704 tab_on_first(&first
);
1705 printf("\t * RF Bands: 0x%x\n", val
);
1710 tab_on_first(&first
);
1711 printf("\t * Selected Registrar: 0x%x\n", val
);
1715 tab_on_first(&first
);
1716 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1720 tab_on_first(&first
);
1721 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1723 val
== 1 ? " (Unconfigured)" : "",
1724 val
== 2 ? " (Configured)" : "");
1728 tab_on_first(&first
);
1729 printf("\t * UUID: ");
1731 printf("(invalid, length=%d)\n", sublen
);
1734 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1735 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1736 data
[4], data
[5], data
[6], data
[7],
1737 data
[8], data
[9], data
[10], data
[11],
1738 data
[12], data
[13], data
[14], data
[15],
1739 data
[16], data
[17], data
[18], data
[19]);
1742 tab_on_first(&first
);
1744 printf("\t * Primary Device Type: (invalid "
1745 "length %d)\n", sublen
);
1748 printf("\t * Primary Device Type: "
1749 "%u-%02x%02x%02x%02x-%u\n",
1750 data
[4] << 8 | data
[5],
1751 data
[6], data
[7], data
[8], data
[9],
1752 data
[10] << 8 | data
[11]);
1757 tab_on_first(&first
);
1758 printf("\t * AP setup locked: 0x%.2x\n", val
);
1763 __u16 meth
= (data
[4] << 8) + data
[5];
1765 tab_on_first(&first
);
1766 printf("\t * %sConfig methods:",
1767 subtype
== 0x1053 ? "Selected Registrar ": "");
1768 #define T(bit, name) do { \
1769 if (meth & (1<<bit)) { \
1789 const __u8
*subdata
= data
+ 4;
1790 __u16 tmplen
= sublen
;
1792 tab_on_first(&first
);
1793 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1796 printf(" %.2x", *subdata
);
1810 printf("\t\t * bogus tail data (%d):", len
);
1812 printf(" %.2x", *data
);
1820 static const struct ie_print wifiprinters
[] = {
1821 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1822 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1823 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1826 static inline void print_p2p(const uint8_t type
, uint8_t len
,
1827 const uint8_t *data
,
1828 const struct print_ies_data
*ie_buffer
)
1836 sublen
= (data
[2] << 8) + data
[1];
1838 if (sublen
> len
- 3)
1842 case 0x02: /* capability */
1843 tab_on_first(&first
);
1845 printf("\t * malformed capability\n");
1848 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1851 case 0x0d: /* device info */
1852 if (sublen
< 6 + 2 + 8 + 1) {
1853 printf("\t * malformed device info\n");
1857 /* fall through for now */
1858 case 0x00: /* status */
1859 case 0x01: /* minor reason */
1860 case 0x03: /* device ID */
1861 case 0x04: /* GO intent */
1862 case 0x05: /* configuration timeout */
1863 case 0x06: /* listen channel */
1864 case 0x07: /* group BSSID */
1865 case 0x08: /* ext listen timing */
1866 case 0x09: /* intended interface address */
1867 case 0x0a: /* manageability */
1868 case 0x0b: /* channel list */
1869 case 0x0c: /* NoA */
1870 case 0x0e: /* group info */
1871 case 0x0f: /* group ID */
1872 case 0x10: /* interface */
1873 case 0x11: /* operating channel */
1874 case 0x12: /* invitation flags */
1875 case 0xdd: /* vendor specific */
1877 const __u8
*subdata
= data
+ 4;
1878 __u16 tmplen
= sublen
;
1880 tab_on_first(&first
);
1881 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1884 printf(" %.2x", *subdata
);
1898 tab_on_first(&first
);
1899 printf("\t * bogus tail data (%d):", len
);
1901 printf(" %.2x", *data
);
1909 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
,
1910 const uint8_t *data
,
1911 const struct print_ies_data
*ie_buffer
)
1913 /* I can't find the spec for this...just going off what wireshark uses. */
1916 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1918 printf("\t\tUnexpected length: %i\n", len
);
1921 static const struct ie_print wfa_printers
[] = {
1922 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1923 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1924 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1927 static void print_vendor(unsigned char len
, unsigned char *data
,
1928 bool unknown
, enum print_ie_type ptype
)
1933 printf("\tVendor specific: <too short> data:");
1934 for(i
= 0; i
< len
; i
++)
1935 printf(" %.02x", data
[i
]);
1940 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1941 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1942 wifiprinters
[data
[3]].name
&&
1943 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1944 print_ie(&wifiprinters
[data
[3]],
1945 data
[3], len
- 4, data
+ 4, 0);
1950 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1951 for(i
= 0; i
< len
- 4; i
++)
1952 printf(" %.02x", data
[i
+ 4]);
1957 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1958 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1959 wfa_printers
[data
[3]].name
&&
1960 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1961 print_ie(&wfa_printers
[data
[3]],
1962 data
[3], len
- 4, data
+ 4, 0);
1967 printf("\tWFA %#.2x, data:", data
[3]);
1968 for(i
= 0; i
< len
- 4; i
++)
1969 printf(" %.02x", data
[i
+ 4]);
1977 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1978 data
[0], data
[1], data
[2]);
1979 for (i
= 3; i
< len
; i
++)
1980 printf(" %.2x", data
[i
]);
1984 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1985 enum print_ie_type ptype
)
1987 struct print_ies_data ie_buffer
= {
1991 while (ielen
>= 2 && ielen
>= ie
[1]) {
1992 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1993 ieprinters
[ie
[0]].name
&&
1994 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1995 print_ie(&ieprinters
[ie
[0]],
1996 ie
[0], ie
[1], ie
+ 2, &ie_buffer
);
1997 } else if (ie
[0] == 221 /* vendor */) {
1998 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1999 } else if (unknown
) {
2002 printf("\tUnknown IE (%d):", ie
[0]);
2003 for (i
=0; i
<ie
[1]; i
++)
2004 printf(" %.2x", ie
[2+i
]);
2012 static void print_capa_dmg(__u16 capa
)
2014 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
2015 case WLAN_CAPABILITY_DMG_TYPE_AP
:
2018 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
2021 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
2022 printf(" DMG_IBSS");
2026 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
2027 printf(" CBAP_Only");
2028 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
2029 printf(" CBAP_Src");
2030 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
2032 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
2034 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
2035 printf(" SpectrumMgmt");
2036 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
2037 printf(" RadioMeasure");
2040 static void print_capa_non_dmg(__u16 capa
)
2042 if (capa
& WLAN_CAPABILITY_ESS
)
2044 if (capa
& WLAN_CAPABILITY_IBSS
)
2046 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
2047 printf(" CfPollable");
2048 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
2049 printf(" CfPollReq");
2050 if (capa
& WLAN_CAPABILITY_PRIVACY
)
2052 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
2053 printf(" ShortPreamble");
2054 if (capa
& WLAN_CAPABILITY_PBCC
)
2056 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
2057 printf(" ChannelAgility");
2058 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
2059 printf(" SpectrumMgmt");
2060 if (capa
& WLAN_CAPABILITY_QOS
)
2062 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
2063 printf(" ShortSlotTime");
2064 if (capa
& WLAN_CAPABILITY_APSD
)
2066 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
2067 printf(" RadioMeasure");
2068 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
2069 printf(" DSSS-OFDM");
2070 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
2071 printf(" DelayedBACK");
2072 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
2073 printf(" ImmediateBACK");
2076 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
2078 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
2079 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
2080 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
2081 char mac_addr
[20], dev
[20];
2082 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
2083 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
2084 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
2085 [NL80211_BSS_BSSID
] = { },
2086 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
2087 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
2088 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
2089 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
2090 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
2091 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
2092 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
2093 [NL80211_BSS_BEACON_IES
] = { },
2095 struct scan_params
*params
= arg
;
2096 int show
= params
->show_both_ie_sets
? 2 : 1;
2097 bool is_dmg
= false;
2099 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
2100 genlmsg_attrlen(gnlh
, 0), NULL
);
2102 if (!tb
[NL80211_ATTR_BSS
]) {
2103 fprintf(stderr
, "bss info missing!\n");
2106 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
2107 tb
[NL80211_ATTR_BSS
],
2109 fprintf(stderr
, "failed to parse nested attributes!\n");
2113 if (!bss
[NL80211_BSS_BSSID
])
2116 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
2117 printf("BSS %s", mac_addr
);
2118 if (tb
[NL80211_ATTR_IFINDEX
]) {
2119 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
2120 printf("(on %s)", dev
);
2123 if (bss
[NL80211_BSS_STATUS
]) {
2124 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
2125 case NL80211_BSS_STATUS_AUTHENTICATED
:
2126 printf(" -- authenticated");
2128 case NL80211_BSS_STATUS_ASSOCIATED
:
2129 printf(" -- associated");
2131 case NL80211_BSS_STATUS_IBSS_JOINED
:
2132 printf(" -- joined");
2135 printf(" -- unknown status: %d",
2136 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
2142 if (bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]) {
2143 unsigned long long bt
;
2144 bt
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_LAST_SEEN_BOOTTIME
]);
2145 printf("\tlast seen: %llu.%.3llus [boottime]\n", bt
/1000000000, (bt
%1000000000)/1000000);
2148 if (bss
[NL80211_BSS_TSF
]) {
2149 unsigned long long tsf
;
2150 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
2151 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2152 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
2153 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
2155 if (bss
[NL80211_BSS_FREQUENCY
]) {
2156 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
2157 printf("\tfreq: %d\n", freq
);
2161 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
2162 printf("\tbeacon interval: %d TUs\n",
2163 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
2164 if (bss
[NL80211_BSS_CAPABILITY
]) {
2165 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
2166 printf("\tcapability:");
2168 print_capa_dmg(capa
);
2170 print_capa_non_dmg(capa
);
2171 printf(" (0x%.4x)\n", capa
);
2173 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
2174 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
2175 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
2177 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
2178 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
2179 printf("\tsignal: %d/100\n", s
);
2181 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
2182 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
2183 printf("\tlast seen: %d ms ago\n", age
);
2186 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
2187 struct nlattr
*ies
= bss
[NL80211_BSS_INFORMATION_ELEMENTS
];
2188 struct nlattr
*bcnies
= bss
[NL80211_BSS_BEACON_IES
];
2190 if (bss
[NL80211_BSS_PRESP_DATA
] ||
2191 (bcnies
&& (nla_len(ies
) != nla_len(bcnies
) ||
2192 memcmp(nla_data(ies
), nla_data(bcnies
), nla_len(ies
)))))
2193 printf("\tInformation elements from Probe Response "
2195 print_ies(nla_data(ies
), nla_len(ies
),
2196 params
->unknown
, params
->type
);
2198 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
2199 printf("\tInformation elements from Beacon frame:\n");
2200 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
2201 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
2202 params
->unknown
, params
->type
);
2208 static struct scan_params scan_params
;
2210 static int handle_scan_dump(struct nl80211_state
*state
,
2212 int argc
, char **argv
,
2218 memset(&scan_params
, 0, sizeof(scan_params
));
2220 if (argc
== 1 && !strcmp(argv
[0], "-u"))
2221 scan_params
.unknown
= true;
2222 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
2223 scan_params
.show_both_ie_sets
= true;
2225 scan_params
.type
= PRINT_SCAN
;
2227 register_handler(print_bss_handler
, &scan_params
);
2231 static int handle_scan_combined(struct nl80211_state
*state
,
2233 int argc
, char **argv
,
2237 static char *dump_argv
[] = {
2243 static const __u32 cmds
[] = {
2244 NL80211_CMD_NEW_SCAN_RESULTS
,
2245 NL80211_CMD_SCAN_ABORTED
,
2247 int trig_argc
, dump_argc
, err
;
2250 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2252 dump_argv
[3] = "-u";
2253 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2255 dump_argv
[3] = "-b";
2259 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2260 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2263 trig_argv
[0] = argv
[0];
2264 trig_argv
[1] = "scan";
2265 trig_argv
[2] = "trigger";
2267 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2268 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2269 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2275 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2277 * This code has a bug, which requires creating a separate
2278 * nl80211 socket to fix:
2279 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2280 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2281 * before (!) we listen to it, because we only start listening
2282 * after we send our scan request.
2284 * Doing it the other way around has a race condition as well,
2285 * if you first open the events socket you may get a notification
2286 * for a previous scan.
2288 * The only proper way to fix this would be to listen to events
2289 * before sending the command, and for the kernel to send the
2290 * scan request along with the event, so that you can match up
2291 * whether the scan you requested was finished or aborted (this
2292 * may result in processing a scan that another application
2293 * requested, but that doesn't seem to be a problem).
2295 * Alas, the kernel doesn't do that (yet).
2298 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2299 NL80211_CMD_SCAN_ABORTED
) {
2300 printf("scan aborted!\n");
2304 dump_argv
[0] = argv
[0];
2305 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2307 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,
2308 CIB_NETDEV
, handle_scan_combined
,
2309 "Scan on the given frequencies and probe for the given SSIDs\n"
2310 "(or wildcard if not given) unless passive scanning is requested.\n"
2311 "If -u is specified print unknown data in the scan results.\n"
2312 "Specified (vendor) IEs must be well-formed.");
2313 COMMAND(scan
, dump
, "[-u]",
2314 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2315 "Dump the current scan results. If -u is specified, print unknown\n"
2316 "data in scan results.");
2317 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]",
2318 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2319 "Trigger a scan on the given frequencies with probing for the given\n"
2320 "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2321 "Duration(in TUs), if specified, will be used to set dwell times.\n");
2324 static int handle_scan_abort(struct nl80211_state
*state
,
2326 int argc
, char **argv
,
2331 COMMAND(scan
, abort
, "",
2332 NL80211_CMD_ABORT_SCAN
, 0, CIB_NETDEV
, handle_scan_abort
,
2333 "Abort ongoing scan");
2335 static int handle_start_sched_scan(struct nl80211_state
*state
,
2337 int argc
, char **argv
, enum id_input id
)
2339 return parse_sched_scan(msg
, &argc
, &argv
);
2342 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2343 struct nl_msg
*msg
, int argc
, char **argv
,
2352 COMMAND(scan
, sched_start
,
2354 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2355 "Start a scheduled scan at the specified interval on the given frequencies\n"
2356 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2357 "scanning is requested. If matches are specified, only matching results\n"
2358 "will be returned.");
2359 COMMAND(scan
, sched_stop
, "",
2360 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2361 "Stop an ongoing scheduled scan.");