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>
20 static int handle_scan(struct nl80211_state
*state
,
23 int argc
, char **argv
)
25 struct nl_msg
*ssids
= NULL
;
28 ssids
= nlmsg_alloc();
31 NLA_PUT(ssids
, 1, 0, "");
32 nla_put_nested(msg
, NL80211_ATTR_SCAN_SSIDS
, ssids
);
39 COMMAND(scan
, trigger
, NULL
,
40 NL80211_CMD_TRIGGER_SCAN
, 0, CIB_NETDEV
, handle_scan
);
42 typedef void (*printfn
)(unsigned char type
, unsigned char len
, unsigned char *data
);
44 static void print_ssid(unsigned char type
, unsigned char len
, unsigned char *data
)
48 for (i
=0; i
<len
; i
++) {
50 printf("%c", data
[i
]);
52 printf("\\x%.2x", data
[i
]);
57 static void print_supprates(unsigned char type
, unsigned char len
, unsigned char *data
)
62 printf("\tSupported rates: ");
64 printf("\tExtended supported rates: ");
66 for (i
=0; i
<len
; i
++) {
67 int r
= data
[i
] & 0x7f;
68 printf("%d.%d%s ", r
/2, 5*(r
&1), data
[i
] & 0x80 ? "*":"");
73 static void print_ds(unsigned char type
, unsigned char len
, unsigned char *data
)
75 printf("\tDS Parameter set: channel %d\n", data
[0]);
78 static void print_ign(unsigned char type
, unsigned char len
, unsigned char *data
)
80 /* ignore for now, not too useful */
83 static const printfn ieprinters
[] = {
85 [1] = print_supprates
,
88 [50] = print_supprates
,
91 static void tab_on_first(bool *first
)
99 static void print_wifi_wps(unsigned char type
, unsigned char len
, unsigned char *data
)
102 __u16 subtype
, sublen
;
107 subtype
= (data
[0] << 8) + data
[1];
108 sublen
= (data
[2] << 8) + data
[3];
114 tab_on_first(&first
);
115 printf("\t * Version: %#.2x\n", data
[4]);
118 tab_on_first(&first
);
119 printf("\t * Device name: %.*s\n", sublen
, data
+ 4);
122 tab_on_first(&first
);
123 printf("\t * Manufacturer: %.*s\n", sublen
, data
+ 4);
126 tab_on_first(&first
);
127 printf("\t * Model: %.*s\n", sublen
, data
+ 4);
130 __u16 meth
= (data
[4] << 8) + data
[5];
132 tab_on_first(&first
);
133 printf("\t * Config methods:");
134 #define T(bit, name) do { \
135 if (meth & (1<<bit)) { \
163 printf("\t\t * bogus tail data (%d):", len
);
165 printf(" %.2x", *data
);
173 static const printfn wifiprinters
[] = {
174 [4] = print_wifi_wps
,
177 static void print_vendor(unsigned char len
, unsigned char *data
,
178 struct scan_params
*params
)
183 printf("\tVendor specific: <too short> data:");
184 for(i
= 0; i
< len
; i
++)
185 printf(" %.02x", data
[i
]);
190 if (len
>= 4 && data
[0] == 0x00 && data
[1] == 0x50 && data
[2] == 0xF2) {
191 if (data
[3] < ARRAY_SIZE(wifiprinters
) && wifiprinters
[data
[3]])
192 return wifiprinters
[data
[3]](data
[3], len
- 4, data
+ 4);
193 if (!params
->unknown
)
195 printf("\tWiFi OUI %#.2x data:", data
[3]);
196 for(i
= 0; i
< len
- 4; i
++)
197 printf(" %.02x", data
[i
+ 4]);
202 if (!params
->unknown
)
205 printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
206 data
[0], data
[1], data
[2]);
207 for (i
= 3; i
< len
; i
++)
208 printf(" %.2x", data
[i
]);
212 static void print_ies(unsigned char *ie
, int ielen
, struct scan_params
*params
)
214 while (ielen
>= 2 && ielen
>= ie
[1]) {
215 if (ie
[0] < ARRAY_SIZE(ieprinters
) && ieprinters
[ie
[0]]) {
216 ieprinters
[ie
[0]](ie
[0], ie
[1], ie
+ 2);
217 } else if (ie
[0] == 221 /* vendor */) {
218 print_vendor(ie
[1], ie
+ 2, params
);
219 } else if (params
->unknown
) {
222 printf("\tUnknown IE (%d):", ie
[0]);
223 for (i
=0; i
<ie
[1]; i
++)
224 printf(" %.2x", ie
[2+i
]);
232 static int print_bss_handler(struct nl_msg
*msg
, void *arg
)
234 struct nlattr
*tb
[NL80211_ATTR_MAX
+ 1];
235 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
236 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
237 char mac_addr
[20], dev
[20];
238 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
239 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
240 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
241 [NL80211_BSS_BSSID
] = { },
242 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
243 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
244 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
245 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
246 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
249 nla_parse(tb
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
250 genlmsg_attrlen(gnlh
, 0), NULL
);
252 if (!tb
[NL80211_ATTR_BSS
]) {
253 fprintf(stderr
, "bss info missing!");
256 if (nla_parse_nested(bss
, NL80211_BSS_MAX
,
257 tb
[NL80211_ATTR_BSS
],
259 fprintf(stderr
, "failed to parse nested attributes!");
263 if (!bss
[NL80211_BSS_BSSID
])
266 mac_addr_n2a(mac_addr
, nla_data(bss
[NL80211_BSS_BSSID
]));
267 if_indextoname(nla_get_u32(tb
[NL80211_ATTR_IFINDEX
]), dev
);
268 printf("BSS %s (on %s)\n", mac_addr
, dev
);
270 if (bss
[NL80211_BSS_TSF
]) {
271 unsigned long long tsf
;
272 tsf
= (unsigned long long)nla_get_u64(bss
[NL80211_BSS_TSF
]);
273 printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
274 tsf
, tsf
/1000/1000/60/60/24, (tsf
/1000/1000/60/60) % 24,
275 (tsf
/1000/1000/60) % 60, (tsf
/1000/1000) % 60);
277 if (bss
[NL80211_BSS_FREQUENCY
])
278 printf("\tfreq: %d\n",
279 nla_get_u32(bss
[NL80211_BSS_FREQUENCY
]));
280 if (bss
[NL80211_BSS_BEACON_INTERVAL
])
281 printf("\tbeacon interval: %d\n",
282 nla_get_u16(bss
[NL80211_BSS_BEACON_INTERVAL
]));
283 if (bss
[NL80211_BSS_CAPABILITY
])
284 printf("\tcapability: 0x%.4x\n",
285 nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]));
286 if (bss
[NL80211_BSS_SIGNAL_MBM
]) {
287 int s
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]);
288 printf("\tsignal: %d.%.2d dBm\n", s
/100, s
%100);
290 if (bss
[NL80211_BSS_SIGNAL_UNSPEC
]) {
291 unsigned char s
= nla_get_u8(bss
[NL80211_BSS_SIGNAL_UNSPEC
]);
292 printf("\tsignal: %d/100\n", s
);
294 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
295 print_ies(nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
296 nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]),
302 static struct scan_params scan_params
;
304 static int handle_scan_dump(struct nl80211_state
*state
,
307 int argc
, char **argv
)
312 scan_params
.unknown
= false;
313 if (argc
== 1 && !strcmp(argv
[0], "-u"))
314 scan_params
.unknown
= true;
316 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, print_bss_handler
,
320 COMMAND(scan
, dump
, "[-u]",
321 NL80211_CMD_GET_SCAN
, NLM_F_DUMP
, CIB_NETDEV
, handle_scan_dump
);
323 static int handle_scan_combined(struct nl80211_state
*state
,
326 int argc
, char **argv
)
328 static char *trig_argv
[] = {
333 static char *dump_argv
[] = {
338 static const __u32 cmds
[] = {
339 NL80211_CMD_NEW_SCAN_RESULTS
,
340 NL80211_CMD_SCAN_ABORTED
,
344 trig_argv
[0] = argv
[0];
345 err
= handle_cmd(state
, II_NETDEV
, ARRAY_SIZE(trig_argv
), trig_argv
);
350 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
352 * This code has a bug, which requires creating a separate
353 * nl80211 socket to fix:
354 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
355 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
356 * before (!) we listen to it, because we only start listening
357 * after we send our scan request.
359 * Doing it the other way around has a race condition as well,
360 * if you first open the events socket you may get a notification
361 * for a previous scan.
363 * The only proper way to fix this would be to listen to events
364 * before sending the command, and for the kernel to send the
365 * scan request along with the event, so that you can match up
366 * whether the scan you requested was finished or aborted (this
367 * may result in processing a scan that another application
368 * requested, but that doesn't seem to be a problem).
370 * Alas, the kernel doesn't do that (yet).
373 if (listen_events(state
, ARRAY_SIZE(cmds
), cmds
) ==
374 NL80211_CMD_SCAN_ABORTED
) {
375 printf("scan aborted!\n");
379 dump_argv
[0] = argv
[0];
380 return handle_cmd(state
, II_NETDEV
, ARRAY_SIZE(dump_argv
), dump_argv
);
382 TOPLEVEL(scan
, NULL
, 0, 0, CIB_NETDEV
, handle_scan_combined
);