1 /* $NetBSD: wlanctl.c,v 1.10 2007/12/22 00:58:15 dyoung Exp $ */
3 * Copyright (c) 2005 David Young. All rights reserved.
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution.
14 * 3. The name of David Young may not be used to endorse or promote
15 * products derived from this software without specific prior
18 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
22 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
38 #include <sys/param.h>
39 #include <sys/sysctl.h>
40 #include <sys/inttypes.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
46 #include <net/if_media.h>
47 #include <netinet/in.h>
48 #include <netinet/if_ether.h>
50 #include <net80211/ieee80211.h>
51 #include <net80211/ieee80211_sysctl.h>
59 int cf_v
; /* verbose */
60 int cf_a
; /* all 802.11 interfaces */
61 int cf_p
; /* public (i.e. non-private) dests */
64 static void print_flags(u_int32_t
, const struct flagname
*, u_int
);
65 static int dump_nodes(const char *, int, struct cmdflags
*);
66 static const char *ether_string(u_int8_t
*);
67 static void parse_args(int *, char ***, struct cmdflags
*);
68 static void print_capinfo(u_int16_t
);
69 static void print_channel(u_int16_t
, u_int16_t
, u_int16_t
);
70 static void print_node_flags(u_int32_t
);
71 static void print_rateset(struct ieee80211_rateset
*, int);
72 static void usage(void);
75 print_rateset(struct ieee80211_rateset
*rs
, int txrate
)
78 const char *fmt
, *basic
;
82 for (i
= 0; i
< rs
->rs_nrates
; i
++) {
84 if ((rs
->rs_rates
[i
] & IEEE80211_RATE_BASIC
) != 0)
92 rate
= 5 * (rs
->rs_rates
[i
] & IEEE80211_RATE_VAL
);
93 printf(fmt
, basic
, rate
/ 10, rate
% 10);
99 print_flags(u_int32_t flags
, const struct flagname
*flagnames
, u_int nname
)
105 for (i
= 0; i
< nname
; i
++) {
106 if ((flags
& flagnames
[i
].fn_flag
) != 0) {
107 printf("%s%s", delim
, flagnames
[i
].fn_name
);
112 printf("%s\n", (delim
[0] == '<') ? "" : ">");
116 print_node_flags(u_int32_t flags
)
118 static const struct flagname nodeflags
[] = {
119 {IEEE80211_NODE_SYSCTL_F_BSS
, "bss"}
120 , {IEEE80211_NODE_SYSCTL_F_STA
, "sta"}
121 , {IEEE80211_NODE_SYSCTL_F_SCAN
, "scan"}
123 printf("\tnode flags %04x", flags
);
125 print_flags(flags
, nodeflags
, __arraycount(nodeflags
));
129 print_capinfo(u_int16_t capinfo
)
131 static const struct flagname capflags
[] = {
132 {IEEE80211_CAPINFO_ESS
, "ess"},
133 {IEEE80211_CAPINFO_IBSS
, "ibss"},
134 {IEEE80211_CAPINFO_CF_POLLABLE
, "cf pollable"},
135 {IEEE80211_CAPINFO_CF_POLLREQ
, "request cf poll"},
136 {IEEE80211_CAPINFO_PRIVACY
, "privacy"},
137 {IEEE80211_CAPINFO_SHORT_PREAMBLE
, "short preamble"},
138 {IEEE80211_CAPINFO_PBCC
, "pbcc"},
139 {IEEE80211_CAPINFO_CHNL_AGILITY
, "channel agility"},
140 {IEEE80211_CAPINFO_SHORT_SLOTTIME
, "short slot-time"},
141 {IEEE80211_CAPINFO_RSN
, "rsn"},
142 {IEEE80211_CAPINFO_DSSSOFDM
, "dsss-ofdm"}
145 printf("\tcapabilities %04x", capinfo
);
147 print_flags(capinfo
, capflags
, __arraycount(capflags
));
151 ether_string(u_int8_t
*addr
)
153 struct ether_addr ea
;
154 (void)memcpy(ea
.ether_addr_octet
, addr
, sizeof(ea
.ether_addr_octet
));
155 return ether_ntoa(&ea
);
159 print_channel(u_int16_t chanidx
, u_int16_t freq
, u_int16_t flags
)
161 static const struct flagname chanflags
[] = {
162 {IEEE80211_CHAN_TURBO
, "turbo"},
163 {IEEE80211_CHAN_CCK
, "cck"},
164 {IEEE80211_CHAN_OFDM
, "ofdm"},
165 {IEEE80211_CHAN_2GHZ
, "2.4GHz"},
166 {IEEE80211_CHAN_5GHZ
, "5GHz"},
167 {IEEE80211_CHAN_PASSIVE
, "passive scan"},
168 {IEEE80211_CHAN_DYN
, "dynamic cck-ofdm"},
169 {IEEE80211_CHAN_GFSK
, "gfsk"}
171 printf("\tchan %d freq %dMHz flags %04x", chanidx
, freq
, flags
);
173 print_flags(flags
, chanflags
, __arraycount(chanflags
));
178 * ifname: dump nodes belonging to the given interface, or belonging
179 * to all interfaces if NULL
180 * hdr_type: header type: IEEE80211_SYSCTL_T_NODE -> generic node,
181 * IEEE80211_SYSCTL_T_RSSADAPT -> rssadapt(9) info,
182 * IEEE80211_SYSCTL_T_DRVSPEC -> driver specific.
183 * cf: command flags, cf_v != 0 -> verbose
186 dump_nodes(const char *ifname_arg
, int hdr_type
, struct cmdflags
*cf
)
189 /*39*/ u_int8_t ns_erp
; /* 11g only */
190 /*40*/ u_int32_t ns_rstamp
; /* recv timestamp */
191 /*64*/ u_int16_t ns_fhdwell
; /* FH only */
192 /*66*/ u_int8_t ns_fhindex
; /* FH only */
196 size_t namelen
, nodes_len
, totallen
;
199 char ifname
[IFNAMSIZ
];
200 struct ieee80211_node_sysctl
*pns
, *ns
;
203 namelen
= __arraycount(name
);
205 if (sysctlnametomib("net.link.ieee80211.nodes", &name
[0],
207 warn("sysctlnametomib");
211 if (ifname_arg
== NULL
)
213 else if ((ifindex
= if_nametoindex(ifname_arg
)) == 0) {
214 warn("if_nametoindex");
218 totallen
= namelen
+ IEEE80211_SYSCTL_NODENAMELEN
;
219 if (totallen
>= __arraycount(name
)) {
220 warnx("Internal error finding sysctl mib");
223 vname
= &name
[namelen
];
225 vname
[IEEE80211_SYSCTL_NODENAME_IF
] = ifindex
;
226 vname
[IEEE80211_SYSCTL_NODENAME_OP
] = IEEE80211_SYSCTL_OP_ALL
;
227 vname
[IEEE80211_SYSCTL_NODENAME_ARG
] = 0;
228 vname
[IEEE80211_SYSCTL_NODENAME_TYPE
] = hdr_type
;
229 vname
[IEEE80211_SYSCTL_NODENAME_ELTSIZE
] = sizeof(*ns
);
230 vname
[IEEE80211_SYSCTL_NODENAME_ELTCOUNT
] = INT_MAX
;
233 if (sysctl(name
, totallen
, NULL
, &nodes_len
, NULL
, 0) != 0) {
234 warn("sysctl(count)");
238 ns
= malloc(nodes_len
);
245 vname
[IEEE80211_SYSCTL_NODENAME_ELTCOUNT
] = nodes_len
/ sizeof(ns
[0]);
248 if (sysctl(name
, totallen
, ns
, &nodes_len
, NULL
, 0) != 0) {
253 for (i
= 0; i
< nodes_len
/ sizeof(ns
[0]); i
++) {
255 if (if_indextoname(pns
->ns_ifindex
, ifname
) == NULL
) {
256 warn("if_indextoname");
259 if (cf
->cf_p
&& (pns
->ns_capinfo
& IEEE80211_CAPINFO_PRIVACY
))
261 printf("%s: mac %s ", ifname
, ether_string(pns
->ns_macaddr
));
262 printf("bss %s\n", ether_string(pns
->ns_bssid
));
263 print_node_flags(pns
->ns_flags
);
265 /* TBD deal with binary ESSID */
266 printf("\tess <%.*s>\n", pns
->ns_esslen
, pns
->ns_essid
);
268 print_channel(pns
->ns_chanidx
, pns
->ns_freq
, pns
->ns_chanflags
);
270 print_capinfo(pns
->ns_capinfo
);
272 assert(sizeof(ts
) == sizeof(pns
->ns_tstamp
));
273 memcpy(&ts
, &pns
->ns_tstamp
[0], sizeof(ts
));
274 printf("\tbeacon-interval %d TU tsft %" PRIu64
" us\n",
275 pns
->ns_intval
, (u_int64_t
)le64toh(ts
));
277 print_rateset(&pns
->ns_rates
, pns
->ns_txrate
);
279 printf("\tassoc-id %d assoc-failed %d inactivity %ds\n",
280 pns
->ns_associd
, pns
->ns_fails
, pns
->ns_inact
);
282 printf("\trssi %d txseq %d rxseq %d\n",
283 pns
->ns_rssi
, pns
->ns_txseq
, pns
->ns_rxseq
);
291 fprintf(stderr
, "usage: %s [ -p ] [ -v ] -a\n"
292 "\t[ -v ] interface [ interface ... ]\n", getprogname());
297 parse_args(int *argcp
, char ***argvp
, struct cmdflags
*cf
)
301 (void)memset(cf
, 0, sizeof(*cf
));
303 while ((ch
= getopt(*argcp
, *argvp
, "apv")) != -1) {
315 warnx("unknown option -%c", ch
);
324 #define LOGICAL_XOR(x, y) (!(x) != !(y))
327 main(int argc
, char **argv
)
332 parse_args(&argc
, &argv
, &cf
);
334 if (!LOGICAL_XOR(argc
> 0, cf
.cf_a
))
338 if (dump_nodes(NULL
, IEEE80211_SYSCTL_T_NODE
, &cf
) != 0)
342 for (i
= 0; i
< argc
; i
++) {
343 if (dump_nodes(argv
[i
], IEEE80211_SYSCTL_T_NODE
, &cf
) != 0)