scan.c revision 97ebbaf55e8729c28513d8a73f3e65e8d759ff80
1#include <net/if.h>
2#include <errno.h>
3#include <string.h>
4#include <ctype.h>
5
6#include <netlink/genl/genl.h>
7#include <netlink/genl/family.h>
8#include <netlink/genl/ctrl.h>
9#include <netlink/msg.h>
10#include <netlink/attr.h>
11
12#include "nl80211.h"
13#include "iw.h"
14
15static int handle_scan(struct nl_cb *cb,
16		       struct nl_msg *msg,
17		       int argc, char **argv)
18{
19	struct nl_msg *ssids = NULL;
20	int err = -ENOBUFS;
21
22	ssids = nlmsg_alloc();
23	if (!ssids)
24		return -ENOMEM;
25	NLA_PUT(ssids, 1, 0, "");
26	nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
27
28	err = 0;
29 nla_put_failure:
30	nlmsg_free(ssids);
31	return err;
32}
33COMMAND(scan, trigger, NULL,
34	NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan);
35
36typedef void (*printfn)(unsigned char type, unsigned char len, unsigned char *data);
37
38static void print_ssid(unsigned char type, unsigned char len, unsigned char *data)
39{
40	int i;
41	printf("\tSSID: ");
42	for (i=0; i<len; i++) {
43		if (isprint(data[i]))
44			printf("%c", data[i]);
45		else
46			printf("\\x%.2x", data[i]);
47	}
48	printf("\n");
49}
50
51static void print_supprates(unsigned char type, unsigned char len, unsigned char *data)
52{
53	int i;
54
55	if (type == 1)
56		printf("\tSupported rates: ");
57	else
58		printf("\tExtended supported rates: ");
59
60	for (i=0; i<len; i++) {
61		int r = data[i] & 0x7f;
62		printf("%d.%d%s ", r/2, 5*(r&1), data[i] & 0x80 ? "*":"");
63	}
64	printf("\n");
65}
66
67static void print_ds(unsigned char type, unsigned char len, unsigned char *data)
68{
69	printf("\tDS Parameter set: channel %d\n", data[0]);
70}
71
72static void print_ign(unsigned char type, unsigned char len, unsigned char *data)
73{
74	/* ignore for now, not too useful */
75}
76
77static void print_vendor(unsigned char type, unsigned char len, unsigned char *data)
78{
79	int i;
80
81	printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data: ",
82		data[0], data[1], data[2]);
83	for (i=3; i<len; i++)
84		printf("\\x%.2x", data[i]);
85	printf("\n");
86}
87
88static const printfn ieprinters[] = {
89	[0] = print_ssid,
90	[1] = print_supprates,
91	[3] = print_ds,
92	[5] = print_ign,
93	[50] = print_supprates,
94	[221] = print_vendor,
95};
96
97static void print_ies(unsigned char *ie, int ielen)
98{
99	while (ielen >= 2 && ielen >= ie[1]) {
100		if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]]) {
101			ieprinters[ie[0]](ie[0], ie[1], ie + 2);
102		} else {
103			int i;
104
105			printf("\tUnknown IE (%d): ", ie[0]);
106			for (i=0; i<ie[1]; i++)
107				printf("\\x%.2x", ie[2+i]);
108			printf("\n");
109		}
110		ielen -= ie[1] + 2;
111		ie += ie[1] + 2;
112	}
113}
114
115static int print_bss_handler(struct nl_msg *msg, void *arg)
116{
117	struct nlattr *tb[NL80211_ATTR_MAX + 1];
118	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
119	struct nlattr *bss[NL80211_BSS_MAX + 1];
120	char mac_addr[20], dev[20];
121	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
122		[NL80211_BSS_TSF] = { .type = NLA_U64 },
123		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
124		[NL80211_BSS_BSSID] = { },
125		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
126		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
127		[NL80211_BSS_INFORMATION_ELEMENTS] = { },
128	};
129
130	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
131		  genlmsg_attrlen(gnlh, 0), NULL);
132
133	if (!tb[NL80211_ATTR_BSS]) {
134		fprintf(stderr, "bss info missing!");
135		return NL_SKIP;
136	}
137	if (nla_parse_nested(bss, NL80211_BSS_MAX,
138			     tb[NL80211_ATTR_BSS],
139			     bss_policy)) {
140		fprintf(stderr, "failed to parse nested attributes!");
141		return NL_SKIP;
142	}
143
144	if (!bss[NL80211_BSS_BSSID])
145		return NL_SKIP;
146
147	mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
148	if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
149	printf("BSS %s (on %s)\n", mac_addr, dev);
150
151	if (bss[NL80211_BSS_TSF])
152		printf("\tTSF: %llu usec\n",
153			(unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]));
154	if (bss[NL80211_BSS_FREQUENCY])
155		printf("\tfreq: %d\n",
156			nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
157	if (bss[NL80211_BSS_BEACON_INTERVAL])
158		printf("\tbeacon interval: %d\n",
159			nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
160	if (bss[NL80211_BSS_CAPABILITY])
161		printf("\tcapability: 0x%.4x\n",
162			nla_get_u16(bss[NL80211_BSS_CAPABILITY]));
163	if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
164		print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
165			  nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
166
167	return NL_SKIP;
168}
169
170
171
172static int handle_scan_dump(struct nl_cb *cb,
173			    struct nl_msg *msg,
174			    int argc, char **argv)
175{
176	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler, NULL);
177	return 0;
178}
179COMMAND(scan, dump, NULL,
180	NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump);
181