7 #include <netlink/genl/genl.h>
8 #include <netlink/genl/family.h>
9 #include <netlink/genl/ctrl.h>
10 #include <netlink/msg.h>
11 #include <netlink/attr.h>
16 #define WLAN_CAPABILITY_ESS (1<<0)
17 #define WLAN_CAPABILITY_IBSS (1<<1)
18 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
19 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
20 #define WLAN_CAPABILITY_PRIVACY (1<<4)
21 #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
22 #define WLAN_CAPABILITY_PBCC (1<<6)
23 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
24 #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
25 #define WLAN_CAPABILITY_QOS (1<<9)
26 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
27 #define WLAN_CAPABILITY_APSD (1<<11)
28 #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
29 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
30 #define WLAN_CAPABILITY_DEL_BACK (1<<14)
31 #define WLAN_CAPABILITY_IMM_BACK (1<<15)
32 /* DMG (60gHz) 802.11ad */
33 /* type - bits 0..1 */
34 #define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
36 #define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
37 #define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
38 #define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
40 #define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
41 #define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
42 #define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
43 #define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
45 #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
46 #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
48 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
49 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
50 static unsigned char wfa_oui
[3] = { 0x50, 0x6f, 0x9a };
54 enum print_ie_type type
;
55 bool show_both_ie_sets
;
58 #define IEEE80211_COUNTRY_EXTENSION_ID 201
60 union ieee80211_country_ie_triplet
{
65 } __attribute__ ((packed
)) chans
;
67 __u8 reg_extension_id
;
70 } __attribute__ ((packed
)) ext
;
71 } __attribute__ ((packed
));
73 static int parse_random_mac_addr(struct nl_msg
*msg
, char *arg
)
75 char *a_addr
, *a_mask
, *sep
;
76 unsigned char addr
[ETH_ALEN
], mask
[ETH_ALEN
];
77 char *addrs
= arg
+ 9;
83 sep
= strchr(addrs
, '/');
91 if (mac_addr_a2n(addr
, a_addr
) || mac_addr_a2n(mask
, a_mask
))
94 NLA_PUT(msg
, NL80211_ATTR_MAC
, ETH_ALEN
, addr
);
95 NLA_PUT(msg
, NL80211_ATTR_MAC_MASK
, ETH_ALEN
, mask
);
102 int parse_sched_scan(struct nl_msg
*msg
, int *argc
, char ***argv
)
104 struct nl_msg
*matchset
= NULL
, *freqs
= NULL
, *ssids
= NULL
;
105 struct nlattr
*match
= NULL
;
111 } parse_state
= ND_TOPLEVEL
;
113 char *end
, **v
= *argv
;
115 unsigned int freq
, interval
= 0, delay
= 0;
116 bool have_matchset
= false, have_freqs
= false, have_ssids
= false;
117 bool have_active
= false, have_passive
= false;
120 matchset
= nlmsg_alloc();
126 freqs
= nlmsg_alloc();
132 ssids
= nlmsg_alloc();
139 switch (parse_state
) {
141 if (!strcmp(v
[0], "interval")) {
145 goto nla_put_failure
;
150 goto nla_put_failure
;
152 interval
= strtoul(v
[0], &end
, 10);
153 if (*end
|| !interval
) {
155 goto nla_put_failure
;
158 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
160 } else if (!strcmp(v
[0], "delay")) {
164 goto nla_put_failure
;
169 goto nla_put_failure
;
171 delay
= strtoul(v
[0], &end
, 10);
174 goto nla_put_failure
;
177 NL80211_ATTR_SCHED_SCAN_DELAY
,
179 } else if (!strcmp(v
[0], "matches")) {
180 parse_state
= ND_MATCH
;
183 goto nla_put_failure
;
187 } else if (!strcmp(v
[0], "freqs")) {
188 parse_state
= ND_FREQS
;
191 goto nla_put_failure
;
196 } else if (!strcmp(v
[0], "active")) {
197 parse_state
= ND_ACTIVE
;
198 if (have_active
|| have_passive
) {
200 goto nla_put_failure
;
205 } else if (!strcmp(v
[0], "passive")) {
206 if (have_active
|| have_passive
) {
208 goto nla_put_failure
;
212 } else if (!strncmp(v
[0], "randomise", 9) ||
213 !strncmp(v
[0], "randomize", 9)) {
214 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
216 err
= parse_random_mac_addr(msg
, v
[0]);
218 goto nla_put_failure
;
221 /* this element is not for us, so
222 * return to continue parsing.
224 goto nla_put_failure
;
230 if (!strcmp(v
[0], "ssid")) {
234 goto nla_put_failure
;
237 /* TODO: for now we can only have an
238 * SSID in the match, so we can start
239 * the match nest here.
241 match
= nla_nest_start(matchset
, i
);
244 goto nla_put_failure
;
248 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
250 nla_nest_end(matchset
, match
);
253 have_matchset
= true;
257 /* other element that cannot be part
258 * of a match indicates the end of the
260 /* need at least one match in the matchset */
263 goto nla_put_failure
;
266 parse_state
= ND_TOPLEVEL
;
271 freq
= strtoul(v
[0], &end
, 10);
275 goto nla_put_failure
;
278 parse_state
= ND_TOPLEVEL
;
280 NLA_PUT_U32(freqs
, i
, freq
);
286 if (!strcmp(v
[0], "ssid")) {
290 goto nla_put_failure
;
294 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
301 /* other element that cannot be part
302 * of a match indicates the end of the
304 /* need at least one item in the set */
307 goto nla_put_failure
;
310 parse_state
= ND_TOPLEVEL
;
317 NLA_PUT(ssids
, 1, 0, "");
319 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
321 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
323 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
325 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
329 nla_nest_end(msg
, match
);
331 nlmsg_free(matchset
);
339 static int handle_scan(struct nl80211_state
*state
,
342 int argc
, char **argv
,
345 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
358 bool passive
= false, have_ssids
= false, have_freqs
= false;
359 size_t ies_len
= 0, meshid_len
= 0;
360 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
361 unsigned int flags
= 0;
363 ssids
= nlmsg_alloc();
367 freqs
= nlmsg_alloc();
373 for (i
= 0; i
< argc
; i
++) {
376 if (strcmp(argv
[i
], "freq") == 0) {
380 } else if (strcmp(argv
[i
], "ies") == 0) {
383 } else if (strcmp(argv
[i
], "lowpri") == 0) {
384 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
386 } else if (strcmp(argv
[i
], "flush") == 0) {
387 flags
|= NL80211_SCAN_FLAG_FLUSH
;
389 } else if (strcmp(argv
[i
], "ap-force") == 0) {
390 flags
|= NL80211_SCAN_FLAG_AP
;
392 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
393 strncmp(argv
[i
], "randomize", 9) == 0) {
394 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
395 err
= parse_random_mac_addr(msg
, argv
[i
]);
397 goto nla_put_failure
;
399 } else if (strcmp(argv
[i
], "ssid") == 0) {
403 } else if (strcmp(argv
[i
], "passive") == 0) {
407 } 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
);
449 goto nla_put_failure
;
451 memcpy(tmpies
, ies
, ies_len
);
455 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
458 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
463 NLA_PUT(ssids
, 1, 0, "");
465 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
468 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
470 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
479 static void tab_on_first(bool *first
)
487 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
490 print_ssid_escaped(len
, data
);
494 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
495 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
497 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
503 for (i
= 0; i
< len
; i
++) {
504 int r
= data
[i
] & 0x7f;
506 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
508 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
511 printf("%d.%d", r
/2, 5*(r
&1));
513 printf("%s ", data
[i
] & 0x80 ? "*" : "");
518 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
520 printf(" channel %d\n", data
[0]);
523 static const char *country_env_str(char environment
)
525 switch (environment
) {
527 return "Indoor only";
529 return "Outdoor only";
531 return "Indoor/Outdoor";
537 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
539 printf(" %.*s", 2, data
);
541 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
547 printf("\t\tNo country IE triplets present\n");
553 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
555 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
556 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
557 triplet
->ext
.reg_extension_id
,
558 triplet
->ext
.reg_class
,
559 triplet
->ext
.coverage_class
,
560 triplet
->ext
.coverage_class
* 450);
568 if (triplet
->chans
.first_channel
<= 14)
569 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
571 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
573 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
582 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
584 printf(" %d dB\n", data
[0]);
587 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
589 printf(" TX power: %d dBm\n", data
[0]);
590 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
593 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
596 printf(" <no flags>");
598 printf(" NonERP_Present");
600 printf(" Use_Protection");
602 printf(" Barker_Preamble_Mode");
606 static void print_cipher(const uint8_t *data
)
608 if (memcmp(data
, ms_oui
, 3) == 0) {
611 printf("Use group cipher suite");
626 printf("%.02x-%.02x-%.02x:%d",
627 data
[0], data
[1] ,data
[2], data
[3]);
630 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
633 printf("Use group cipher suite");
648 printf("AES-128-CMAC");
657 printf("%.02x-%.02x-%.02x:%d",
658 data
[0], data
[1] ,data
[2], data
[3]);
662 printf("%.02x-%.02x-%.02x:%d",
663 data
[0], data
[1] ,data
[2], data
[3]);
666 static void print_auth(const uint8_t *data
)
668 if (memcmp(data
, ms_oui
, 3) == 0) {
671 printf("IEEE 802.1X");
677 printf("%.02x-%.02x-%.02x:%d",
678 data
[0], data
[1] ,data
[2], data
[3]);
681 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
684 printf("IEEE 802.1X");
690 printf("FT/IEEE 802.1X");
696 printf("IEEE 802.1X/SHA-256");
699 printf("PSK/SHA-256");
705 printf("%.02x-%.02x-%.02x:%d",
706 data
[0], data
[1] ,data
[2], data
[3]);
709 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
715 printf("%.02x-%.02x-%.02x:%d",
716 data
[0], data
[1] ,data
[2], data
[3]);
720 printf("%.02x-%.02x-%.02x:%d",
721 data
[0], data
[1] ,data
[2], data
[3]);
724 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
725 uint8_t len
, const uint8_t *data
, int is_osen
)
733 version
= data
[0] + (data
[1] << 8);
734 tab_on_first(&first
);
735 printf("\t * Version: %d\n", version
);
742 tab_on_first(&first
);
743 printf("\t * Group cipher: %s\n", defcipher
);
744 printf("\t * Pairwise ciphers: %s\n", defcipher
);
748 tab_on_first(&first
);
749 printf("\t * Group cipher: ");
757 tab_on_first(&first
);
758 printf("\t * Pairwise ciphers: %s\n", defcipher
);
762 count
= data
[0] | (data
[1] << 8);
763 if (2 + (count
* 4) > len
)
766 tab_on_first(&first
);
767 printf("\t * Pairwise ciphers:");
768 for (i
= 0; i
< count
; i
++) {
770 print_cipher(data
+ 2 + (i
* 4));
774 data
+= 2 + (count
* 4);
775 len
-= 2 + (count
* 4);
778 tab_on_first(&first
);
779 printf("\t * Authentication suites: %s\n", defauth
);
783 count
= data
[0] | (data
[1] << 8);
784 if (2 + (count
* 4) > len
)
787 tab_on_first(&first
);
788 printf("\t * Authentication suites:");
789 for (i
= 0; i
< count
; i
++) {
791 print_auth(data
+ 2 + (i
* 4));
795 data
+= 2 + (count
* 4);
796 len
-= 2 + (count
* 4);
799 capa
= data
[0] | (data
[1] << 8);
800 tab_on_first(&first
);
801 printf("\t * Capabilities:");
805 printf(" NoPairwise");
806 switch ((capa
& 0x000c) >> 2) {
808 printf(" 1-PTKSA-RC");
811 printf(" 2-PTKSA-RC");
814 printf(" 4-PTKSA-RC");
817 printf(" 16-PTKSA-RC");
820 switch ((capa
& 0x0030) >> 4) {
822 printf(" 1-GTKSA-RC");
825 printf(" 2-GTKSA-RC");
828 printf(" 4-GTKSA-RC");
831 printf(" 16-GTKSA-RC");
835 printf(" MFP-required");
837 printf(" MFP-capable");
839 printf(" Peerkey-enabled");
841 printf(" SPP-AMSDU-capable");
843 printf(" SPP-AMSDU-required");
844 printf(" (0x%.4x)\n", capa
);
850 int pmkid_count
= data
[0] | (data
[1] << 8);
852 if (len
>= 2 + 16 * pmkid_count
) {
853 tab_on_first(&first
);
854 printf("\t * %d PMKIDs\n", pmkid_count
);
855 /* not printing PMKID values */
856 data
+= 2 + 16 * pmkid_count
;
857 len
-= 2 + 16 * pmkid_count
;
863 tab_on_first(&first
);
864 printf("\t * Group mgmt cipher suite: ");
873 printf("\t\t * bogus tail data (%d):", len
);
875 printf(" %.2x", *data
);
883 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
884 uint8_t len
, const uint8_t *data
)
886 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
889 static void print_osen_ie(const char *defcipher
, const char *defauth
,
890 uint8_t len
, const uint8_t *data
)
893 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
896 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
898 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
901 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
904 print_ht_capability(data
[0] | (data
[1] << 8));
905 print_ampdu_length(data
[2] & 3);
906 print_ampdu_spacing((data
[2] >> 2) & 7);
907 print_ht_mcs(data
+ 3);
910 static const char* ntype_11u(uint8_t t
)
913 case 0: return "Private";
914 case 1: return "Private with Guest";
915 case 2: return "Chargeable Public";
916 case 3: return "Free Public";
917 case 4: return "Personal Device";
918 case 5: return "Emergency Services Only";
919 case 14: return "Test or Experimental";
920 case 15: return "Wildcard";
921 default: return "Reserved";
925 static const char* vgroup_11u(uint8_t t
)
928 case 0: return "Unspecified";
929 case 1: return "Assembly";
930 case 2: return "Business";
931 case 3: return "Educational";
932 case 4: return "Factory and Industrial";
933 case 5: return "Institutional";
934 case 6: return "Mercantile";
935 case 7: return "Residential";
936 case 8: return "Storage";
937 case 9: return "Utility and Miscellaneous";
938 case 10: return "Vehicular";
939 case 11: return "Outdoor";
940 default: return "Reserved";
944 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
946 /* See Section 7.3.2.92 in the 802.11u spec. */
949 uint8_t ano
= data
[0];
950 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
951 printf("\t\t\tNetwork Type: %i (%s)\n",
952 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
954 printf("\t\t\tInternet\n");
956 printf("\t\t\tASRA\n");
958 printf("\t\t\tESR\n");
960 printf("\t\t\tUESA\n");
962 if ((len
== 3) || (len
== 9)) {
963 printf("\t\tVenue Group: %i (%s)\n",
964 (int)(data
[1]), vgroup_11u(data
[1]));
965 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
968 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
969 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
971 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
972 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
975 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
977 /* See Section 7.3.2.93 in the 802.11u spec. */
978 /* TODO: This code below does not decode private protocol IDs */
981 while (idx
< (len
- 1)) {
982 uint8_t qri
= data
[idx
];
983 uint8_t proto_id
= data
[idx
+ 1];
984 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
985 printf("\t\t\tQuery Response Length Limit: %i\n",
988 printf("\t\t\tPAME-BI\n");
991 printf("\t\t\tANQP\n"); break;
993 printf("\t\t\tMIH Information Service\n"); break;
995 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
997 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
999 printf("\t\t\tVendor Specific\n"); break;
1001 printf("\t\t\tReserved: %i\n", proto_id
); break;
1007 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1009 /* See Section 7.3.2.96 in the 802.11u spec. */
1011 int ln0
= data
[1] & 0xf;
1012 int ln1
= ((data
[1] & 0xf0) >> 4);
1017 ln2
= len
- 2 - ln0
- ln1
;
1019 printf("\t\tANQP OIs: %i\n", data
[0]);
1022 printf("\t\tOI 1: ");
1023 if (2 + ln0
> len
) {
1024 printf("Invalid IE length.\n");
1026 for (idx
= 0; idx
< ln0
; idx
++) {
1027 printf("%02hx", data
[2 + idx
]);
1034 printf("\t\tOI 2: ");
1035 if (2 + ln0
+ ln1
> len
) {
1036 printf("Invalid IE length.\n");
1038 for (idx
= 0; idx
< ln1
; idx
++) {
1039 printf("%02hx", data
[2 + ln0
+ idx
]);
1046 printf("\t\tOI 3: ");
1047 if (2 + ln0
+ ln1
+ ln2
> len
) {
1048 printf("Invalid IE length.\n");
1050 for (idx
= 0; idx
< ln2
; idx
++) {
1051 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1058 static const char *ht_secondary_offset
[4] = {
1065 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1067 static const char *protection
[4] = {
1073 static const char *sta_chan_width
[2] = {
1079 printf("\t\t * primary channel: %d\n", data
[0]);
1080 printf("\t\t * secondary channel offset: %s\n",
1081 ht_secondary_offset
[data
[1] & 0x3]);
1082 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1083 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1084 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1085 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1086 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1087 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1088 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1089 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1090 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1091 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1092 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1095 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1101 for (i
= 0; i
< len
; i
++) {
1104 for (bit
= 0; bit
< 8; bit
++) {
1105 if (!(data
[i
] & (1 << bit
)))
1113 #define CAPA(bit, name) case bit: printf(" " name); break
1115 switch (bit
+ base
) {
1116 CAPA(0, "HT Information Exchange Supported");
1117 CAPA(1, "reserved (On-demand Beacon)");
1118 CAPA(2, "Extended Channel Switching");
1119 CAPA(3, "reserved (Wave Indication)");
1120 CAPA(4, "PSMP Capability");
1121 CAPA(5, "reserved (Service Interval Granularity)");
1122 CAPA(6, "S-PSMP Capability");
1124 CAPA(8, "Diagnostics");
1125 CAPA(9, "Multicast Diagnostics");
1126 CAPA(10, "Location Tracking");
1128 CAPA(12, "Proxy ARP Service");
1129 CAPA(13, "Collocated Interference Reporting");
1130 CAPA(14, "Civic Location");
1131 CAPA(15, "Geospatial Location");
1133 CAPA(17, "WNM-Sleep Mode");
1134 CAPA(18, "TIM Broadcast");
1135 CAPA(19, "BSS Transition");
1136 CAPA(20, "QoS Traffic Capability");
1137 CAPA(21, "AC Station Count");
1138 CAPA(22, "Multiple BSSID");
1139 CAPA(23, "Timing Measurement");
1140 CAPA(24, "Channel Usage");
1141 CAPA(25, "SSID List");
1143 CAPA(27, "UTC TSF Offset");
1144 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1145 CAPA(29, "TDLS Peer PSM Support");
1146 CAPA(30, "TDLS channel switching");
1147 CAPA(31, "Interworking");
1148 CAPA(32, "QoS Map");
1150 CAPA(34, "SSPN Interface");
1151 CAPA(35, "Reserved");
1152 CAPA(36, "MSGCF Capability");
1153 CAPA(37, "TDLS Support");
1154 CAPA(38, "TDLS Prohibited");
1155 CAPA(39, "TDLS Channel Switching Prohibited");
1156 CAPA(40, "Reject Unadmitted Frame");
1157 CAPA(44, "Identifier Location");
1158 CAPA(45, "U-APSD Coexistence");
1159 CAPA(46, "WNM-Notification");
1160 CAPA(47, "Reserved");
1161 CAPA(48, "UTF-8 SSID");
1173 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1175 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1177 data
[0], data
[1], data
[2], data
[3]);
1179 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1183 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1185 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1188 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1191 print_vht_info(data
[0] | (data
[1] << 8) |
1192 (data
[2] << 16) | (data
[3] << 24),
1196 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1198 const char *chandwidths
[] = {
1199 [0] = "20 or 40 MHz",
1206 printf("\t\t * channel width: %d (%s)\n", data
[0],
1207 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1208 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1209 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1210 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1213 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1216 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1217 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1218 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1219 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1220 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1221 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1222 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1223 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1226 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1228 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1229 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1231 printf(" %d\n", data
[0]);
1234 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1237 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1238 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1239 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1242 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1245 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1246 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1247 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1248 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1249 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1250 printf("\t\t * Mesh Formation Info:\n");
1251 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1253 printf("\t\t\t Connected to Mesh Gate\n");
1255 printf("\t\t\t Connected to AS\n");
1256 printf("\t\t * Mesh Capability\n");
1258 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1260 printf("\t\t\t MCCA Supported\n");
1262 printf("\t\t\t MCCA Enabled\n");
1264 printf("\t\t\t Forwarding\n");
1266 printf("\t\t\t MBCA Supported\n");
1268 printf("\t\t\t TBTT Adjusting\n");
1270 printf("\t\t\t Mesh Power Save Level\n");
1275 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1276 uint8_t minlen
, maxlen
;
1280 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1281 uint8_t len
, const uint8_t *data
)
1288 printf("\t%s:", p
->name
);
1289 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1291 printf(" <invalid: %d bytes:", len
);
1292 for (i
= 0; i
< len
; i
++)
1293 printf(" %.02x", data
[i
]);
1296 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1298 printf(" <invalid: no data>\n");
1302 p
->print(type
, len
, data
);
1305 #define PRINT_IGN { \
1312 static const struct ie_print ieprinters
[] = {
1313 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1314 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1315 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1316 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1317 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1318 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1319 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1320 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1321 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1322 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1323 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1324 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1325 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1326 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1327 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1328 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1329 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1330 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1331 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1332 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1333 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1334 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1335 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1336 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1337 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1340 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1342 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1345 static void print_wifi_osen(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1347 print_osen_ie("OSEN", "OSEN", len
, data
);
1350 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1353 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1359 printf("Parameter: not version 1: ");
1363 printf("\t * Parameter version 1");
1368 printf("\n\t\t * u-APSD");
1372 for (i
= 0; i
< 4; i
++) {
1373 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1376 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1377 (1 << (data
[1] >> 4)) - 1);
1378 printf(", AIFSN %d", data
[0] & 0xf);
1379 if (data
[2] | data
[3])
1380 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1388 printf("invalid: ");
1392 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1398 printf(" information:");
1401 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1405 printf(" type %d:", data
[0]);
1409 for(i
= 1; i
< len
; i
++)
1410 printf(" %.02x", data
[i
]);
1414 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1418 return "Default (PIN)";
1420 return "User-specified";
1422 return "Machine-specified";
1426 return "PushButton";
1428 return "Registrar-specified";
1434 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1437 __u16 subtype
, sublen
;
1440 subtype
= (data
[0] << 8) + data
[1];
1441 sublen
= (data
[2] << 8) + data
[3];
1447 tab_on_first(&first
);
1448 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1451 tab_on_first(&first
);
1452 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1456 tab_on_first(&first
);
1458 printf("\t * Device Password ID: (invalid "
1459 "length %d)\n", sublen
);
1462 id
= data
[4] << 8 | data
[5];
1463 printf("\t * Device Password ID: %u (%s)\n",
1464 id
, wifi_wps_dev_passwd_id(id
));
1468 tab_on_first(&first
);
1469 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1472 tab_on_first(&first
);
1473 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1476 tab_on_first(&first
);
1477 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1481 tab_on_first(&first
);
1482 printf("\t * Response Type: %d%s\n",
1483 val
, val
== 3 ? " (AP)" : "");
1488 tab_on_first(&first
);
1489 printf("\t * RF Bands: 0x%x\n", val
);
1494 tab_on_first(&first
);
1495 printf("\t * Selected Registrar: 0x%x\n", val
);
1499 tab_on_first(&first
);
1500 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1504 tab_on_first(&first
);
1505 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1507 val
== 1 ? " (Unconfigured)" : "",
1508 val
== 2 ? " (Configured)" : "");
1512 tab_on_first(&first
);
1513 printf("\t * UUID: ");
1515 printf("(invalid, length=%d)\n", sublen
);
1518 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1519 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1520 data
[4], data
[5], data
[6], data
[7],
1521 data
[8], data
[9], data
[10], data
[11],
1522 data
[12], data
[13], data
[14], data
[15],
1523 data
[16], data
[17], data
[18], data
[19]);
1526 tab_on_first(&first
);
1528 printf("\t * Primary Device Type: (invalid "
1529 "length %d)\n", sublen
);
1532 printf("\t * Primary Device Type: "
1533 "%u-%02x%02x%02x%02x-%u\n",
1534 data
[4] << 8 | data
[5],
1535 data
[6], data
[7], data
[8], data
[9],
1536 data
[10] << 8 | data
[11]);
1541 tab_on_first(&first
);
1542 printf("\t * AP setup locked: 0x%.2x\n", val
);
1547 __u16 meth
= (data
[4] << 8) + data
[5];
1549 tab_on_first(&first
);
1550 printf("\t * %sConfig methods:",
1551 subtype
== 0x1053 ? "Selected Registrar ": "");
1552 #define T(bit, name) do { \
1553 if (meth & (1<<bit)) { \
1573 const __u8
*subdata
= data
+ 4;
1574 __u16 tmplen
= sublen
;
1576 tab_on_first(&first
);
1577 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1580 printf(" %.2x", *subdata
);
1594 printf("\t\t * bogus tail data (%d):", len
);
1596 printf(" %.2x", *data
);
1604 static const struct ie_print wifiprinters
[] = {
1605 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1606 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1607 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1610 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1618 sublen
= (data
[2] << 8) + data
[1];
1620 if (sublen
> len
- 3)
1624 case 0x02: /* capability */
1625 tab_on_first(&first
);
1627 printf("\t * malformed capability\n");
1630 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1633 case 0x0d: /* device info */
1634 if (sublen
< 6 + 2 + 8 + 1) {
1635 printf("\t * malformed device info\n");
1638 /* fall through for now */
1639 case 0x00: /* status */
1640 case 0x01: /* minor reason */
1641 case 0x03: /* device ID */
1642 case 0x04: /* GO intent */
1643 case 0x05: /* configuration timeout */
1644 case 0x06: /* listen channel */
1645 case 0x07: /* group BSSID */
1646 case 0x08: /* ext listen timing */
1647 case 0x09: /* intended interface address */
1648 case 0x0a: /* manageability */
1649 case 0x0b: /* channel list */
1650 case 0x0c: /* NoA */
1651 case 0x0e: /* group info */
1652 case 0x0f: /* group ID */
1653 case 0x10: /* interface */
1654 case 0x11: /* operating channel */
1655 case 0x12: /* invitation flags */
1656 case 0xdd: /* vendor specific */
1658 const __u8
*subdata
= data
+ 4;
1659 __u16 tmplen
= sublen
;
1661 tab_on_first(&first
);
1662 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1665 printf(" %.2x", *subdata
);
1679 tab_on_first(&first
);
1680 printf("\t * bogus tail data (%d):", len
);
1682 printf(" %.2x", *data
);
1690 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1692 /* I can't find the spec for this...just going off what wireshark uses. */
1695 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1697 printf("\t\tUnexpected length: %i\n", len
);
1700 static const struct ie_print wfa_printers
[] = {
1701 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1702 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1703 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1706 static void print_vendor(unsigned char len
, unsigned char *data
,
1707 bool unknown
, enum print_ie_type ptype
)
1712 printf("\tVendor specific: <too short> data:");
1713 for(i
= 0; i
< len
; i
++)
1714 printf(" %.02x", data
[i
]);
1719 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1720 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1721 wifiprinters
[data
[3]].name
&&
1722 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1723 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1728 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1729 for(i
= 0; i
< len
- 4; i
++)
1730 printf(" %.02x", data
[i
+ 4]);
1735 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1736 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1737 wfa_printers
[data
[3]].name
&&
1738 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1739 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1744 printf("\tWFA %#.2x, data:", data
[3]);
1745 for(i
= 0; i
< len
- 4; i
++)
1746 printf(" %.02x", data
[i
+ 4]);
1754 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1755 data
[0], data
[1], data
[2]);
1756 for (i
= 3; i
< len
; i
++)
1757 printf(" %.2x", data
[i
]);
1761 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1762 enum print_ie_type ptype
)
1764 while (ielen
>= 2 && ielen
>= ie
[1]) {
1765 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1766 ieprinters
[ie
[0]].name
&&
1767 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1768 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1769 } else if (ie
[0] == 221 /* vendor */) {
1770 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1771 } else if (unknown
) {
1774 printf("\tUnknown IE (%d):", ie
[0]);
1775 for (i
=0; i
<ie
[1]; i
++)
1776 printf(" %.2x", ie
[2+i
]);
1784 static void print_capa_dmg(__u16 capa
)
1786 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1787 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1790 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1793 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1794 printf(" DMG_IBSS");
1798 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1799 printf(" CBAP_Only");
1800 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1801 printf(" CBAP_Src");
1802 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1804 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1806 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1807 printf(" SpectrumMgmt");
1808 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1809 printf(" RadioMeasure");
1812 static void print_capa_non_dmg(__u16 capa
)
1814 if (capa
& WLAN_CAPABILITY_ESS
)
1816 if (capa
& WLAN_CAPABILITY_IBSS
)
1818 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1819 printf(" CfPollable");
1820 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1821 printf(" CfPollReq");
1822 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1824 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1825 printf(" ShortPreamble");
1826 if (capa
& WLAN_CAPABILITY_PBCC
)
1828 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1829 printf(" ChannelAgility");
1830 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1831 printf(" SpectrumMgmt");
1832 if (capa
& WLAN_CAPABILITY_QOS
)
1834 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1835 printf(" ShortSlotTime");
1836 if (capa
& WLAN_CAPABILITY_APSD
)
1838 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1839 printf(" RadioMeasure");
1840 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1841 printf(" DSSS-OFDM");
1842 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1843 printf(" DelayedBACK");
1844 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1845 printf(" ImmediateBACK");
1848 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1850 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1851 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1852 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1853 char mac_addr
[20], dev
[20];
1854 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1855 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1856 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1857 [NL80211_BSS_BSSID
] = { },
1858 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1859 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1860 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1861 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1862 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1863 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1864 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1865 [NL80211_BSS_BEACON_IES
] = { },
1867 struct scan_params
*params
= arg
;
1868 int show
= params
->show_both_ie_sets
? 2 : 1;
1869 bool is_dmg
= false;
1871 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1872 genlmsg_attrlen(gnlh
, 0), NULL
);
1874 if (!tb
[NL80211_ATTR_BSS
]) {
1875 fprintf(stderr
, "bss info missing!\n");
1878 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1879 tb
[NL80211_ATTR_BSS
],
1881 fprintf(stderr
, "failed to parse nested attributes!\n");
1885 if (!bss
[NL80211_BSS_BSSID
])
1888 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1889 printf("BSS %s", mac_addr
);
1890 if (tb
[NL80211_ATTR_IFINDEX
]) {
1891 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1892 printf("(on %s)", dev
);
1895 if (bss
[NL80211_BSS_STATUS
]) {
1896 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1897 case NL80211_BSS_STATUS_AUTHENTICATED
:
1898 printf(" -- authenticated");
1900 case NL80211_BSS_STATUS_ASSOCIATED
:
1901 printf(" -- associated");
1903 case NL80211_BSS_STATUS_IBSS_JOINED
:
1904 printf(" -- joined");
1907 printf(" -- unknown status: %d",
1908 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1914 if (bss
[NL80211_BSS_TSF
]) {
1915 unsigned long long tsf
;
1916 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1917 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1918 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1919 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1921 if (bss
[NL80211_BSS_FREQUENCY
]) {
1922 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1923 printf("\tfreq: %d\n", freq
);
1927 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1928 printf("\tbeacon interval: %d TUs\n",
1929 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1930 if (bss
[NL80211_BSS_CAPABILITY
]) {
1931 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1932 printf("\tcapability:");
1934 print_capa_dmg(capa
);
1936 print_capa_non_dmg(capa
);
1937 printf(" (0x%.4x)\n", capa
);
1939 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1940 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1941 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1943 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1944 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1945 printf("\tsignal: %d/100\n", s
);
1947 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1948 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1949 printf("\tlast seen: %d ms ago\n", age
);
1952 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1953 if (bss
[NL80211_BSS_BEACON_IES
])
1954 printf("\tInformation elements from Probe Response "
1956 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1957 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1958 params
->unknown
, params
->type
);
1960 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1961 printf("\tInformation elements from Beacon frame:\n");
1962 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1963 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1964 params
->unknown
, params
->type
);
1970 static struct scan_params scan_params
;
1972 static int handle_scan_dump(struct nl80211_state
*state
,
1975 int argc
, char **argv
,
1981 memset(&scan_params
, 0, sizeof(scan_params
));
1983 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1984 scan_params
.unknown
= true;
1985 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1986 scan_params
.show_both_ie_sets
= true;
1988 scan_params
.type
= PRINT_SCAN
;
1990 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1995 static int handle_scan_combined(struct nl80211_state
*state
,
1998 int argc
, char **argv
,
2002 static char *dump_argv
[] = {
2008 static const __u32 cmds
[] = {
2009 NL80211_CMD_NEW_SCAN_RESULTS
,
2010 NL80211_CMD_SCAN_ABORTED
,
2012 int trig_argc
, dump_argc
, err
;
2014 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2016 dump_argv
[3] = "-u";
2017 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2019 dump_argv
[3] = "-b";
2023 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2024 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2027 trig_argv
[0] = argv
[0];
2028 trig_argv
[1] = "scan";
2029 trig_argv
[2] = "trigger";
2031 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2032 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2033 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2039 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2041 * This code has a bug, which requires creating a separate
2042 * nl80211 socket to fix:
2043 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2044 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2045 * before (!) we listen to it, because we only start listening
2046 * after we send our scan request.
2048 * Doing it the other way around has a race condition as well,
2049 * if you first open the events socket you may get a notification
2050 * for a previous scan.
2052 * The only proper way to fix this would be to listen to events
2053 * before sending the command, and for the kernel to send the
2054 * scan request along with the event, so that you can match up
2055 * whether the scan you requested was finished or aborted (this
2056 * may result in processing a scan that another application
2057 * requested, but that doesn't seem to be a problem).
2059 * Alas, the kernel doesn't do that (yet).
2062 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2063 NL80211_CMD_SCAN_ABORTED
) {
2064 printf("scan aborted!\n");
2068 dump_argv
[0] = argv
[0];
2069 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2071 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2072 CIB_NETDEV
, handle_scan_combined
,
2073 "Scan on the given frequencies and probe for the given SSIDs\n"
2074 "(or wildcard if not given) unless passive scanning is requested.\n"
2075 "If -u is specified print unknown data in the scan results.\n"
2076 "Specified (vendor) IEs must be well-formed.");
2077 COMMAND(scan
, dump
, "[-u]",
2078 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2079 "Dump the current scan results. If -u is specified, print unknown\n"
2080 "data in scan results.");
2081 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2082 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2083 "Trigger a scan on the given frequencies with probing for the given\n"
2084 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2087 static int handle_start_sched_scan(struct nl80211_state
*state
,
2088 struct nl_cb
*cb
, struct nl_msg
*msg
,
2089 int argc
, char **argv
, enum id_input id
)
2091 return parse_sched_scan(msg
, &argc
, &argv
);
2094 static int handle_stop_sched_scan(struct nl80211_state
*state
, struct nl_cb
*cb
,
2095 struct nl_msg
*msg
, int argc
, char **argv
,
2104 COMMAND(scan
, sched_start
,
2106 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2107 "Start a scheduled scan at the specified interval on the given frequencies\n"
2108 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2109 "scanning is requested. If matches are specified, only matching results\n"
2110 "will be returned.");
2111 COMMAND(scan
, sched_stop
, "",
2112 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2113 "Stop an ongoing scheduled scan.");