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