scan.c revision 6ff0c93ad7c73c16892dd261612a71255fdbf978
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
1692a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_ESS		(1<<0)
1792a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_IBSS		(1<<1)
1892a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_CF_POLLABLE	(1<<2)
1992a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_CF_POLL_REQUEST	(1<<3)
2092a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_PRIVACY		(1<<4)
2192a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
2292a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_PBCC		(1<<6)
2392a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
2492a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
2592a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_QOS		(1<<9)
2692a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
2792a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_APSD		(1<<11)
2892a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann#define WLAN_CAPABILITY_DSSS_OFDM	(1<<13)
2992a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann
30764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstruct scan_params {
31764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	bool unknown;
32764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg};
33764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
347c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Bergstatic int handle_scan(struct nl80211_state *state,
357c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Berg		       struct nl_cb *cb,
363563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		       struct nl_msg *msg,
373563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		       int argc, char **argv)
383563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
393563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nl_msg *ssids = NULL;
403563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int err = -ENOBUFS;
413563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
423563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	ssids = nlmsg_alloc();
433563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!ssids)
443563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return -ENOMEM;
453563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NLA_PUT(ssids, 1, 0, "");
463563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
473563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
483563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	err = 0;
493563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg nla_put_failure:
503563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nlmsg_free(ssids);
513563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return err;
523563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
533563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes BergCOMMAND(scan, trigger, NULL,
543563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan);
553563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
563563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergtypedef void (*printfn)(unsigned char type, unsigned char len, unsigned char *data);
573563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
583563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ssid(unsigned char type, unsigned char len, unsigned char *data)
593563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
603563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
613563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\tSSID: ");
623563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	for (i=0; i<len; i++) {
633563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		if (isprint(data[i]))
643563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("%c", data[i]);
653563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		else
663563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("\\x%.2x", data[i]);
673563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
683563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
693563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
703563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
713563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_supprates(unsigned char type, unsigned char len, unsigned char *data)
723563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
733563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
743563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
753563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (type == 1)
763563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tSupported rates: ");
773563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	else
783563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tExtended supported rates: ");
793563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
803563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	for (i=0; i<len; i++) {
813563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		int r = data[i] & 0x7f;
823563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
833563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
843563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
853563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
863563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
873563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ds(unsigned char type, unsigned char len, unsigned char *data)
883563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
893563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\tDS Parameter set: channel %d\n", data[0]);
903563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
913563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
923563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic void print_ign(unsigned char type, unsigned char len, unsigned char *data)
933563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
943563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	/* ignore for now, not too useful */
953563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
963563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
97b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmannstatic void print_country(unsigned char type, unsigned char len, unsigned char *data)
98b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann{
99b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	int i;
100b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann
101b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	printf("\tCountry: %.*s", 2, data);
102b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	switch (data[2]) {
103b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	case 'I':
104b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann		printf(" (indoor)");
105b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann		break;
106b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	case 'O':
107b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann		printf(" (outdoor)");
108b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann		break;
109b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	}
110b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	printf(", data:");
111b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	for(i=0; i<len-3; i++)
112b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann		printf(" %.02x", data[i + 3]);
113b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	printf("\n");
114b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann}
115b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann
116fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmannstatic void print_erp(unsigned char type, unsigned char len, unsigned char *data)
117fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann{
118fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	if (data[0] == 0x00)
119fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann		return;
120fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann
121fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	printf("\tERP:");
122fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	if (data[0] & 0x01)
123fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann		printf(" NonERP_Present");
124fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	if (data[0] & 0x02)
125fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann		printf(" Use_Protection");
126fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	if (data[0] & 0x04)
127fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann		printf(" Barker_Preamble_Mode");
128fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	printf("\n");
129fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann}
130fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann
1319b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmannstatic void print_capabilities(unsigned char type, unsigned char len, unsigned char *data)
1329b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann{
1339b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann	int i;
1349b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann
1359b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann	printf("\tExtended capabilties:");
1369b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann	for(i=0; i<len; i++)
1379b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann		printf(" %.02x", data[i]);
1389b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann	printf("\n");
1399b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann}
1409b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann
141764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic const printfn ieprinters[] = {
142764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[0] = print_ssid,
143764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[1] = print_supprates,
144764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[3] = print_ds,
145764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[5] = print_ign,
146b7e8fa37d03cb17e69cdcf37041ffdc299c693dfMarcel Holtmann	[7] = print_country,
147fc4d1484a18a2f67df901126123177ea94e8037bMarcel Holtmann	[42] = print_erp,
148764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	[50] = print_supprates,
1499b880b00e4a3b4a9befbdf55f90c89568781cf73Marcel Holtmann	[127] = print_capabilities,
150764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg};
151764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
1524673a894dae2780e395204eab01af4d40220b9f5Johannes Bergstatic void tab_on_first(bool *first)
1534673a894dae2780e395204eab01af4d40220b9f5Johannes Berg{
1544673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	if (!*first)
1554673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\t");
1564673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	else
1574673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		*first = false;
1584673a894dae2780e395204eab01af4d40220b9f5Johannes Berg}
1594673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
1606ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmannstatic void print_wifi_wmm(unsigned char type, unsigned char len, unsigned char *data)
1616ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann{
1626ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	int i;
1636ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann
1646ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	printf("\tWMM ");
1656ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	switch (data[0]) {
1666ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	case 0x00:
1676ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		printf("information:");
1686ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		break;
1696ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	case 0x01:
1706ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		printf("parameter:");
1716ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		break;
1726ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	default:
1736ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		printf("type %d:", data[0]);
1746ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		break;
1756ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	}
1766ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann
1776ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	for(i=0; i<len-1; i++)
1786ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann		printf(" %.02x", data[i + 1]);
1796ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	printf("\n");
1806ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann}
1816ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann
1824673a894dae2780e395204eab01af4d40220b9f5Johannes Bergstatic void print_wifi_wps(unsigned char type, unsigned char len, unsigned char *data)
1834673a894dae2780e395204eab01af4d40220b9f5Johannes Berg{
1844673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	bool first = true;
1854673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	__u16 subtype, sublen;
1864673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
1874673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	printf("\tWPS:");
1884673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
1894673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	while (len >= 4) {
1904673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		subtype = (data[0] << 8) + data[1];
1914673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		sublen = (data[2] << 8) + data[3];
1924673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		if (sublen > len)
1934673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
1944673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
1954673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		switch (subtype) {
1964673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		case 0x104a:
1974673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			tab_on_first(&first);
1984673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\t * Version: %#.2x\n", data[4]);
1994673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2004673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		case 0x1011:
2014673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			tab_on_first(&first);
2024673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\t * Device name: %.*s\n", sublen, data + 4);
2034673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2044673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		case 0x1021:
2054673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			tab_on_first(&first);
2064673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
2074673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2084673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		case 0x1023:
2094673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			tab_on_first(&first);
2104673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\t * Model: %.*s\n", sublen, data + 4);
2114673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2127ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg		case 0x1057: {
2137ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg			__u16 val = (data[4] << 8) | data[5];
2147ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg			tab_on_first(&first);
2157ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg			printf("\t * AP setup locked: 0x%.4x\n", val);
2167ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg			break;
2177ee5a86565fcf11ea33356ae9b202bc0336e13d6Johannes Berg		}
2184673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		case 0x1008: {
2194673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			__u16 meth = (data[4] << 8) + data[5];
2204673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			bool comma = false;
2214673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			tab_on_first(&first);
2224673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\t * Config methods:");
2234673a894dae2780e395204eab01af4d40220b9f5Johannes Berg#define T(bit, name) do {		\
2244673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	if (meth & (1<<bit)) {		\
2254673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		if (comma)		\
2264673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf(",");	\
2274673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		comma = true;		\
2284673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf(" " name);	\
2294673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	} } while (0)
2304673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(0, "USB");
2314673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(1, "Ethernet");
2324673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(2, "Label");
2334673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(3, "Display");
2344673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(4, "Ext. NFC");
2354673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(5, "Int. NFC");
2364673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(6, "NFC Intf.");
2374673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(7, "PBC");
2384673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			T(8, "Keypad");
2394673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf("\n");
2404673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2414673a894dae2780e395204eab01af4d40220b9f5Johannes Berg#undef T
2424673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		}
2434673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		default:
2444673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			break;
2454673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		}
2464673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
2474673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		data += sublen + 4;
2484673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		len -= sublen + 4;
2494673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	}
2504673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
2514673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	if (len != 0) {
2524673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\t\t * bogus tail data (%d):", len);
2534673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		while (len) {
2544673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf(" %.2x", *data);
2554673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			data++;
2564673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			len--;
2574673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		}
2584673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\n");
2594673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	}
2604673a894dae2780e395204eab01af4d40220b9f5Johannes Berg}
2614673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
2624673a894dae2780e395204eab01af4d40220b9f5Johannes Bergstatic const printfn wifiprinters[] = {
2636ff0c93ad7c73c16892dd261612a71255fdbf978Marcel Holtmann	[2] = print_wifi_wmm,
2644673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	[4] = print_wifi_wps,
2654673a894dae2780e395204eab01af4d40220b9f5Johannes Berg};
2664673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
267764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic void print_vendor(unsigned char len, unsigned char *data,
268764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			 struct scan_params *params)
2693563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
2703563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	int i;
2713563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
272fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	if (len < 3) {
2734673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\tVendor specific: <too short> data:");
274fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		for(i = 0; i < len; i++)
275fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg			printf(" %.02x", data[i]);
276fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		printf("\n");
277fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		return;
278fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	}
279fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg
2804673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	if (len >= 4 && data[0] == 0x00 && data[1] == 0x50 && data[2] == 0xF2) {
2814673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]])
2824673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			return wifiprinters[data[3]](data[3], len - 4, data + 4);
2834673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		if (!params->unknown)
2844673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			return;
2854673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\tWiFi OUI %#.2x data:", data[3]);
2864673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		for(i = 0; i < len - 4; i++)
2874673a894dae2780e395204eab01af4d40220b9f5Johannes Berg			printf(" %.02x", data[i + 4]);
2884673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		printf("\n");
2894673a894dae2780e395204eab01af4d40220b9f5Johannes Berg		return;
2904673a894dae2780e395204eab01af4d40220b9f5Johannes Berg	}
2914673a894dae2780e395204eab01af4d40220b9f5Johannes Berg
292764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (!params->unknown)
293764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		return;
294764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
295fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2963563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		data[0], data[1], data[2]);
297fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg	for (i = 3; i < len; i++)
298fbf80af54408799f7e3c03430b798759019dd79bJohannes Berg		printf(" %.2x", data[i]);
2993563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("\n");
3003563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
3013563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
302764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic void print_ies(unsigned char *ie, int ielen, struct scan_params *params)
3033563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
3043563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	while (ielen >= 2 && ielen >= ie[1]) {
30597ebbaf55e8729c28513d8a73f3e65e8d759ff80Johannes Berg		if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]]) {
3063563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			ieprinters[ie[0]](ie[0], ie[1], ie + 2);
307764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		} else if (ie[0] == 221 /* vendor */) {
308764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			print_vendor(ie[1], ie + 2, params);
309764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		} else if (params->unknown) {
3103563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			int i;
3113563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3128086b7007d8a7f9d2bc22d154e26e9060f0e9676Johannes Berg			printf("\tUnknown IE (%d):", ie[0]);
3133563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			for (i=0; i<ie[1]; i++)
3148086b7007d8a7f9d2bc22d154e26e9060f0e9676Johannes Berg				printf(" %.2x", ie[2+i]);
3153563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			printf("\n");
3163563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		}
3173563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		ielen -= ie[1] + 2;
3183563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		ie += ie[1] + 2;
3193563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
3203563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
3213563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3223563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Bergstatic int print_bss_handler(struct nl_msg *msg, void *arg)
3233563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
3243563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nlattr *tb[NL80211_ATTR_MAX + 1];
3253563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
3263563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	struct nlattr *bss[NL80211_BSS_MAX + 1];
3273563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	char mac_addr[20], dev[20];
3283563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
3293563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_TSF] = { .type = NLA_U64 },
3303563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
3313563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_BSSID] = { },
3323563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
3333563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
3343563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
335f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
336f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
3373563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	};
3383563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3393563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
3403563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		  genlmsg_attrlen(gnlh, 0), NULL);
3413563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3423563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!tb[NL80211_ATTR_BSS]) {
3433563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		fprintf(stderr, "bss info missing!");
3443563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
3453563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
3463563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (nla_parse_nested(bss, NL80211_BSS_MAX,
3473563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			     tb[NL80211_ATTR_BSS],
3483563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			     bss_policy)) {
3493563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		fprintf(stderr, "failed to parse nested attributes!");
3503563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
3513563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	}
3523563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3533563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (!bss[NL80211_BSS_BSSID])
3543563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		return NL_SKIP;
3553563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
3563563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
3573563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
3583563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	printf("BSS %s (on %s)\n", mac_addr, dev);
3593563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
360e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg	if (bss[NL80211_BSS_TSF]) {
361e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		unsigned long long tsf;
362e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
363e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg		printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
364e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg			tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
365e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg			(tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
366e7109a8aa93fab514d0c71803df622bec6dd23d4Johannes Berg	}
3673563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_FREQUENCY])
3683563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tfreq: %d\n",
3693563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
3703563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_BEACON_INTERVAL])
3713563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		printf("\tbeacon interval: %d\n",
3723563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
37392a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann	if (bss[NL80211_BSS_CAPABILITY]) {
37492a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		__u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
37592a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		printf("\tcapability:");
37692a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_ESS)
37792a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" ESS");
37892a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_IBSS)
37992a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" IBSS");
38092a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_PRIVACY)
38192a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" Privacy");
38292a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
38392a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" ShortPreamble");
38492a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_PBCC)
38592a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" PBCC");
38692a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
38792a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" ChannelAgility");
38892a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
38992a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" SpectrumMgmt");
39092a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_QOS)
39192a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" QoS");
39292a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
39392a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" ShortSlotTime");
39492a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_APSD)
39592a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" APSD");
39692a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		if (capa & WLAN_CAPABILITY_DSSS_OFDM)
39792a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann			printf(" DSSS-OFDM");
39892a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann		printf(" (0x%.4x)\n", capa);
39992a04ecd916b20e151c4b40e740b6bd85131e31eMarcel Holtmann	}
400f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	if (bss[NL80211_BSS_SIGNAL_MBM]) {
401f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
402f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
403f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	}
404f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
405f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
406f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg		printf("\tsignal: %d/100\n", s);
407f2e17e1fa6d4b2634564e2a8819cd4ce5f8469edJohannes Berg	}
4083563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
4093563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg		print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
410764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			  nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
411764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg			  arg);
4123563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
4133563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return NL_SKIP;
4143563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
4153563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
416764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Bergstatic struct scan_params scan_params;
4173563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg
4187c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Bergstatic int handle_scan_dump(struct nl80211_state *state,
4197c37a24d7570cd9ff6b89d6fa8c1846c9b66969dJohannes Berg			    struct nl_cb *cb,
4203563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			    struct nl_msg *msg,
4213563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg			    int argc, char **argv)
4223563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg{
423764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (argc > 1)
424764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		return 1;
425764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
426764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	scan_params.unknown = false;
427764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	if (argc == 1 && !strcmp(argv[0], "-u"))
428764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		scan_params.unknown = true;
429764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg
430764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler,
431764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes Berg		  &scan_params);
4323563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	return 0;
4333563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg}
434764fe7533b74fb064f112497c9a1d5651a1ee5b8Johannes BergCOMMAND(scan, dump, "[-u]",
4353563f4c510e0afbf18bf616f7e35a9b05a535ec2Johannes Berg	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump);
436a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
437a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Bergstatic int handle_scan_combined(struct nl80211_state *state,
438a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				struct nl_cb *cb,
439a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				struct nl_msg *msg,
440a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg				int argc, char **argv)
441a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg{
442a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static char *trig_argv[] = {
443a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NULL,
444a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"scan",
445a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"trigger",
446a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
447a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static char *dump_argv[] = {
448a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NULL,
449a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"scan",
450a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		"dump",
45192649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann		NULL,
452a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
453a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	static const __u32 cmds[] = {
454a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NL80211_CMD_NEW_SCAN_RESULTS,
455a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		NL80211_CMD_SCAN_ABORTED,
456a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	};
45792649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann	int dump_argc, err;
458a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
459a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	trig_argv[0] = argv[0];
460a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	err = handle_cmd(state, II_NETDEV, ARRAY_SIZE(trig_argv), trig_argv);
461a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	if (err)
462a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		return err;
463a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
46461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	/*
46561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
46661725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
46761725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * This code has a bug, which requires creating a separate
46861725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * nl80211 socket to fix:
46961725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
47061725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
47161725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * before (!) we listen to it, because we only start listening
47261725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * after we send our scan request.
47361725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
47461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * Doing it the other way around has a race condition as well,
47561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * if you first open the events socket you may get a notification
47661725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * for a previous scan.
47761725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
47861725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * The only proper way to fix this would be to listen to events
47961725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * before sending the command, and for the kernel to send the
48061725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * scan request along with the event, so that you can match up
48161725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * whether the scan you requested was finished or aborted (this
48261725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * may result in processing a scan that another application
48361725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * requested, but that doesn't seem to be a problem).
48461725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 *
48561725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 * Alas, the kernel doesn't do that (yet).
48661725dbed6df376809e8dc3865640244d8f1d690Johannes Berg	 */
48761725dbed6df376809e8dc3865640244d8f1d690Johannes Berg
488a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
489a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg					NL80211_CMD_SCAN_ABORTED) {
490a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		printf("scan aborted!\n");
491a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg		return 0;
492a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	}
493a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg
49492649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann	if (argc == 3 && !strcmp(argv[2], "-u")) {
49592649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann		dump_argc = 4;
49692649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann		dump_argv[3] = "-u";
49792649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann	} else
49892649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann		dump_argc = 3;
49992649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann
500a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg	dump_argv[0] = argv[0];
50192649eab6b3ccb0be600b8501fa7b83e9467819cMarcel Holtmann	return handle_cmd(state, II_NETDEV, dump_argc, dump_argv);
502a5fe4ef2f3e282a789c86edee838f338b07d5033Johannes Berg}
50392649eab6b3ccb0be600b8501fa7b83e9467819cMarcel HoltmannTOPLEVEL(scan, "[-u]", 0, 0, CIB_NETDEV, handle_scan_combined);
504