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
,
341 int argc
, char **argv
,
344 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
357 bool passive
= false, have_ssids
= false, have_freqs
= false;
358 size_t ies_len
= 0, meshid_len
= 0;
359 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
360 unsigned int flags
= 0;
362 ssids
= nlmsg_alloc();
366 freqs
= nlmsg_alloc();
372 for (i
= 0; i
< argc
; i
++) {
375 if (strcmp(argv
[i
], "freq") == 0) {
379 } else if (strcmp(argv
[i
], "ies") == 0) {
382 } else if (strcmp(argv
[i
], "lowpri") == 0) {
383 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
385 } else if (strcmp(argv
[i
], "flush") == 0) {
386 flags
|= NL80211_SCAN_FLAG_FLUSH
;
388 } else if (strcmp(argv
[i
], "ap-force") == 0) {
389 flags
|= NL80211_SCAN_FLAG_AP
;
391 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
392 strncmp(argv
[i
], "randomize", 9) == 0) {
393 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
394 err
= parse_random_mac_addr(msg
, argv
[i
]);
396 goto nla_put_failure
;
398 } else if (strcmp(argv
[i
], "ssid") == 0) {
402 } else if (strcmp(argv
[i
], "passive") == 0) {
406 } else if (strcmp(argv
[i
], "meshid") == 0) {
415 freq
= strtoul(argv
[i
], &eptr
, 10);
416 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
417 /* failed to parse as number -- maybe a tag? */
422 NLA_PUT_U32(freqs
, i
, freq
);
425 ies
= parse_hex(argv
[i
], &ies_len
);
427 goto nla_put_failure
;
431 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
434 meshid_len
= strlen(argv
[i
]);
435 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
437 goto nla_put_failure
;
438 meshid
[0] = 114; /* mesh element id */
439 meshid
[1] = meshid_len
;
440 memcpy(&meshid
[2], argv
[i
], meshid_len
);
448 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
450 goto nla_put_failure
;
452 memcpy(tmpies
, ies
, ies_len
);
456 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
459 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
464 NLA_PUT(ssids
, 1, 0, "");
466 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
469 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
471 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
480 static void tab_on_first(bool *first
)
488 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
491 print_ssid_escaped(len
, data
);
495 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
496 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
498 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
504 for (i
= 0; i
< len
; i
++) {
505 int r
= data
[i
] & 0x7f;
507 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
509 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
512 printf("%d.%d", r
/2, 5*(r
&1));
514 printf("%s ", data
[i
] & 0x80 ? "*" : "");
519 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
521 printf(" channel %d\n", data
[0]);
524 static const char *country_env_str(char environment
)
526 switch (environment
) {
528 return "Indoor only";
530 return "Outdoor only";
532 return "Indoor/Outdoor";
538 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
540 printf(" %.*s", 2, data
);
542 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
548 printf("\t\tNo country IE triplets present\n");
554 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
556 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
557 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
558 triplet
->ext
.reg_extension_id
,
559 triplet
->ext
.reg_class
,
560 triplet
->ext
.coverage_class
,
561 triplet
->ext
.coverage_class
* 450);
569 if (triplet
->chans
.first_channel
<= 14)
570 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
572 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
574 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
583 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
585 printf(" %d dB\n", data
[0]);
588 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
590 printf(" TX power: %d dBm\n", data
[0]);
591 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
594 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
597 printf(" <no flags>");
599 printf(" NonERP_Present");
601 printf(" Use_Protection");
603 printf(" Barker_Preamble_Mode");
607 static void print_cipher(const uint8_t *data
)
609 if (memcmp(data
, ms_oui
, 3) == 0) {
612 printf("Use group cipher suite");
627 printf("%.02x-%.02x-%.02x:%d",
628 data
[0], data
[1] ,data
[2], data
[3]);
631 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
634 printf("Use group cipher suite");
649 printf("AES-128-CMAC");
658 printf("%.02x-%.02x-%.02x:%d",
659 data
[0], data
[1] ,data
[2], data
[3]);
663 printf("%.02x-%.02x-%.02x:%d",
664 data
[0], data
[1] ,data
[2], data
[3]);
667 static void print_auth(const uint8_t *data
)
669 if (memcmp(data
, ms_oui
, 3) == 0) {
672 printf("IEEE 802.1X");
678 printf("%.02x-%.02x-%.02x:%d",
679 data
[0], data
[1] ,data
[2], data
[3]);
682 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
685 printf("IEEE 802.1X");
691 printf("FT/IEEE 802.1X");
697 printf("IEEE 802.1X/SHA-256");
700 printf("PSK/SHA-256");
706 printf("%.02x-%.02x-%.02x:%d",
707 data
[0], data
[1] ,data
[2], data
[3]);
710 } else if (memcmp(data
, wfa_oui
, 3) == 0) {
716 printf("%.02x-%.02x-%.02x:%d",
717 data
[0], data
[1] ,data
[2], data
[3]);
721 printf("%.02x-%.02x-%.02x:%d",
722 data
[0], data
[1] ,data
[2], data
[3]);
725 static void _print_rsn_ie(const char *defcipher
, const char *defauth
,
726 uint8_t len
, const uint8_t *data
, int is_osen
)
734 version
= data
[0] + (data
[1] << 8);
735 tab_on_first(&first
);
736 printf("\t * Version: %d\n", version
);
743 tab_on_first(&first
);
744 printf("\t * Group cipher: %s\n", defcipher
);
745 printf("\t * Pairwise ciphers: %s\n", defcipher
);
749 tab_on_first(&first
);
750 printf("\t * Group cipher: ");
758 tab_on_first(&first
);
759 printf("\t * Pairwise ciphers: %s\n", defcipher
);
763 count
= data
[0] | (data
[1] << 8);
764 if (2 + (count
* 4) > len
)
767 tab_on_first(&first
);
768 printf("\t * Pairwise ciphers:");
769 for (i
= 0; i
< count
; i
++) {
771 print_cipher(data
+ 2 + (i
* 4));
775 data
+= 2 + (count
* 4);
776 len
-= 2 + (count
* 4);
779 tab_on_first(&first
);
780 printf("\t * Authentication suites: %s\n", defauth
);
784 count
= data
[0] | (data
[1] << 8);
785 if (2 + (count
* 4) > len
)
788 tab_on_first(&first
);
789 printf("\t * Authentication suites:");
790 for (i
= 0; i
< count
; i
++) {
792 print_auth(data
+ 2 + (i
* 4));
796 data
+= 2 + (count
* 4);
797 len
-= 2 + (count
* 4);
800 capa
= data
[0] | (data
[1] << 8);
801 tab_on_first(&first
);
802 printf("\t * Capabilities:");
806 printf(" NoPairwise");
807 switch ((capa
& 0x000c) >> 2) {
809 printf(" 1-PTKSA-RC");
812 printf(" 2-PTKSA-RC");
815 printf(" 4-PTKSA-RC");
818 printf(" 16-PTKSA-RC");
821 switch ((capa
& 0x0030) >> 4) {
823 printf(" 1-GTKSA-RC");
826 printf(" 2-GTKSA-RC");
829 printf(" 4-GTKSA-RC");
832 printf(" 16-GTKSA-RC");
836 printf(" MFP-required");
838 printf(" MFP-capable");
840 printf(" Peerkey-enabled");
842 printf(" SPP-AMSDU-capable");
844 printf(" SPP-AMSDU-required");
845 printf(" (0x%.4x)\n", capa
);
851 int pmkid_count
= data
[0] | (data
[1] << 8);
853 if (len
>= 2 + 16 * pmkid_count
) {
854 tab_on_first(&first
);
855 printf("\t * %d PMKIDs\n", pmkid_count
);
856 /* not printing PMKID values */
857 data
+= 2 + 16 * pmkid_count
;
858 len
-= 2 + 16 * pmkid_count
;
864 tab_on_first(&first
);
865 printf("\t * Group mgmt cipher suite: ");
874 printf("\t\t * bogus tail data (%d):", len
);
876 printf(" %.2x", *data
);
884 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
885 uint8_t len
, const uint8_t *data
)
887 _print_rsn_ie(defcipher
, defauth
, len
, data
, 0);
890 static void print_osen_ie(const char *defcipher
, const char *defauth
,
891 uint8_t len
, const uint8_t *data
)
894 _print_rsn_ie(defcipher
, defauth
, len
, data
, 1);
897 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
899 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
902 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
905 print_ht_capability(data
[0] | (data
[1] << 8));
906 print_ampdu_length(data
[2] & 3);
907 print_ampdu_spacing((data
[2] >> 2) & 7);
908 print_ht_mcs(data
+ 3);
911 static const char* ntype_11u(uint8_t t
)
914 case 0: return "Private";
915 case 1: return "Private with Guest";
916 case 2: return "Chargeable Public";
917 case 3: return "Free Public";
918 case 4: return "Personal Device";
919 case 5: return "Emergency Services Only";
920 case 14: return "Test or Experimental";
921 case 15: return "Wildcard";
922 default: return "Reserved";
926 static const char* vgroup_11u(uint8_t t
)
929 case 0: return "Unspecified";
930 case 1: return "Assembly";
931 case 2: return "Business";
932 case 3: return "Educational";
933 case 4: return "Factory and Industrial";
934 case 5: return "Institutional";
935 case 6: return "Mercantile";
936 case 7: return "Residential";
937 case 8: return "Storage";
938 case 9: return "Utility and Miscellaneous";
939 case 10: return "Vehicular";
940 case 11: return "Outdoor";
941 default: return "Reserved";
945 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
947 /* See Section 7.3.2.92 in the 802.11u spec. */
950 uint8_t ano
= data
[0];
951 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
952 printf("\t\t\tNetwork Type: %i (%s)\n",
953 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
955 printf("\t\t\tInternet\n");
957 printf("\t\t\tASRA\n");
959 printf("\t\t\tESR\n");
961 printf("\t\t\tUESA\n");
963 if ((len
== 3) || (len
== 9)) {
964 printf("\t\tVenue Group: %i (%s)\n",
965 (int)(data
[1]), vgroup_11u(data
[1]));
966 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
969 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
970 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
972 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
973 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
976 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
978 /* See Section 7.3.2.93 in the 802.11u spec. */
979 /* TODO: This code below does not decode private protocol IDs */
982 while (idx
< (len
- 1)) {
983 uint8_t qri
= data
[idx
];
984 uint8_t proto_id
= data
[idx
+ 1];
985 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
986 printf("\t\t\tQuery Response Length Limit: %i\n",
989 printf("\t\t\tPAME-BI\n");
992 printf("\t\t\tANQP\n"); break;
994 printf("\t\t\tMIH Information Service\n"); break;
996 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
998 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1000 printf("\t\t\tVendor Specific\n"); break;
1002 printf("\t\t\tReserved: %i\n", proto_id
); break;
1008 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1010 /* See Section 7.3.2.96 in the 802.11u spec. */
1012 int ln0
= data
[1] & 0xf;
1013 int ln1
= ((data
[1] & 0xf0) >> 4);
1018 ln2
= len
- 2 - ln0
- ln1
;
1020 printf("\t\tANQP OIs: %i\n", data
[0]);
1023 printf("\t\tOI 1: ");
1024 if (2 + ln0
> len
) {
1025 printf("Invalid IE length.\n");
1027 for (idx
= 0; idx
< ln0
; idx
++) {
1028 printf("%02hx", data
[2 + idx
]);
1035 printf("\t\tOI 2: ");
1036 if (2 + ln0
+ ln1
> len
) {
1037 printf("Invalid IE length.\n");
1039 for (idx
= 0; idx
< ln1
; idx
++) {
1040 printf("%02hx", data
[2 + ln0
+ idx
]);
1047 printf("\t\tOI 3: ");
1048 if (2 + ln0
+ ln1
+ ln2
> len
) {
1049 printf("Invalid IE length.\n");
1051 for (idx
= 0; idx
< ln2
; idx
++) {
1052 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1059 static const char *ht_secondary_offset
[4] = {
1066 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1068 static const char *protection
[4] = {
1074 static const char *sta_chan_width
[2] = {
1080 printf("\t\t * primary channel: %d\n", data
[0]);
1081 printf("\t\t * secondary channel offset: %s\n",
1082 ht_secondary_offset
[data
[1] & 0x3]);
1083 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1084 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1085 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1086 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1087 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1088 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1089 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1090 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1091 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1092 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1093 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1096 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1102 for (i
= 0; i
< len
; i
++) {
1105 for (bit
= 0; bit
< 8; bit
++) {
1106 if (!(data
[i
] & (1 << bit
)))
1114 #define CAPA(bit, name) case bit: printf(" " name); break
1116 switch (bit
+ base
) {
1117 CAPA(0, "HT Information Exchange Supported");
1118 CAPA(1, "reserved (On-demand Beacon)");
1119 CAPA(2, "Extended Channel Switching");
1120 CAPA(3, "reserved (Wave Indication)");
1121 CAPA(4, "PSMP Capability");
1122 CAPA(5, "reserved (Service Interval Granularity)");
1123 CAPA(6, "S-PSMP Capability");
1125 CAPA(8, "Diagnostics");
1126 CAPA(9, "Multicast Diagnostics");
1127 CAPA(10, "Location Tracking");
1129 CAPA(12, "Proxy ARP Service");
1130 CAPA(13, "Collocated Interference Reporting");
1131 CAPA(14, "Civic Location");
1132 CAPA(15, "Geospatial Location");
1134 CAPA(17, "WNM-Sleep Mode");
1135 CAPA(18, "TIM Broadcast");
1136 CAPA(19, "BSS Transition");
1137 CAPA(20, "QoS Traffic Capability");
1138 CAPA(21, "AC Station Count");
1139 CAPA(22, "Multiple BSSID");
1140 CAPA(23, "Timing Measurement");
1141 CAPA(24, "Channel Usage");
1142 CAPA(25, "SSID List");
1144 CAPA(27, "UTC TSF Offset");
1145 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1146 CAPA(29, "TDLS Peer PSM Support");
1147 CAPA(30, "TDLS channel switching");
1148 CAPA(31, "Interworking");
1149 CAPA(32, "QoS Map");
1151 CAPA(34, "SSPN Interface");
1152 CAPA(35, "Reserved");
1153 CAPA(36, "MSGCF Capability");
1154 CAPA(37, "TDLS Support");
1155 CAPA(38, "TDLS Prohibited");
1156 CAPA(39, "TDLS Channel Switching Prohibited");
1157 CAPA(40, "Reject Unadmitted Frame");
1158 CAPA(44, "Identifier Location");
1159 CAPA(45, "U-APSD Coexistence");
1160 CAPA(46, "WNM-Notification");
1161 CAPA(47, "Reserved");
1162 CAPA(48, "UTF-8 SSID");
1163 CAPA(70, "FTM Responder");
1164 CAPA(71, "FTM Initiator");
1176 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1178 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1180 data
[0], data
[1], data
[2], data
[3]);
1182 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1186 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1188 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1191 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1194 print_vht_info(data
[0] | (data
[1] << 8) |
1195 (data
[2] << 16) | (data
[3] << 24),
1199 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1201 const char *chandwidths
[] = {
1202 [0] = "20 or 40 MHz",
1209 printf("\t\t * channel width: %d (%s)\n", data
[0],
1210 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1211 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1212 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1213 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1216 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1219 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1220 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1221 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1222 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1223 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1224 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1225 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1226 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1229 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1231 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1232 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1234 printf(" %d\n", data
[0]);
1237 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1240 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1241 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1242 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1245 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1248 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1249 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1250 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1251 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1252 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1253 printf("\t\t * Mesh Formation Info:\n");
1254 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1256 printf("\t\t\t Connected to Mesh Gate\n");
1258 printf("\t\t\t Connected to AS\n");
1259 printf("\t\t * Mesh Capability\n");
1261 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1263 printf("\t\t\t MCCA Supported\n");
1265 printf("\t\t\t MCCA Enabled\n");
1267 printf("\t\t\t Forwarding\n");
1269 printf("\t\t\t MBCA Supported\n");
1271 printf("\t\t\t TBTT Adjusting\n");
1273 printf("\t\t\t Mesh Power Save Level\n");
1278 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1279 uint8_t minlen
, maxlen
;
1283 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1284 uint8_t len
, const uint8_t *data
)
1291 printf("\t%s:", p
->name
);
1292 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1294 printf(" <invalid: %d bytes:", len
);
1295 for (i
= 0; i
< len
; i
++)
1296 printf(" %.02x", data
[i
]);
1299 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1301 printf(" <invalid: no data>\n");
1305 p
->print(type
, len
, data
);
1308 #define PRINT_IGN { \
1315 static const struct ie_print ieprinters
[] = {
1316 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1317 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1318 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1319 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1320 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1321 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1322 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1323 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1324 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1325 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1326 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1327 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1328 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1329 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1330 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1331 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1332 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1333 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1334 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1335 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1336 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1337 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1338 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1339 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1340 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1343 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1345 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1348 static void print_wifi_osen(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1350 print_osen_ie("OSEN", "OSEN", len
, data
);
1353 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1356 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1362 printf("Parameter: not version 1: ");
1366 printf("\t * Parameter version 1");
1371 printf("\n\t\t * u-APSD");
1375 for (i
= 0; i
< 4; i
++) {
1376 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1379 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1380 (1 << (data
[1] >> 4)) - 1);
1381 printf(", AIFSN %d", data
[0] & 0xf);
1382 if (data
[2] | data
[3])
1383 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1391 printf("invalid: ");
1395 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1401 printf(" information:");
1404 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1408 printf(" type %d:", data
[0]);
1412 for(i
= 1; i
< len
; i
++)
1413 printf(" %.02x", data
[i
]);
1417 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1421 return "Default (PIN)";
1423 return "User-specified";
1425 return "Machine-specified";
1429 return "PushButton";
1431 return "Registrar-specified";
1437 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1440 __u16 subtype
, sublen
;
1443 subtype
= (data
[0] << 8) + data
[1];
1444 sublen
= (data
[2] << 8) + data
[3];
1450 tab_on_first(&first
);
1451 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1454 tab_on_first(&first
);
1455 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1459 tab_on_first(&first
);
1461 printf("\t * Device Password ID: (invalid "
1462 "length %d)\n", sublen
);
1465 id
= data
[4] << 8 | data
[5];
1466 printf("\t * Device Password ID: %u (%s)\n",
1467 id
, wifi_wps_dev_passwd_id(id
));
1471 tab_on_first(&first
);
1472 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1475 tab_on_first(&first
);
1476 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1479 tab_on_first(&first
);
1480 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1484 tab_on_first(&first
);
1485 printf("\t * Response Type: %d%s\n",
1486 val
, val
== 3 ? " (AP)" : "");
1491 tab_on_first(&first
);
1492 printf("\t * RF Bands: 0x%x\n", val
);
1497 tab_on_first(&first
);
1498 printf("\t * Selected Registrar: 0x%x\n", val
);
1502 tab_on_first(&first
);
1503 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1507 tab_on_first(&first
);
1508 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1510 val
== 1 ? " (Unconfigured)" : "",
1511 val
== 2 ? " (Configured)" : "");
1515 tab_on_first(&first
);
1516 printf("\t * UUID: ");
1518 printf("(invalid, length=%d)\n", sublen
);
1521 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1522 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1523 data
[4], data
[5], data
[6], data
[7],
1524 data
[8], data
[9], data
[10], data
[11],
1525 data
[12], data
[13], data
[14], data
[15],
1526 data
[16], data
[17], data
[18], data
[19]);
1529 tab_on_first(&first
);
1531 printf("\t * Primary Device Type: (invalid "
1532 "length %d)\n", sublen
);
1535 printf("\t * Primary Device Type: "
1536 "%u-%02x%02x%02x%02x-%u\n",
1537 data
[4] << 8 | data
[5],
1538 data
[6], data
[7], data
[8], data
[9],
1539 data
[10] << 8 | data
[11]);
1544 tab_on_first(&first
);
1545 printf("\t * AP setup locked: 0x%.2x\n", val
);
1550 __u16 meth
= (data
[4] << 8) + data
[5];
1552 tab_on_first(&first
);
1553 printf("\t * %sConfig methods:",
1554 subtype
== 0x1053 ? "Selected Registrar ": "");
1555 #define T(bit, name) do { \
1556 if (meth & (1<<bit)) { \
1576 const __u8
*subdata
= data
+ 4;
1577 __u16 tmplen
= sublen
;
1579 tab_on_first(&first
);
1580 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1583 printf(" %.2x", *subdata
);
1597 printf("\t\t * bogus tail data (%d):", len
);
1599 printf(" %.2x", *data
);
1607 static const struct ie_print wifiprinters
[] = {
1608 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1609 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1610 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1613 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1621 sublen
= (data
[2] << 8) + data
[1];
1623 if (sublen
> len
- 3)
1627 case 0x02: /* capability */
1628 tab_on_first(&first
);
1630 printf("\t * malformed capability\n");
1633 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1636 case 0x0d: /* device info */
1637 if (sublen
< 6 + 2 + 8 + 1) {
1638 printf("\t * malformed device info\n");
1641 /* fall through for now */
1642 case 0x00: /* status */
1643 case 0x01: /* minor reason */
1644 case 0x03: /* device ID */
1645 case 0x04: /* GO intent */
1646 case 0x05: /* configuration timeout */
1647 case 0x06: /* listen channel */
1648 case 0x07: /* group BSSID */
1649 case 0x08: /* ext listen timing */
1650 case 0x09: /* intended interface address */
1651 case 0x0a: /* manageability */
1652 case 0x0b: /* channel list */
1653 case 0x0c: /* NoA */
1654 case 0x0e: /* group info */
1655 case 0x0f: /* group ID */
1656 case 0x10: /* interface */
1657 case 0x11: /* operating channel */
1658 case 0x12: /* invitation flags */
1659 case 0xdd: /* vendor specific */
1661 const __u8
*subdata
= data
+ 4;
1662 __u16 tmplen
= sublen
;
1664 tab_on_first(&first
);
1665 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1668 printf(" %.2x", *subdata
);
1682 tab_on_first(&first
);
1683 printf("\t * bogus tail data (%d):", len
);
1685 printf(" %.2x", *data
);
1693 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1695 /* I can't find the spec for this...just going off what wireshark uses. */
1698 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1700 printf("\t\tUnexpected length: %i\n", len
);
1703 static const struct ie_print wfa_printers
[] = {
1704 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1705 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1706 [18] = { "HotSpot 2.0 OSEN", print_wifi_osen
, 1, 255, BIT(PRINT_SCAN
), },
1709 static void print_vendor(unsigned char len
, unsigned char *data
,
1710 bool unknown
, enum print_ie_type ptype
)
1715 printf("\tVendor specific: <too short> data:");
1716 for(i
= 0; i
< len
; i
++)
1717 printf(" %.02x", data
[i
]);
1722 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1723 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1724 wifiprinters
[data
[3]].name
&&
1725 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1726 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1731 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1732 for(i
= 0; i
< len
- 4; i
++)
1733 printf(" %.02x", data
[i
+ 4]);
1738 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1739 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1740 wfa_printers
[data
[3]].name
&&
1741 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1742 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1747 printf("\tWFA %#.2x, data:", data
[3]);
1748 for(i
= 0; i
< len
- 4; i
++)
1749 printf(" %.02x", data
[i
+ 4]);
1757 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1758 data
[0], data
[1], data
[2]);
1759 for (i
= 3; i
< len
; i
++)
1760 printf(" %.2x", data
[i
]);
1764 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1765 enum print_ie_type ptype
)
1767 while (ielen
>= 2 && ielen
>= ie
[1]) {
1768 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1769 ieprinters
[ie
[0]].name
&&
1770 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1771 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1772 } else if (ie
[0] == 221 /* vendor */) {
1773 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1774 } else if (unknown
) {
1777 printf("\tUnknown IE (%d):", ie
[0]);
1778 for (i
=0; i
<ie
[1]; i
++)
1779 printf(" %.2x", ie
[2+i
]);
1787 static void print_capa_dmg(__u16 capa
)
1789 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1790 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1793 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1796 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1797 printf(" DMG_IBSS");
1801 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1802 printf(" CBAP_Only");
1803 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1804 printf(" CBAP_Src");
1805 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1807 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1809 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1810 printf(" SpectrumMgmt");
1811 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1812 printf(" RadioMeasure");
1815 static void print_capa_non_dmg(__u16 capa
)
1817 if (capa
& WLAN_CAPABILITY_ESS
)
1819 if (capa
& WLAN_CAPABILITY_IBSS
)
1821 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1822 printf(" CfPollable");
1823 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1824 printf(" CfPollReq");
1825 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1827 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1828 printf(" ShortPreamble");
1829 if (capa
& WLAN_CAPABILITY_PBCC
)
1831 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1832 printf(" ChannelAgility");
1833 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1834 printf(" SpectrumMgmt");
1835 if (capa
& WLAN_CAPABILITY_QOS
)
1837 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1838 printf(" ShortSlotTime");
1839 if (capa
& WLAN_CAPABILITY_APSD
)
1841 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1842 printf(" RadioMeasure");
1843 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1844 printf(" DSSS-OFDM");
1845 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1846 printf(" DelayedBACK");
1847 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1848 printf(" ImmediateBACK");
1851 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1853 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1854 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1855 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1856 char mac_addr
[20], dev
[20];
1857 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1858 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1859 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1860 [NL80211_BSS_BSSID
] = { },
1861 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1862 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1863 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1864 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1865 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1866 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1867 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1868 [NL80211_BSS_BEACON_IES
] = { },
1870 struct scan_params
*params
= arg
;
1871 int show
= params
->show_both_ie_sets
? 2 : 1;
1872 bool is_dmg
= false;
1874 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1875 genlmsg_attrlen(gnlh
, 0), NULL
);
1877 if (!tb
[NL80211_ATTR_BSS
]) {
1878 fprintf(stderr
, "bss info missing!\n");
1881 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1882 tb
[NL80211_ATTR_BSS
],
1884 fprintf(stderr
, "failed to parse nested attributes!\n");
1888 if (!bss
[NL80211_BSS_BSSID
])
1891 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1892 printf("BSS %s", mac_addr
);
1893 if (tb
[NL80211_ATTR_IFINDEX
]) {
1894 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1895 printf("(on %s)", dev
);
1898 if (bss
[NL80211_BSS_STATUS
]) {
1899 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1900 case NL80211_BSS_STATUS_AUTHENTICATED
:
1901 printf(" -- authenticated");
1903 case NL80211_BSS_STATUS_ASSOCIATED
:
1904 printf(" -- associated");
1906 case NL80211_BSS_STATUS_IBSS_JOINED
:
1907 printf(" -- joined");
1910 printf(" -- unknown status: %d",
1911 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1917 if (bss
[NL80211_BSS_TSF
]) {
1918 unsigned long long tsf
;
1919 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1920 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1921 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1922 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1924 if (bss
[NL80211_BSS_FREQUENCY
]) {
1925 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1926 printf("\tfreq: %d\n", freq
);
1930 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1931 printf("\tbeacon interval: %d TUs\n",
1932 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1933 if (bss
[NL80211_BSS_CAPABILITY
]) {
1934 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1935 printf("\tcapability:");
1937 print_capa_dmg(capa
);
1939 print_capa_non_dmg(capa
);
1940 printf(" (0x%.4x)\n", capa
);
1942 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1943 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1944 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1946 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1947 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1948 printf("\tsignal: %d/100\n", s
);
1950 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1951 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1952 printf("\tlast seen: %d ms ago\n", age
);
1955 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1956 if (bss
[NL80211_BSS_BEACON_IES
])
1957 printf("\tInformation elements from Probe Response "
1959 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1960 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1961 params
->unknown
, params
->type
);
1963 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1964 printf("\tInformation elements from Beacon frame:\n");
1965 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1966 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1967 params
->unknown
, params
->type
);
1973 static struct scan_params scan_params
;
1975 static int handle_scan_dump(struct nl80211_state
*state
,
1977 int argc
, char **argv
,
1983 memset(&scan_params
, 0, sizeof(scan_params
));
1985 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1986 scan_params
.unknown
= true;
1987 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1988 scan_params
.show_both_ie_sets
= true;
1990 scan_params
.type
= PRINT_SCAN
;
1992 register_handler(print_bss_handler
,
1997 static int handle_scan_combined(struct nl80211_state
*state
,
1999 int argc
, char **argv
,
2003 static char *dump_argv
[] = {
2009 static const __u32 cmds
[] = {
2010 NL80211_CMD_NEW_SCAN_RESULTS
,
2011 NL80211_CMD_SCAN_ABORTED
,
2013 int trig_argc
, dump_argc
, err
;
2016 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
2018 dump_argv
[3] = "-u";
2019 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
2021 dump_argv
[3] = "-b";
2025 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
2026 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
2029 trig_argv
[0] = argv
[0];
2030 trig_argv
[1] = "scan";
2031 trig_argv
[2] = "trigger";
2033 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
2034 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
2035 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2041 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2043 * This code has a bug, which requires creating a separate
2044 * nl80211 socket to fix:
2045 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2046 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2047 * before (!) we listen to it, because we only start listening
2048 * after we send our scan request.
2050 * Doing it the other way around has a race condition as well,
2051 * if you first open the events socket you may get a notification
2052 * for a previous scan.
2054 * The only proper way to fix this would be to listen to events
2055 * before sending the command, and for the kernel to send the
2056 * scan request along with the event, so that you can match up
2057 * whether the scan you requested was finished or aborted (this
2058 * may result in processing a scan that another application
2059 * requested, but that doesn't seem to be a problem).
2061 * Alas, the kernel doesn't do that (yet).
2064 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2065 NL80211_CMD_SCAN_ABORTED
) {
2066 printf("scan aborted!\n");
2070 dump_argv
[0] = argv
[0];
2071 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2073 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2074 CIB_NETDEV
, handle_scan_combined
,
2075 "Scan on the given frequencies and probe for the given SSIDs\n"
2076 "(or wildcard if not given) unless passive scanning is requested.\n"
2077 "If -u is specified print unknown data in the scan results.\n"
2078 "Specified (vendor) IEs must be well-formed.");
2079 COMMAND(scan
, dump
, "[-u]",
2080 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2081 "Dump the current scan results. If -u is specified, print unknown\n"
2082 "data in scan results.");
2083 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2084 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2085 "Trigger a scan on the given frequencies with probing for the given\n"
2086 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2089 static int handle_start_sched_scan(struct nl80211_state
*state
,
2091 int argc
, char **argv
, enum id_input id
)
2093 return parse_sched_scan(msg
, &argc
, &argv
);
2096 static int handle_stop_sched_scan(struct nl80211_state
*state
,
2097 struct nl_msg
*msg
, int argc
, char **argv
,
2106 COMMAND(scan
, sched_start
,
2108 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2109 "Start a scheduled scan at the specified interval on the given frequencies\n"
2110 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2111 "scanning is requested. If matches are specified, only matching results\n"
2112 "will be returned.");
2113 COMMAND(scan
, sched_stop
, "",
2114 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2115 "Stop an ongoing scheduled scan.");