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