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;
119 matchset
= nlmsg_alloc();
125 freqs
= nlmsg_alloc();
131 ssids
= nlmsg_alloc();
138 switch (parse_state
) {
140 if (!strcmp(v
[0], "interval")) {
144 goto nla_put_failure
;
149 goto nla_put_failure
;
151 interval
= strtoul(v
[0], &end
, 10);
152 if (*end
|| !interval
) {
154 goto nla_put_failure
;
157 NL80211_ATTR_SCHED_SCAN_INTERVAL
,
159 } else if (!strcmp(v
[0], "delay")) {
163 goto nla_put_failure
;
168 goto nla_put_failure
;
170 delay
= strtoul(v
[0], &end
, 10);
173 goto nla_put_failure
;
176 NL80211_ATTR_SCHED_SCAN_DELAY
,
178 } else if (!strcmp(v
[0], "matches")) {
179 parse_state
= ND_MATCH
;
182 goto nla_put_failure
;
186 } else if (!strcmp(v
[0], "freqs")) {
187 parse_state
= ND_FREQS
;
190 goto nla_put_failure
;
195 } else if (!strcmp(v
[0], "active")) {
196 parse_state
= ND_ACTIVE
;
197 if (have_active
|| have_passive
) {
199 goto nla_put_failure
;
204 } else if (!strcmp(v
[0], "passive")) {
205 if (have_active
|| have_passive
) {
207 goto nla_put_failure
;
212 /* this element is not for us, so
213 * return to continue parsing.
215 goto nla_put_failure
;
221 if (!strcmp(v
[0], "ssid")) {
225 goto nla_put_failure
;
228 /* TODO: for now we can only have an
229 * SSID in the match, so we can start
230 * the match nest here.
232 match
= nla_nest_start(matchset
, i
);
235 goto nla_put_failure
;
239 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
241 nla_nest_end(matchset
, match
);
244 have_matchset
= true;
248 /* other element that cannot be part
249 * of a match indicates the end of the
251 /* need at least one match in the matchset */
254 goto nla_put_failure
;
257 parse_state
= ND_TOPLEVEL
;
262 freq
= strtoul(v
[0], &end
, 10);
266 goto nla_put_failure
;
269 parse_state
= ND_TOPLEVEL
;
271 NLA_PUT_U32(freqs
, i
, freq
);
277 if (!strcmp(v
[0], "ssid")) {
281 goto nla_put_failure
;
285 NL80211_SCHED_SCAN_MATCH_ATTR_SSID
,
292 /* other element that cannot be part
293 * of a match indicates the end of the
295 /* need at least one item in the set */
298 goto nla_put_failure
;
301 parse_state
= ND_TOPLEVEL
;
308 NLA_PUT(ssids
, 1, 0, "");
310 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
312 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
314 nla_put_nested(msg
, NL80211_ATTR_SCHED_SCAN_MATCH
, matchset
);
318 nla_nest_end(msg
, match
);
320 nlmsg_free(matchset
);
328 static int handle_scan(struct nl80211_state
*state
,
331 int argc
, char **argv
,
334 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
347 bool passive
= false, have_ssids
= false, have_freqs
= false;
348 size_t ies_len
= 0, meshid_len
= 0;
349 unsigned char *ies
= NULL
, *meshid
= NULL
, *tmpies
;
350 unsigned int flags
= 0;
352 ssids
= nlmsg_alloc();
356 freqs
= nlmsg_alloc();
362 for (i
= 0; i
< argc
; i
++) {
365 if (strcmp(argv
[i
], "freq") == 0) {
369 } else if (strcmp(argv
[i
], "ies") == 0) {
372 } else if (strcmp(argv
[i
], "lowpri") == 0) {
373 flags
|= NL80211_SCAN_FLAG_LOW_PRIORITY
;
375 } else if (strcmp(argv
[i
], "flush") == 0) {
376 flags
|= NL80211_SCAN_FLAG_FLUSH
;
378 } else if (strcmp(argv
[i
], "ap-force") == 0) {
379 flags
|= NL80211_SCAN_FLAG_AP
;
381 } else if (strncmp(argv
[i
], "randomise", 9) == 0 ||
382 strncmp(argv
[i
], "randomize", 9) == 0) {
383 flags
|= NL80211_SCAN_FLAG_RANDOM_ADDR
;
384 err
= parse_random_mac_addr(msg
, argv
[i
]);
386 goto nla_put_failure
;
388 } else if (strcmp(argv
[i
], "ssid") == 0) {
392 } else if (strcmp(argv
[i
], "passive") == 0) {
396 } else if (strcmp(argv
[i
], "meshid") == 0) {
403 freq
= strtoul(argv
[i
], &eptr
, 10);
404 if (eptr
!= argv
[i
] + strlen(argv
[i
])) {
405 /* failed to parse as number -- maybe a tag? */
410 NLA_PUT_U32(freqs
, i
, freq
);
413 ies
= parse_hex(argv
[i
], &ies_len
);
415 goto nla_put_failure
;
419 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
422 meshid_len
= strlen(argv
[i
]);
423 meshid
= (unsigned char *) malloc(meshid_len
+ 2);
425 goto nla_put_failure
;
426 meshid
[0] = 114; /* mesh element id */
427 meshid
[1] = meshid_len
;
428 memcpy(&meshid
[2], argv
[i
], meshid_len
);
436 tmpies
= (unsigned char *) malloc(ies_len
+ meshid_len
);
438 goto nla_put_failure
;
440 memcpy(tmpies
, ies
, ies_len
);
444 memcpy(&tmpies
[ies_len
], meshid
, meshid_len
);
447 NLA_PUT(msg
, NL80211_ATTR_IE
, ies_len
+ meshid_len
, tmpies
);
452 NLA_PUT(ssids
, 1, 0, "");
454 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
457 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
459 NLA_PUT_U32(msg
, NL80211_ATTR_SCAN_FLAGS
, flags
);
468 static void tab_on_first(bool *first
)
476 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
479 print_ssid_escaped(len
, data
);
483 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
484 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
486 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
492 for (i
= 0; i
< len
; i
++) {
493 int r
= data
[i
] & 0x7f;
495 if (r
== BSS_MEMBERSHIP_SELECTOR_VHT_PHY
&& data
[i
] & 0x80)
497 else if (r
== BSS_MEMBERSHIP_SELECTOR_HT_PHY
&& data
[i
] & 0x80)
500 printf("%d.%d", r
/2, 5*(r
&1));
502 printf("%s ", data
[i
] & 0x80 ? "*" : "");
507 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
509 printf(" channel %d\n", data
[0]);
512 static const char *country_env_str(char environment
)
514 switch (environment
) {
516 return "Indoor only";
518 return "Outdoor only";
520 return "Indoor/Outdoor";
526 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
528 printf(" %.*s", 2, data
);
530 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
536 printf("\t\tNo country IE triplets present\n");
542 union ieee80211_country_ie_triplet
*triplet
= (void *) data
;
544 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
545 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
546 triplet
->ext
.reg_extension_id
,
547 triplet
->ext
.reg_class
,
548 triplet
->ext
.coverage_class
,
549 triplet
->ext
.coverage_class
* 450);
557 if (triplet
->chans
.first_channel
<= 14)
558 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
560 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
562 printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet
->chans
.first_channel
, end_channel
, triplet
->chans
.max_power
);
571 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
573 printf(" %d dB\n", data
[0]);
576 static void print_tpcreport(const uint8_t type
, uint8_t len
, const uint8_t *data
)
578 printf(" TX power: %d dBm\n", data
[0]);
579 /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
582 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
585 printf(" <no flags>");
587 printf(" NonERP_Present");
589 printf(" Use_Protection");
591 printf(" Barker_Preamble_Mode");
595 static void print_cipher(const uint8_t *data
)
597 if (memcmp(data
, ms_oui
, 3) == 0) {
600 printf("Use group cipher suite");
615 printf("%.02x-%.02x-%.02x:%d",
616 data
[0], data
[1] ,data
[2], data
[3]);
619 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
622 printf("Use group cipher suite");
637 printf("AES-128-CMAC");
643 printf("%.02x-%.02x-%.02x:%d",
644 data
[0], data
[1] ,data
[2], data
[3]);
648 printf("%.02x-%.02x-%.02x:%d",
649 data
[0], data
[1] ,data
[2], data
[3]);
652 static void print_auth(const uint8_t *data
)
654 if (memcmp(data
, ms_oui
, 3) == 0) {
657 printf("IEEE 802.1X");
663 printf("%.02x-%.02x-%.02x:%d",
664 data
[0], data
[1] ,data
[2], data
[3]);
667 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
670 printf("IEEE 802.1X");
676 printf("FT/IEEE 802.1X");
682 printf("IEEE 802.1X/SHA-256");
685 printf("PSK/SHA-256");
691 printf("%.02x-%.02x-%.02x:%d",
692 data
[0], data
[1] ,data
[2], data
[3]);
696 printf("%.02x-%.02x-%.02x:%d",
697 data
[0], data
[1] ,data
[2], data
[3]);
700 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
701 uint8_t len
, const uint8_t *data
)
704 __u16 version
, count
, capa
;
707 version
= data
[0] + (data
[1] << 8);
708 tab_on_first(&first
);
709 printf("\t * Version: %d\n", version
);
715 tab_on_first(&first
);
716 printf("\t * Group cipher: %s\n", defcipher
);
717 printf("\t * Pairwise ciphers: %s\n", defcipher
);
721 tab_on_first(&first
);
722 printf("\t * Group cipher: ");
730 tab_on_first(&first
);
731 printf("\t * Pairwise ciphers: %s\n", defcipher
);
735 count
= data
[0] | (data
[1] << 8);
736 if (2 + (count
* 4) > len
)
739 tab_on_first(&first
);
740 printf("\t * Pairwise ciphers:");
741 for (i
= 0; i
< count
; i
++) {
743 print_cipher(data
+ 2 + (i
* 4));
747 data
+= 2 + (count
* 4);
748 len
-= 2 + (count
* 4);
751 tab_on_first(&first
);
752 printf("\t * Authentication suites: %s\n", defauth
);
756 count
= data
[0] | (data
[1] << 8);
757 if (2 + (count
* 4) > len
)
760 tab_on_first(&first
);
761 printf("\t * Authentication suites:");
762 for (i
= 0; i
< count
; i
++) {
764 print_auth(data
+ 2 + (i
* 4));
768 data
+= 2 + (count
* 4);
769 len
-= 2 + (count
* 4);
772 capa
= data
[0] | (data
[1] << 8);
773 tab_on_first(&first
);
774 printf("\t * Capabilities:");
778 printf(" NoPairwise");
779 switch ((capa
& 0x000c) >> 2) {
781 printf(" 1-PTKSA-RC");
784 printf(" 2-PTKSA-RC");
787 printf(" 4-PTKSA-RC");
790 printf(" 16-PTKSA-RC");
793 switch ((capa
& 0x0030) >> 4) {
795 printf(" 1-GTKSA-RC");
798 printf(" 2-GTKSA-RC");
801 printf(" 4-GTKSA-RC");
804 printf(" 16-GTKSA-RC");
808 printf(" MFP-required");
810 printf(" MFP-capable");
812 printf(" Peerkey-enabled");
814 printf(" SPP-AMSDU-capable");
816 printf(" SPP-AMSDU-required");
817 printf(" (0x%.4x)\n", capa
);
823 int pmkid_count
= data
[0] | (data
[1] << 8);
825 if (len
>= 2 + 16 * pmkid_count
) {
826 tab_on_first(&first
);
827 printf("\t * %d PMKIDs\n", pmkid_count
);
828 /* not printing PMKID values */
829 data
+= 2 + 16 * pmkid_count
;
830 len
-= 2 + 16 * pmkid_count
;
836 tab_on_first(&first
);
837 printf("\t * Group mgmt cipher suite: ");
846 printf("\t\t * bogus tail data (%d):", len
);
848 printf(" %.2x", *data
);
856 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
858 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
861 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
864 print_ht_capability(data
[0] | (data
[1] << 8));
865 print_ampdu_length(data
[2] & 3);
866 print_ampdu_spacing((data
[2] >> 2) & 7);
867 print_ht_mcs(data
+ 3);
870 static const char* ntype_11u(uint8_t t
)
873 case 0: return "Private";
874 case 1: return "Private with Guest";
875 case 2: return "Chargeable Public";
876 case 3: return "Free Public";
877 case 4: return "Personal Device";
878 case 5: return "Emergency Services Only";
879 case 14: return "Test or Experimental";
880 case 15: return "Wildcard";
881 default: return "Reserved";
885 static const char* vgroup_11u(uint8_t t
)
888 case 0: return "Unspecified";
889 case 1: return "Assembly";
890 case 2: return "Business";
891 case 3: return "Educational";
892 case 4: return "Factory and Industrial";
893 case 5: return "Institutional";
894 case 6: return "Mercantile";
895 case 7: return "Residential";
896 case 8: return "Storage";
897 case 9: return "Utility and Miscellaneous";
898 case 10: return "Vehicular";
899 case 11: return "Outdoor";
900 default: return "Reserved";
904 static void print_interworking(const uint8_t type
, uint8_t len
, const uint8_t *data
)
906 /* See Section 7.3.2.92 in the 802.11u spec. */
909 uint8_t ano
= data
[0];
910 printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano
));
911 printf("\t\t\tNetwork Type: %i (%s)\n",
912 (int)(ano
& 0xf), ntype_11u(ano
& 0xf));
914 printf("\t\t\tInternet\n");
916 printf("\t\t\tASRA\n");
918 printf("\t\t\tESR\n");
920 printf("\t\t\tUESA\n");
922 if ((len
== 3) || (len
== 9)) {
923 printf("\t\tVenue Group: %i (%s)\n",
924 (int)(data
[1]), vgroup_11u(data
[1]));
925 printf("\t\tVenue Type: %i\n", (int)(data
[2]));
928 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
929 data
[3], data
[4], data
[5], data
[6], data
[7], data
[8]);
931 printf("\t\tHESSID: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n",
932 data
[1], data
[2], data
[3], data
[4], data
[5], data
[6]);
935 static void print_11u_advert(const uint8_t type
, uint8_t len
, const uint8_t *data
)
937 /* See Section 7.3.2.93 in the 802.11u spec. */
938 /* TODO: This code below does not decode private protocol IDs */
941 while (idx
< (len
- 1)) {
942 uint8_t qri
= data
[idx
];
943 uint8_t proto_id
= data
[idx
+ 1];
944 printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri
));
945 printf("\t\t\tQuery Response Length Limit: %i\n",
948 printf("\t\t\tPAME-BI\n");
951 printf("\t\t\tANQP\n"); break;
953 printf("\t\t\tMIH Information Service\n"); break;
955 printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
957 printf("\t\t\tEmergency Alert System (EAS)\n"); break;
959 printf("\t\t\tVendor Specific\n"); break;
961 printf("\t\t\tReserved: %i\n", proto_id
); break;
967 static void print_11u_rcon(const uint8_t type
, uint8_t len
, const uint8_t *data
)
969 /* See Section 7.3.2.96 in the 802.11u spec. */
971 int ln0
= data
[1] & 0xf;
972 int ln1
= ((data
[1] & 0xf0) >> 4);
977 ln2
= len
- 2 - ln0
- ln1
;
979 printf("\t\tANQP OIs: %i\n", data
[0]);
982 printf("\t\tOI 1: ");
984 printf("Invalid IE length.\n");
986 for (idx
= 0; idx
< ln0
; idx
++) {
987 printf("%02hx", data
[2 + idx
]);
994 printf("\t\tOI 2: ");
995 if (2 + ln0
+ ln1
> len
) {
996 printf("Invalid IE length.\n");
998 for (idx
= 0; idx
< ln1
; idx
++) {
999 printf("%02hx", data
[2 + ln0
+ idx
]);
1006 printf("\t\tOI 3: ");
1007 if (2 + ln0
+ ln1
+ ln2
> len
) {
1008 printf("Invalid IE length.\n");
1010 for (idx
= 0; idx
< ln2
; idx
++) {
1011 printf("%02hx", data
[2 + ln0
+ ln1
+ idx
]);
1018 static const char *ht_secondary_offset
[4] = {
1025 static void print_ht_op(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1027 static const char *protection
[4] = {
1033 static const char *sta_chan_width
[2] = {
1039 printf("\t\t * primary channel: %d\n", data
[0]);
1040 printf("\t\t * secondary channel offset: %s\n",
1041 ht_secondary_offset
[data
[1] & 0x3]);
1042 printf("\t\t * STA channel width: %s\n", sta_chan_width
[(data
[1] & 0x4)>>2]);
1043 printf("\t\t * RIFS: %d\n", (data
[1] & 0x8)>>3);
1044 printf("\t\t * HT protection: %s\n", protection
[data
[2] & 0x3]);
1045 printf("\t\t * non-GF present: %d\n", (data
[2] & 0x4) >> 2);
1046 printf("\t\t * OBSS non-GF present: %d\n", (data
[2] & 0x10) >> 4);
1047 printf("\t\t * dual beacon: %d\n", (data
[4] & 0x40) >> 6);
1048 printf("\t\t * dual CTS protection: %d\n", (data
[4] & 0x80) >> 7);
1049 printf("\t\t * STBC beacon: %d\n", data
[5] & 0x1);
1050 printf("\t\t * L-SIG TXOP Prot: %d\n", (data
[5] & 0x2) >> 1);
1051 printf("\t\t * PCO active: %d\n", (data
[5] & 0x4) >> 2);
1052 printf("\t\t * PCO phase: %d\n", (data
[5] & 0x8) >> 3);
1055 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1061 for (i
= 0; i
< len
; i
++) {
1064 for (bit
= 0; bit
< 8; bit
++) {
1065 if (!(data
[i
] & (1 << bit
)))
1073 #define CAPA(bit, name) case bit: printf(" " name); break
1075 switch (bit
+ base
) {
1076 CAPA(0, "HT Information Exchange Supported");
1077 CAPA(1, "reserved (On-demand Beacon)");
1078 CAPA(2, "Extended Channel Switching");
1079 CAPA(3, "reserved (Wave Indication)");
1080 CAPA(4, "PSMP Capability");
1081 CAPA(5, "reserved (Service Interval Granularity)");
1082 CAPA(6, "S-PSMP Capability");
1084 CAPA(8, "Diagnostics");
1085 CAPA(9, "Multicast Diagnostics");
1086 CAPA(10, "Location Tracking");
1088 CAPA(12, "Proxy ARP Service");
1089 CAPA(13, "Collocated Interference Reporting");
1090 CAPA(14, "Civic Location");
1091 CAPA(15, "Geospatial Location");
1093 CAPA(17, "WNM-Sleep Mode");
1094 CAPA(18, "TIM Broadcast");
1095 CAPA(19, "BSS Transition");
1096 CAPA(20, "QoS Traffic Capability");
1097 CAPA(21, "AC Station Count");
1098 CAPA(22, "Multiple BSSID");
1099 CAPA(23, "Timing Measurement");
1100 CAPA(24, "Channel Usage");
1101 CAPA(25, "SSID List");
1103 CAPA(27, "UTC TSF Offset");
1104 CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1105 CAPA(29, "TDLS Peer PSM Support");
1106 CAPA(30, "TDLS channel switching");
1107 CAPA(31, "Interworking");
1108 CAPA(32, "QoS Map");
1110 CAPA(34, "SSPN Interface");
1111 CAPA(35, "Reserved");
1112 CAPA(36, "MSGCF Capability");
1113 CAPA(37, "TDLS Support");
1114 CAPA(38, "TDLS Prohibited");
1115 CAPA(39, "TDLS Channel Switching Prohibited");
1116 CAPA(40, "Reject Unadmitted Frame");
1117 CAPA(44, "Identifier Location");
1118 CAPA(45, "U-APSD Coexistence");
1119 CAPA(46, "WNM-Notification");
1120 CAPA(47, "Reserved");
1121 CAPA(48, "UTF-8 SSID");
1133 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1135 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1137 data
[0], data
[1], data
[2], data
[3]);
1139 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
1143 static void print_ibssatim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1145 printf(" %d TUs", (data
[1] << 8) + data
[0]);
1148 static void print_vht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1151 print_vht_info(data
[0] | (data
[1] << 8) |
1152 (data
[2] << 16) | (data
[3] << 24),
1156 static void print_vht_oper(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1158 const char *chandwidths
[] = {
1159 [0] = "20 or 40 MHz",
1166 printf("\t\t * channel width: %d (%s)\n", data
[0],
1167 data
[0] < ARRAY_SIZE(chandwidths
) ? chandwidths
[data
[0]] : "unknown");
1168 printf("\t\t * center freq segment 1: %d\n", data
[1]);
1169 printf("\t\t * center freq segment 2: %d\n", data
[2]);
1170 printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data
[4], data
[3]);
1173 static void print_obss_scan_params(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1176 printf("\t\t * passive dwell: %d TUs\n", (data
[1] << 8) | data
[0]);
1177 printf("\t\t * active dwell: %d TUs\n", (data
[3] << 8) | data
[2]);
1178 printf("\t\t * channel width trigger scan interval: %d s\n", (data
[5] << 8) | data
[4]);
1179 printf("\t\t * scan passive total per channel: %d TUs\n", (data
[7] << 8) | data
[6]);
1180 printf("\t\t * scan active total per channel: %d TUs\n", (data
[9] << 8) | data
[8]);
1181 printf("\t\t * BSS width channel transition delay factor: %d\n", (data
[11] << 8) | data
[10]);
1182 printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1183 ((data
[13] << 8) | data
[12]) / 100, ((data
[13] << 8) | data
[12]) % 100);
1186 static void print_secchan_offs(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1188 if (data
[0] < ARRAY_SIZE(ht_secondary_offset
))
1189 printf(" %s (%d)\n", ht_secondary_offset
[data
[0]], data
[0]);
1191 printf(" %d\n", data
[0]);
1194 static void print_bss_load(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1197 printf("\t\t * station count: %d\n", (data
[1] << 8) | data
[0]);
1198 printf("\t\t * channel utilisation: %d/255\n", data
[2]);
1199 printf("\t\t * available admission capacity: %d [*32us]\n", (data
[4] << 8) | data
[3]);
1202 static void print_mesh_conf(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1205 printf("\t\t * Active Path Selection Protocol ID: %d\n", data
[0]);
1206 printf("\t\t * Active Path Selection Metric ID: %d\n", data
[1]);
1207 printf("\t\t * Congestion Control Mode ID: %d\n", data
[2]);
1208 printf("\t\t * Synchronization Method ID: %d\n", data
[3]);
1209 printf("\t\t * Authentication Protocol ID: %d\n", data
[4]);
1210 printf("\t\t * Mesh Formation Info:\n");
1211 printf("\t\t\t Number of Peerings: %d\n", (data
[5] & 0x7E) >> 1);
1213 printf("\t\t\t Connected to Mesh Gate\n");
1215 printf("\t\t\t Connected to AS\n");
1216 printf("\t\t * Mesh Capability\n");
1218 printf("\t\t\t Accepting Additional Mesh Peerings\n");
1220 printf("\t\t\t MCCA Supported\n");
1222 printf("\t\t\t MCCA Enabled\n");
1224 printf("\t\t\t Forwarding\n");
1226 printf("\t\t\t MBCA Supported\n");
1228 printf("\t\t\t TBTT Adjusting\n");
1230 printf("\t\t\t Mesh Power Save Level\n");
1235 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
1236 uint8_t minlen
, maxlen
;
1240 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
1241 uint8_t len
, const uint8_t *data
)
1248 printf("\t%s:", p
->name
);
1249 if (len
< p
->minlen
|| len
> p
->maxlen
) {
1251 printf(" <invalid: %d bytes:", len
);
1252 for (i
= 0; i
< len
; i
++)
1253 printf(" %.02x", data
[i
]);
1256 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
1258 printf(" <invalid: no data>\n");
1262 p
->print(type
, len
, data
);
1265 #define PRINT_IGN { \
1272 static const struct ie_print ieprinters
[] = {
1273 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1274 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1275 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
1276 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
1277 [6] = { "IBSS ATIM window", print_ibssatim
, 2, 2, BIT(PRINT_SCAN
), },
1278 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
1279 [11] = { "BSS Load", print_bss_load
, 5, 5, BIT(PRINT_SCAN
), },
1280 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
1281 [35] = { "TPC report", print_tpcreport
, 2, 2, BIT(PRINT_SCAN
), },
1282 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1283 [45] = { "HT capabilities", print_ht_capa
, 26, 26, BIT(PRINT_SCAN
), },
1284 [47] = { "ERP D4.0", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
1285 [74] = { "Overlapping BSS scan params", print_obss_scan_params
, 14, 255, BIT(PRINT_SCAN
), },
1286 [61] = { "HT operation", print_ht_op
, 22, 22, BIT(PRINT_SCAN
), },
1287 [62] = { "Secondary Channel Offset", print_secchan_offs
, 1, 1, BIT(PRINT_SCAN
), },
1288 [191] = { "VHT capabilities", print_vht_capa
, 12, 255, BIT(PRINT_SCAN
), },
1289 [192] = { "VHT operation", print_vht_oper
, 5, 255, BIT(PRINT_SCAN
), },
1290 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
1291 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
1292 [113] = { "MESH Configuration", print_mesh_conf
, 7, 7, BIT(PRINT_SCAN
), },
1293 [114] = { "MESH ID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
1294 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
1295 [107] = { "802.11u Interworking", print_interworking
, 0, 255, BIT(PRINT_SCAN
), },
1296 [108] = { "802.11u Advertisement", print_11u_advert
, 0, 255, BIT(PRINT_SCAN
), },
1297 [111] = { "802.11u Roaming Consortium", print_11u_rcon
, 0, 255, BIT(PRINT_SCAN
), },
1300 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1302 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
1305 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
1308 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
1314 printf("Parameter: not version 1: ");
1318 printf("\t * Parameter version 1");
1323 printf("\n\t\t * u-APSD");
1327 for (i
= 0; i
< 4; i
++) {
1328 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
1331 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
1332 (1 << (data
[1] >> 4)) - 1);
1333 printf(", AIFSN %d", data
[0] & 0xf);
1334 if (data
[2] | data
[3])
1335 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
1343 printf("invalid: ");
1347 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1353 printf(" information:");
1356 if (print_wifi_wmm_param(data
+ 1, len
- 1))
1360 printf(" type %d:", data
[0]);
1364 for(i
= 1; i
< len
; i
++)
1365 printf(" %.02x", data
[i
]);
1369 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
1373 return "Default (PIN)";
1375 return "User-specified";
1377 return "Machine-specified";
1381 return "PushButton";
1383 return "Registrar-specified";
1389 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1392 __u16 subtype
, sublen
;
1395 subtype
= (data
[0] << 8) + data
[1];
1396 sublen
= (data
[2] << 8) + data
[3];
1402 tab_on_first(&first
);
1403 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
1406 tab_on_first(&first
);
1407 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
1411 tab_on_first(&first
);
1413 printf("\t * Device Password ID: (invalid "
1414 "length %d)\n", sublen
);
1417 id
= data
[4] << 8 | data
[5];
1418 printf("\t * Device Password ID: %u (%s)\n",
1419 id
, wifi_wps_dev_passwd_id(id
));
1423 tab_on_first(&first
);
1424 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
1427 tab_on_first(&first
);
1428 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
1431 tab_on_first(&first
);
1432 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
1436 tab_on_first(&first
);
1437 printf("\t * Response Type: %d%s\n",
1438 val
, val
== 3 ? " (AP)" : "");
1443 tab_on_first(&first
);
1444 printf("\t * RF Bands: 0x%x\n", val
);
1449 tab_on_first(&first
);
1450 printf("\t * Selected Registrar: 0x%x\n", val
);
1454 tab_on_first(&first
);
1455 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
1459 tab_on_first(&first
);
1460 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1462 val
== 1 ? " (Unconfigured)" : "",
1463 val
== 2 ? " (Configured)" : "");
1467 tab_on_first(&first
);
1468 printf("\t * UUID: ");
1470 printf("(invalid, length=%d)\n", sublen
);
1473 printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1474 "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1475 data
[4], data
[5], data
[6], data
[7],
1476 data
[8], data
[9], data
[10], data
[11],
1477 data
[12], data
[13], data
[14], data
[15],
1478 data
[16], data
[17], data
[18], data
[19]);
1481 tab_on_first(&first
);
1483 printf("\t * Primary Device Type: (invalid "
1484 "length %d)\n", sublen
);
1487 printf("\t * Primary Device Type: "
1488 "%u-%02x%02x%02x%02x-%u\n",
1489 data
[4] << 8 | data
[5],
1490 data
[6], data
[7], data
[8], data
[9],
1491 data
[10] << 8 | data
[11]);
1496 tab_on_first(&first
);
1497 printf("\t * AP setup locked: 0x%.2x\n", val
);
1502 __u16 meth
= (data
[4] << 8) + data
[5];
1504 tab_on_first(&first
);
1505 printf("\t * %sConfig methods:",
1506 subtype
== 0x1053 ? "Selected Registrar ": "");
1507 #define T(bit, name) do { \
1508 if (meth & (1<<bit)) { \
1528 const __u8
*subdata
= data
+ 4;
1529 __u16 tmplen
= sublen
;
1531 tab_on_first(&first
);
1532 printf("\t * Unknown TLV (%#.4x, %d bytes):",
1535 printf(" %.2x", *subdata
);
1549 printf("\t\t * bogus tail data (%d):", len
);
1551 printf(" %.2x", *data
);
1559 static const struct ie_print wifiprinters
[] = {
1560 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
1561 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
1562 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
1565 static inline void print_p2p(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1573 sublen
= (data
[2] << 8) + data
[1];
1575 if (sublen
> len
- 3)
1579 case 0x02: /* capability */
1580 tab_on_first(&first
);
1582 printf("\t * malformed capability\n");
1585 printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
1588 case 0x0d: /* device info */
1589 if (sublen
< 6 + 2 + 8 + 1) {
1590 printf("\t * malformed device info\n");
1593 /* fall through for now */
1594 case 0x00: /* status */
1595 case 0x01: /* minor reason */
1596 case 0x03: /* device ID */
1597 case 0x04: /* GO intent */
1598 case 0x05: /* configuration timeout */
1599 case 0x06: /* listen channel */
1600 case 0x07: /* group BSSID */
1601 case 0x08: /* ext listen timing */
1602 case 0x09: /* intended interface address */
1603 case 0x0a: /* manageability */
1604 case 0x0b: /* channel list */
1605 case 0x0c: /* NoA */
1606 case 0x0e: /* group info */
1607 case 0x0f: /* group ID */
1608 case 0x10: /* interface */
1609 case 0x11: /* operating channel */
1610 case 0x12: /* invitation flags */
1611 case 0xdd: /* vendor specific */
1613 const __u8
*subdata
= data
+ 4;
1614 __u16 tmplen
= sublen
;
1616 tab_on_first(&first
);
1617 printf("\t * Unknown TLV (%#.2x, %d bytes):",
1620 printf(" %.2x", *subdata
);
1634 tab_on_first(&first
);
1635 printf("\t * bogus tail data (%d):", len
);
1637 printf(" %.2x", *data
);
1645 static inline void print_hs20_ind(const uint8_t type
, uint8_t len
, const uint8_t *data
)
1647 /* I can't find the spec for this...just going off what wireshark uses. */
1650 printf("\t\tDGAF: %i\n", (int)(data
[0] & 0x1));
1652 printf("\t\tUnexpected length: %i\n", len
);
1655 static const struct ie_print wfa_printers
[] = {
1656 [9] = { "P2P", print_p2p
, 2, 255, BIT(PRINT_SCAN
), },
1657 [16] = { "HotSpot 2.0 Indication", print_hs20_ind
, 1, 255, BIT(PRINT_SCAN
), },
1660 static void print_vendor(unsigned char len
, unsigned char *data
,
1661 bool unknown
, enum print_ie_type ptype
)
1666 printf("\tVendor specific: <too short> data:");
1667 for(i
= 0; i
< len
; i
++)
1668 printf(" %.02x", data
[i
]);
1673 if (len
>= 4 && memcmp(data
, ms_oui
, 3) == 0) {
1674 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
1675 wifiprinters
[data
[3]].name
&&
1676 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
1677 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
1682 printf("\tMS/WiFi %#.2x, data:", data
[3]);
1683 for(i
= 0; i
< len
- 4; i
++)
1684 printf(" %.02x", data
[i
+ 4]);
1689 if (len
>= 4 && memcmp(data
, wfa_oui
, 3) == 0) {
1690 if (data
[3] < ARRAY_SIZE(wfa_printers
) &&
1691 wfa_printers
[data
[3]].name
&&
1692 wfa_printers
[data
[3]].flags
& BIT(ptype
)) {
1693 print_ie(&wfa_printers
[data
[3]], data
[3], len
- 4, data
+ 4);
1698 printf("\tWFA %#.2x, data:", data
[3]);
1699 for(i
= 0; i
< len
- 4; i
++)
1700 printf(" %.02x", data
[i
+ 4]);
1708 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1709 data
[0], data
[1], data
[2]);
1710 for (i
= 3; i
< len
; i
++)
1711 printf(" %.2x", data
[i
]);
1715 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
1716 enum print_ie_type ptype
)
1718 while (ielen
>= 2 && ielen
>= ie
[1]) {
1719 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
1720 ieprinters
[ie
[0]].name
&&
1721 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
1722 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
1723 } else if (ie
[0] == 221 /* vendor */) {
1724 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
1725 } else if (unknown
) {
1728 printf("\tUnknown IE (%d):", ie
[0]);
1729 for (i
=0; i
<ie
[1]; i
++)
1730 printf(" %.2x", ie
[2+i
]);
1738 static void print_capa_dmg(__u16 capa
)
1740 switch (capa
& WLAN_CAPABILITY_DMG_TYPE_MASK
) {
1741 case WLAN_CAPABILITY_DMG_TYPE_AP
:
1744 case WLAN_CAPABILITY_DMG_TYPE_PBSS
:
1747 case WLAN_CAPABILITY_DMG_TYPE_IBSS
:
1748 printf(" DMG_IBSS");
1752 if (capa
& WLAN_CAPABILITY_DMG_CBAP_ONLY
)
1753 printf(" CBAP_Only");
1754 if (capa
& WLAN_CAPABILITY_DMG_CBAP_SOURCE
)
1755 printf(" CBAP_Src");
1756 if (capa
& WLAN_CAPABILITY_DMG_PRIVACY
)
1758 if (capa
& WLAN_CAPABILITY_DMG_ECPAC
)
1760 if (capa
& WLAN_CAPABILITY_DMG_SPECTRUM_MGMT
)
1761 printf(" SpectrumMgmt");
1762 if (capa
& WLAN_CAPABILITY_DMG_RADIO_MEASURE
)
1763 printf(" RadioMeasure");
1766 static void print_capa_non_dmg(__u16 capa
)
1768 if (capa
& WLAN_CAPABILITY_ESS
)
1770 if (capa
& WLAN_CAPABILITY_IBSS
)
1772 if (capa
& WLAN_CAPABILITY_CF_POLLABLE
)
1773 printf(" CfPollable");
1774 if (capa
& WLAN_CAPABILITY_CF_POLL_REQUEST
)
1775 printf(" CfPollReq");
1776 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1778 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1779 printf(" ShortPreamble");
1780 if (capa
& WLAN_CAPABILITY_PBCC
)
1782 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1783 printf(" ChannelAgility");
1784 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1785 printf(" SpectrumMgmt");
1786 if (capa
& WLAN_CAPABILITY_QOS
)
1788 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1789 printf(" ShortSlotTime");
1790 if (capa
& WLAN_CAPABILITY_APSD
)
1792 if (capa
& WLAN_CAPABILITY_RADIO_MEASURE
)
1793 printf(" RadioMeasure");
1794 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1795 printf(" DSSS-OFDM");
1796 if (capa
& WLAN_CAPABILITY_DEL_BACK
)
1797 printf(" DelayedBACK");
1798 if (capa
& WLAN_CAPABILITY_IMM_BACK
)
1799 printf(" ImmediateBACK");
1802 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
1804 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
1805 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
1806 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1807 char mac_addr
[20], dev
[20];
1808 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1809 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1810 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1811 [NL80211_BSS_BSSID
] = { },
1812 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1813 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1814 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1815 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1816 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1817 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1818 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1819 [NL80211_BSS_BEACON_IES
] = { },
1821 struct scan_params
*params
= arg
;
1822 int show
= params
->show_both_ie_sets
? 2 : 1;
1823 bool is_dmg
= false;
1825 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
1826 genlmsg_attrlen(gnlh
, 0), NULL
);
1828 if (!tb
[NL80211_ATTR_BSS
]) {
1829 fprintf(stderr
, "bss info missing!\n");
1832 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
1833 tb
[NL80211_ATTR_BSS
],
1835 fprintf(stderr
, "failed to parse nested attributes!\n");
1839 if (!bss
[NL80211_BSS_BSSID
])
1842 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
1843 printf("BSS %s", mac_addr
);
1844 if (tb
[NL80211_ATTR_IFINDEX
]) {
1845 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
1846 printf("(on %s)", dev
);
1849 if (bss
[NL80211_BSS_STATUS
]) {
1850 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
1851 case NL80211_BSS_STATUS_AUTHENTICATED
:
1852 printf(" -- authenticated");
1854 case NL80211_BSS_STATUS_ASSOCIATED
:
1855 printf(" -- associated");
1857 case NL80211_BSS_STATUS_IBSS_JOINED
:
1858 printf(" -- joined");
1861 printf(" -- unknown status: %d",
1862 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
1868 if (bss
[NL80211_BSS_TSF
]) {
1869 unsigned long long tsf
;
1870 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
1871 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
1872 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
1873 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
1875 if (bss
[NL80211_BSS_FREQUENCY
]) {
1876 int freq
= nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]);
1877 printf("\tfreq: %d\n", freq
);
1881 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1882 printf("\tbeacon interval: %d TUs\n",
1883 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1884 if (bss
[NL80211_BSS_CAPABILITY
]) {
1885 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1886 printf("\tcapability:");
1888 print_capa_dmg(capa
);
1890 print_capa_non_dmg(capa
);
1891 printf(" (0x%.4x)\n", capa
);
1893 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1894 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1895 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1897 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1898 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1899 printf("\tsignal: %d/100\n", s
);
1901 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1902 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1903 printf("\tlast seen: %d ms ago\n", age
);
1906 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1907 if (bss
[NL80211_BSS_BEACON_IES
])
1908 printf("\tInformation elements from Probe Response "
1910 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1911 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1912 params
->unknown
, params
->type
);
1914 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1915 printf("\tInformation elements from Beacon frame:\n");
1916 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1917 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1918 params
->unknown
, params
->type
);
1924 static struct scan_params scan_params
;
1926 static int handle_scan_dump(struct nl80211_state
*state
,
1929 int argc
, char **argv
,
1935 memset(&scan_params
, 0, sizeof(scan_params
));
1937 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1938 scan_params
.unknown
= true;
1939 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1940 scan_params
.show_both_ie_sets
= true;
1942 scan_params
.type
= PRINT_SCAN
;
1944 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1949 static int handle_scan_combined(struct nl80211_state
*state
,
1952 int argc
, char **argv
,
1956 static char *dump_argv
[] = {
1962 static const __u32 cmds
[] = {
1963 NL80211_CMD_NEW_SCAN_RESULTS
,
1964 NL80211_CMD_SCAN_ABORTED
,
1966 int trig_argc
, dump_argc
, err
;
1968 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1970 dump_argv
[3] = "-u";
1971 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1973 dump_argv
[3] = "-b";
1977 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1978 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1981 trig_argv
[0] = argv
[0];
1982 trig_argv
[1] = "scan";
1983 trig_argv
[2] = "trigger";
1985 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1986 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1987 err
= handle_cmd(state
, id
, trig_argc
, trig_argv
);
1993 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1995 * This code has a bug, which requires creating a separate
1996 * nl80211 socket to fix:
1997 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1998 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1999 * before (!) we listen to it, because we only start listening
2000 * after we send our scan request.
2002 * Doing it the other way around has a race condition as well,
2003 * if you first open the events socket you may get a notification
2004 * for a previous scan.
2006 * The only proper way to fix this would be to listen to events
2007 * before sending the command, and for the kernel to send the
2008 * scan request along with the event, so that you can match up
2009 * whether the scan you requested was finished or aborted (this
2010 * may result in processing a scan that another application
2011 * requested, but that doesn't seem to be a problem).
2013 * Alas, the kernel doesn't do that (yet).
2016 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
2017 NL80211_CMD_SCAN_ABORTED
) {
2018 printf("scan aborted!\n");
2022 dump_argv
[0] = argv
[0];
2023 return handle_cmd(state
, id
, dump_argc
, dump_argv
);
2025 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2026 CIB_NETDEV
, handle_scan_combined
,
2027 "Scan on the given frequencies and probe for the given SSIDs\n"
2028 "(or wildcard if not given) unless passive scanning is requested.\n"
2029 "If -u is specified print unknown data in the scan results.\n"
2030 "Specified (vendor) IEs must be well-formed.");
2031 COMMAND(scan
, dump
, "[-u]",
2032 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
2033 "Dump the current scan results. If -u is specified, print unknown\n"
2034 "data in scan results.");
2035 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2036 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
2037 "Trigger a scan on the given frequencies with probing for the given\n"
2038 "SSIDs (or wildcard if not given) unless passive scanning is requested.");
2041 static int handle_start_sched_scan(struct nl80211_state
*state
,
2042 struct nl_cb
*cb
, struct nl_msg
*msg
,
2043 int argc
, char **argv
, enum id_input id
)
2045 return parse_sched_scan(msg
, &argc
, &argv
);
2048 static int handle_stop_sched_scan(struct nl80211_state
*state
, struct nl_cb
*cb
,
2049 struct nl_msg
*msg
, int argc
, char **argv
,
2058 COMMAND(scan
, sched_start
,
2060 NL80211_CMD_START_SCHED_SCAN
, 0, CIB_NETDEV
, handle_start_sched_scan
,
2061 "Start a scheduled scan at the specified interval on the given frequencies\n"
2062 "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2063 "scanning is requested. If matches are specified, only matching results\n"
2064 "will be returned.");
2065 COMMAND(scan
, sched_stop
, "",
2066 NL80211_CMD_STOP_SCHED_SCAN
, 0, CIB_NETDEV
, handle_stop_sched_scan
,
2067 "Stop an ongoing scheduled scan.");