/*- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $Id$ */ /* * Simple Atheros-specific tool to inspect and monitor network traffic * statistics. * athstats [-i interface] [interval] * (default interface is wifi0). If interval is specified a rolling output * is displayed every interval seconds. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ah_desc.h" #include "wireless_copy.h" #include "if_athioctl.h" #undef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static const struct { u_int phyerr; const char *desc; } phyerrdescriptions[] = { { HAL_PHYERR_UNDERRUN, "transmit underrun" }, { HAL_PHYERR_TIMING, "timing error" }, { HAL_PHYERR_PARITY, "illegal parity" }, { HAL_PHYERR_RATE, "illegal rate" }, { HAL_PHYERR_LENGTH, "illegal length" }, { HAL_PHYERR_RADAR, "radar detect" }, { HAL_PHYERR_SERVICE, "illegal service" }, { HAL_PHYERR_TOR, "transmit override receive" }, { HAL_PHYERR_OFDM_TIMING, "OFDM timing" }, { HAL_PHYERR_OFDM_SIGNAL_PARITY,"OFDM illegal parity" }, { HAL_PHYERR_OFDM_RATE_ILLEGAL, "OFDM illegal rate" }, { HAL_PHYERR_OFDM_POWER_DROP, "OFDM power drop" }, { HAL_PHYERR_OFDM_SERVICE, "OFDM illegal service" }, { HAL_PHYERR_OFDM_RESTART, "OFDM restart" }, { HAL_PHYERR_CCK_TIMING, "CCK timing" }, { HAL_PHYERR_CCK_HEADER_CRC, "CCK header crc" }, { HAL_PHYERR_CCK_RATE_ILLEGAL, "CCK illegal rate" }, { HAL_PHYERR_CCK_SERVICE, "CCK illegal service" }, { HAL_PHYERR_CCK_RESTART, "CCK restart" }, }; static void printstats(FILE *fd, const struct ath_stats *stats) { #define STAT(x,fmt) \ if (stats->ast_##x) fprintf(fd, "%u " fmt "\n", stats->ast_##x) #define STATI(x,fmt) \ if (stats->ast_##x) fprintf(fd, "%d " fmt "\n", stats->ast_##x) int i, j; STAT(watchdog, "watchdog timeouts"); STAT(hardware, "hardware error interrupts"); STAT(bmiss, "beacon miss interrupts"); STAT(rxorn, "recv overrun interrupts"); STAT(rxeol, "recv eol interrupts"); STAT(txurn, "txmit underrun interrupts"); STAT(tx_mgmt, "tx management frames"); STAT(tx_discard, "tx frames discarded due to queue depth"); STAT(tx_invalid, "tx frames discarded due to device gone"); STAT(tx_qstop, "tx queue stopped because full"); STAT(tx_encap, "tx encapsulation failed"); STAT(tx_nonode, "tx failed due to no node"); STAT(tx_nobuf, "tx failed due to no tx buffer (data)"); STAT(tx_nobufmgt, "tx failed due to no tx buffer (mgt)"); STAT(tx_xretries, "tx failed due to too many retries"); STAT(tx_fifoerr, "tx failed due to FIFO underrun"); STAT(tx_filtered, "tx failed due to xmit filtered"); STAT(tx_shortretry, "short on-chip tx retries"); STAT(tx_longretry, "long on-chip tx retries"); STAT(tx_badrate, "tx failed due to bogus xmit rate"); STAT(tx_noack, "tx frames with no ack marked"); STAT(tx_rts, "tx frames with rts enabled"); STAT(tx_cts, "tx frames with cts enabled"); STAT(tx_shortpre, "tx frames with short preamble"); STAT(tx_altrate, "tx frames with an alternate rate"); STAT(tx_protect, "tx frames with 11g protection"); STAT(rx_orn, "rx failed due to desc overrun"); STAT(rx_crcerr, "rx failed due to bad CRC"); STAT(rx_fifoerr, "rx failed due to FIFO overrun"); STAT(rx_badcrypt, "rx failed due to decryption"); STAT(rx_badmic, "rx failed due to MIC failure"); STAT(rx_tooshort, "rx failed due to frame too short"); STAT(rx_nobuf, "rx setup failed due to no skbuff"); STAT(rx_mgt, "rx management frames"); STAT(rx_ctl, "rx control frames"); STAT(rx_phyerr, "PHY errors"); if (stats->ast_rx_phyerr != 0) { for (i = 0; i < 32; i++) { if (stats->ast_rx_phy[i] == 0) continue; for (j = 0; j < ARRAY_SIZE(phyerrdescriptions); j++) if (phyerrdescriptions[j].phyerr == i) break; if (j == ARRAY_SIZE(phyerrdescriptions)) fprintf(fd, " %u (unknown phy error code %u)\n", stats->ast_rx_phy[i], i); else fprintf(fd, " %u %s\n", stats->ast_rx_phy[i], phyerrdescriptions[j].desc); } } STAT(be_nobuf, "no skbuff available for beacon"); STAT(be_xmit, "beacons transmitted"); STAT(per_cal, "periodic calibrations"); STAT(per_calfail, "periodic calibration failures"); STAT(per_rfgain, "rfgain value change"); STAT(rate_calls, "rate control checks"); STAT(rate_raise, "rate control raised xmit rate"); STAT(rate_drop, "rate control dropped xmit rate"); if (stats->ast_tx_rssi) fprintf(fd, "rssi of last ack: %u\n", stats->ast_tx_rssi); if (stats->ast_rx_rssi) fprintf(fd, "rssi of last rcv: %u\n", stats->ast_rx_rssi); STAT(ant_defswitch, "switched default/rx antenna"); STAT(ant_txswitch, "tx used alternate antenna"); fprintf(fd, "Antenna profile:\n"); for (i = 0; i < 8; i++) if (stats->ast_ant_rx[i] || stats->ast_ant_tx[i]) fprintf(fd, "[%u] tx %8u rx %8u\n", i, stats->ast_ant_tx[i], stats->ast_ant_rx[i]); #undef STAT #undef STATI } static u_int getifrate(int s, const char *ifname) { struct iwreq wrq; (void) memset(&wrq, 0, sizeof(wrq)); strncpy(wrq.ifr_name, ifname, IFNAMSIZ); if (ioctl(s, SIOCGIWRATE, &wrq) < 0) return 0; else return wrq.u.bitrate.value / 1000000; } static int getifstats(const char *ifname, u_long *iframes, u_long *oframes) { FILE * fd = fopen("/proc/net/dev", "r"); if (fd != NULL) { char line[256]; while (fgets(line, sizeof(line), fd)) { char *cp, *tp; for (cp = line; isspace(*cp); cp++) ; if (cp[0] != ifname[0]) continue; for (tp = cp; *tp != ':' && *tp; tp++) ; if (*tp == ':') { *tp++ = '\0'; if (strcmp(cp, ifname) != 0) continue; sscanf(tp, "%*u %lu %*u %*u %*u %*u %*u %*u %*u %lu", iframes, oframes); fclose(fd); return 1; } } fclose(fd); } return 0; } static int signalled; static void catchalarm(int signo) { signalled = 1; } int main(int argc, char *argv[]) { #ifdef __linux__ const char *ifname = "wifi0"; #else const char *ifname = "ath0"; #endif int s; struct ifreq ifr; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) err(1, "socket"); if (argc > 1 && strcmp(argv[1], "-i") == 0) { if (argc < 2) { fprintf(stderr, "%s: missing interface name for -i\n", argv[0]); exit(-1); } ifname = argv[2]; argc -= 2, argv += 2; } strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (argc > 1) { u_long interval = strtoul(argv[1], NULL, 0); int line; sigset_t omask, nmask; u_int rate; struct ath_stats cur, total; u_long icur, ocur; u_long itot, otot; if (interval < 1) interval = 1; signal(SIGALRM, catchalarm); signalled = 0; alarm(interval); banner: printf("%8s %8s %7s %7s %7s %6s %6s %6s %7s %4s %4s", "input", "output", "altrate", "short", "long", "xretry", "crcerr", "crypt", "phyerr", "rssi", "rate"); putchar('\n'); fflush(stdout); line = 0; loop: rate = getifrate(s, ifr.ifr_name); if (line != 0) { ifr.ifr_data = (caddr_t) &cur; if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) err(1, ifr.ifr_name); if (!getifstats(ifr.ifr_name, &icur, &ocur)) err(1, ifr.ifr_name); printf("%8lu %8lu %7u %7u %7u %6u %6u %6u %7u %4u %3uM\n", (icur - itot) - (cur.ast_rx_mgt - total.ast_rx_mgt), ocur - otot, cur.ast_tx_altrate - total.ast_tx_altrate, cur.ast_tx_shortretry - total.ast_tx_shortretry, cur.ast_tx_longretry - total.ast_tx_longretry, cur.ast_tx_xretries - total.ast_tx_xretries, cur.ast_rx_crcerr - total.ast_rx_crcerr, cur.ast_rx_badcrypt - total.ast_rx_badcrypt, cur.ast_rx_phyerr - total.ast_rx_phyerr, cur.ast_rx_rssi, rate); total = cur; itot = icur; otot = ocur; } else { ifr.ifr_data = (caddr_t) &total; if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) err(1, ifr.ifr_name); if (!getifstats(ifr.ifr_name, &itot, &otot)) err(1, ifr.ifr_name); printf("%8lu %8lu %7u %7u %7u %6u %6u %6u %7u %4u %3uM\n", itot - total.ast_rx_mgt, otot, total.ast_tx_altrate, total.ast_tx_shortretry, total.ast_tx_longretry, total.ast_tx_xretries, total.ast_rx_crcerr, total.ast_rx_badcrypt, total.ast_rx_phyerr, total.ast_rx_rssi, rate); } fflush(stdout); sigemptyset(&nmask); sigaddset(&nmask, SIGALRM); sigprocmask(SIG_BLOCK, &nmask, &omask); sigemptyset(&nmask); if (!signalled) sigsuspend(&nmask); sigprocmask(SIG_SETMASK, &omask, NULL); signalled = 0; alarm(interval); line++; if (line == 21) /* XXX tty line count */ goto banner; else goto loop; /*NOTREACHED*/ } else { struct ath_stats stats; ifr.ifr_data = (caddr_t) &stats; if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) err(1, ifr.ifr_name); printstats(stdout, &stats); } return 0; }