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 nlattr
*match
= NULL
;
110 } parse_state
= ND_TOPLEVEL
;
112 char *end
, **v
= *argv
;
114 unsigned int freq
, interval
= 0, delay
= 0;
115 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
116 bool have_active
= false, have_passive
= false;
119 matchset
= nlmsg_alloc();
125 freqs
= nlmsg_alloc();
131 ssids
= nlmsg_alloc();
138 switch (parse_state
) {
140 if (!strcmp(v
[0], "interval")) {
144 goto nla_put_failure
;
149 goto nla_put_failure
;
151 interval
= strtoul(v
[0], &end
, 10);
152 if (*end
|| !interval
) {
154 goto nla_put_failure
;
157 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
159 } else if (!strcmp(v
[0], "delay")) {
163 goto nla_put_failure
;
168 goto nla_put_failure
;
170 delay
= strtoul(v
[0], &end
, 10);
173 goto nla_put_failure
;
176 NL80211_ATTR_SCHED_SCAN_DELAY
,
178 } else if (!strcmp(v
[0], "matches")) {
179 parse_state
= ND_MATCH
;
182 goto nla_put_failure
;
186 } else if (!strcmp(v
[0], "freqs")) {
187 parse_state
= ND_FREQS
;
190 goto nla_put_failure
;
195 } else if (!strcmp(v
[0], "active")) {
196 parse_state
= ND_ACTIVE
;
197 if (have_active
|| have_passive
) {
199 goto nla_put_failure
;
204 } else if (!strcmp(v
[0], "passive")) {
205 if (have_active
|| have_passive
) {
207 goto nla_put_failure
;
211 } else if (!strncmp(v
[0], "randomise", 9) ||
212 !strncmp(v
[0], "randomize", 9)) {
213 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
215 err
= parse_random_mac_addr(msg
, v
[0]);
217 goto nla_put_failure
;
220 /* this element is not for us, so
221 * return to continue parsing.
223 goto nla_put_failure
;
229 if (!strcmp(v
[0], "ssid")) {
233 goto nla_put_failure
;
236 /* TODO: for now we can only have an
237 * SSID in the match, so we can start
238 * the match nest here.
240 match
= nla_nest_start(matchset
, i
);
243 goto nla_put_failure
;
247 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
249 nla_nest_end(matchset
, match
);
252 have_matchset
= true;
256 /* other element that cannot be part
257 * of a match indicates the end of the
259 /* need at least one match in the matchset */
262 goto nla_put_failure
;
265 parse_state
= ND_TOPLEVEL
;
270 freq
= strtoul(v
[0], &end
, 10);
274 goto nla_put_failure
;
277 parse_state
= ND_TOPLEVEL
;
279 NLA_PUT_U32(freqs
, i
, freq
);
285 if (!strcmp(v
[0], "ssid")) {
289 goto nla_put_failure
;
293 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
300 /* other element that cannot be part
301 * of a match indicates the end of the
303 /* need at least one item in the set */
306 goto nla_put_failure
;
309 parse_state
= ND_TOPLEVEL
;
316 NLA_PUT(ssids
, 1, 0, "");
318 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
320 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
322 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
324 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
328 nla_nest_end(msg
, match
);
330 nlmsg_free(matchset
);
338 static int handle_scan(struct nl80211_state
*state
,
340 int argc
, char **argv
,
343 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
356 bool passive
= false, have_ssids
= false, have_freqs
= false;
357 size_t ies_len
= 0, meshid_len
= 0;
358 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
359 unsigned int flags
= 0;
361 ssids
= nlmsg_alloc();
365 freqs
= nlmsg_alloc();
371 for (i
= 0; i
< argc
; i
++) {
374 if (strcmp(argv
[i
], "freq") == 0) {
378 } else if (strcmp(argv
[i
], "ies") == 0) {
381 } else if (strcmp(argv
[i
], "lowpri") == 0) {
382 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
384 } else if (strcmp(argv
[i
], "flush") == 0) {
385 flags
|= NL80211_SCAN_FLAG_FLUSH
;
387 } else if (strcmp(argv
[i
], "ap-force") == 0) {
388 flags
|= NL80211_SCAN_FLAG_AP
;
390 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
391 strncmp(argv
[i
], "randomize", 9) == 0) {
392 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
393 err
= parse_random_mac_addr(msg
, argv
[i
]);
395 goto nla_put_failure
;
397 } else if (strcmp(argv
[i
], "ssid") == 0) {
401 } else if (strcmp(argv
[i
], "passive") == 0) {
405 } else if (strcmp(argv
[i
], "meshid") == 0) {
414 freq
= strtoul(argv
[i
], &eptr
, 10);
415 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
416 /* failed to parse as number -- maybe a tag? */
421 NLA_PUT_U32(freqs
, i
, freq
);
424 ies
= parse_hex(argv
[i
], &ies_len
);
426 goto nla_put_failure
;
430 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
433 meshid_len
= strlen(argv
[i
]);
434 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
436 goto nla_put_failure
;
437 meshid
[0] = 114; /* mesh element id */
438 meshid
[1] = meshid_len
;
439 memcpy(&meshid
[2], argv
[i
], meshid_len
);
447 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
451 goto nla_put_failure
;
454 memcpy(tmpies
, ies
, ies_len
);
458 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
461 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
466 NLA_PUT(ssids
, 1, 0, "");
468 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
471 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
473 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
482 static void tab_on_first(bool *first
)
490 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
493 print_ssid_escaped(len
, data
);
497 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
498 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
500 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
506 for (i
= 0; i
< len
; i
++) {
507 int r
= data
[i
] & 0x7f;
509 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
511 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
514 printf("%d.%d", r
/2, 5*(r
&1));
516 printf("%s ", data
[i
] & 0x80 ? "*" : "");
521 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
523 printf(" channel %d\n", data
[0]);
526 static const char *country_env_str(char environment
)
528 switch (environment
) {
530 return "Indoor only";
532 return "Outdoor only";
534 return "Indoor/Outdoor";
540 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
542 printf(" %.*s", 2, data
);
544 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
550 printf("\t\tNo country IE triplets present\n");
556 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
558 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
559 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
560 triplet
->ext
.reg_extension_id
,
561 triplet
->ext
.reg_class
,
562 triplet
->ext
.coverage_class
,
563 triplet
->ext
.coverage_class
* 450);
571 if (triplet
->chans
.first_channel
<= 14)
572 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
574 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
576 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
585 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
587 printf(" %d dB\n", data
[0]);
590 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
592 printf(" TX power: %d dBm\n", data
[0]);
593 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
596 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
599 printf(" <no flags>");
601 printf(" NonERP_Present");
603 printf(" Use_Protection");
605 printf(" Barker_Preamble_Mode");
609 static void print_cipher(const uint8_t *data
)
611 if (memcmp(data
, ms_oui
, 3) == 0) {
614 printf("Use group cipher suite");
629 printf("%.02x-%.02x-%.02x:%d",
630 data
[0], data
[1] ,data
[2], data
[3]);
633 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
636 printf("Use group cipher suite");
651 printf("AES-128-CMAC");
660 printf("%.02x-%.02x-%.02x:%d",
661 data
[0], data
[1] ,data
[2], data
[3]);
665 printf("%.02x-%.02x-%.02x:%d",
666 data
[0], data
[1] ,data
[2], data
[3]);
669 static void print_auth(const uint8_t *data
)
671 if (memcmp(data
, ms_oui
, 3) == 0) {
674 printf("IEEE 802.1X");
680 printf("%.02x-%.02x-%.02x:%d",
681 data
[0], data
[1] ,data
[2], data
[3]);
684 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
687 printf("IEEE 802.1X");
693 printf("FT/IEEE 802.1X");
699 printf("IEEE 802.1X/SHA-256");
702 printf("PSK/SHA-256");
708 printf("%.02x-%.02x-%.02x:%d",
709 data
[0], data
[1] ,data
[2], data
[3]);
712 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
718 printf("%.02x-%.02x-%.02x:%d",
719 data
[0], data
[1] ,data
[2], data
[3]);
723 printf("%.02x-%.02x-%.02x:%d",
724 data
[0], data
[1] ,data
[2], data
[3]);
727 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
728 uint8_t len
, const uint8_t *data
, int is_osen
)
736 version
= data
[0] + (data
[1] << 8);
737 tab_on_first(&first
);
738 printf("\t * Version: %d\n", version
);
745 tab_on_first(&first
);
746 printf("\t * Group cipher: %s\n", defcipher
);
747 printf("\t * Pairwise ciphers: %s\n", defcipher
);
751 tab_on_first(&first
);
752 printf("\t * Group cipher: ");
760 tab_on_first(&first
);
761 printf("\t * Pairwise ciphers: %s\n", defcipher
);
765 count
= data
[0] | (data
[1] << 8);
766 if (2 + (count
* 4) > len
)
769 tab_on_first(&first
);
770 printf("\t * Pairwise ciphers:");
771 for (i
= 0; i
< count
; i
++) {
773 print_cipher(data
+ 2 + (i
* 4));
777 data
+= 2 + (count
* 4);
778 len
-= 2 + (count
* 4);
781 tab_on_first(&first
);
782 printf("\t * Authentication suites: %s\n", defauth
);
786 count
= data
[0] | (data
[1] << 8);
787 if (2 + (count
* 4) > len
)
790 tab_on_first(&first
);
791 printf("\t * Authentication suites:");
792 for (i
= 0; i
< count
; i
++) {
794 print_auth(data
+ 2 + (i
* 4));
798 data
+= 2 + (count
* 4);
799 len
-= 2 + (count
* 4);
802 capa
= data
[0] | (data
[1] << 8);
803 tab_on_first(&first
);
804 printf("\t * Capabilities:");
808 printf(" NoPairwise");
809 switch ((capa
& 0x000c) >> 2) {
811 printf(" 1-PTKSA-RC");
814 printf(" 2-PTKSA-RC");
817 printf(" 4-PTKSA-RC");
820 printf(" 16-PTKSA-RC");
823 switch ((capa
& 0x0030) >> 4) {
825 printf(" 1-GTKSA-RC");
828 printf(" 2-GTKSA-RC");
831 printf(" 4-GTKSA-RC");
834 printf(" 16-GTKSA-RC");
838 printf(" MFP-required");
840 printf(" MFP-capable");
842 printf(" Peerkey-enabled");
844 printf(" SPP-AMSDU-capable");
846 printf(" SPP-AMSDU-required");
847 printf(" (0x%.4x)\n", capa
);
853 int pmkid_count
= data
[0] | (data
[1] << 8);
855 if (len
>= 2 + 16 * pmkid_count
) {
856 tab_on_first(&first
);
857 printf("\t * %d PMKIDs\n", pmkid_count
);
858 /* not printing PMKID values */
859 data
+= 2 + 16 * pmkid_count
;
860 len
-= 2 + 16 * pmkid_count
;
866 tab_on_first(&first
);
867 printf("\t * Group mgmt cipher suite: ");
876 printf("\t\t * bogus tail data (%d):", len
);
878 printf(" %.2x", *data
);
886 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
887 uint8_t len
, const uint8_t *data
)
889 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
892 static void print_osen_ie(const char *defcipher
, const char *defauth
,
893 uint8_t len
, const uint8_t *data
)
896 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
899 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
901 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
904 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
907 print_ht_capability(data
[0] | (data
[1] << 8));
908 print_ampdu_length(data
[2] & 3);
909 print_ampdu_spacing((data
[2] >> 2) & 7);
910 print_ht_mcs(data
+ 3);
913 static const char* ntype_11u(uint8_t t
)
916 case 0: return "Private";
917 case 1: return "Private with Guest";
918 case 2: return "Chargeable Public";
919 case 3: return "Free Public";
920 case 4: return "Personal Device";
921 case 5: return "Emergency Services Only";
922 case 14: return "Test or Experimental";
923 case 15: return "Wildcard";
924 default: return "Reserved";
928 static const char* vgroup_11u(uint8_t t
)
931 case 0: return "Unspecified";
932 case 1: return "Assembly";
933 case 2: return "Business";
934 case 3: return "Educational";
935 case 4: return "Factory and Industrial";
936 case 5: return "Institutional";
937 case 6: return "Mercantile";
938 case 7: return "Residential";
939 case 8: return "Storage";
940 case 9: return "Utility and Miscellaneous";
941 case 10: return "Vehicular";
942 case 11: return "Outdoor";
943 default: return "Reserved";
947 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
949 /* See Section 7.3.2.92 in the 802.11u spec. */
952 uint8_t ano
= data
[0];
953 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
954 printf("\t\t\tNetwork Type: %i (%s)\n",
955 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
957 printf("\t\t\tInternet\n");
959 printf("\t\t\tASRA\n");
961 printf("\t\t\tESR\n");
963 printf("\t\t\tUESA\n");
965 if ((len
== 3) || (len
== 9)) {
966 printf("\t\tVenue Group: %i (%s)\n",
967 (int)(data
[1]), vgroup_11u(data
[1]));
968 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
971 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
972 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
974 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
975 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
978 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
980 /* See Section 7.3.2.93 in the 802.11u spec. */
981 /* TODO: This code below does not decode private protocol IDs */
984 while (idx
< (len
- 1)) {
985 uint8_t qri
= data
[idx
];
986 uint8_t proto_id
= data
[idx
+ 1];
987 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
988 printf("\t\t\tQuery Response Length Limit: %i\n",
991 printf("\t\t\tPAME-BI\n");
994 printf("\t\t\tANQP\n"); break;
996 printf("\t\t\tMIH Information Service\n"); break;
998 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1000 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1002 printf("\t\t\tVendor Specific\n"); break;
1004 printf("\t\t\tReserved: %i\n", proto_id
); break;
1010 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1012 /* See Section 7.3.2.96 in the 802.11u spec. */
1014 int ln0
= data
[1] & 0xf;
1015 int ln1
= ((data
[1] & 0xf0) >> 4);
1020 ln2
= len
- 2 - ln0
- ln1
;
1022 printf("\t\tANQP OIs: %i\n", data
[0]);
1025 printf("\t\tOI 1: ");
1026 if (2 + ln0
> len
) {
1027 printf("Invalid IE length.\n");
1029 for (idx
= 0; idx
< ln0
; idx
++) {
1030 printf("%02hx", data
[2 + idx
]);
1037 printf("\t\tOI 2: ");
1038 if (2 + ln0
+ ln1
> len
) {
1039 printf("Invalid IE length.\n");
1041 for (idx
= 0; idx
< ln1
; idx
++) {
1042 printf("%02hx", data
[2 + ln0
+ idx
]);
1049 printf("\t\tOI 3: ");
1050 if (2 + ln0
+ ln1
+ ln2
> len
) {
1051 printf("Invalid IE length.\n");
1053 for (idx
= 0; idx
< ln2
; idx
++) {
1054 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1061 static const char *ht_secondary_offset
[4] = {
1068 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1070 static const char *protection
[4] = {
1076 static const char *sta_chan_width
[2] = {
1082 printf("\t\t * primary channel: %d\n", data
[0]);
1083 printf("\t\t * secondary channel offset: %s\n",
1084 ht_secondary_offset
[data
[1] & 0x3]);
1085 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1086 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1087 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1088 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1089 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1090 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1091 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1092 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1093 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1094 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1095 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1098 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1104 for (i
= 0; i
< len
; i
++) {
1107 for (bit
= 0; bit
< 8; bit
++) {
1108 if (!(data
[i
] & (1 << bit
)))
1116 #define CAPA(bit, name) case bit: printf(" " name); break
1118 switch (bit
+ base
) {
1119 CAPA(0, "HT Information Exchange Supported");
1120 CAPA(1, "reserved (On-demand Beacon)");
1121 CAPA(2, "Extended Channel Switching");
1122 CAPA(3, "reserved (Wave Indication)");
1123 CAPA(4, "PSMP Capability");
1124 CAPA(5, "reserved (Service Interval Granularity)");
1125 CAPA(6, "S-PSMP Capability");
1127 CAPA(8, "Diagnostics");
1128 CAPA(9, "Multicast Diagnostics");
1129 CAPA(10, "Location Tracking");
1131 CAPA(12, "Proxy ARP Service");
1132 CAPA(13, "Collocated Interference Reporting");
1133 CAPA(14, "Civic Location");
1134 CAPA(15, "Geospatial Location");
1136 CAPA(17, "WNM-Sleep Mode");
1137 CAPA(18, "TIM Broadcast");
1138 CAPA(19, "BSS Transition");
1139 CAPA(20, "QoS Traffic Capability");
1140 CAPA(21, "AC Station Count");
1141 CAPA(22, "Multiple BSSID");
1142 CAPA(23, "Timing Measurement");
1143 CAPA(24, "Channel Usage");
1144 CAPA(25, "SSID List");
1146 CAPA(27, "UTC TSF Offset");
1147 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1148 CAPA(29, "TDLS Peer PSM Support");
1149 CAPA(30, "TDLS channel switching");
1150 CAPA(31, "Interworking");
1151 CAPA(32, "QoS Map");
1153 CAPA(34, "SSPN Interface");
1154 CAPA(35, "Reserved");
1155 CAPA(36, "MSGCF Capability");
1156 CAPA(37, "TDLS Support");
1157 CAPA(38, "TDLS Prohibited");
1158 CAPA(39, "TDLS Channel Switching Prohibited");
1159 CAPA(40, "Reject Unadmitted Frame");
1160 CAPA(44, "Identifier Location");
1161 CAPA(45, "U-APSD Coexistence");
1162 CAPA(46, "WNM-Notification");
1163 CAPA(47, "Reserved");
1164 CAPA(48, "UTF-8 SSID");
1165 CAPA(70, "FTM Responder");
1166 CAPA(71, "FTM Initiator");
1178 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1180 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1182 data
[0], data
[1], data
[2], data
[3]);
1184 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1188 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1190 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1193 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1196 print_vht_info(data
[0] | (data
[1] << 8) |
1197 (data
[2] << 16) | (data
[3] << 24),
1201 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1203 const char *chandwidths
[] = {
1204 [0] = "20 or 40 MHz",
1211 printf("\t\t * channel width: %d (%s)\n", data
[0],
1212 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1213 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1214 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1215 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1218 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1221 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1222 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1223 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1224 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1225 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1226 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1227 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1228 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1231 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1233 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1234 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1236 printf(" %d\n", data
[0]);
1239 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1242 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1243 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1244 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1247 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1250 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1251 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1252 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1253 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1254 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1255 printf("\t\t * Mesh Formation Info:\n");
1256 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1258 printf("\t\t\t Connected to Mesh Gate\n");
1260 printf("\t\t\t Connected to AS\n");
1261 printf("\t\t * Mesh Capability\n");
1263 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1265 printf("\t\t\t MCCA Supported\n");
1267 printf("\t\t\t MCCA Enabled\n");
1269 printf("\t\t\t Forwarding\n");
1271 printf("\t\t\t MBCA Supported\n");
1273 printf("\t\t\t TBTT Adjusting\n");
1275 printf("\t\t\t Mesh Power Save Level\n");
1280 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1281 uint8_t minlen
, maxlen
;
1285 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1286 uint8_t len
, const uint8_t *data
)
1293 printf("\t%s:", p
->name
);
1294 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1296 printf(" <invalid: %d bytes:", len
);
1297 for (i
= 0; i
< len
; i
++)
1298 printf(" %.02x", data
[i
]);
1301 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1303 printf(" <invalid: no data>\n");
1307 p
->print(type
, len
, data
);
1310 #define PRINT_IGN { \
1317 static const struct ie_print ieprinters
[] = {
1318 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1319 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1320 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1321 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1322 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1323 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1324 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1325 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1326 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1327 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1328 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1329 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1330 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1331 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1332 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1333 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1334 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1335 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1336 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1337 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1338 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1339 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1340 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1341 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1342 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1345 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1347 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1350 static void print_wifi_osen(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1352 print_osen_ie("OSEN", "OSEN", len
, data
);
1355 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1358 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1364 printf("Parameter: not version 1: ");
1368 printf("\t * Parameter version 1");
1373 printf("\n\t\t * u-APSD");
1377 for (i
= 0; i
< 4; i
++) {
1378 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1381 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1382 (1 << (data
[1] >> 4)) - 1);
1383 printf(", AIFSN %d", data
[0] & 0xf);
1384 if (data
[2] | data
[3])
1385 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1393 printf("invalid: ");
1397 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1403 printf(" information:");
1406 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1410 printf(" type %d:", data
[0]);
1414 for(i
= 1; i
< len
; i
++)
1415 printf(" %.02x", data
[i
]);
1419 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1423 return "Default (PIN)";
1425 return "User-specified";
1427 return "Machine-specified";
1431 return "PushButton";
1433 return "Registrar-specified";
1439 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1442 __u16 subtype
, sublen
;
1445 subtype
= (data
[0] << 8) + data
[1];
1446 sublen
= (data
[2] << 8) + data
[3];
1452 tab_on_first(&first
);
1453 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1456 tab_on_first(&first
);
1457 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1461 tab_on_first(&first
);
1463 printf("\t * Device Password ID: (invalid "
1464 "length %d)\n", sublen
);
1467 id
= data
[4] << 8 | data
[5];
1468 printf("\t * Device Password ID: %u (%s)\n",
1469 id
, wifi_wps_dev_passwd_id(id
));
1473 tab_on_first(&first
);
1474 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1477 tab_on_first(&first
);
1478 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1481 tab_on_first(&first
);
1482 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1486 tab_on_first(&first
);
1487 printf("\t * Response Type: %d%s\n",
1488 val
, val
== 3 ? " (AP)" : "");
1493 tab_on_first(&first
);
1494 printf("\t * RF Bands: 0x%x\n", val
);
1499 tab_on_first(&first
);
1500 printf("\t * Selected Registrar: 0x%x\n", val
);
1504 tab_on_first(&first
);
1505 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1509 tab_on_first(&first
);
1510 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1512 val
== 1 ? " (Unconfigured)" : "",
1513 val
== 2 ? " (Configured)" : "");
1517 tab_on_first(&first
);
1518 printf("\t * UUID: ");
1520 printf("(invalid, length=%d)\n", sublen
);
1523 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1524 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1525 data
[4], data
[5], data
[6], data
[7],
1526 data
[8], data
[9], data
[10], data
[11],
1527 data
[12], data
[13], data
[14], data
[15],
1528 data
[16], data
[17], data
[18], data
[19]);
1531 tab_on_first(&first
);
1533 printf("\t * Primary Device Type: (invalid "
1534 "length %d)\n", sublen
);
1537 printf("\t * Primary Device Type: "
1538 "%u-%02x%02x%02x%02x-%u\n",
1539 data
[4] << 8 | data
[5],
1540 data
[6], data
[7], data
[8], data
[9],
1541 data
[10] << 8 | data
[11]);
1546 tab_on_first(&first
);
1547 printf("\t * AP setup locked: 0x%.2x\n", val
);
1552 __u16 meth
= (data
[4] << 8) + data
[5];
1554 tab_on_first(&first
);
1555 printf("\t * %sConfig methods:",
1556 subtype
== 0x1053 ? "Selected Registrar ": "");
1557 #define T(bit, name) do { \
1558 if (meth & (1<<bit)) { \
1578 const __u8
*subdata
= data
+ 4;
1579 __u16 tmplen
= sublen
;
1581 tab_on_first(&first
);
1582 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1585 printf(" %.2x", *subdata
);
1599 printf("\t\t * bogus tail data (%d):", len
);
1601 printf(" %.2x", *data
);
1609 static const struct ie_print wifiprinters
[] = {
1610 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1611 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1612 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1615 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1623 sublen
= (data
[2] << 8) + data
[1];
1625 if (sublen
> len
- 3)
1629 case 0x02: /* capability */
1630 tab_on_first(&first
);
1632 printf("\t * malformed capability\n");
1635 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1638 case 0x0d: /* device info */
1639 if (sublen
< 6 + 2 + 8 + 1) {
1640 printf("\t * malformed device info\n");
1643 /* fall through for now */
1644 case 0x00: /* status */
1645 case 0x01: /* minor reason */
1646 case 0x03: /* device ID */
1647 case 0x04: /* GO intent */
1648 case 0x05: /* configuration timeout */
1649 case 0x06: /* listen channel */
1650 case 0x07: /* group BSSID */
1651 case 0x08: /* ext listen timing */
1652 case 0x09: /* intended interface address */
1653 case 0x0a: /* manageability */
1654 case 0x0b: /* channel list */
1655 case 0x0c: /* NoA */
1656 case 0x0e: /* group info */
1657 case 0x0f: /* group ID */
1658 case 0x10: /* interface */
1659 case 0x11: /* operating channel */
1660 case 0x12: /* invitation flags */
1661 case 0xdd: /* vendor specific */
1663 const __u8
*subdata
= data
+ 4;
1664 __u16 tmplen
= sublen
;
1666 tab_on_first(&first
);
1667 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1670 printf(" %.2x", *subdata
);
1684 tab_on_first(&first
);
1685 printf("\t * bogus tail data (%d):", len
);
1687 printf(" %.2x", *data
);
1695 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1697 /* I can't find the spec for this...just going off what wireshark uses. */
1700 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1702 printf("\t\tUnexpected length: %i\n", len
);
1705 static const struct ie_print wfa_printers
[] = {
1706 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1707 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1708 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1711 static void print_vendor(unsigned char len
, unsigned char *data
,
1712 bool unknown
, enum print_ie_type ptype
)
1717 printf("\tVendor specific: <too short> data:");
1718 for(i
= 0; i
< len
; i
++)
1719 printf(" %.02x", data
[i
]);
1724 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1725 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1726 wifiprinters
[data
[3]].name
&&
1727 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1728 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1733 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1734 for(i
= 0; i
< len
- 4; i
++)
1735 printf(" %.02x", data
[i
+ 4]);
1740 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1741 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1742 wfa_printers
[data
[3]].name
&&
1743 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1744 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1749 printf("\tWFA %#.2x, data:", data
[3]);
1750 for(i
= 0; i
< len
- 4; i
++)
1751 printf(" %.02x", data
[i
+ 4]);
1759 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1760 data
[0], data
[1], data
[2]);
1761 for (i
= 3; i
< len
; i
++)
1762 printf(" %.2x", data
[i
]);
1766 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1767 enum print_ie_type ptype
)
1769 while (ielen
>= 2 && ielen
>= ie
[1]) {
1770 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1771 ieprinters
[ie
[0]].name
&&
1772 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1773 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1774 } else if (ie
[0] == 221 /* vendor */) {
1775 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1776 } else if (unknown
) {
1779 printf("\tUnknown IE (%d):", ie
[0]);
1780 for (i
=0; i
<ie
[1]; i
++)
1781 printf(" %.2x", ie
[2+i
]);
1789 static void print_capa_dmg(__u16 capa
)
1791 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1792 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1795 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1798 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1799 printf(" DMG_IBSS");
1803 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1804 printf(" CBAP_Only");
1805 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1806 printf(" CBAP_Src");
1807 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1809 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1811 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1812 printf(" SpectrumMgmt");
1813 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1814 printf(" RadioMeasure");
1817 static void print_capa_non_dmg(__u16 capa
)
1819 if (capa
& WLAN_CAPABILITY_ESS
)
1821 if (capa
& WLAN_CAPABILITY_IBSS
)
1823 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1824 printf(" CfPollable");
1825 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1826 printf(" CfPollReq");
1827 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1829 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1830 printf(" ShortPreamble");
1831 if (capa
& WLAN_CAPABILITY_PBCC
)
1833 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1834 printf(" ChannelAgility");
1835 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1836 printf(" SpectrumMgmt");
1837 if (capa
& WLAN_CAPABILITY_QOS
)
1839 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1840 printf(" ShortSlotTime");
1841 if (capa
& WLAN_CAPABILITY_APSD
)
1843 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1844 printf(" RadioMeasure");
1845 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1846 printf(" DSSS-OFDM");
1847 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1848 printf(" DelayedBACK");
1849 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1850 printf(" ImmediateBACK");
1853 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1855 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1856 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1857 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1858 char mac_addr
[20], dev
[20];
1859 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1860 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1861 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1862 [NL80211_BSS_BSSID
] = { },
1863 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1864 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1865 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1866 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1867 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1868 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1869 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1870 [NL80211_BSS_BEACON_IES
] = { },
1872 struct scan_params
*params
= arg
;
1873 int show
= params
->show_both_ie_sets
? 2 : 1;
1874 bool is_dmg
= false;
1876 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1877 genlmsg_attrlen(gnlh
, 0), NULL
);
1879 if (!tb
[NL80211_ATTR_BSS
]) {
1880 fprintf(stderr
, "bss info missing!\n");
1883 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1884 tb
[NL80211_ATTR_BSS
],
1886 fprintf(stderr
, "failed to parse nested attributes!\n");
1890 if (!bss
[NL80211_BSS_BSSID
])
1893 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1894 printf("BSS %s", mac_addr
);
1895 if (tb
[NL80211_ATTR_IFINDEX
]) {
1896 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1897 printf("(on %s)", dev
);
1900 if (bss
[NL80211_BSS_STATUS
]) {
1901 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1902 case NL80211_BSS_STATUS_AUTHENTICATED
:
1903 printf(" -- authenticated");
1905 case NL80211_BSS_STATUS_ASSOCIATED
:
1906 printf(" -- associated");
1908 case NL80211_BSS_STATUS_IBSS_JOINED
:
1909 printf(" -- joined");
1912 printf(" -- unknown status: %d",
1913 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1919 if (bss
[NL80211_BSS_TSF
]) {
1920 unsigned long long tsf
;
1921 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1922 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1923 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1924 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1926 if (bss
[NL80211_BSS_FREQUENCY
]) {
1927 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1928 printf("\tfreq: %d\n", freq
);
1932 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1933 printf("\tbeacon interval: %d TUs\n",
1934 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1935 if (bss
[NL80211_BSS_CAPABILITY
]) {
1936 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1937 printf("\tcapability:");
1939 print_capa_dmg(capa
);
1941 print_capa_non_dmg(capa
);
1942 printf(" (0x%.4x)\n", capa
);
1944 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1945 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1946 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1948 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1949 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1950 printf("\tsignal: %d/100\n", s
);
1952 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1953 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1954 printf("\tlast seen: %d ms ago\n", age
);
1957 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1958 if (bss
[NL80211_BSS_BEACON_IES
])
1959 printf("\tInformation elements from Probe Response "
1961 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1962 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1963 params
->unknown
, params
->type
);
1965 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1966 printf("\tInformation elements from Beacon frame:\n");
1967 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1968 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1969 params
->unknown
, params
->type
);
1975 static struct scan_params scan_params
;
1977 static int handle_scan_dump(struct nl80211_state
*state
,
1979 int argc
, char **argv
,
1985 memset(&scan_params
, 0, sizeof(scan_params
));
1987 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1988 scan_params
.unknown
= true;
1989 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1990 scan_params
.show_both_ie_sets
= true;
1992 scan_params
.type
= PRINT_SCAN
;
1994 register_handler(print_bss_handler
,
1999 static int handle_scan_combined(struct nl80211_state
*state
,
2001 int argc
, char **argv
,
2005 static char *dump_argv
[] = {
2011 static const __u32 cmds
[] = {
2012 NL80211_CMD_NEW_SCAN_RESULTS
,
2013 NL80211_CMD_SCAN_ABORTED
,
2015 int trig_argc
, dump_argc
, err
;
2018 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2020 dump_argv
[3] = "-u";
2021 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2023 dump_argv
[3] = "-b";
2027 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2028 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2031 trig_argv
[0] = argv
[0];
2032 trig_argv
[1] = "scan";
2033 trig_argv
[2] = "trigger";
2035 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2036 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2037 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2043 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2045 * This code has a bug, which requires creating a separate
2046 * nl80211 socket to fix:
2047 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2048 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2049 * before (!) we listen to it, because we only start listening
2050 * after we send our scan request.
2052 * Doing it the other way around has a race condition as well,
2053 * if you first open the events socket you may get a notification
2054 * for a previous scan.
2056 * The only proper way to fix this would be to listen to events
2057 * before sending the command, and for the kernel to send the
2058 * scan request along with the event, so that you can match up
2059 * whether the scan you requested was finished or aborted (this
2060 * may result in processing a scan that another application
2061 * requested, but that doesn't seem to be a problem).
2063 * Alas, the kernel doesn't do that (yet).
2066 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2067 NL80211_CMD_SCAN_ABORTED
) {
2068 printf("scan aborted!\n");
2072 dump_argv
[0] = argv
[0];
2073 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2075 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2076 CIB_NETDEV
, handle_scan_combined
,
2077 "Scan on the given frequencies and probe for the given SSIDs\n"
2078 "(or wildcard if not given) unless passive scanning is requested.\n"
2079 "If -u is specified print unknown data in the scan results.\n"
2080 "Specified (vendor) IEs must be well-formed.");
2081 COMMAND(scan
, dump
, "[-u]",
2082 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2083 "Dump the current scan results. If -u is specified, print unknown\n"
2084 "data in scan results.");
2085 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2086 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2087 "Trigger a scan on the given frequencies with probing for the given\n"
2088 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2091 static int handle_start_sched_scan(struct nl80211_state
*state
,
2093 int argc
, char **argv
, enum id_input id
)
2095 return parse_sched_scan(msg
, &argc
, &argv
);
2098 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2099 struct nl_msg
*msg
, int argc
, char **argv
,
2108 COMMAND(scan
, sched_start
,
2110 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2111 "Start a scheduled scan at the specified interval on the given frequencies\n"
2112 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2113 "scanning is requested. If matches are specified, only matching results\n"
2114 "will be returned.");
2115 COMMAND(scan
, sched_stop
, "",
2116 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2117 "Stop an ongoing scheduled scan.");