xref: /netbsd-src/usr.sbin/wlanctl/wlanctl.c (revision 29f735df08dafc6ecec1adeaac83e13e33404a82)
1*29f735dfSchristos /* $NetBSD: wlanctl.c,v 1.14 2014/04/22 15:55:16 christos Exp $ */
2e0ca220cSdyoung /*-
3e0ca220cSdyoung  * Copyright (c) 2005 David Young.  All rights reserved.
4e0ca220cSdyoung  *
5e0ca220cSdyoung  * Redistribution and use in source and binary forms, with or
6e0ca220cSdyoung  * without modification, are permitted provided that the following
7e0ca220cSdyoung  * conditions are met:
8e0ca220cSdyoung  * 1. Redistributions of source code must retain the above copyright
9e0ca220cSdyoung  *    notice, this list of conditions and the following disclaimer.
10e0ca220cSdyoung  * 2. Redistributions in binary form must reproduce the above
11e0ca220cSdyoung  *    copyright notice, this list of conditions and the following
12e0ca220cSdyoung  *    disclaimer in the documentation and/or other materials provided
13e0ca220cSdyoung  *    with the distribution.
14e0ca220cSdyoung  * 3. The name of David Young may not be used to endorse or promote
15e0ca220cSdyoung  *    products derived from this software without specific prior
16e0ca220cSdyoung  *    written permission.
17e0ca220cSdyoung  *
18e0ca220cSdyoung  * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
19e0ca220cSdyoung  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20e0ca220cSdyoung  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21e0ca220cSdyoung  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL David
22e0ca220cSdyoung  * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23e0ca220cSdyoung  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24e0ca220cSdyoung  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25e0ca220cSdyoung  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26e0ca220cSdyoung  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27e0ca220cSdyoung  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28e0ca220cSdyoung  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
29e0ca220cSdyoung  * OF SUCH DAMAGE.
30e0ca220cSdyoung  */
31e0ca220cSdyoung #include <err.h>
32e0ca220cSdyoung #include <stdio.h>
33e0ca220cSdyoung #include <stdlib.h>
34e0ca220cSdyoung #include <string.h>
35e0ca220cSdyoung #include <unistd.h>
361e34bd3eSmartin #include <assert.h>
37e0ca220cSdyoung 
38e0ca220cSdyoung #include <sys/param.h>
39e0ca220cSdyoung #include <sys/sysctl.h>
40e0ca220cSdyoung #include <sys/inttypes.h>
41e0ca220cSdyoung #include <sys/ioctl.h>
42e0ca220cSdyoung #include <sys/types.h>
43e0ca220cSdyoung #include <sys/socket.h>
44e0ca220cSdyoung 
45e0ca220cSdyoung #include <net/if.h>
46e0ca220cSdyoung #include <net/if_media.h>
47e0ca220cSdyoung #include <netinet/in.h>
48e0ca220cSdyoung #include <netinet/if_ether.h>
49e0ca220cSdyoung 
50e0ca220cSdyoung #include <net80211/ieee80211.h>
51e0ca220cSdyoung #include <net80211/ieee80211_sysctl.h>
52e0ca220cSdyoung 
53e0ca220cSdyoung struct flagname {
54e0ca220cSdyoung 	u_int32_t fn_flag;
55e0ca220cSdyoung 	const char *fn_name;
56e0ca220cSdyoung };
57e0ca220cSdyoung 
58e0ca220cSdyoung struct cmdflags {
59e0ca220cSdyoung 	int	cf_a;	/* all 802.11 interfaces */
60566517a8Sdogcow   	int     cf_p;   /* public (i.e. non-private) dests */
61e0ca220cSdyoung };
62e0ca220cSdyoung 
63e0ca220cSdyoung static void		print_flags(u_int32_t, const struct flagname *, u_int);
64e0ca220cSdyoung static int		dump_nodes(const char *, int, struct cmdflags *);
65e0ca220cSdyoung static const char	*ether_string(u_int8_t *);
66e0ca220cSdyoung static void		parse_args(int *, char ***, struct cmdflags *);
67e0ca220cSdyoung static void		print_capinfo(u_int16_t);
68e0ca220cSdyoung static void		print_channel(u_int16_t, u_int16_t, u_int16_t);
69e0ca220cSdyoung static void		print_node_flags(u_int32_t);
70e0ca220cSdyoung static void		print_rateset(struct ieee80211_rateset *, int);
71bec77c5fSjoerg __dead static void	usage(void);
72e0ca220cSdyoung 
73e0ca220cSdyoung static void
print_rateset(struct ieee80211_rateset * rs,int txrate)74e0ca220cSdyoung print_rateset(struct ieee80211_rateset *rs, int txrate)
75e0ca220cSdyoung {
76e0ca220cSdyoung 	int i, rate;
77d5189d25Schristos 	const char *basic;
78e0ca220cSdyoung 
79e0ca220cSdyoung 	printf("\trates");
80e0ca220cSdyoung 
81e0ca220cSdyoung 	for (i = 0; i < rs->rs_nrates; i++) {
82e0ca220cSdyoung 
83e0ca220cSdyoung 		if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0)
84e0ca220cSdyoung 			basic = "*";
85e0ca220cSdyoung 		else
86e0ca220cSdyoung 			basic = "";
87e0ca220cSdyoung 		rate = 5 * (rs->rs_rates[i] & IEEE80211_RATE_VAL);
88d5189d25Schristos 		if (i == txrate)
89d5189d25Schristos 			printf(" [%s%d.%d]", basic, rate / 10, rate % 10);
90d5189d25Schristos 		else
91d5189d25Schristos 			printf(" %s%d.%d", basic, rate / 10, rate % 10);
92e0ca220cSdyoung 	}
93e0ca220cSdyoung 	printf("\n");
94e0ca220cSdyoung }
95e0ca220cSdyoung 
96e0ca220cSdyoung static void
print_flags(u_int32_t flags,const struct flagname * flagnames,u_int nname)97e0ca220cSdyoung print_flags(u_int32_t flags, const struct flagname *flagnames, u_int nname)
98e0ca220cSdyoung {
9922847523Slukem 	u_int i;
100e0ca220cSdyoung 	const char *delim;
101e0ca220cSdyoung 	delim = "<";
102e0ca220cSdyoung 
103e0ca220cSdyoung 	for (i = 0; i < nname; i++) {
104e0ca220cSdyoung 		if ((flags & flagnames[i].fn_flag) != 0) {
105e0ca220cSdyoung 			printf("%s%s", delim, flagnames[i].fn_name);
106e0ca220cSdyoung 			delim = ",";
107e0ca220cSdyoung 		}
108e0ca220cSdyoung 	}
109e0ca220cSdyoung 
110e0ca220cSdyoung 	printf("%s\n", (delim[0] == '<') ? "" : ">");
111e0ca220cSdyoung }
112e0ca220cSdyoung 
113e0ca220cSdyoung static void
print_node_flags(u_int32_t flags)114e0ca220cSdyoung print_node_flags(u_int32_t flags)
115e0ca220cSdyoung {
11622847523Slukem 	static const struct flagname nodeflags[] = {
117e0ca220cSdyoung 		  {IEEE80211_NODE_SYSCTL_F_BSS, "bss"}
118f8251d63Sdyoung 		, {IEEE80211_NODE_SYSCTL_F_STA, "sta"}
119f8251d63Sdyoung 		, {IEEE80211_NODE_SYSCTL_F_SCAN, "scan"}
120e0ca220cSdyoung 	};
121e0ca220cSdyoung 	printf("\tnode flags %04x", flags);
122e0ca220cSdyoung 
12345c4dfeeSdyoung 	print_flags(flags, nodeflags, __arraycount(nodeflags));
124e0ca220cSdyoung }
125e0ca220cSdyoung 
126e0ca220cSdyoung static void
print_capinfo(u_int16_t capinfo)127e0ca220cSdyoung print_capinfo(u_int16_t capinfo)
128e0ca220cSdyoung {
12922847523Slukem 	static const struct flagname capflags[] = {
130e0ca220cSdyoung 		{IEEE80211_CAPINFO_ESS, "ess"},
131e0ca220cSdyoung 		{IEEE80211_CAPINFO_IBSS, "ibss"},
132e0ca220cSdyoung 		{IEEE80211_CAPINFO_CF_POLLABLE, "cf pollable"},
133e0ca220cSdyoung 		{IEEE80211_CAPINFO_CF_POLLREQ, "request cf poll"},
134e0ca220cSdyoung 		{IEEE80211_CAPINFO_PRIVACY, "privacy"},
135e0ca220cSdyoung 		{IEEE80211_CAPINFO_SHORT_PREAMBLE, "short preamble"},
136e0ca220cSdyoung 		{IEEE80211_CAPINFO_PBCC, "pbcc"},
137e0ca220cSdyoung 		{IEEE80211_CAPINFO_CHNL_AGILITY, "channel agility"},
138e0ca220cSdyoung 		{IEEE80211_CAPINFO_SHORT_SLOTTIME, "short slot-time"},
139e0ca220cSdyoung 		{IEEE80211_CAPINFO_RSN, "rsn"},
140e0ca220cSdyoung 		{IEEE80211_CAPINFO_DSSSOFDM, "dsss-ofdm"}
141e0ca220cSdyoung 	};
142e0ca220cSdyoung 
143e0ca220cSdyoung 	printf("\tcapabilities %04x", capinfo);
144e0ca220cSdyoung 
14545c4dfeeSdyoung 	print_flags(capinfo, capflags, __arraycount(capflags));
146e0ca220cSdyoung }
147e0ca220cSdyoung 
148e0ca220cSdyoung static const char *
ether_string(u_int8_t * addr)149e0ca220cSdyoung ether_string(u_int8_t *addr)
150e0ca220cSdyoung {
151e0ca220cSdyoung 	struct ether_addr ea;
152e0ca220cSdyoung 	(void)memcpy(ea.ether_addr_octet, addr, sizeof(ea.ether_addr_octet));
153e0ca220cSdyoung 	return ether_ntoa(&ea);
154e0ca220cSdyoung }
155e0ca220cSdyoung 
156e0ca220cSdyoung static void
print_channel(u_int16_t chanidx,u_int16_t freq,u_int16_t flags)157e0ca220cSdyoung print_channel(u_int16_t chanidx, u_int16_t freq, u_int16_t flags)
158e0ca220cSdyoung {
15922847523Slukem 	static const struct flagname chanflags[] = {
160e0ca220cSdyoung 		{IEEE80211_CHAN_TURBO, "turbo"},
161e0ca220cSdyoung 		{IEEE80211_CHAN_CCK, "cck"},
162e0ca220cSdyoung 		{IEEE80211_CHAN_OFDM, "ofdm"},
163e0ca220cSdyoung 		{IEEE80211_CHAN_2GHZ, "2.4GHz"},
164e0ca220cSdyoung 		{IEEE80211_CHAN_5GHZ, "5GHz"},
165e0ca220cSdyoung 		{IEEE80211_CHAN_PASSIVE, "passive scan"},
166e0ca220cSdyoung 		{IEEE80211_CHAN_DYN, "dynamic cck-ofdm"},
167e0ca220cSdyoung 		{IEEE80211_CHAN_GFSK, "gfsk"}
168e0ca220cSdyoung 	};
169e0ca220cSdyoung 	printf("\tchan %d freq %dMHz flags %04x", chanidx, freq, flags);
170e0ca220cSdyoung 
17145c4dfeeSdyoung 	print_flags(flags, chanflags, __arraycount(chanflags));
172e0ca220cSdyoung }
173e0ca220cSdyoung 
174e0ca220cSdyoung /*
175e0ca220cSdyoung  *
176e0ca220cSdyoung  * ifname:   dump nodes belonging to the given interface, or belonging
177e0ca220cSdyoung  *           to all interfaces if NULL
178e0ca220cSdyoung  * hdr_type: header type: IEEE80211_SYSCTL_T_NODE -> generic node,
179e0ca220cSdyoung  *                        IEEE80211_SYSCTL_T_RSSADAPT -> rssadapt(9) info,
180e0ca220cSdyoung  *                        IEEE80211_SYSCTL_T_DRVSPEC -> driver specific.
181*29f735dfSchristos  * cf:       command flags: cf_a != 0 -> all 802.11 interfaces
182*29f735dfSchristos  *                          cf_p != 0 -> public dests
183e0ca220cSdyoung  */
184e0ca220cSdyoung static int
dump_nodes(const char * ifname_arg,int hdr_type,struct cmdflags * cf)185e0ca220cSdyoung dump_nodes(const char *ifname_arg, int hdr_type, struct cmdflags *cf)
186e0ca220cSdyoung {
187e0ca220cSdyoung #if 0
188e0ca220cSdyoung /*39*/	u_int8_t	ns_erp;		/* 11g only */
189e0ca220cSdyoung /*40*/	u_int32_t	ns_rstamp;	/* recv timestamp */
190e0ca220cSdyoung /*64*/	u_int16_t	ns_fhdwell;	/* FH only */
191e0ca220cSdyoung /*66*/	u_int8_t	ns_fhindex;	/* FH only */
192e0ca220cSdyoung /*68*/
193e0ca220cSdyoung #endif
194e0ca220cSdyoung 	u_int i, ifindex;
195fdb88213Schristos 	size_t namelen, nodes_len, totallen;
19698917af5Schristos 	int name[12];
197e0ca220cSdyoung 	int *vname;
198e0ca220cSdyoung 	char ifname[IFNAMSIZ];
199e0ca220cSdyoung 	struct ieee80211_node_sysctl *pns, *ns;
2001e34bd3eSmartin 	u_int64_t ts;
201e0ca220cSdyoung 
20245c4dfeeSdyoung 	namelen = __arraycount(name);
203e0ca220cSdyoung 
204e0ca220cSdyoung 	if (sysctlnametomib("net.link.ieee80211.nodes", &name[0],
205e0ca220cSdyoung 	    &namelen) != 0) {
206e0ca220cSdyoung 		warn("sysctlnametomib");
207e0ca220cSdyoung 		return -1;
208e0ca220cSdyoung 	}
209e0ca220cSdyoung 
210e0ca220cSdyoung 	if (ifname_arg == NULL)
211e0ca220cSdyoung 		ifindex = 0;
212e0ca220cSdyoung 	else if ((ifindex = if_nametoindex(ifname_arg)) == 0) {
213e0ca220cSdyoung 		warn("if_nametoindex");
214e0ca220cSdyoung 		return -1;
215e0ca220cSdyoung 	}
216e0ca220cSdyoung 
217fdb88213Schristos 	totallen = namelen + IEEE80211_SYSCTL_NODENAMELEN;
21845c4dfeeSdyoung 	if (totallen >= __arraycount(name)) {
219b3c28e1dSchristos 		warnx("Internal error finding sysctl mib");
220fdb88213Schristos 		return -1;
221fdb88213Schristos 	}
222e0ca220cSdyoung 	vname = &name[namelen];
223e0ca220cSdyoung 
224e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_IF] = ifindex;
225e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_OP] = IEEE80211_SYSCTL_OP_ALL;
226e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_ARG] = 0;
227e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_TYPE] = hdr_type;
228e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_ELTSIZE] = sizeof(*ns);
229f8251d63Sdyoung 	vname[IEEE80211_SYSCTL_NODENAME_ELTCOUNT] = INT_MAX;
230e0ca220cSdyoung 
231e0ca220cSdyoung 	/* how many? */
232fdb88213Schristos 	if (sysctl(name, totallen, NULL, &nodes_len, NULL, 0) != 0) {
233e0ca220cSdyoung 		warn("sysctl(count)");
234e0ca220cSdyoung 		return -1;
235e0ca220cSdyoung 	}
236e0ca220cSdyoung 
237fdb88213Schristos 	ns = malloc(nodes_len);
238e0ca220cSdyoung 
239e0ca220cSdyoung 	if (ns == NULL) {
240e0ca220cSdyoung 		warn("malloc");
241e0ca220cSdyoung 		return -1;
242e0ca220cSdyoung 	}
243e0ca220cSdyoung 
244e0ca220cSdyoung 	vname[IEEE80211_SYSCTL_NODENAME_ELTCOUNT] = nodes_len / sizeof(ns[0]);
245e0ca220cSdyoung 
246e0ca220cSdyoung 	/* Get them. */
247fdb88213Schristos 	if (sysctl(name, totallen, ns, &nodes_len, NULL, 0) != 0) {
248e0ca220cSdyoung 		warn("sysctl(get)");
249e0ca220cSdyoung 		return -1;
250e0ca220cSdyoung 	}
251e0ca220cSdyoung 
252e0ca220cSdyoung 	for (i = 0; i < nodes_len / sizeof(ns[0]); i++) {
253e0ca220cSdyoung 		pns = &ns[i];
254e0ca220cSdyoung 		if (if_indextoname(pns->ns_ifindex, ifname) == NULL) {
255e0ca220cSdyoung 			warn("if_indextoname");
256e0ca220cSdyoung 			return -1;
257e0ca220cSdyoung 		}
258566517a8Sdogcow 		if (cf->cf_p && (pns->ns_capinfo & IEEE80211_CAPINFO_PRIVACY))
259566517a8Sdogcow 		  	continue;
260e0ca220cSdyoung 		printf("%s: mac %s ", ifname, ether_string(pns->ns_macaddr));
261e0ca220cSdyoung 		printf("bss %s\n", ether_string(pns->ns_bssid));
262e0ca220cSdyoung 		print_node_flags(pns->ns_flags);
263e0ca220cSdyoung 
264e0ca220cSdyoung 		/* TBD deal with binary ESSID */
265e0ca220cSdyoung 		printf("\tess <%.*s>\n", pns->ns_esslen, pns->ns_essid);
266e0ca220cSdyoung 
267e0ca220cSdyoung 		print_channel(pns->ns_chanidx, pns->ns_freq, pns->ns_chanflags);
268e0ca220cSdyoung 
269e0ca220cSdyoung 		print_capinfo(pns->ns_capinfo);
270e0ca220cSdyoung 
2711e34bd3eSmartin 		assert(sizeof(ts) == sizeof(pns->ns_tstamp));
2721e34bd3eSmartin 		memcpy(&ts, &pns->ns_tstamp[0], sizeof(ts));
273e0ca220cSdyoung 		printf("\tbeacon-interval %d TU tsft %" PRIu64 " us\n",
2741e34bd3eSmartin 		    pns->ns_intval, (u_int64_t)le64toh(ts));
275e0ca220cSdyoung 
276e0ca220cSdyoung 		print_rateset(&pns->ns_rates, pns->ns_txrate);
277e0ca220cSdyoung 
278e0ca220cSdyoung 		printf("\tassoc-id %d assoc-failed %d inactivity %ds\n",
279e0ca220cSdyoung 		    pns->ns_associd, pns->ns_fails, pns->ns_inact);
280e0ca220cSdyoung 
281e0ca220cSdyoung 		printf("\trssi %d txseq %d rxseq %d\n",
282e0ca220cSdyoung 		    pns->ns_rssi, pns->ns_txseq, pns->ns_rxseq);
283e0ca220cSdyoung 	}
284e0ca220cSdyoung 	return 0;
285e0ca220cSdyoung }
286e0ca220cSdyoung 
287e0ca220cSdyoung static void
usage(void)288e0ca220cSdyoung usage(void)
289e0ca220cSdyoung {
290*29f735dfSchristos 	fprintf(stderr,
291*29f735dfSchristos 	    "Usage: %s [ -p ] -a\n"
292*29f735dfSchristos 	    "       %s [ -p ] interface [ interface ... ]\n",
293*29f735dfSchristos 	    getprogname(), getprogname());
294e0ca220cSdyoung 	exit(EXIT_FAILURE);
295e0ca220cSdyoung }
296e0ca220cSdyoung 
297e0ca220cSdyoung static void
parse_args(int * argcp,char *** argvp,struct cmdflags * cf)298e0ca220cSdyoung parse_args(int *argcp, char ***argvp, struct cmdflags *cf)
299e0ca220cSdyoung {
300e0ca220cSdyoung 	int ch;
301e0ca220cSdyoung 
302e0ca220cSdyoung 	(void)memset(cf, 0, sizeof(*cf));
303e0ca220cSdyoung 
304*29f735dfSchristos 	while ((ch = getopt(*argcp, *argvp, "ap")) != -1) {
305e0ca220cSdyoung 		switch (ch) {
306e0ca220cSdyoung 		case 'a':
307e0ca220cSdyoung 			cf->cf_a = 1;
308e0ca220cSdyoung 			break;
309566517a8Sdogcow 		case 'p':
310566517a8Sdogcow 			cf->cf_p = 1;
311566517a8Sdogcow 			break;
312e0ca220cSdyoung 		default:
313e0ca220cSdyoung 			warnx("unknown option -%c", ch);
314e0ca220cSdyoung 			usage();
315e0ca220cSdyoung 		}
316e0ca220cSdyoung 	}
317e0ca220cSdyoung 
318e0ca220cSdyoung 	*argcp -= optind;
319e0ca220cSdyoung 	*argvp += optind;
320e0ca220cSdyoung }
321e0ca220cSdyoung 
322e0ca220cSdyoung #define	LOGICAL_XOR(x, y) (!(x) != !(y))
323e0ca220cSdyoung 
324e0ca220cSdyoung int
main(int argc,char ** argv)325e0ca220cSdyoung main(int argc, char **argv)
326e0ca220cSdyoung {
327e0ca220cSdyoung 	int i;
328e0ca220cSdyoung 	struct cmdflags cf;
329e0ca220cSdyoung 
330e0ca220cSdyoung 	parse_args(&argc, &argv, &cf);
331e0ca220cSdyoung 
332e0ca220cSdyoung 	if (!LOGICAL_XOR(argc > 0, cf.cf_a))
333e0ca220cSdyoung 		usage();
334e0ca220cSdyoung 
335e0ca220cSdyoung 	if (cf.cf_a) {
336e0ca220cSdyoung 		if (dump_nodes(NULL, IEEE80211_SYSCTL_T_NODE, &cf) != 0)
337e0ca220cSdyoung 			return EXIT_FAILURE;
338e0ca220cSdyoung 		return EXIT_SUCCESS;
339e0ca220cSdyoung 	}
340e0ca220cSdyoung 	for (i = 0; i < argc; i++) {
341e0ca220cSdyoung 		if (dump_nodes(argv[i], IEEE80211_SYSCTL_T_NODE, &cf) != 0)
342e0ca220cSdyoung 			return EXIT_FAILURE;
343e0ca220cSdyoung 	}
344e0ca220cSdyoung 
345e0ca220cSdyoung 	return EXIT_SUCCESS;
346e0ca220cSdyoung }
347