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_DSSS_OFDM (1<<13)
30 static unsigned char wifi_oui
[3] = { 0x00, 0x50, 0xf2 };
31 static unsigned char ieee80211_oui
[3] = { 0x00, 0x0f, 0xac };
35 enum print_ie_type type
;
36 bool show_both_ie_sets
;
39 #define IEEE80211_COUNTRY_EXTENSION_ID 201
41 struct ieee80211_country_ie_triplet
{
47 } __attribute__ ((packed
)) chans
;
49 __u8 reg_extension_id
;
52 } __attribute__ ((packed
)) ext
;
54 } __attribute__ ((packed
));
56 static int handle_scan(struct nl80211_state
*state
,
59 int argc
, char **argv
)
61 struct nl_msg
*ssids
= NULL
, *freqs
= NULL
;
73 bool passive
= false, have_ssids
= false, have_freqs
= false;
77 ssids
= nlmsg_alloc();
81 freqs
= nlmsg_alloc();
87 for (i
= 0; i
< argc
; i
++) {
90 if (strcmp(argv
[i
], "freq") == 0) {
94 } else if (strcmp(argv
[i
], "ies") == 0) {
97 } else if (strcmp(argv
[i
], "ssid") == 0) {
101 } else if (strcmp(argv
[i
], "passive") == 0) {
109 freq
= strtoul(argv
[i
], &eptr
, 10);
110 if (eptr
!= argv
[i
] + strlen(argv
[i
]))
112 NLA_PUT_U32(freqs
, i
, freq
);
116 ies
= parse_hex(argv
[i
], &tmp
);
118 goto nla_put_failure
;
119 NLA_PUT(msg
, NL80211_ATTR_IE
, tmp
, ies
);
124 NLA_PUT(ssids
, i
, strlen(argv
[i
]), argv
[i
]);
130 NLA_PUT(ssids
, 1, 0, "");
132 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
135 nla_put_nested(msg
, NL80211_ATTR_SCAN_FREQUENCIES
, freqs
);
144 static void tab_on_first(bool *first
)
152 static void print_ssid(const uint8_t type
, uint8_t len
, const uint8_t *data
)
155 print_ssid_escaped(len
, data
);
159 static void print_supprates(const uint8_t type
, uint8_t len
, const uint8_t *data
)
165 for (i
= 0; i
< len
; i
++) {
166 int r
= data
[i
] & 0x7f;
167 printf("%d.%d%s ", r
/2, 5*(r
&1), data
[i
] & 0x80 ? "*":"");
172 static void print_ds(const uint8_t type
, uint8_t len
, const uint8_t *data
)
174 printf(" channel %d\n", data
[0]);
177 static const char *country_env_str(char environment
)
179 switch (environment
) {
181 return "Indoor only";
183 return "Outdoor only";
185 return "Indoor/Outdoor";
191 static void print_country(const uint8_t type
, uint8_t len
, const uint8_t *data
)
193 printf(" %.*s", 2, data
);
195 printf("\tEnvironment: %s\n", country_env_str(data
[2]));
201 printf("\t\tNo country IE triplets present\n");
207 struct ieee80211_country_ie_triplet
*triplet
=
208 (struct ieee80211_country_ie_triplet
*) data
;
210 if (triplet
->ext
.reg_extension_id
>= IEEE80211_COUNTRY_EXTENSION_ID
) {
211 printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
212 triplet
->ext
.reg_extension_id
,
213 triplet
->ext
.reg_class
,
214 triplet
->ext
.coverage_class
,
215 triplet
->ext
.coverage_class
* 450);
223 if (triplet
->chans
.first_channel
<= 14)
224 end_channel
= triplet
->chans
.first_channel
+ (triplet
->chans
.num_channels
- 1);
226 end_channel
= triplet
->chans
.first_channel
+ (4 * (triplet
->chans
.num_channels
- 1));
228 printf("\t\tChannels [%d - %d]\n", triplet
->chans
.first_channel
, end_channel
);
237 static void print_powerconstraint(const uint8_t type
, uint8_t len
, const uint8_t *data
)
239 printf(" %d dB\n", data
[0]);
242 static void print_erp(const uint8_t type
, uint8_t len
, const uint8_t *data
)
245 printf(" <no flags>");
247 printf(" NonERP_Present");
249 printf(" Use_Protection");
251 printf(" Barker_Preamble_Mode");
255 static void print_cipher(const uint8_t *data
)
257 if (memcmp(data
, wifi_oui
, 3) == 0) {
260 printf("Use group cipher suite");
275 printf("%.02x-%.02x-%.02x:%d",
276 data
[0], data
[1] ,data
[2], data
[3]);
279 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
282 printf("Use group cipher suite");
297 printf("AES-128-CMAC");
300 printf("%.02x-%.02x-%.02x:%d",
301 data
[0], data
[1] ,data
[2], data
[3]);
305 printf("%.02x-%.02x-%.02x:%d",
306 data
[0], data
[1] ,data
[2], data
[3]);
309 static void print_auth(const uint8_t *data
)
311 if (memcmp(data
, wifi_oui
, 3) == 0) {
314 printf("IEEE 802.1X");
320 printf("%.02x-%.02x-%.02x:%d",
321 data
[0], data
[1] ,data
[2], data
[3]);
324 } else if (memcmp(data
, ieee80211_oui
, 3) == 0) {
327 printf("IEEE 802.1X");
333 printf("FT/IEEE 802.1X");
339 printf("IEEE 802.1X/SHA-256");
342 printf("PSK/SHA-256");
345 printf("%.02x-%.02x-%.02x:%d",
346 data
[0], data
[1] ,data
[2], data
[3]);
350 printf("%.02x-%.02x-%.02x:%d",
351 data
[0], data
[1] ,data
[2], data
[3]);
354 static void print_rsn_ie(const char *defcipher
, const char *defauth
,
355 uint8_t len
, const uint8_t *data
)
358 __u16 version
, count
, capa
;
361 version
= data
[0] + (data
[1] << 8);
362 tab_on_first(&first
);
363 printf("\t * Version: %d\n", version
);
369 tab_on_first(&first
);
370 printf("\t * Group cipher: %s\n", defcipher
);
371 printf("\t * Pairwise ciphers: %s\n", defcipher
);
375 tab_on_first(&first
);
376 printf("\t * Group cipher: ");
384 tab_on_first(&first
);
385 printf("\t * Pairwise ciphers: %s\n", defcipher
);
389 count
= data
[0] | (data
[1] << 8);
390 if (2 + (count
* 4) > len
)
393 tab_on_first(&first
);
394 printf("\t * Pairwise ciphers:");
395 for (i
= 0; i
< count
; i
++) {
397 print_cipher(data
+ 2 + (i
* 4));
401 data
+= 2 + (count
* 4);
402 len
-= 2 + (count
* 4);
405 tab_on_first(&first
);
406 printf("\t * Authentication suites: %s\n", defauth
);
410 count
= data
[0] | (data
[1] << 8);
411 if (2 + (count
* 4) > len
)
414 tab_on_first(&first
);
415 printf("\t * Authentication suites:");
416 for (i
= 0; i
< count
; i
++) {
418 print_auth(data
+ 2 + (i
* 4));
422 data
+= 2 + (count
* 4);
423 len
-= 2 + (count
* 4);
426 capa
= data
[0] | (data
[1] << 8);
427 tab_on_first(&first
);
428 printf("\t * Capabilities:");
432 printf(" NoPairwise");
433 switch ((capa
& 0x000c) >> 2) {
437 printf(" 2-PTKSA-RC");
440 printf(" 4-PTKSA-RC");
443 printf(" 16-PTKSA-RC");
446 switch ((capa
& 0x0030) >> 4) {
450 printf(" 2-GTKSA-RC");
453 printf(" 4-GTKSA-RC");
456 printf(" 16-GTKSA-RC");
460 printf(" MFP-required");
462 printf(" MFP-capable");
464 printf(" Peerkey-enabled");
466 printf(" SPP-AMSDU-capable");
468 printf(" SPP-AMSDU-required");
469 printf(" (0x%.4x)\n", capa
);
476 printf("\t\t * bogus tail data (%d):", len
);
478 printf(" %.2x", *data
);
486 static void print_rsn(const uint8_t type
, uint8_t len
, const uint8_t *data
)
488 print_rsn_ie("CCMP", "IEEE 802.1X", len
, data
);
491 static void print_ht_capa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
494 printf("\n\t\tHT Capability IE len != expected 26 bytes, skipping parse\n");
498 print_ht_capability(data
[0] | (data
[1] << 8));
499 print_ampdu_length(data
[2] & 3);
500 print_ampdu_spacing((data
[2] >> 2) & 3);
501 print_ht_mcs(data
+ 3);
504 static void print_capabilities(const uint8_t type
, uint8_t len
, const uint8_t *data
)
510 for (i
= 0; i
< len
; i
++) {
513 for (bit
= 0; bit
< 8; bit
++) {
514 if (!(data
[i
] & (1 << bit
)))
522 switch (bit
+ base
) {
524 printf(" HT Information Exchange Supported");
527 printf(" On-demand Beacon");
530 printf(" Extended Channel Switching");
533 printf(" Wave Indication");
536 printf(" PSMP Capability");
539 printf(" Service Interval Granularity");
542 printf(" S-PSMP Capability");
554 static void print_tim(const uint8_t type
, uint8_t len
, const uint8_t *data
)
556 printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
558 data
[0], data
[1], data
[2], data
[3]);
560 printf(" (+ %u octet%s)", len
- 4, len
- 4 == 1 ? "" : "s");
566 void (*print
)(const uint8_t type
, uint8_t len
, const uint8_t *data
);
567 uint8_t minlen
, maxlen
;
571 static void print_ie(const struct ie_print
*p
, const uint8_t type
,
572 uint8_t len
, const uint8_t *data
)
579 printf("\t%s:", p
->name
);
580 if (len
< p
->minlen
|| len
> p
->maxlen
) {
582 printf(" <invalid: %d bytes:", len
);
583 for (i
= 0; i
< len
; i
++)
584 printf(" %.02x", data
[i
]);
587 printf(" <invalid: 1 byte: %.02x>\n", data
[0]);
589 printf(" <invalid: no data>\n");
593 p
->print(type
, len
, data
);
596 #define PRINT_IGN { \
603 static const struct ie_print ieprinters
[] = {
604 [0] = { "SSID", print_ssid
, 0, 32, BIT(PRINT_SCAN
) | BIT(PRINT_LINK
), },
605 [1] = { "Supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
606 [3] = { "DS Parameter set", print_ds
, 1, 1, BIT(PRINT_SCAN
), },
607 [5] = { "TIM", print_tim
, 4, 255, BIT(PRINT_SCAN
), },
608 [7] = { "Country", print_country
, 3, 255, BIT(PRINT_SCAN
), },
609 [32] = { "Power constraint", print_powerconstraint
, 1, 1, BIT(PRINT_SCAN
), },
610 [42] = { "ERP", print_erp
, 1, 255, BIT(PRINT_SCAN
), },
611 [45] = { "HT capabilities", print_ht_capa
, 1, 255, BIT(PRINT_SCAN
), },
612 [48] = { "RSN", print_rsn
, 2, 255, BIT(PRINT_SCAN
), },
613 [50] = { "Extended supported rates", print_supprates
, 0, 255, BIT(PRINT_SCAN
), },
614 [127] = { "Extended capabilities", print_capabilities
, 0, 255, BIT(PRINT_SCAN
), },
617 static void print_wifi_wpa(const uint8_t type
, uint8_t len
, const uint8_t *data
)
619 print_rsn_ie("TKIP", "IEEE 802.1X", len
, data
);
622 static bool print_wifi_wmm_param(const uint8_t *data
, uint8_t len
)
625 static const char *aci_tbl
[] = { "BE", "BK", "VI", "VO" };
631 printf("Parameter: not version 1: ");
635 printf("\t * Parameter version 1");
640 printf("\n\t\t * u-APSD");
644 for (i
= 0; i
< 4; i
++) {
645 printf("\n\t\t * %s:", aci_tbl
[(data
[0] >> 5) & 3]);
648 printf(" CW %d-%d", (1 << (data
[1] & 0xf)) - 1,
649 (1 << (data
[1] >> 4)) - 1);
650 printf(", AIFSN %d", data
[0] & 0xf);
651 if (data
[2] | data
[3])
652 printf(", TXOP %d usec", (data
[2] + (data
[3] << 8)) * 32);
664 static void print_wifi_wmm(const uint8_t type
, uint8_t len
, const uint8_t *data
)
670 printf(" information:");
673 if (print_wifi_wmm_param(data
+ 1, len
- 1))
677 printf(" type %d:", data
[0]);
681 for(i
= 1; i
< len
; i
++)
682 printf(" %.02x", data
[i
]);
686 static const char * wifi_wps_dev_passwd_id(uint16_t id
)
690 return "Default (PIN)";
692 return "User-specified";
694 return "Machine-specified";
700 return "Registrar-specified";
706 static void print_wifi_wps(const uint8_t type
, uint8_t len
, const uint8_t *data
)
709 __u16 subtype
, sublen
;
712 subtype
= (data
[0] << 8) + data
[1];
713 sublen
= (data
[2] << 8) + data
[3];
719 tab_on_first(&first
);
720 printf("\t * Version: %d.%d\n", data
[4] >> 4, data
[4] & 0xF);
723 tab_on_first(&first
);
724 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
728 tab_on_first(&first
);
730 printf("\t * Device Password ID: (invalid "
731 "length %d)\n", sublen
);
734 id
= data
[4] << 8 | data
[5];
735 printf("\t * Device Password ID: %u (%s)\n",
736 id
, wifi_wps_dev_passwd_id(id
));
740 tab_on_first(&first
);
741 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
744 tab_on_first(&first
);
745 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
748 tab_on_first(&first
);
749 printf("\t * Model Number: %.*s\n", sublen
, data
+ 4);
753 tab_on_first(&first
);
754 printf("\t * Response Type: %d%s\n",
755 val
, val
== 3 ? " (AP)" : "");
760 tab_on_first(&first
);
761 printf("\t * RF Bands: 0x%x\n", val
);
766 tab_on_first(&first
);
767 printf("\t * Selected Registrar: 0x%x\n", val
);
771 tab_on_first(&first
);
772 printf("\t * Serial Number: %.*s\n", sublen
, data
+ 4);
776 tab_on_first(&first
);
777 printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
779 val
== 1 ? " (Unconfigured)" : "",
780 val
== 2 ? " (Configured)" : "");
784 tab_on_first(&first
);
786 printf("\t * Primary Device Type: (invalid "
787 "length %d)\n", sublen
);
790 printf("\t * Primary Device Type: "
791 "%u-%02x%02x%02x%02x-%u\n",
792 data
[4] << 8 | data
[5],
793 data
[6], data
[7], data
[8], data
[9],
794 data
[10] << 8 | data
[11]);
799 tab_on_first(&first
);
800 printf("\t * AP setup locked: 0x%.2x\n", val
);
805 __u16 meth
= (data
[4] << 8) + data
[5];
807 tab_on_first(&first
);
808 printf("\t * %sConfig methods:",
809 subtype
== 0x1053 ? "Selected Registrar ": "");
810 #define T(bit, name) do { \
811 if (meth & (1<<bit)) { \
831 const __u8
*subdata
= data
+ 4;
832 __u16 tmplen
= sublen
;
834 tab_on_first(&first
);
835 printf("\t * Unknown TLV (%#.4x, %d bytes):",
838 printf(" %.2x", *subdata
);
852 printf("\t\t * bogus tail data (%d):", len
);
854 printf(" %.2x", *data
);
862 static const struct ie_print wifiprinters
[] = {
863 [1] = { "WPA", print_wifi_wpa
, 2, 255, BIT(PRINT_SCAN
), },
864 [2] = { "WMM", print_wifi_wmm
, 1, 255, BIT(PRINT_SCAN
), },
865 [4] = { "WPS", print_wifi_wps
, 0, 255, BIT(PRINT_SCAN
), },
868 static void print_vendor(unsigned char len
, unsigned char *data
,
869 bool unknown
, enum print_ie_type ptype
)
874 printf("\tVendor specific: <too short> data:");
875 for(i
= 0; i
< len
; i
++)
876 printf(" %.02x", data
[i
]);
881 if (len
>= 4 && memcmp(data
, wifi_oui
, 3) == 0) {
882 if (data
[3] < ARRAY_SIZE(wifiprinters
) &&
883 wifiprinters
[data
[3]].name
&&
884 wifiprinters
[data
[3]].flags
& BIT(ptype
)) {
885 print_ie(&wifiprinters
[data
[3]], data
[3], len
- 4, data
+ 4);
890 printf("\tWiFi OUI %#.2x, data:", data
[3]);
891 for(i
= 0; i
< len
- 4; i
++)
892 printf(" %.02x", data
[i
+ 4]);
900 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
901 data
[0], data
[1], data
[2]);
902 for (i
= 3; i
< len
; i
++)
903 printf(" %.2x", data
[i
]);
907 void print_ies(unsigned char *ie
, int ielen
, bool unknown
,
908 enum print_ie_type ptype
)
910 while (ielen
>= 2 && ielen
>= ie
[1]) {
911 if (ie
[0] < ARRAY_SIZE(ieprinters
) &&
912 ieprinters
[ie
[0]].name
&&
913 ieprinters
[ie
[0]].flags
& BIT(ptype
)) {
914 print_ie(&ieprinters
[ie
[0]], ie
[0], ie
[1], ie
+ 2);
915 } else if (ie
[0] == 221 /* vendor */) {
916 print_vendor(ie
[1], ie
+ 2, unknown
, ptype
);
917 } else if (unknown
) {
920 printf("\tUnknown IE (%d):", ie
[0]);
921 for (i
=0; i
<ie
[1]; i
++)
922 printf(" %.2x", ie
[2+i
]);
930 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
932 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
933 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
934 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
935 char mac_addr
[20], dev
[20];
936 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
937 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
938 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
939 [NL80211_BSS_BSSID
] = { },
940 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
941 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
942 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
943 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
944 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
945 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
946 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
947 [NL80211_BSS_BEACON_IES
] = { },
949 struct scan_params
*params
= arg
;
950 int show
= params
->show_both_ie_sets
? 2 : 1;
952 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
953 genlmsg_attrlen(gnlh
, 0), NULL
);
955 if (!tb
[NL80211_ATTR_BSS
]) {
956 fprintf(stderr
, "bss info missing!\n");
959 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
960 tb
[NL80211_ATTR_BSS
],
962 fprintf(stderr
, "failed to parse nested attributes!\n");
966 if (!bss
[NL80211_BSS_BSSID
])
969 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
970 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
971 printf("BSS %s (on %s)", mac_addr
, dev
);
973 if (bss
[NL80211_BSS_STATUS
]) {
974 switch (nla_get_u32(bss
[NL80211_BSS_STATUS
])) {
975 case NL80211_BSS_STATUS_AUTHENTICATED
:
976 printf(" -- authenticated");
978 case NL80211_BSS_STATUS_ASSOCIATED
:
979 printf(" -- associated");
981 case NL80211_BSS_STATUS_IBSS_JOINED
:
982 printf(" -- joined");
985 printf(" -- unknown status: %d",
986 nla_get_u32(bss
[NL80211_BSS_STATUS
]));
992 if (bss
[NL80211_BSS_TSF
]) {
993 unsigned long long tsf
;
994 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
995 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
996 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
997 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
999 if (bss
[NL80211_BSS_FREQUENCY
])
1000 printf("\tfreq: %d\n",
1001 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
1002 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
1003 printf("\tbeacon interval: %d\n",
1004 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
1005 if (bss
[NL80211_BSS_CAPABILITY
]) {
1006 __u16 capa
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1007 printf("\tcapability:");
1008 if (capa
& WLAN_CAPABILITY_ESS
)
1010 if (capa
& WLAN_CAPABILITY_IBSS
)
1012 if (capa
& WLAN_CAPABILITY_PRIVACY
)
1014 if (capa
& WLAN_CAPABILITY_SHORT_PREAMBLE
)
1015 printf(" ShortPreamble");
1016 if (capa
& WLAN_CAPABILITY_PBCC
)
1018 if (capa
& WLAN_CAPABILITY_CHANNEL_AGILITY
)
1019 printf(" ChannelAgility");
1020 if (capa
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
1021 printf(" SpectrumMgmt");
1022 if (capa
& WLAN_CAPABILITY_QOS
)
1024 if (capa
& WLAN_CAPABILITY_SHORT_SLOT_TIME
)
1025 printf(" ShortSlotTime");
1026 if (capa
& WLAN_CAPABILITY_APSD
)
1028 if (capa
& WLAN_CAPABILITY_DSSS_OFDM
)
1029 printf(" DSSS-OFDM");
1030 printf(" (0x%.4x)\n", capa
);
1032 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
1033 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
1034 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
1036 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
1037 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
1038 printf("\tsignal: %d/100\n", s
);
1040 if (bss
[NL80211_BSS_SEEN_MS_AGO
]) {
1041 int age
= nla_get_u32(bss
[NL80211_BSS_SEEN_MS_AGO
]);
1042 printf("\tlast seen: %d ms ago\n", age
);
1045 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
] && show
--) {
1046 if (bss
[NL80211_BSS_BEACON_IES
])
1047 printf("\tInformation elements from Probe Response "
1049 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1050 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
1051 params
->unknown
, params
->type
);
1053 if (bss
[NL80211_BSS_BEACON_IES
] && show
--) {
1054 printf("\tInformation elements from Beacon frame:\n");
1055 print_ies(nla_data(bss
[NL80211_BSS_BEACON_IES
]),
1056 nla_len(bss
[NL80211_BSS_BEACON_IES
]),
1057 params
->unknown
, params
->type
);
1063 static struct scan_params scan_params
;
1065 static int handle_scan_dump(struct nl80211_state
*state
,
1068 int argc
, char **argv
)
1073 memset(&scan_params
, 0, sizeof(scan_params
));
1075 if (argc
== 1 && !strcmp(argv
[0], "-u"))
1076 scan_params
.unknown
= true;
1077 else if (argc
== 1 && !strcmp(argv
[0], "-b"))
1078 scan_params
.show_both_ie_sets
= true;
1080 scan_params
.type
= PRINT_SCAN
;
1082 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
1087 static int handle_scan_combined(struct nl80211_state
*state
,
1090 int argc
, char **argv
)
1093 static char *dump_argv
[] = {
1099 static const __u32 cmds
[] = {
1100 NL80211_CMD_NEW_SCAN_RESULTS
,
1101 NL80211_CMD_SCAN_ABORTED
,
1103 int trig_argc
, dump_argc
, err
;
1105 if (argc
>= 3 && !strcmp(argv
[2], "-u")) {
1107 dump_argv
[3] = "-u";
1108 } else if (argc
>= 3 && !strcmp(argv
[2], "-b")) {
1110 dump_argv
[3] = "-b";
1114 trig_argc
= 3 + (argc
- 2) + (3 - dump_argc
);
1115 trig_argv
= calloc(trig_argc
, sizeof(*trig_argv
));
1118 trig_argv
[0] = argv
[0];
1119 trig_argv
[1] = "scan";
1120 trig_argv
[2] = "trigger";
1122 for (i
= 0; i
< argc
- 2 - (dump_argc
- 3); i
++)
1123 trig_argv
[i
+ 3] = argv
[i
+ 2 + (dump_argc
- 3)];
1124 err
= handle_cmd(state
, II_NETDEV
, trig_argc
, trig_argv
);
1130 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
1132 * This code has a bug, which requires creating a separate
1133 * nl80211 socket to fix:
1134 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
1135 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
1136 * before (!) we listen to it, because we only start listening
1137 * after we send our scan request.
1139 * Doing it the other way around has a race condition as well,
1140 * if you first open the events socket you may get a notification
1141 * for a previous scan.
1143 * The only proper way to fix this would be to listen to events
1144 * before sending the command, and for the kernel to send the
1145 * scan request along with the event, so that you can match up
1146 * whether the scan you requested was finished or aborted (this
1147 * may result in processing a scan that another application
1148 * requested, but that doesn't seem to be a problem).
1150 * Alas, the kernel doesn't do that (yet).
1153 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
1154 NL80211_CMD_SCAN_ABORTED
) {
1155 printf("scan aborted!\n");
1159 dump_argv
[0] = argv
[0];
1160 return handle_cmd(state
, II_NETDEV
, dump_argc
, dump_argv
);
1162 TOPLEVEL(scan
, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]", 0, 0,
1163 CIB_NETDEV
, handle_scan_combined
,
1164 "Scan on the given frequencies and probe for the given SSIDs\n"
1165 "(or wildcard if not given) unless passive scanning is requested.\n"
1166 "If -u is specified print unknown data in the scan results.\n"
1167 "Specified (vendor) IEs must be well-formed.");
1168 COMMAND(scan
, dump
, "[-u]",
1169 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
,
1170 "Dump the current scan results. If -u is specified, print unknown\n"
1171 "data in scan results.");
1172 COMMAND(scan
, trigger
, "[freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]",
1173 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
,
1174 "Trigger a scan on the given frequencies with probing for the given\n"
1175 "SSIDs (or wildcard if not given) unless passive scanning is requested.");