xref: /freebsd/tools/tools/ath/athstats/athstats.c (revision 4f29da19bd44f0e99f021510460a81bf754c21d2)
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$
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 
64 static 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 
89 static void
90 printstats(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(rx_nombuf,	"rx setup failed 'cuz no mbuf");
129 	STAT(rx_busdma,	"rx setup failed for dma resrcs");
130 	STAT(rx_orn, "rx failed 'cuz of desc overrun");
131 	STAT(rx_crcerr, "rx failed 'cuz of bad CRC");
132 	STAT(rx_fifoerr, "rx failed 'cuz of FIFO overrun");
133 	STAT(rx_badcrypt, "rx failed 'cuz decryption");
134 	STAT(rx_badmic, "rx failed 'cuz MIC failure");
135 	STAT(rx_tooshort, "rx failed 'cuz frame too short");
136 	STAT(rx_toobig, "rx failed 'cuz frame too large");
137 	STAT(rx_mgt, "rx management frames");
138 	STAT(rx_ctl, "rx control frames");
139 	STAT(rx_phyerr, "rx failed 'cuz of PHY err");
140 	if (stats->ast_rx_phyerr != 0) {
141 		for (i = 0; i < 32; i++) {
142 			if (stats->ast_rx_phy[i] == 0)
143 				continue;
144 			for (j = 0; j < N(phyerrdescriptions); j++)
145 				if (phyerrdescriptions[j].phyerr == i)
146 					break;
147 			if (j == N(phyerrdescriptions))
148 				fprintf(fd,
149 					"    %u (unknown phy error code %u)\n",
150 					stats->ast_rx_phy[i], i);
151 			else
152 				fprintf(fd, "    %u %s\n",
153 					stats->ast_rx_phy[i],
154 					phyerrdescriptions[j].desc);
155 		}
156 	}
157 	STAT(be_nombuf,	"beacon setup failed 'cuz no mbuf");
158 	STAT(be_xmit,	"beacons transmitted");
159 	STAT(per_cal, "periodic calibrations");
160 	STAT(per_calfail, "periodic calibration failures");
161 	STAT(per_rfgain, "rfgain value change");
162 	STAT(rate_calls, "rate control checks");
163 	STAT(rate_raise, "rate control raised xmit rate");
164 	STAT(rate_drop, "rate control dropped xmit rate");
165 	if (stats->ast_tx_rssi)
166 		fprintf(fd, "rssi of last ack: %u\n", stats->ast_tx_rssi);
167 	if (stats->ast_rx_rssi)
168 		fprintf(fd, "avg recv rssi: %u\n", stats->ast_rx_rssi);
169 	STAT(ant_defswitch, "switched default/rx antenna");
170 	STAT(ant_txswitch, "tx used alternate antenna");
171 	fprintf(fd, "Antenna profile:\n");
172 	for (i = 0; i < 8; i++)
173 		if (stats->ast_ant_rx[i] || stats->ast_ant_tx[i])
174 			fprintf(fd, "[%u] tx %8u rx %8u\n", i,
175 				stats->ast_ant_tx[i], stats->ast_ant_rx[i]);
176 #undef STAT
177 #undef N
178 }
179 
180 static u_int
181 getifrate(int s, const char* ifname)
182 {
183 #define	N(a)	(sizeof(a) / sizeof(a[0]))
184 	static const int rates[] = {
185 		0,		/* IFM_AUTO */
186 		0,		/* IFM_MANUAL */
187 		0,		/* IFM_NONE */
188 		1,		/* IFM_IEEE80211_FH1 */
189 		2,		/* IFM_IEEE80211_FH2 */
190 		1,		/* IFM_IEEE80211_DS1 */
191 		2,		/* IFM_IEEE80211_DS2 */
192 		5,		/* IFM_IEEE80211_DS5 */
193 		11,		/* IFM_IEEE80211_DS11 */
194 		22,		/* IFM_IEEE80211_DS22 */
195 		6,		/* IFM_IEEE80211_OFDM6 */
196 		9,		/* IFM_IEEE80211_OFDM9 */
197 		12,		/* IFM_IEEE80211_OFDM12 */
198 		18,		/* IFM_IEEE80211_OFDM18 */
199 		24,		/* IFM_IEEE80211_OFDM24 */
200 		36,		/* IFM_IEEE80211_OFDM36 */
201 		48,		/* IFM_IEEE80211_OFDM48 */
202 		54,		/* IFM_IEEE80211_OFDM54 */
203 		72,		/* IFM_IEEE80211_OFDM72 */
204 	};
205 	struct ifmediareq ifmr;
206 	int *media_list, i;
207 
208 	(void) memset(&ifmr, 0, sizeof(ifmr));
209 	(void) strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
210 
211 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
212 		return 0;
213 	return IFM_SUBTYPE(ifmr.ifm_active) < N(rates) ?
214 		rates[IFM_SUBTYPE(ifmr.ifm_active)] : 0;
215 #undef N
216 }
217 
218 static int signalled;
219 
220 static void
221 catchalarm(int signo __unused)
222 {
223 	signalled = 1;
224 }
225 
226 int
227 main(int argc, char *argv[])
228 {
229 	int s;
230 	struct ifreq ifr;
231 
232 	s = socket(AF_INET, SOCK_DGRAM, 0);
233 	if (s < 0)
234 		err(1, "socket");
235 	if (argc > 1 && strcmp(argv[1], "-i") == 0) {
236 		if (argc < 2) {
237 			fprintf(stderr, "%s: missing interface name for -i\n",
238 				argv[0]);
239 			exit(-1);
240 		}
241 		strncpy(ifr.ifr_name, argv[2], sizeof (ifr.ifr_name));
242 		argc -= 2, argv += 2;
243 	} else
244 		strncpy(ifr.ifr_name, "ath0", sizeof (ifr.ifr_name));
245 	if (argc > 1) {
246 		u_long interval = strtoul(argv[1], NULL, 0);
247 		int line, omask;
248 		u_int rate = getifrate(s, ifr.ifr_name);
249 		struct ath_stats cur, total;
250 
251 		if (interval < 1)
252 			interval = 1;
253 		signal(SIGALRM, catchalarm);
254 		signalled = 0;
255 		alarm(interval);
256 	banner:
257 		printf("%8s %8s %7s %7s %7s %6s %6s %5s %7s %4s %4s"
258 			, "input"
259 			, "output"
260 			, "altrate"
261 			, "short"
262 			, "long"
263 			, "xretry"
264 			, "crcerr"
265 			, "crypt"
266 			, "phyerr"
267 			, "rssi"
268 			, "rate"
269 		);
270 		putchar('\n');
271 		fflush(stdout);
272 		line = 0;
273 	loop:
274 		if (line != 0) {
275 			ifr.ifr_data = (caddr_t) &cur;
276 			if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
277 				err(1, ifr.ifr_name);
278 			rate = getifrate(s, ifr.ifr_name);
279 			printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n"
280 				, cur.ast_rx_packets - total.ast_rx_packets
281 				, cur.ast_tx_packets - total.ast_tx_packets
282 				, cur.ast_tx_altrate - total.ast_tx_altrate
283 				, cur.ast_tx_shortretry - total.ast_tx_shortretry
284 				, cur.ast_tx_longretry - total.ast_tx_longretry
285 				, cur.ast_tx_xretries - total.ast_tx_xretries
286 				, cur.ast_rx_crcerr - total.ast_rx_crcerr
287 				, cur.ast_rx_badcrypt - total.ast_rx_badcrypt
288 				, cur.ast_rx_phyerr - total.ast_rx_phyerr
289 				, cur.ast_rx_rssi
290 				, rate
291 			);
292 			total = cur;
293 		} else {
294 			ifr.ifr_data = (caddr_t) &total;
295 			if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
296 				err(1, ifr.ifr_name);
297 			rate = getifrate(s, ifr.ifr_name);
298 			printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n"
299 				, total.ast_rx_packets
300 				, total.ast_tx_packets
301 				, total.ast_tx_altrate
302 				, total.ast_tx_shortretry
303 				, total.ast_tx_longretry
304 				, total.ast_tx_xretries
305 				, total.ast_rx_crcerr
306 				, total.ast_rx_badcrypt
307 				, total.ast_rx_phyerr
308 				, total.ast_rx_rssi
309 				, rate
310 			);
311 		}
312 		fflush(stdout);
313 		omask = sigblock(sigmask(SIGALRM));
314 		if (!signalled)
315 			sigpause(0);
316 		sigsetmask(omask);
317 		signalled = 0;
318 		alarm(interval);
319 		line++;
320 		if (line == 21)		/* XXX tty line count */
321 			goto banner;
322 		else
323 			goto loop;
324 		/*NOTREACHED*/
325 	} else {
326 		struct ath_stats stats;
327 
328 		ifr.ifr_data = (caddr_t) &stats;
329 		if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
330 			err(1, ifr.ifr_name);
331 		printstats(stdout, &stats);
332 	}
333 	return 0;
334 }
335