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");
654 printf("%.02x-%.02x-%.02x:%d",
655 data
[0], data
[1] ,data
[2], data
[3]);
659 printf("%.02x-%.02x-%.02x:%d",
660 data
[0], data
[1] ,data
[2], data
[3]);
663 static void print_auth(const uint8_t *data
)
665 if (memcmp(data
, ms_oui
, 3) == 0) {
668 printf("IEEE 802.1X");
674 printf("%.02x-%.02x-%.02x:%d",
675 data
[0], data
[1] ,data
[2], data
[3]);
678 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
681 printf("IEEE 802.1X");
687 printf("FT/IEEE 802.1X");
693 printf("IEEE 802.1X/SHA-256");
696 printf("PSK/SHA-256");
702 printf("%.02x-%.02x-%.02x:%d",
703 data
[0], data
[1] ,data
[2], data
[3]);
707 printf("%.02x-%.02x-%.02x:%d",
708 data
[0], data
[1] ,data
[2], data
[3]);
711 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
712 uint8_t len
, const uint8_t *data
)
715 __u16 version
, count
, capa
;
718 version
= data
[0] + (data
[1] << 8);
719 tab_on_first(&first
);
720 printf("\t * Version: %d\n", version
);
726 tab_on_first(&first
);
727 printf("\t * Group cipher: %s\n", defcipher
);
728 printf("\t * Pairwise ciphers: %s\n", defcipher
);
732 tab_on_first(&first
);
733 printf("\t * Group cipher: ");
741 tab_on_first(&first
);
742 printf("\t * Pairwise ciphers: %s\n", defcipher
);
746 count
= data
[0] | (data
[1] << 8);
747 if (2 + (count
* 4) > len
)
750 tab_on_first(&first
);
751 printf("\t * Pairwise ciphers:");
752 for (i
= 0; i
< count
; i
++) {
754 print_cipher(data
+ 2 + (i
* 4));
758 data
+= 2 + (count
* 4);
759 len
-= 2 + (count
* 4);
762 tab_on_first(&first
);
763 printf("\t * Authentication suites: %s\n", defauth
);
767 count
= data
[0] | (data
[1] << 8);
768 if (2 + (count
* 4) > len
)
771 tab_on_first(&first
);
772 printf("\t * Authentication suites:");
773 for (i
= 0; i
< count
; i
++) {
775 print_auth(data
+ 2 + (i
* 4));
779 data
+= 2 + (count
* 4);
780 len
-= 2 + (count
* 4);
783 capa
= data
[0] | (data
[1] << 8);
784 tab_on_first(&first
);
785 printf("\t * Capabilities:");
789 printf(" NoPairwise");
790 switch ((capa
& 0x000c) >> 2) {
792 printf(" 1-PTKSA-RC");
795 printf(" 2-PTKSA-RC");
798 printf(" 4-PTKSA-RC");
801 printf(" 16-PTKSA-RC");
804 switch ((capa
& 0x0030) >> 4) {
806 printf(" 1-GTKSA-RC");
809 printf(" 2-GTKSA-RC");
812 printf(" 4-GTKSA-RC");
815 printf(" 16-GTKSA-RC");
819 printf(" MFP-required");
821 printf(" MFP-capable");
823 printf(" Peerkey-enabled");
825 printf(" SPP-AMSDU-capable");
827 printf(" SPP-AMSDU-required");
828 printf(" (0x%.4x)\n", capa
);
834 int pmkid_count
= data
[0] | (data
[1] << 8);
836 if (len
>= 2 + 16 * pmkid_count
) {
837 tab_on_first(&first
);
838 printf("\t * %d PMKIDs\n", pmkid_count
);
839 /* not printing PMKID values */
840 data
+= 2 + 16 * pmkid_count
;
841 len
-= 2 + 16 * pmkid_count
;
847 tab_on_first(&first
);
848 printf("\t * Group mgmt cipher suite: ");
857 printf("\t\t * bogus tail data (%d):", len
);
859 printf(" %.2x", *data
);
867 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
869 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
872 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
875 print_ht_capability(data
[0] | (data
[1] << 8));
876 print_ampdu_length(data
[2] & 3);
877 print_ampdu_spacing((data
[2] >> 2) & 7);
878 print_ht_mcs(data
+ 3);
881 static const char* ntype_11u(uint8_t t
)
884 case 0: return "Private";
885 case 1: return "Private with Guest";
886 case 2: return "Chargeable Public";
887 case 3: return "Free Public";
888 case 4: return "Personal Device";
889 case 5: return "Emergency Services Only";
890 case 14: return "Test or Experimental";
891 case 15: return "Wildcard";
892 default: return "Reserved";
896 static const char* vgroup_11u(uint8_t t
)
899 case 0: return "Unspecified";
900 case 1: return "Assembly";
901 case 2: return "Business";
902 case 3: return "Educational";
903 case 4: return "Factory and Industrial";
904 case 5: return "Institutional";
905 case 6: return "Mercantile";
906 case 7: return "Residential";
907 case 8: return "Storage";
908 case 9: return "Utility and Miscellaneous";
909 case 10: return "Vehicular";
910 case 11: return "Outdoor";
911 default: return "Reserved";
915 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
917 /* See Section 7.3.2.92 in the 802.11u spec. */
920 uint8_t ano
= data
[0];
921 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
922 printf("\t\t\tNetwork Type: %i (%s)\n",
923 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
925 printf("\t\t\tInternet\n");
927 printf("\t\t\tASRA\n");
929 printf("\t\t\tESR\n");
931 printf("\t\t\tUESA\n");
933 if ((len
== 3) || (len
== 9)) {
934 printf("\t\tVenue Group: %i (%s)\n",
935 (int)(data
[1]), vgroup_11u(data
[1]));
936 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
939 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
940 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
942 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
943 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
946 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
948 /* See Section 7.3.2.93 in the 802.11u spec. */
949 /* TODO: This code below does not decode private protocol IDs */
952 while (idx
< (len
- 1)) {
953 uint8_t qri
= data
[idx
];
954 uint8_t proto_id
= data
[idx
+ 1];
955 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
956 printf("\t\t\tQuery Response Length Limit: %i\n",
959 printf("\t\t\tPAME-BI\n");
962 printf("\t\t\tANQP\n"); break;
964 printf("\t\t\tMIH Information Service\n"); break;
966 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
968 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
970 printf("\t\t\tVendor Specific\n"); break;
972 printf("\t\t\tReserved: %i\n", proto_id
); break;
978 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
980 /* See Section 7.3.2.96 in the 802.11u spec. */
982 int ln0
= data
[1] & 0xf;
983 int ln1
= ((data
[1] & 0xf0) >> 4);
988 ln2
= len
- 2 - ln0
- ln1
;
990 printf("\t\tANQP OIs: %i\n", data
[0]);
993 printf("\t\tOI 1: ");
995 printf("Invalid IE length.\n");
997 for (idx
= 0; idx
< ln0
; idx
++) {
998 printf("%02hx", data
[2 + idx
]);
1005 printf("\t\tOI 2: ");
1006 if (2 + ln0
+ ln1
> len
) {
1007 printf("Invalid IE length.\n");
1009 for (idx
= 0; idx
< ln1
; idx
++) {
1010 printf("%02hx", data
[2 + ln0
+ idx
]);
1017 printf("\t\tOI 3: ");
1018 if (2 + ln0
+ ln1
+ ln2
> len
) {
1019 printf("Invalid IE length.\n");
1021 for (idx
= 0; idx
< ln2
; idx
++) {
1022 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1029 static const char *ht_secondary_offset
[4] = {
1036 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1038 static const char *protection
[4] = {
1044 static const char *sta_chan_width
[2] = {
1050 printf("\t\t * primary channel: %d\n", data
[0]);
1051 printf("\t\t * secondary channel offset: %s\n",
1052 ht_secondary_offset
[data
[1] & 0x3]);
1053 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1054 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1055 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1056 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1057 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1058 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1059 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1060 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1061 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1062 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1063 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1066 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1072 for (i
= 0; i
< len
; i
++) {
1075 for (bit
= 0; bit
< 8; bit
++) {
1076 if (!(data
[i
] & (1 << bit
)))
1084 #define CAPA(bit, name) case bit: printf(" " name); break
1086 switch (bit
+ base
) {
1087 CAPA(0, "HT Information Exchange Supported");
1088 CAPA(1, "reserved (On-demand Beacon)");
1089 CAPA(2, "Extended Channel Switching");
1090 CAPA(3, "reserved (Wave Indication)");
1091 CAPA(4, "PSMP Capability");
1092 CAPA(5, "reserved (Service Interval Granularity)");
1093 CAPA(6, "S-PSMP Capability");
1095 CAPA(8, "Diagnostics");
1096 CAPA(9, "Multicast Diagnostics");
1097 CAPA(10, "Location Tracking");
1099 CAPA(12, "Proxy ARP Service");
1100 CAPA(13, "Collocated Interference Reporting");
1101 CAPA(14, "Civic Location");
1102 CAPA(15, "Geospatial Location");
1104 CAPA(17, "WNM-Sleep Mode");
1105 CAPA(18, "TIM Broadcast");
1106 CAPA(19, "BSS Transition");
1107 CAPA(20, "QoS Traffic Capability");
1108 CAPA(21, "AC Station Count");
1109 CAPA(22, "Multiple BSSID");
1110 CAPA(23, "Timing Measurement");
1111 CAPA(24, "Channel Usage");
1112 CAPA(25, "SSID List");
1114 CAPA(27, "UTC TSF Offset");
1115 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1116 CAPA(29, "TDLS Peer PSM Support");
1117 CAPA(30, "TDLS channel switching");
1118 CAPA(31, "Interworking");
1119 CAPA(32, "QoS Map");
1121 CAPA(34, "SSPN Interface");
1122 CAPA(35, "Reserved");
1123 CAPA(36, "MSGCF Capability");
1124 CAPA(37, "TDLS Support");
1125 CAPA(38, "TDLS Prohibited");
1126 CAPA(39, "TDLS Channel Switching Prohibited");
1127 CAPA(40, "Reject Unadmitted Frame");
1128 CAPA(44, "Identifier Location");
1129 CAPA(45, "U-APSD Coexistence");
1130 CAPA(46, "WNM-Notification");
1131 CAPA(47, "Reserved");
1132 CAPA(48, "UTF-8 SSID");
1144 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1146 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1148 data
[0], data
[1], data
[2], data
[3]);
1150 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1154 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1156 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1159 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1162 print_vht_info(data
[0] | (data
[1] << 8) |
1163 (data
[2] << 16) | (data
[3] << 24),
1167 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1169 const char *chandwidths
[] = {
1170 [0] = "20 or 40 MHz",
1177 printf("\t\t * channel width: %d (%s)\n", data
[0],
1178 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1179 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1180 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1181 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1184 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1187 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1188 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1189 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1190 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1191 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1192 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1193 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1194 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1197 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1199 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1200 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1202 printf(" %d\n", data
[0]);
1205 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1208 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1209 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1210 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1213 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1216 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1217 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1218 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1219 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1220 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1221 printf("\t\t * Mesh Formation Info:\n");
1222 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1224 printf("\t\t\t Connected to Mesh Gate\n");
1226 printf("\t\t\t Connected to AS\n");
1227 printf("\t\t * Mesh Capability\n");
1229 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1231 printf("\t\t\t MCCA Supported\n");
1233 printf("\t\t\t MCCA Enabled\n");
1235 printf("\t\t\t Forwarding\n");
1237 printf("\t\t\t MBCA Supported\n");
1239 printf("\t\t\t TBTT Adjusting\n");
1241 printf("\t\t\t Mesh Power Save Level\n");
1246 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1247 uint8_t minlen
, maxlen
;
1251 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1252 uint8_t len
, const uint8_t *data
)
1259 printf("\t%s:", p
->name
);
1260 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1262 printf(" <invalid: %d bytes:", len
);
1263 for (i
= 0; i
< len
; i
++)
1264 printf(" %.02x", data
[i
]);
1267 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1269 printf(" <invalid: no data>\n");
1273 p
->print(type
, len
, data
);
1276 #define PRINT_IGN { \
1283 static const struct ie_print ieprinters
[] = {
1284 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1285 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1286 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1287 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1288 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1289 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1290 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1291 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1292 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1293 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1294 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1295 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1296 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1297 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1298 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1299 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1300 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1301 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1302 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1303 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1304 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1305 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1306 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1307 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1308 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1311 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1313 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1316 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1319 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1325 printf("Parameter: not version 1: ");
1329 printf("\t * Parameter version 1");
1334 printf("\n\t\t * u-APSD");
1338 for (i
= 0; i
< 4; i
++) {
1339 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1342 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1343 (1 << (data
[1] >> 4)) - 1);
1344 printf(", AIFSN %d", data
[0] & 0xf);
1345 if (data
[2] | data
[3])
1346 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1354 printf("invalid: ");
1358 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1364 printf(" information:");
1367 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1371 printf(" type %d:", data
[0]);
1375 for(i
= 1; i
< len
; i
++)
1376 printf(" %.02x", data
[i
]);
1380 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1384 return "Default (PIN)";
1386 return "User-specified";
1388 return "Machine-specified";
1392 return "PushButton";
1394 return "Registrar-specified";
1400 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1403 __u16 subtype
, sublen
;
1406 subtype
= (data
[0] << 8) + data
[1];
1407 sublen
= (data
[2] << 8) + data
[3];
1413 tab_on_first(&first
);
1414 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1417 tab_on_first(&first
);
1418 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1422 tab_on_first(&first
);
1424 printf("\t * Device Password ID: (invalid "
1425 "length %d)\n", sublen
);
1428 id
= data
[4] << 8 | data
[5];
1429 printf("\t * Device Password ID: %u (%s)\n",
1430 id
, wifi_wps_dev_passwd_id(id
));
1434 tab_on_first(&first
);
1435 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1438 tab_on_first(&first
);
1439 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1442 tab_on_first(&first
);
1443 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1447 tab_on_first(&first
);
1448 printf("\t * Response Type: %d%s\n",
1449 val
, val
== 3 ? " (AP)" : "");
1454 tab_on_first(&first
);
1455 printf("\t * RF Bands: 0x%x\n", val
);
1460 tab_on_first(&first
);
1461 printf("\t * Selected Registrar: 0x%x\n", val
);
1465 tab_on_first(&first
);
1466 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1470 tab_on_first(&first
);
1471 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1473 val
== 1 ? " (Unconfigured)" : "",
1474 val
== 2 ? " (Configured)" : "");
1478 tab_on_first(&first
);
1479 printf("\t * UUID: ");
1481 printf("(invalid, length=%d)\n", sublen
);
1484 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1485 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1486 data
[4], data
[5], data
[6], data
[7],
1487 data
[8], data
[9], data
[10], data
[11],
1488 data
[12], data
[13], data
[14], data
[15],
1489 data
[16], data
[17], data
[18], data
[19]);
1492 tab_on_first(&first
);
1494 printf("\t * Primary Device Type: (invalid "
1495 "length %d)\n", sublen
);
1498 printf("\t * Primary Device Type: "
1499 "%u-%02x%02x%02x%02x-%u\n",
1500 data
[4] << 8 | data
[5],
1501 data
[6], data
[7], data
[8], data
[9],
1502 data
[10] << 8 | data
[11]);
1507 tab_on_first(&first
);
1508 printf("\t * AP setup locked: 0x%.2x\n", val
);
1513 __u16 meth
= (data
[4] << 8) + data
[5];
1515 tab_on_first(&first
);
1516 printf("\t * %sConfig methods:",
1517 subtype
== 0x1053 ? "Selected Registrar ": "");
1518 #define T(bit, name) do { \
1519 if (meth & (1<<bit)) { \
1539 const __u8
*subdata
= data
+ 4;
1540 __u16 tmplen
= sublen
;
1542 tab_on_first(&first
);
1543 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1546 printf(" %.2x", *subdata
);
1560 printf("\t\t * bogus tail data (%d):", len
);
1562 printf(" %.2x", *data
);
1570 static const struct ie_print wifiprinters
[] = {
1571 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1572 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1573 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1576 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1584 sublen
= (data
[2] << 8) + data
[1];
1586 if (sublen
> len
- 3)
1590 case 0x02: /* capability */
1591 tab_on_first(&first
);
1593 printf("\t * malformed capability\n");
1596 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1599 case 0x0d: /* device info */
1600 if (sublen
< 6 + 2 + 8 + 1) {
1601 printf("\t * malformed device info\n");
1604 /* fall through for now */
1605 case 0x00: /* status */
1606 case 0x01: /* minor reason */
1607 case 0x03: /* device ID */
1608 case 0x04: /* GO intent */
1609 case 0x05: /* configuration timeout */
1610 case 0x06: /* listen channel */
1611 case 0x07: /* group BSSID */
1612 case 0x08: /* ext listen timing */
1613 case 0x09: /* intended interface address */
1614 case 0x0a: /* manageability */
1615 case 0x0b: /* channel list */
1616 case 0x0c: /* NoA */
1617 case 0x0e: /* group info */
1618 case 0x0f: /* group ID */
1619 case 0x10: /* interface */
1620 case 0x11: /* operating channel */
1621 case 0x12: /* invitation flags */
1622 case 0xdd: /* vendor specific */
1624 const __u8
*subdata
= data
+ 4;
1625 __u16 tmplen
= sublen
;
1627 tab_on_first(&first
);
1628 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1631 printf(" %.2x", *subdata
);
1645 tab_on_first(&first
);
1646 printf("\t * bogus tail data (%d):", len
);
1648 printf(" %.2x", *data
);
1656 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1658 /* I can't find the spec for this...just going off what wireshark uses. */
1661 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1663 printf("\t\tUnexpected length: %i\n", len
);
1666 static const struct ie_print wfa_printers
[] = {
1667 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1668 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1671 static void print_vendor(unsigned char len
, unsigned char *data
,
1672 bool unknown
, enum print_ie_type ptype
)
1677 printf("\tVendor specific: <too short> data:");
1678 for(i
= 0; i
< len
; i
++)
1679 printf(" %.02x", data
[i
]);
1684 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1685 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1686 wifiprinters
[data
[3]].name
&&
1687 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1688 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1693 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1694 for(i
= 0; i
< len
- 4; i
++)
1695 printf(" %.02x", data
[i
+ 4]);
1700 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1701 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1702 wfa_printers
[data
[3]].name
&&
1703 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1704 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1709 printf("\tWFA %#.2x, data:", data
[3]);
1710 for(i
= 0; i
< len
- 4; i
++)
1711 printf(" %.02x", data
[i
+ 4]);
1719 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1720 data
[0], data
[1], data
[2]);
1721 for (i
= 3; i
< len
; i
++)
1722 printf(" %.2x", data
[i
]);
1726 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1727 enum print_ie_type ptype
)
1729 while (ielen
>= 2 && ielen
>= ie
[1]) {
1730 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1731 ieprinters
[ie
[0]].name
&&
1732 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1733 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1734 } else if (ie
[0] == 221 /* vendor */) {
1735 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1736 } else if (unknown
) {
1739 printf("\tUnknown IE (%d):", ie
[0]);
1740 for (i
=0; i
<ie
[1]; i
++)
1741 printf(" %.2x", ie
[2+i
]);
1749 static void print_capa_dmg(__u16 capa
)
1751 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1752 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1755 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1758 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1759 printf(" DMG_IBSS");
1763 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1764 printf(" CBAP_Only");
1765 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1766 printf(" CBAP_Src");
1767 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1769 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1771 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1772 printf(" SpectrumMgmt");
1773 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1774 printf(" RadioMeasure");
1777 static void print_capa_non_dmg(__u16 capa
)
1779 if (capa
& WLAN_CAPABILITY_ESS
)
1781 if (capa
& WLAN_CAPABILITY_IBSS
)
1783 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1784 printf(" CfPollable");
1785 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1786 printf(" CfPollReq");
1787 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1789 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1790 printf(" ShortPreamble");
1791 if (capa
& WLAN_CAPABILITY_PBCC
)
1793 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1794 printf(" ChannelAgility");
1795 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1796 printf(" SpectrumMgmt");
1797 if (capa
& WLAN_CAPABILITY_QOS
)
1799 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1800 printf(" ShortSlotTime");
1801 if (capa
& WLAN_CAPABILITY_APSD
)
1803 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1804 printf(" RadioMeasure");
1805 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1806 printf(" DSSS-OFDM");
1807 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1808 printf(" DelayedBACK");
1809 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1810 printf(" ImmediateBACK");
1813 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1815 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1816 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1817 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1818 char mac_addr
[20], dev
[20];
1819 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1820 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1821 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1822 [NL80211_BSS_BSSID
] = { },
1823 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1824 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1825 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1826 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1827 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1828 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1829 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1830 [NL80211_BSS_BEACON_IES
] = { },
1832 struct scan_params
*params
= arg
;
1833 int show
= params
->show_both_ie_sets
? 2 : 1;
1834 bool is_dmg
= false;
1836 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1837 genlmsg_attrlen(gnlh
, 0), NULL
);
1839 if (!tb
[NL80211_ATTR_BSS
]) {
1840 fprintf(stderr
, "bss info missing!\n");
1843 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1844 tb
[NL80211_ATTR_BSS
],
1846 fprintf(stderr
, "failed to parse nested attributes!\n");
1850 if (!bss
[NL80211_BSS_BSSID
])
1853 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1854 printf("BSS %s", mac_addr
);
1855 if (tb
[NL80211_ATTR_IFINDEX
]) {
1856 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1857 printf("(on %s)", dev
);
1860 if (bss
[NL80211_BSS_STATUS
]) {
1861 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1862 case NL80211_BSS_STATUS_AUTHENTICATED
:
1863 printf(" -- authenticated");
1865 case NL80211_BSS_STATUS_ASSOCIATED
:
1866 printf(" -- associated");
1868 case NL80211_BSS_STATUS_IBSS_JOINED
:
1869 printf(" -- joined");
1872 printf(" -- unknown status: %d",
1873 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1879 if (bss
[NL80211_BSS_TSF
]) {
1880 unsigned long long tsf
;
1881 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1882 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1883 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1884 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1886 if (bss
[NL80211_BSS_FREQUENCY
]) {
1887 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1888 printf("\tfreq: %d\n", freq
);
1892 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1893 printf("\tbeacon interval: %d TUs\n",
1894 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1895 if (bss
[NL80211_BSS_CAPABILITY
]) {
1896 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1897 printf("\tcapability:");
1899 print_capa_dmg(capa
);
1901 print_capa_non_dmg(capa
);
1902 printf(" (0x%.4x)\n", capa
);
1904 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1905 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1906 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1908 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1909 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1910 printf("\tsignal: %d/100\n", s
);
1912 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1913 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1914 printf("\tlast seen: %d ms ago\n", age
);
1917 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1918 if (bss
[NL80211_BSS_BEACON_IES
])
1919 printf("\tInformation elements from Probe Response "
1921 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1922 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1923 params
->unknown
, params
->type
);
1925 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1926 printf("\tInformation elements from Beacon frame:\n");
1927 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1928 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1929 params
->unknown
, params
->type
);
1935 static struct scan_params scan_params
;
1937 static int handle_scan_dump(struct nl80211_state
*state
,
1940 int argc
, char **argv
,
1946 memset(&scan_params
, 0, sizeof(scan_params
));
1948 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1949 scan_params
.unknown
= true;
1950 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1951 scan_params
.show_both_ie_sets
= true;
1953 scan_params
.type
= PRINT_SCAN
;
1955 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1960 static int handle_scan_combined(struct nl80211_state
*state
,
1963 int argc
, char **argv
,
1967 static char *dump_argv
[] = {
1973 static const __u32 cmds
[] = {
1974 NL80211_CMD_NEW_SCAN_RESULTS
,
1975 NL80211_CMD_SCAN_ABORTED
,
1977 int trig_argc
, dump_argc
, err
;
1979 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1981 dump_argv
[3] = "-u";
1982 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1984 dump_argv
[3] = "-b";
1988 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1989 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1992 trig_argv
[0] = argv
[0];
1993 trig_argv
[1] = "scan";
1994 trig_argv
[2] = "trigger";
1996 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1997 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1998 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
2004 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2006 * This code has a bug, which requires creating a separate
2007 * nl80211 socket to fix:
2008 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2009 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2010 * before (!) we listen to it, because we only start listening
2011 * after we send our scan request.
2013 * Doing it the other way around has a race condition as well,
2014 * if you first open the events socket you may get a notification
2015 * for a previous scan.
2017 * The only proper way to fix this would be to listen to events
2018 * before sending the command, and for the kernel to send the
2019 * scan request along with the event, so that you can match up
2020 * whether the scan you requested was finished or aborted (this
2021 * may result in processing a scan that another application
2022 * requested, but that doesn't seem to be a problem).
2024 * Alas, the kernel doesn't do that (yet).
2027 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2028 NL80211_CMD_SCAN_ABORTED
) {
2029 printf("scan aborted!\n");
2033 dump_argv
[0] = argv
[0];
2034 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2036 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2037 CIB_NETDEV
, handle_scan_combined
,
2038 "Scan on the given frequencies and probe for the given SSIDs\n"
2039 "(or wildcard if not given) unless passive scanning is requested.\n"
2040 "If -u is specified print unknown data in the scan results.\n"
2041 "Specified (vendor) IEs must be well-formed.");
2042 COMMAND(scan
, dump
, "[-u]",
2043 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2044 "Dump the current scan results. If -u is specified, print unknown\n"
2045 "data in scan results.");
2046 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2047 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2048 "Trigger a scan on the given frequencies with probing for the given\n"
2049 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2052 static int handle_start_sched_scan(struct nl80211_state
*state
,
2053 struct nl_cb
*cb
, struct nl_msg
*msg
,
2054 int argc
, char **argv
, enum id_input id
)
2056 return parse_sched_scan(msg
, &argc
, &argv
);
2059 static int handle_stop_sched_scan(struct nl80211_state
*state
, struct nl_cb
*cb
,
2060 struct nl_msg
*msg
, int argc
, char **argv
,
2069 COMMAND(scan
, sched_start
,
2071 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2072 "Start a scheduled scan at the specified interval on the given frequencies\n"
2073 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2074 "scanning is requested. If matches are specified, only matching results\n"
2075 "will be returned.");
2076 COMMAND(scan
, sched_stop
, "",
2077 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2078 "Stop an ongoing scheduled scan.");