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