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