wlanstats.c revision 153392
1153317Ssam/*-
2153317Ssam * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3153317Ssam * All rights reserved.
4153317Ssam *
5153317Ssam * Redistribution and use in source and binary forms, with or without
6153317Ssam * modification, are permitted provided that the following conditions
7153317Ssam * are met:
8153317Ssam * 1. Redistributions of source code must retain the above copyright
9153317Ssam *    notice, this list of conditions and the following disclaimer,
10153317Ssam *    without modification.
11153317Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12153317Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13153317Ssam *    redistribution must be conditioned upon including a substantially
14153317Ssam *    similar Disclaimer requirement for further binary redistribution.
15153317Ssam * 3. Neither the names of the above-listed copyright holders nor the names
16153317Ssam *    of any contributors may be used to endorse or promote products derived
17153317Ssam *    from this software without specific prior written permission.
18153317Ssam *
19153317Ssam * Alternatively, this software may be distributed under the terms of the
20153317Ssam * GNU General Public License ("GPL") version 2 as published by the Free
21153317Ssam * Software Foundation.
22153317Ssam *
23153317Ssam * NO WARRANTY
24153317Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25153317Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26153317Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27153317Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28153317Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29153317Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30153317Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31153317Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32153317Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33153317Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34153317Ssam * THE POSSIBILITY OF SUCH DAMAGES.
35153317Ssam *
36153317Ssam * $FreeBSD: head/tools/tools/net80211/wlanstats/wlanstats.c 153392 2005-12-13 22:15:09Z sam $
37153317Ssam */
38153317Ssam
39153317Ssam/*
40153317Ssam * wlanstats [-i interface]
41153317Ssam * (default interface is ath0).
42153317Ssam */
43153317Ssam#include <sys/types.h>
44153317Ssam#include <sys/file.h>
45153317Ssam#include <sys/sockio.h>
46153317Ssam#include <sys/socket.h>
47153317Ssam#include <net/if.h>
48153317Ssam#include <net/if_media.h>
49153317Ssam#include <net/if_var.h>
50153317Ssam#include <net/ethernet.h>
51153317Ssam
52153317Ssam#include <stdio.h>
53153317Ssam#include <signal.h>
54153317Ssam#include <unistd.h>
55153317Ssam#include <err.h>
56153317Ssam
57153392Ssam#include "../../../../sys/net80211/ieee80211_ioctl.h"
58153317Ssam
59153317Ssamconst char *progname;
60153317Ssam
61153317Ssamstatic void
62153317Ssamprintstats(FILE *fd, const struct ieee80211_stats *stats)
63153317Ssam{
64153317Ssam#define	N(a)	(sizeof(a) / sizeof(a[0]))
65153317Ssam#define	STAT(x,fmt) \
66153317Ssam	if (stats->is_##x) fprintf(fd, "%u " fmt "\n", stats->is_##x)
67153317Ssam	STAT(rx_badversion,	"rx frame with bad version");
68153317Ssam	STAT(rx_tooshort,	"rx frame too short");
69153317Ssam	STAT(rx_wrongbss,	"rx from wrong bssid");
70153317Ssam	STAT(rx_dup,		"rx discard 'cuz dup");
71153317Ssam	STAT(rx_wrongdir,	"rx w/ wrong direction");
72153317Ssam	STAT(rx_mcastecho,	"rx discard 'cuz mcast echo");
73153317Ssam	STAT(rx_notassoc,	"rx discard 'cuz sta !assoc");
74153317Ssam	STAT(rx_noprivacy,	"rx w/ wep but privacy off");
75153317Ssam	STAT(rx_unencrypted,	"rx w/o wep and privacy on");
76153317Ssam	STAT(rx_wepfail,	"rx wep processing failed");
77153317Ssam	STAT(rx_decap,		"rx decapsulation failed");
78153317Ssam	STAT(rx_mgtdiscard,	"rx discard mgt frames");
79153317Ssam	STAT(rx_ctl,		"rx discard ctrl frames");
80153317Ssam	STAT(rx_beacon,		"rx beacon frames");
81153317Ssam	STAT(rx_rstoobig,	"rx rate set truncated");
82153317Ssam	STAT(rx_elem_missing,	"rx required element missing");
83153317Ssam	STAT(rx_elem_toobig,	"rx element too big");
84153317Ssam	STAT(rx_elem_toosmall,	"rx element too small");
85153317Ssam	STAT(rx_elem_unknown,	"rx element unknown");
86153317Ssam	STAT(rx_badchan,	"rx frame w/ invalid chan");
87153317Ssam	STAT(rx_chanmismatch,	"rx frame chan mismatch");
88153317Ssam	STAT(rx_nodealloc,	"nodes allocated (rx)");
89153317Ssam	STAT(rx_ssidmismatch,	"rx frame ssid mismatch");
90153317Ssam	STAT(rx_auth_unsupported,"rx w/ unsupported auth alg");
91153317Ssam	STAT(rx_auth_fail,	"rx sta auth failure");
92153317Ssam	STAT(rx_auth_countermeasures,
93153317Ssam		"rx sta auth failure 'cuz of TKIP countermeasures");
94153317Ssam	STAT(rx_assoc_bss,	"rx assoc from wrong bssid");
95153317Ssam	STAT(rx_assoc_notauth,	"rx assoc w/o auth");
96153317Ssam	STAT(rx_assoc_capmismatch,"rx assoc w/ cap mismatch");
97153317Ssam	STAT(rx_assoc_norate,	"rx assoc w/ no rate match");
98153317Ssam	STAT(rx_assoc_badwpaie,	"rx assoc w/ bad WPA IE");
99153317Ssam	STAT(rx_deauth,		"rx deauthentication");
100153317Ssam	STAT(rx_disassoc,	"rx disassociation");
101153317Ssam	STAT(rx_badsubtype,	"rx frame w/ unknown subtype");
102153317Ssam	STAT(rx_nobuf,		"rx failed for lack of sk_buffer");
103153317Ssam	STAT(rx_decryptcrc,	"rx decrypt failed on crc");
104153317Ssam	STAT(rx_ahdemo_mgt,
105153317Ssam		"rx discard mgmt frame received in ahdoc demo mode");
106153317Ssam	STAT(rx_bad_auth,	"rx bad authentication request");
107153317Ssam	STAT(rx_unauth,		"rx discard 'cuz port unauthorized");
108153317Ssam	STAT(rx_badkeyid,	"rx w/ incorrect keyid");
109153317Ssam	STAT(rx_ccmpreplay,	"rx seq# violation (CCMP)");
110153317Ssam	STAT(rx_ccmpformat,	"rx format bad (CCMP)");
111153317Ssam	STAT(rx_ccmpmic,	"rx MIC check failed (CCMP)");
112153317Ssam	STAT(rx_tkipreplay,	"rx seq# violation (TKIP)");
113153317Ssam	STAT(rx_tkipformat,	"rx format bad (TKIP)");
114153317Ssam	STAT(rx_tkipmic,	"rx MIC check failed (TKIP)");
115153317Ssam	STAT(rx_tkipicv,	"rx ICV check failed (TKIP)");
116153317Ssam	STAT(rx_badcipher,	"rx failed 'cuz bad cipher/key type");
117153317Ssam	STAT(rx_nocipherctx,	"rx failed 'cuz key/cipher ctx not setup");
118153317Ssam	STAT(rx_acl,		"rx discard 'cuz acl policy");
119153317Ssam	STAT(tx_nobuf,		"tx failed for lack of sk_buffer");
120153317Ssam	STAT(tx_nonode,		"tx failed for no node");
121153317Ssam	STAT(tx_unknownmgt,	"tx of unknown mgt frame");
122153317Ssam	STAT(tx_badcipher,	"tx failed 'cuz bad ciper/key type");
123153317Ssam	STAT(tx_nodefkey,	"tx failed 'cuz no defkey");
124153317Ssam	STAT(tx_noheadroom,	"tx failed 'cuz no space for crypto hdrs");
125153317Ssam	STAT(tx_fragframes,	"tx frames fragmented");
126153317Ssam	STAT(tx_frags,		"tx frags generated");
127153317Ssam	STAT(scan_active,	"active scans started");
128153317Ssam	STAT(scan_passive,	"passive scans started");
129153317Ssam	STAT(node_timeout,	"nodes timed out inactivity");
130153317Ssam	STAT(crypto_nomem,	"cipher context malloc failed");
131153317Ssam	STAT(crypto_tkip,	"tkip crypto done in s/w");
132153317Ssam	STAT(crypto_tkipenmic,	"tkip tx MIC done in s/w");
133153317Ssam	STAT(crypto_tkipdemic,	"tkip rx MIC done in s/w");
134153317Ssam	STAT(crypto_tkipcm,	"tkip dropped frames 'cuz of countermeasures");
135153317Ssam	STAT(crypto_ccmp,	"ccmp crypto done in s/w");
136153317Ssam	STAT(crypto_wep,	"wep crypto done in s/w");
137153317Ssam	STAT(crypto_setkey_cipher,"setkey failed 'cuz cipher rejected data");
138153317Ssam	STAT(crypto_setkey_nokey,"setkey failed 'cuz no key index");
139153317Ssam	STAT(crypto_delkey,	"driver key delete failed");
140153317Ssam	STAT(crypto_badcipher,	"setkey failed 'cuz unknown cipher");
141153317Ssam	STAT(crypto_nocipher,	"setkey failed 'cuz cipher module unavailable");
142153317Ssam	STAT(crypto_attachfail,	"setkey failed 'cuz cipher attach failed");
143153317Ssam	STAT(crypto_swfallback,	"crypto fell back to s/w implementation");
144153317Ssam	STAT(crypto_keyfail,	"setkey failed 'cuz driver key alloc failed");
145153317Ssam	STAT(crypto_enmicfail,	"enmic failed (may be mbuf exhaustion)");
146153317Ssam	STAT(ibss_capmismatch,	"ibss merge faied 'cuz capabilities mismatch");
147153317Ssam	STAT(ibss_norate,	"ibss merge faied 'cuz rate set mismatch");
148153317Ssam	STAT(ps_unassoc,	"ps-poll received for unassociated station");
149153317Ssam	STAT(ps_badaid,		"ps-poll received with invalid association id");
150153317Ssam	STAT(ps_qempty,		"ps-poll received with nothing to send");
151153317Ssam	STAT(ff_badhdr,		"fast frame rx'd w/ bad hdr");
152153317Ssam	STAT(ff_tooshort,	"fast frame rx decap error");
153153317Ssam	STAT(ff_split,		"fast frame rx split error");
154153317Ssam	STAT(ff_decap,		"fast frames decap'd");
155153317Ssam	STAT(ff_encap,		"fast frames encap'd for tx");
156153317Ssam#undef STAT
157153317Ssam#undef N
158153317Ssam}
159153317Ssam
160153317Ssamstruct ifreq ifr;
161153317Ssamint	s;
162153317Ssam
163153317Ssamstatic void
164153317Ssamprint_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN])
165153317Ssam{
166153317Ssam#define	STAT(x,fmt) \
167153317Ssam	if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; }
168153317Ssam	struct ieee80211req ireq;
169153317Ssam	struct ieee80211req_sta_stats stats;
170153317Ssam	const struct ieee80211_nodestats *ns = &stats.is_stats;
171153317Ssam	const char *sep;
172153317Ssam
173153317Ssam	(void) memset(&ireq, 0, sizeof(ireq));
174153317Ssam	(void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name));
175153317Ssam	ireq.i_type = IEEE80211_IOC_STA_STATS;
176153317Ssam	ireq.i_data = &stats;
177153317Ssam	ireq.i_len = sizeof(stats);
178153317Ssam	memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN);
179153317Ssam	if (ioctl(s, SIOCG80211, &ireq) < 0)
180153317Ssam		err(1, "unable to get station stats for %s",
181153317Ssam			ether_ntoa((const struct ether_addr*) macaddr));
182153317Ssam
183153317Ssam	fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr));
184153317Ssam
185153317Ssam	sep = "\t";
186153317Ssam	STAT(rx_data, "%u");
187153317Ssam	STAT(rx_mgmt, "%u");
188153317Ssam	STAT(rx_ctrl, "%u");
189153317Ssam	STAT(rx_beacons, "%u");
190153317Ssam	STAT(rx_proberesp, "%u");
191153317Ssam	STAT(rx_ucast, "%u");
192153317Ssam	STAT(rx_mcast, "%u");
193153317Ssam	STAT(rx_bytes, "%llu");
194153317Ssam	STAT(rx_dup, "%u");
195153317Ssam	STAT(rx_noprivacy, "%u");
196153317Ssam	STAT(rx_wepfail, "%u");
197153317Ssam	STAT(rx_demicfail, "%u");
198153317Ssam	STAT(rx_decap, "%u");
199153317Ssam	STAT(rx_defrag, "%u");
200153317Ssam	STAT(rx_disassoc, "%u");
201153317Ssam	STAT(rx_deauth, "%u");
202153317Ssam	STAT(rx_decryptcrc, "%u");
203153317Ssam	STAT(rx_unauth, "%u");
204153317Ssam	STAT(rx_unencrypted, "%u");
205153317Ssam	fprintf(fd, "\n");
206153317Ssam
207153317Ssam	sep = "\t";
208153317Ssam	STAT(tx_data, "%u");
209153317Ssam	STAT(tx_mgmt, "%u");
210153317Ssam	STAT(tx_probereq, "%u");
211153317Ssam	STAT(tx_ucast, "%u");
212153317Ssam	STAT(tx_mcast, "%u");
213153317Ssam	STAT(tx_bytes, "%llu");
214153317Ssam	STAT(tx_novlantag, "%u");
215153317Ssam	STAT(tx_vlanmismatch, "%u");
216153317Ssam	fprintf(fd, "\n");
217153317Ssam
218153317Ssam	sep = "\t";
219153317Ssam	STAT(tx_assoc, "%u");
220153317Ssam	STAT(tx_assoc_fail, "%u");
221153317Ssam	STAT(tx_auth, "%u");
222153317Ssam	STAT(tx_auth_fail, "%u");
223153317Ssam	STAT(tx_deauth, "%u");
224153317Ssam	STAT(tx_deauth_code, "%llu");
225153317Ssam	STAT(tx_disassoc, "%u");
226153317Ssam	STAT(tx_disassoc_code, "%u");
227153317Ssam	fprintf(fd, "\n");
228153317Ssam
229153317Ssam#undef STAT
230153317Ssam}
231153317Ssam
232153317Ssamint
233153317Ssammain(int argc, char *argv[])
234153317Ssam{
235153317Ssam	int c, len;
236153317Ssam	struct ieee80211req_sta_info *si;
237153317Ssam	uint8_t buf[24*1024], *cp;
238153317Ssam	struct ieee80211req ireq;
239153317Ssam	int allnodes = 0;
240153317Ssam
241153317Ssam	progname = argv[0];
242153317Ssam
243153317Ssam	s = socket(AF_INET, SOCK_DGRAM, 0);
244153317Ssam	if (s < 0)
245153317Ssam		err(1, "socket");
246153317Ssam	strncpy(ifr.ifr_name, "ath0", sizeof (ifr.ifr_name));
247153317Ssam	while ((c = getopt(argc, argv, "ai:")) != -1)
248153317Ssam		switch (c) {
249153317Ssam		case 'a':
250153317Ssam			allnodes++;
251153317Ssam			break;
252153317Ssam		case 'i':
253153317Ssam			strncpy(ifr.ifr_name, optarg, sizeof (ifr.ifr_name));
254153317Ssam			break;
255153317Ssam		default:
256153317Ssam			errx(1, "usage: %s [-a] [-i device] [mac...]\n", progname);
257153317Ssam			/*NOTREACHED*/
258153317Ssam		}
259153317Ssam
260153317Ssam	if (argc == optind && !allnodes) {
261153317Ssam		struct ieee80211_stats stats;
262153317Ssam
263153317Ssam		/* no args, just show global stats */
264153317Ssam		ifr.ifr_data = (caddr_t) &stats;
265153317Ssam		if (ioctl(s, SIOCG80211STATS, &ifr) < 0)
266153317Ssam			err(1, ifr.ifr_name);
267153317Ssam		printstats(stdout, &stats);
268153317Ssam		return 0;
269153317Ssam	}
270153317Ssam	if (allnodes) {
271153317Ssam		/*
272153317Ssam		 * Retrieve station/neighbor table and print stats for each.
273153317Ssam		 */
274153317Ssam		(void) memset(&ireq, 0, sizeof(ireq));
275153317Ssam		(void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name));
276153317Ssam		ireq.i_type = IEEE80211_IOC_STA_INFO;
277153317Ssam		ireq.i_data = buf;
278153317Ssam		ireq.i_len = sizeof(buf);
279153317Ssam		if (ioctl(s, SIOCG80211, &ireq) < 0)
280153317Ssam			err(1, "unable to get station information");
281153317Ssam		len = ireq.i_len;
282153317Ssam		if (len >= sizeof(struct ieee80211req_sta_info)) {
283153317Ssam			cp = buf;
284153317Ssam			do {
285153317Ssam				si = (struct ieee80211req_sta_info *) cp;
286153317Ssam				print_sta_stats(stdout, si->isi_macaddr);
287153317Ssam				cp += si->isi_len, len -= si->isi_len;
288153317Ssam			} while (len >= sizeof(struct ieee80211req_sta_info));
289153317Ssam		}
290153317Ssam	} else {
291153317Ssam		/*
292153317Ssam		 * Print stats for specified stations.
293153317Ssam		 */
294153317Ssam		for (c = optind; c < argc; c++) {
295153317Ssam			const struct ether_addr *ea = ether_aton(argv[c]);
296153317Ssam			if (ea != NULL)
297153317Ssam				print_sta_stats(stdout, ea->octet);
298153317Ssam		}
299153317Ssam	}
300153317Ssam}
301