athstats.c revision 160993
1/*-
2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 *    redistribution must be conditioned upon including a substantially
14 *    similar Disclaimer requirement for further binary redistribution.
15 * 3. Neither the names of the above-listed copyright holders nor the names
16 *    of any contributors may be used to endorse or promote products derived
17 *    from this software without specific prior written permission.
18 *
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
22 *
23 * NO WARRANTY
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34 * THE POSSIBILITY OF SUCH DAMAGES.
35 *
36 * $FreeBSD: head/tools/tools/ath/athstats/athstats.c 160993 2006-08-05 05:09:20Z sam $
37 */
38
39/*
40 * Simple Atheros-specific tool to inspect and monitor network traffic
41 * statistics.
42 *	athstats [-i interface] [interval]
43 * (default interface is ath0).  If interval is specified a rolling output
44 * a la netstat -i is displayed every interval seconds.
45 *
46 * To build: cc -o athstats athstats.c -lkvm
47 */
48#include <sys/types.h>
49#include <sys/file.h>
50#include <sys/sockio.h>
51#include <sys/socket.h>
52#include <net/if.h>
53#include <net/if_media.h>
54#include <net/if_var.h>
55
56#include <stdio.h>
57#include <signal.h>
58
59#include "../../../../sys/contrib/dev/ath/ah_desc.h"
60#include "../../../../sys/net80211/ieee80211_ioctl.h"
61#include "../../../../sys/net80211/ieee80211_radiotap.h"
62#include "../../../../sys/dev/ath/if_athioctl.h"
63
64static const struct {
65	u_int		phyerr;
66	const char*	desc;
67} phyerrdescriptions[] = {
68	{ HAL_PHYERR_UNDERRUN,		"transmit underrun" },
69	{ HAL_PHYERR_TIMING,		"timing error" },
70	{ HAL_PHYERR_PARITY,		"illegal parity" },
71	{ HAL_PHYERR_RATE,		"illegal rate" },
72	{ HAL_PHYERR_LENGTH,		"illegal length" },
73	{ HAL_PHYERR_RADAR,		"radar detect" },
74	{ HAL_PHYERR_SERVICE,		"illegal service" },
75	{ HAL_PHYERR_TOR,		"transmit override receive" },
76	{ HAL_PHYERR_OFDM_TIMING,	"OFDM timing" },
77	{ HAL_PHYERR_OFDM_SIGNAL_PARITY,"OFDM illegal parity" },
78	{ HAL_PHYERR_OFDM_RATE_ILLEGAL,	"OFDM illegal rate" },
79	{ HAL_PHYERR_OFDM_POWER_DROP,	"OFDM power drop" },
80	{ HAL_PHYERR_OFDM_SERVICE,	"OFDM illegal service" },
81	{ HAL_PHYERR_OFDM_RESTART,	"OFDM restart" },
82	{ HAL_PHYERR_CCK_TIMING,	"CCK timing" },
83	{ HAL_PHYERR_CCK_HEADER_CRC,	"CCK header crc" },
84	{ HAL_PHYERR_CCK_RATE_ILLEGAL,	"CCK illegal rate" },
85	{ HAL_PHYERR_CCK_SERVICE,	"CCK illegal service" },
86	{ HAL_PHYERR_CCK_RESTART,	"CCK restart" },
87};
88
89static void
90printstats(FILE *fd, const struct ath_stats *stats)
91{
92#define	N(a)	(sizeof(a) / sizeof(a[0]))
93#define	STAT(x,fmt) \
94	if (stats->ast_##x) fprintf(fd, "%u " fmt "\n", stats->ast_##x)
95	int i, j;
96
97	STAT(watchdog, "watchdog timeouts");
98	STAT(hardware, "hardware error interrupts");
99	STAT(bmiss, "beacon miss interrupts");
100	STAT(bstuck, "stuck beacon conditions");
101	STAT(rxorn, "recv overrun interrupts");
102	STAT(rxeol, "recv eol interrupts");
103	STAT(txurn, "txmit underrun interrupts");
104	STAT(mib, "mib overflow interrupts");
105	STAT(intrcoal, "interrupts coalesced");
106	STAT(tx_mgmt, "tx management frames");
107	STAT(tx_discard, "tx frames discarded prior to association");
108	STAT(tx_qstop, "tx stopped 'cuz no xmit buffer");
109	STAT(tx_encap, "tx encapsulation failed");
110	STAT(tx_nonode, "tx failed 'cuz no node");
111	STAT(tx_nombuf, "tx failed 'cuz no mbuf");
112	STAT(tx_nomcl, "tx failed 'cuz no cluster");
113	STAT(tx_linear, "tx linearized to cluster");
114	STAT(tx_nodata, "tx discarded empty frame");
115	STAT(tx_busdma, "tx failed for dma resrcs");
116	STAT(tx_xretries, "tx failed 'cuz too many retries");
117	STAT(tx_fifoerr, "tx failed 'cuz FIFO underrun");
118	STAT(tx_filtered, "tx failed 'cuz xmit filtered");
119	STAT(tx_shortretry, "short on-chip tx retries");
120	STAT(tx_longretry, "long on-chip tx retries");
121	STAT(tx_badrate, "tx failed 'cuz bogus xmit rate");
122	STAT(tx_noack, "tx frames with no ack marked");
123	STAT(tx_rts, "tx frames with rts enabled");
124	STAT(tx_cts, "tx frames with cts enabled");
125	STAT(tx_shortpre, "tx frames with short preamble");
126	STAT(tx_altrate, "tx frames with an alternate rate");
127	STAT(tx_protect, "tx frames with 11g protection");
128	STAT(tx_raw, "tx frames through raw api");
129	STAT(rx_nombuf,	"rx setup failed 'cuz no mbuf");
130	STAT(rx_busdma,	"rx setup failed for dma resrcs");
131	STAT(rx_orn, "rx failed 'cuz of desc overrun");
132	STAT(rx_crcerr, "rx failed 'cuz of bad CRC");
133	STAT(rx_fifoerr, "rx failed 'cuz of FIFO overrun");
134	STAT(rx_badcrypt, "rx failed 'cuz decryption");
135	STAT(rx_badmic, "rx failed 'cuz MIC failure");
136	STAT(rx_tooshort, "rx failed 'cuz frame too short");
137	STAT(rx_toobig, "rx failed 'cuz frame too large");
138	STAT(rx_mgt, "rx management frames");
139	STAT(rx_ctl, "rx control frames");
140	STAT(rx_phyerr, "rx failed 'cuz of PHY err");
141	if (stats->ast_rx_phyerr != 0) {
142		for (i = 0; i < 32; i++) {
143			if (stats->ast_rx_phy[i] == 0)
144				continue;
145			for (j = 0; j < N(phyerrdescriptions); j++)
146				if (phyerrdescriptions[j].phyerr == i)
147					break;
148			if (j == N(phyerrdescriptions))
149				fprintf(fd,
150					"    %u (unknown phy error code %u)\n",
151					stats->ast_rx_phy[i], i);
152			else
153				fprintf(fd, "    %u %s\n",
154					stats->ast_rx_phy[i],
155					phyerrdescriptions[j].desc);
156		}
157	}
158	STAT(be_nombuf,	"beacon setup failed 'cuz no mbuf");
159	STAT(be_xmit,	"beacons transmitted");
160	STAT(cabq_xmit,	"cabq frames transmitted");
161	STAT(cabq_busy,	"cabq xmit overflowed beacon interval");
162	STAT(per_cal, "periodic calibrations");
163	STAT(per_calfail, "periodic calibration failures");
164	STAT(per_rfgain, "rfgain value change");
165	STAT(rate_calls, "rate control checks");
166	STAT(rate_raise, "rate control raised xmit rate");
167	STAT(rate_drop, "rate control dropped xmit rate");
168	if (stats->ast_tx_rssi)
169		fprintf(fd, "rssi of last ack: %u\n", stats->ast_tx_rssi);
170	if (stats->ast_rx_rssi)
171		fprintf(fd, "avg recv rssi: %u\n", stats->ast_rx_rssi);
172	STAT(ant_defswitch, "switched default/rx antenna");
173	STAT(ant_txswitch, "tx used alternate antenna");
174	fprintf(fd, "Antenna profile:\n");
175	for (i = 0; i < 8; i++)
176		if (stats->ast_ant_rx[i] || stats->ast_ant_tx[i])
177			fprintf(fd, "[%u] tx %8u rx %8u\n", i,
178				stats->ast_ant_tx[i], stats->ast_ant_rx[i]);
179#undef STAT
180#undef N
181}
182
183static u_int
184getifrate(int s, const char* ifname)
185{
186#define	N(a)	(sizeof(a) / sizeof(a[0]))
187	static const int rates[] = {
188		0,		/* IFM_AUTO */
189		0,		/* IFM_MANUAL */
190		0,		/* IFM_NONE */
191		1,		/* IFM_IEEE80211_FH1 */
192		2,		/* IFM_IEEE80211_FH2 */
193		1,		/* IFM_IEEE80211_DS1 */
194		2,		/* IFM_IEEE80211_DS2 */
195		5,		/* IFM_IEEE80211_DS5 */
196		11,		/* IFM_IEEE80211_DS11 */
197		22,		/* IFM_IEEE80211_DS22 */
198		6,		/* IFM_IEEE80211_OFDM6 */
199		9,		/* IFM_IEEE80211_OFDM9 */
200		12,		/* IFM_IEEE80211_OFDM12 */
201		18,		/* IFM_IEEE80211_OFDM18 */
202		24,		/* IFM_IEEE80211_OFDM24 */
203		36,		/* IFM_IEEE80211_OFDM36 */
204		48,		/* IFM_IEEE80211_OFDM48 */
205		54,		/* IFM_IEEE80211_OFDM54 */
206		72,		/* IFM_IEEE80211_OFDM72 */
207	};
208	struct ifmediareq ifmr;
209	int *media_list, i;
210
211	(void) memset(&ifmr, 0, sizeof(ifmr));
212	(void) strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
213
214	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
215		return 0;
216	return IFM_SUBTYPE(ifmr.ifm_active) < N(rates) ?
217		rates[IFM_SUBTYPE(ifmr.ifm_active)] : 0;
218#undef N
219}
220
221static int signalled;
222
223static void
224catchalarm(int signo __unused)
225{
226	signalled = 1;
227}
228
229int
230main(int argc, char *argv[])
231{
232	int s;
233	struct ifreq ifr;
234
235	s = socket(AF_INET, SOCK_DGRAM, 0);
236	if (s < 0)
237		err(1, "socket");
238	if (argc > 1 && strcmp(argv[1], "-i") == 0) {
239		if (argc < 2) {
240			fprintf(stderr, "%s: missing interface name for -i\n",
241				argv[0]);
242			exit(-1);
243		}
244		strncpy(ifr.ifr_name, argv[2], sizeof (ifr.ifr_name));
245		argc -= 2, argv += 2;
246	} else
247		strncpy(ifr.ifr_name, "ath0", sizeof (ifr.ifr_name));
248	if (argc > 1) {
249		u_long interval = strtoul(argv[1], NULL, 0);
250		int line, omask;
251		u_int rate = getifrate(s, ifr.ifr_name);
252		struct ath_stats cur, total;
253
254		if (interval < 1)
255			interval = 1;
256		signal(SIGALRM, catchalarm);
257		signalled = 0;
258		alarm(interval);
259	banner:
260		printf("%8s %8s %7s %7s %7s %6s %6s %5s %7s %4s %4s"
261			, "input"
262			, "output"
263			, "altrate"
264			, "short"
265			, "long"
266			, "xretry"
267			, "crcerr"
268			, "crypt"
269			, "phyerr"
270			, "rssi"
271			, "rate"
272		);
273		putchar('\n');
274		fflush(stdout);
275		line = 0;
276	loop:
277		if (line != 0) {
278			ifr.ifr_data = (caddr_t) &cur;
279			if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
280				err(1, ifr.ifr_name);
281			rate = getifrate(s, ifr.ifr_name);
282			printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n"
283				, cur.ast_rx_packets - total.ast_rx_packets
284				, cur.ast_tx_packets - total.ast_tx_packets
285				, cur.ast_tx_altrate - total.ast_tx_altrate
286				, cur.ast_tx_shortretry - total.ast_tx_shortretry
287				, cur.ast_tx_longretry - total.ast_tx_longretry
288				, cur.ast_tx_xretries - total.ast_tx_xretries
289				, cur.ast_rx_crcerr - total.ast_rx_crcerr
290				, cur.ast_rx_badcrypt - total.ast_rx_badcrypt
291				, cur.ast_rx_phyerr - total.ast_rx_phyerr
292				, cur.ast_rx_rssi
293				, rate
294			);
295			total = cur;
296		} else {
297			ifr.ifr_data = (caddr_t) &total;
298			if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
299				err(1, ifr.ifr_name);
300			rate = getifrate(s, ifr.ifr_name);
301			printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n"
302				, total.ast_rx_packets
303				, total.ast_tx_packets
304				, total.ast_tx_altrate
305				, total.ast_tx_shortretry
306				, total.ast_tx_longretry
307				, total.ast_tx_xretries
308				, total.ast_rx_crcerr
309				, total.ast_rx_badcrypt
310				, total.ast_rx_phyerr
311				, total.ast_rx_rssi
312				, rate
313			);
314		}
315		fflush(stdout);
316		omask = sigblock(sigmask(SIGALRM));
317		if (!signalled)
318			sigpause(0);
319		sigsetmask(omask);
320		signalled = 0;
321		alarm(interval);
322		line++;
323		if (line == 21)		/* XXX tty line count */
324			goto banner;
325		else
326			goto loop;
327		/*NOTREACHED*/
328	} else {
329		struct ath_stats stats;
330
331		ifr.ifr_data = (caddr_t) &stats;
332		if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
333			err(1, ifr.ifr_name);
334		printstats(stdout, &stats);
335	}
336	return 0;
337}
338