scan.c revision fbf80af54408799f7e3c03430b798759019dd79b
13563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <net/if.h>
23563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <errno.h>
33563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <string.h>
43563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <ctype.h>
5764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg#include <stdbool.h>
63563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
73563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <netlink/genl/genl.h>
83563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <netlink/genl/family.h>
93563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <netlink/genl/ctrl.h>
103563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <netlink/msg.h>
113563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include <netlink/attr.h>
123563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
133563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include "nl80211.h"
143563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg#include "iw.h"
153563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
16764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstruct scan_params {
17764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	bool unknown;
18764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg};
19764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
207c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Bergstatic int handle_scan(struct nl80211_state *state,
217c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Berg		       struct nl_cb *cb,
223563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		       struct nl_msg *msg,
233563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		       int argc, char **argv)
243563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
253563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nl_msg *ssids = NULL;
263563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int err = -ENOBUFS;
273563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
283563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	ssids = nlmsg_alloc();
293563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!ssids)
303563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return -ENOMEM;
313563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NLA_PUT(ssids, 1, 0, "");
323563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
333563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
343563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	err = 0;
353563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg nla_put_failure:
363563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nlmsg_free(ssids);
373563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return err;
383563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
393563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes BergCOMMAND(scan, trigger, NULL,
403563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan);
413563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
423563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergtypedef void (*printfn)(unsigned char type, unsigned char len, unsigned char *data);
433563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
443563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ssid(unsigned char type, unsigned char len, unsigned char *data)
453563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
463563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
473563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\tSSID: ");
483563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	for (i=0; i<len; i++) {
493563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		if (isprint(data[i]))
503563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("%c", data[i]);
513563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		else
523563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("\\x%.2x", data[i]);
533563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
543563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
553563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
563563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
573563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_supprates(unsigned char type, unsigned char len, unsigned char *data)
583563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
593563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
603563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
613563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (type == 1)
623563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tSupported rates: ");
633563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	else
643563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tExtended supported rates: ");
653563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
663563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	for (i=0; i<len; i++) {
673563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		int r = data[i] & 0x7f;
683563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
693563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
703563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
713563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
723563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
733563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ds(unsigned char type, unsigned char len, unsigned char *data)
743563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
753563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\tDS Parameter set: channel %d\n", data[0]);
763563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
773563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
783563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ign(unsigned char type, unsigned char len, unsigned char *data)
793563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
803563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	/* ignore for now, not too useful */
813563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
823563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
83764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic const printfn ieprinters[] = {
84764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[0] = print_ssid,
85764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[1] = print_supprates,
86764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[3] = print_ds,
87764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[5] = print_ign,
88764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[50] = print_supprates,
89764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg};
90764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
91764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic void print_vendor(unsigned char len, unsigned char *data,
92764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			 struct scan_params *params)
933563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
943563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
953563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
96fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	if (len < 3) {
97fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		printf("\tVendor specific: <too short> data:\n");
98fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		for(i = 0; i < len; i++)
99fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg			printf(" %.02x", data[i]);
100fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		printf("\n");
101fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		return;
102fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	}
103fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg
104764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	/* currently _all_ vendor IEs are unknown (not parsed) */
105764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (!params->unknown)
106764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		return;
107764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
108fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
1093563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		data[0], data[1], data[2]);
110fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	for (i = 3; i < len; i++)
111fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		printf(" %.2x", data[i]);
1123563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
1133563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
1143563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
115764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic void print_ies(unsigned char *ie, int ielen, struct scan_params *params)
1163563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
1173563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	while (ielen >= 2 && ielen >= ie[1]) {
11897ebbaf55e8729c28513d8a73f3e65e8d759ff80Johannes Berg		if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]]) {
1193563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			ieprinters[ie[0]](ie[0], ie[1], ie + 2);
120764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		} else if (ie[0] == 221 /* vendor */) {
121764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			print_vendor(ie[1], ie + 2, params);
122764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		} else if (params->unknown) {
1233563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			int i;
1243563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1253563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("\tUnknown IE (%d): ", ie[0]);
1263563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			for (i=0; i<ie[1]; i++)
1273563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg				printf("\\x%.2x", ie[2+i]);
1283563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("\n");
1293563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		}
1303563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		ielen -= ie[1] + 2;
1313563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		ie += ie[1] + 2;
1323563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
1333563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
1343563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1353563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic int print_bss_handler(struct nl_msg *msg, void *arg)
1363563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
1373563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nlattr *tb[NL80211_ATTR_MAX + 1];
1383563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
1393563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nlattr *bss[NL80211_BSS_MAX + 1];
1403563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	char mac_addr[20], dev[20];
1413563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1423563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_TSF] = { .type = NLA_U64 },
1433563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1443563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_BSSID] = { },
1453563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1463563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1473563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
148f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
149f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1503563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	};
1513563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1523563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1533563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		  genlmsg_attrlen(gnlh, 0), NULL);
1543563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1553563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!tb[NL80211_ATTR_BSS]) {
1563563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		fprintf(stderr, "bss info missing!");
1573563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
1583563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
1593563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (nla_parse_nested(bss, NL80211_BSS_MAX,
1603563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			     tb[NL80211_ATTR_BSS],
1613563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			     bss_policy)) {
1623563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		fprintf(stderr, "failed to parse nested attributes!");
1633563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
1643563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
1653563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1663563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!bss[NL80211_BSS_BSSID])
1673563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
1683563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
1693563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
1703563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
1713563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("BSS %s (on %s)\n", mac_addr, dev);
1723563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
173e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg	if (bss[NL80211_BSS_TSF]) {
174e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		unsigned long long tsf;
175e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
176e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
177e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg			tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
178e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg			(tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
179e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg	}
1803563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_FREQUENCY])
1813563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tfreq: %d\n",
1823563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
1833563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_BEACON_INTERVAL])
1843563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tbeacon interval: %d\n",
1853563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
1863563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_CAPABILITY])
1873563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tcapability: 0x%.4x\n",
1883563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			nla_get_u16(bss[NL80211_BSS_CAPABILITY]));
189f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	if (bss[NL80211_BSS_SIGNAL_MBM]) {
190f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
191f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
192f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	}
193f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
194f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
195f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		printf("\tsignal: %d/100\n", s);
196f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	}
1973563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
1983563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
199764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			  nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
200764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			  arg);
2013563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
2023563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return NL_SKIP;
2033563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
2043563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
205764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic struct scan_params scan_params;
2063563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
2077c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Bergstatic int handle_scan_dump(struct nl80211_state *state,
2087c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Berg			    struct nl_cb *cb,
2093563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			    struct nl_msg *msg,
2103563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			    int argc, char **argv)
2113563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
212764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (argc > 1)
213764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		return 1;
214764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
215764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	scan_params.unknown = false;
216764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (argc == 1 && !strcmp(argv[0], "-u"))
217764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		scan_params.unknown = true;
218764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
219764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
220764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		  &scan_params);
2213563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return 0;
2223563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
223764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes BergCOMMAND(scan, dump, "[-u]",
2243563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump);
225a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
226a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Bergstatic int handle_scan_combined(struct nl80211_state *state,
227a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				struct nl_cb *cb,
228a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				struct nl_msg *msg,
229a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				int argc, char **argv)
230a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg{
231a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static char *trig_argv[] = {
232a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NULL,
233a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"scan",
234a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"trigger",
235a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
236a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static char *dump_argv[] = {
237a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NULL,
238a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"scan",
239a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"dump",
240a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
241a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static const __u32 cmds[] = {
242a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NL80211_CMD_NEW_SCAN_RESULTS,
243a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NL80211_CMD_SCAN_ABORTED,
244a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
245a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	int err;
246a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
247a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	trig_argv[0] = argv[0];
248a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(trig_argv), trig_argv);
249a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	if (err)
250a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		return err;
251a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
25261725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	/*
25361725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
25461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
25561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * This code has a bug, which requires creating a separate
25661725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * nl80211 socket to fix:
25761725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
25861725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
25961725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * before (!) we listen to it, because we only start listening
26061725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * after we send our scan request.
26161725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
26261725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * Doing it the other way around has a race condition as well,
26361725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * if you first open the events socket you may get a notification
26461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * for a previous scan.
26561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
26661725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * The only proper way to fix this would be to listen to events
26761725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * before sending the command, and for the kernel to send the
26861725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * scan request along with the event, so that you can match up
26961725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * whether the scan you requested was finished or aborted (this
27061725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * may result in processing a scan that another application
27161725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * requested, but that doesn't seem to be a problem).
27261725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
27361725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * Alas, the kernel doesn't do that (yet).
27461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 */
27561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg
276a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
277a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg					NL80211_CMD_SCAN_ABORTED) {
278a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		printf("scan aborted!\n");
279a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		return 0;
280a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	}
281a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
282a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	dump_argv[0] = argv[0];
283a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	return handle_cmd(state, II_NETDEV, ARRAY_SIZE(dump_argv), dump_argv);
284a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg}
285a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes BergTOPLEVEL(scan, NULL, 0, 0, CIB_NETDEV, handle_scan_combined);
286