diff options
author | sam <sam@FreeBSD.org> | 2006-08-10 19:01:16 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2006-08-10 19:01:16 +0000 |
commit | 22a881785b89e1f9afead2cb065457efefade197 (patch) | |
tree | bb1b9d0ed308d25e380fd47f8fbcc0fbdd6756a4 /tools | |
parent | b594a7a463db91b141902f79864d524ba7de9520 (diff) | |
download | FreeBSD-src-22a881785b89e1f9afead2cb065457efefade197.zip FreeBSD-src-22a881785b89e1f9afead2cb065457efefade197.tar.gz |
checkpoint new version
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/ath/athstats/Makefile | 2 | ||||
-rw-r--r-- | tools/tools/ath/athstats/athstats.c | 924 | ||||
-rw-r--r-- | tools/tools/ath/athstats/athstats.h | 52 | ||||
-rw-r--r-- | tools/tools/ath/athstats/main.c | 134 | ||||
-rw-r--r-- | tools/tools/ath/athstats/statfoo.c | 191 | ||||
-rw-r--r-- | tools/tools/ath/athstats/statfoo.h | 127 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/Makefile | 2 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/main.c | 255 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/statfoo.c | 191 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/statfoo.h | 127 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/wlanstats.c | 876 | ||||
-rw-r--r-- | tools/tools/net80211/wlanstats/wlanstats.h | 56 |
12 files changed, 2454 insertions, 483 deletions
diff --git a/tools/tools/ath/athstats/Makefile b/tools/tools/ath/athstats/Makefile index f70b45d..0d9c761 100644 --- a/tools/tools/ath/athstats/Makefile +++ b/tools/tools/ath/athstats/Makefile @@ -4,4 +4,6 @@ PROG= athstats BINDIR= /usr/local/bin NO_MAN= +SRCS= main.c statfoo.c athstats.c + .include <bsd.prog.mk> diff --git a/tools/tools/ath/athstats/athstats.c b/tools/tools/ath/athstats/athstats.c index d94a450..8d3eb3b 100644 --- a/tools/tools/ath/athstats/athstats.c +++ b/tools/tools/ath/athstats/athstats.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,13 +37,7 @@ */ /* - * Simple Atheros-specific tool to inspect and monitor network traffic - * statistics. - * athstats [-i interface] [interval] - * (default interface is ath0). If interval is specified a rolling output - * a la netstat -i is displayed every interval seconds. - * - * To build: cc -o athstats athstats.c -lkvm + * ath statistics class. */ #include <sys/types.h> #include <sys/file.h> @@ -55,283 +49,697 @@ #include <stdio.h> #include <signal.h> +#include <string.h> +#include <unistd.h> +#include <err.h> #include "../../../../sys/contrib/dev/ath/ah_desc.h" #include "../../../../sys/net80211/ieee80211_ioctl.h" #include "../../../../sys/net80211/ieee80211_radiotap.h" #include "../../../../sys/dev/ath/if_athioctl.h" -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" }, +#include "athstats.h" + +#define NOTPRESENT { 0, "", "" } + +static const struct fmt athstats[] = { +#define S_INPUT 0 + { 8, "input", "input", "data frames received" }, +#define S_OUTPUT 1 + { 8, "output", "output", "data frames transmit" }, +#define S_TX_ALTRATE 2 + { 7, "altrate", "altrate", "tx frames with an alternate rate" }, +#define S_TX_SHORTRETRY 3 + { 7, "short", "short", "short on-chip tx retries" }, +#define S_TX_LONGRETRY 4 + { 7, "long", "long", "long on-chip tx retries" }, +#define S_TX_XRETRIES 5 + { 6, "xretry", "xretry", "tx failed 'cuz too many retries" }, +#define S_MIB 6 + { 5, "mib", "mib", "mib overflow interrupts" }, +#ifndef __linux__ +#define S_TX_LINEAR 7 + { 5, "txlinear", "txlinear", "tx linearized to cluster" }, +#define S_BSTUCK 8 + { 5, "bstuck", "bstuck", "stuck beacon conditions" }, +#define S_INTRCOAL 9 + { 5, "intrcoal", "intrcoal", "interrupts coalesced" }, +#else + NOTPRESENT, NOTPRESENT, NOTPRESENT, +#endif +#define S_RATE 10 + { 4, "rate", "rate", "current transmit rate" }, +#define S_WATCHDOG 11 + { 5, "wdog", "wdog", "watchdog timeouts" }, +#define S_FATAL 12 + { 5, "fatal", "fatal", "hardware error interrupts" }, +#define S_BMISS 13 + { 5, "bmiss", "bmiss", "beacon miss interrupts" }, +#define S_RXORN 14 + { 5, "rxorn", "rxorn", "recv overrun interrupts" }, +#define S_RXEOL 15 + { 5, "rxeol", "rxeol", "recv eol interrupts" }, +#define S_TXURN 16 + { 5, "txurn", "txurn", "txmit underrun interrupts" }, +#define S_TX_MGMT 17 + { 5, "txmgt", "txmgt", "tx management frames" }, +#define S_TX_DISCARD 18 + { 5, "txdisc", "txdisc", "tx frames discarded prior to association" }, +#define S_TX_INVALID 19 + { 5, "txinv", "txinv", "tx invalid (19)" }, +#define S_TX_QSTOP 20 + { 5, "qstop", "qstop", "tx stopped 'cuz no xmit buffer" }, +#define S_TX_ENCAP 21 + { 5, "txencode", "txencode", "tx encapsulation failed" }, +#define S_TX_NONODE 22 + { 5, "txnonode", "txnonode", "tx failed 'cuz no node" }, +#define S_TX_NOMBUF 23 + { 5, "txnombuf", "txnombuf", "tx failed 'cuz mbuf allocation failed" }, +#ifndef __linux__ +#define S_TX_NOMCL 24 + { 5, "txnomcl", "txnomcl", "tx failed 'cuz cluster allocation failed" }, +#else + NOTPRESENT, +#endif +#define S_TX_FIFOERR 25 + { 5, "efifo", "efifo", "tx failed 'cuz FIFO underrun" }, +#define S_TX_FILTERED 26 + { 5, "efilt", "efilt", "tx failed 'cuz destination filtered" }, +#define S_TX_BADRATE 27 + { 5, "txbadrate", "txbadrate", "tx failed 'cuz bogus xmit rate" }, +#define S_TX_NOACK 28 + { 5, "noack", "noack", "tx frames with no ack marked" }, +#define S_TX_RTS 29 + { 5, "rts", "rts", "tx frames with rts enabled" }, +#define S_TX_CTS 30 + { 5, "cts", "cts", "tx frames with cts enabled" }, +#define S_TX_SHORTPRE 31 + { 5, "shpre", "shpre", "tx frames with short preamble" }, +#define S_TX_PROTECT 32 + { 5, "protect", "protect", "tx frames with 11g protection" }, +#define S_RX_ORN 33 + { 5, "rxorn", "rxorn", "rx failed 'cuz of desc overrun" }, +#define S_RX_CRC_ERR 34 + { 6, "crcerr", "crcerr", "rx failed 'cuz of bad CRC" }, +#define S_RX_FIFO_ERR 35 + { 5, "rxfifo", "rxfifo", "rx failed 'cuz of FIFO overrun" }, +#define S_RX_CRYPTO_ERR 36 + { 5, "crypt", "crypt", "rx failed 'cuz decryption" }, +#define S_RX_MIC_ERR 37 + { 4, "mic", "mic", "rx failed 'cuz MIC failure" }, +#define S_RX_TOOSHORT 38 + { 5, "rxshort", "rxshort", "rx failed 'cuz frame too short" }, +#define S_RX_NOMBUF 39 + { 5, "rxnombuf", "rxnombuf", "rx setup failed 'cuz no mbuf" }, +#define S_RX_MGT 40 + { 5, "rxmgt", "rxmgt", "rx management frames" }, +#define S_RX_CTL 41 + { 5, "rxctl", "rxctl", "rx control frames" }, +#define S_RX_PHY_ERR 42 + { 7, "phyerr", "phyerr", "rx failed 'cuz of PHY err" }, +#define S_RX_PHY_UNDERRUN 43 + { 6, "phyund", "phyund", "transmit underrun" }, +#define S_RX_PHY_TIMING 44 + { 6, "phytim", "phytim", "timing error" }, +#define S_RX_PHY_PARITY 45 + { 6, "phypar", "phypar", "illegal parity" }, +#define S_RX_PHY_RATE 46 + { 6, "phyrate", "phyrate", "illegal rate" }, +#define S_RX_PHY_LENGTH 47 + { 6, "phylen", "phylen", "illegal length" }, +#define S_RX_PHY_RADAR 48 + { 6, "phyradar", "phyradar", "radar detect" }, +#define S_RX_PHY_SERVICE 49 + { 6, "physervice", "physervice", "illegal service" }, +#define S_RX_PHY_TOR 50 + { 6, "phytor", "phytor", "transmit override receive" }, +#define S_RX_PHY_OFDM_TIMING 51 + { 6, "ofdmtim", "ofdmtim", "OFDM timing" }, +#define S_RX_PHY_OFDM_SIGNAL_PARITY 52 + { 6, "ofdmsig", "ofdmsig", "OFDM illegal parity" }, +#define S_RX_PHY_OFDM_RATE_ILLEGAL 53 + { 6, "ofdmrate", "ofdmrate", "OFDM illegal rate" }, +#define S_RX_PHY_OFDM_POWER_DROP 54 + { 6, "ofdmpow", "ofdmpow", "OFDM power drop" }, +#define S_RX_PHY_OFDM_SERVICE 55 + { 6, "ofdmservice", "ofdmservice", "OFDM illegal service" }, +#define S_RX_PHY_OFDM_RESTART 56 + { 6, "ofdmrestart", "ofdmrestart", "OFDM restart" }, +#define S_RX_PHY_CCK_TIMING 57 + { 6, "ccktim", "ccktim", "CCK timing" }, +#define S_RX_PHY_CCK_HEADER_CRC 58 + { 6, "cckhead", "cckhead", "CCK header crc" }, +#define S_RX_PHY_CCK_RATE_ILLEGAL 59 + { 6, "cckrate", "cckrate", "CCK illegal rate" }, +#define S_RX_PHY_CCK_SERVICE 60 + { 6, "cckservice", "cckservice", "CCK illegal service" }, +#define S_RX_PHY_CCK_RESTART 61 + { 6, "cckrestar", "cckrestar", "CCK restart" }, +#define S_BE_NOMBUF 62 + { 4, "benombuf", "benombuf", "beacon setup failed 'cuz no mbuf" }, +#define S_BE_XMIT 63 + { 7, "bexmit", "bexmit", "beacons transmitted" }, +#define S_PER_CAL 64 + { 4, "pcal", "pcal", "periodic calibrations" }, +#define S_PER_CALFAIL 65 + { 4, "pcalf", "pcalf", "periodic calibration failures" }, +#define S_PER_RFGAIN 66 + { 4, "prfga", "prfga", "rfgain value change" }, +#if 0 +#define S_TDMA_UPDATE 67 + { 5, "tdmau", "tdmau", "TDMA slot timing updates" }, +#define S_TDMA_TIMERS 68 + { 5, "tdmab", "tdmab", "TDMA slot update set beacon timers" }, +#define S_TDMA_TSF 69 + { 5, "tdmat", "tdmat", "TDMA slot update set TSF" }, +#else + NOTPRESENT, NOTPRESENT, NOTPRESENT, +#endif +#define S_RATE_CALLS 70 + { 5, "ratec", "ratec", "rate control checks" }, +#define S_RATE_RAISE 71 + { 5, "rate+", "rate+", "rate control raised xmit rate" }, +#define S_RATE_DROP 72 + { 5, "rate-", "rate-", "rate control dropped xmit rate" }, +#define S_TX_RSSI 73 + { 4, "arssi", "arssi", "rssi of last ack" }, +#define S_RX_RSSI 74 + { 4, "rssi", "rssi", "avg recv rssi" }, +#define S_RX_NOISE 75 + { 5, "noise", "noise", "rx noise floor" }, +#define S_BMISS_PHANTOM 76 + { 5, "bmissphantom", "bmissphantom", "phantom beacon misses" }, +#define S_TX_RAW 77 + { 5, "txraw", "txraw", "tx frames through raw api" }, +#define S_RX_TOOBIG 78 + { 5, "rx2big", "rx2big", "rx failed 'cuz frame too large" }, +#ifndef __linux__ +#define S_CABQ_XMIT 79 + { 5, "cabxmit", "cabxmit", "cabq frames transmitted" }, +#define S_CABQ_BUSY 80 + { 5, "cabqbusy", "cabqbusy", "cabq xmit overflowed beacon interval" }, +#define S_TX_NODATA 81 + { 5, "txnodata", "txnodata", "tx discarded empty frame" }, +#define S_TX_BUSDMA 82 + { 5, "txbusdma", "txbusdma", "tx failed for dma resrcs" }, +#define S_RX_BUSDMA 83 + { 5, "rxbusdma", "rxbusdma", "rx setup failed for dma resrcs" }, +#else + NOTPRESENT, NOTPRESENT, NOTPRESENT, NOTPRESENT, NOTPRESENT, +#endif +#if 0 +#define S_FF_TXOK 84 + { 5, "fftxok", "fftxok", "fast frames xmit successfully" }, +#define S_FF_TXERR 85 + { 5, "fftxerr", "fftxerr", "fast frames not xmit due to error" }, +#define S_FF_RX 86 + { 5, "ffrx", "ffrx", "fast frames received" }, +#define S_FF_FLUSH 87 + { 5, "ffflush", "ffflush", "fast frames flushed from staging q" }, +#else + NOTPRESENT, NOTPRESENT, NOTPRESENT, NOTPRESENT, +#endif +#define S_ANT_DEFSWITCH 88 + { 5, "defsw", "defsw", "switched default/rx antenna" }, +#define S_ANT_TXSWITCH 89 + { 5, "txsw", "txsw", "tx used alternate antenna" }, +#define S_ANT_TX0 90 + { 8, "tx0", "ant0(tx)", "frames tx on antenna 0" }, +#define S_ANT_TX1 91 + { 8, "tx1", "ant1(tx)", "frames tx on antenna 1" }, +#define S_ANT_TX2 92 + { 8, "tx2", "ant2(tx)", "frames tx on antenna 2" }, +#define S_ANT_TX3 93 + { 8, "tx3", "ant3(tx)", "frames tx on antenna 3" }, +#define S_ANT_TX4 94 + { 8, "tx4", "ant4(tx)", "frames tx on antenna 4" }, +#define S_ANT_TX5 95 + { 8, "tx5", "ant5(tx)", "frames tx on antenna 5" }, +#define S_ANT_TX6 96 + { 8, "tx6", "ant6(tx)", "frames tx on antenna 6" }, +#define S_ANT_TX7 97 + { 8, "tx7", "ant7(tx)", "frames tx on antenna 7" }, +#define S_ANT_RX0 98 + { 8, "rx0", "ant0(rx)", "frames rx on antenna 0" }, +#define S_ANT_RX1 99 + { 8, "rx1", "ant1(rx)", "frames rx on antenna 1" }, +#define S_ANT_RX2 100 + { 8, "rx2", "ant2(rx)", "frames rx on antenna 2" }, +#define S_ANT_RX3 101 + { 8, "rx3", "ant3(rx)", "frames rx on antenna 3" }, +#define S_ANT_RX4 102 + { 8, "rx4", "ant4(rx)", "frames rx on antenna 4" }, +#define S_ANT_RX5 103 + { 8, "rx5", "ant5(rx)", "frames rx on antenna 5" }, +#define S_ANT_RX6 104 + { 8, "rx6", "ant6(rx)", "frames rx on antenna 6" }, +#define S_ANT_RX7 105 + { 8, "rx7", "ant7(rx)", "frames rx on antenna 7" }, +#define S_TX_SIGNAL 106 + { 4, "asignal", "asig", "signal of last ack (dBm)" }, +#define S_RX_SIGNAL 107 + { 4, "signal", "sig", "avg recv signal (dBm)" }, +}; +#define S_PHY_MIN S_RX_PHY_UNDERRUN +#define S_PHY_MAX S_RX_PHY_CCK_RESTART +#define S_LAST S_ANT_TX0 +#define S_MAX S_ANT_RX7+1 + +struct athstatfoo_p { + struct athstatfoo base; + int s; + struct ifreq ifr; + struct ath_stats cur; + struct ath_stats total; }; static void -printstats(FILE *fd, const struct ath_stats *stats) +ath_setifname(struct athstatfoo *wf0, const char *ifname) { -#define N(a) (sizeof(a) / sizeof(a[0])) -#define STAT(x,fmt) \ - if (stats->ast_##x) fprintf(fd, "%u " fmt "\n", stats->ast_##x) - int i, j; + struct athstatfoo_p *wf = (struct athstatfoo_p *) wf0; - STAT(watchdog, "watchdog timeouts"); - STAT(hardware, "hardware error interrupts"); - STAT(bmiss, "beacon miss interrupts"); - STAT(bstuck, "stuck beacon conditions"); - STAT(rxorn, "recv overrun interrupts"); - STAT(rxeol, "recv eol interrupts"); - STAT(txurn, "txmit underrun interrupts"); - STAT(mib, "mib overflow interrupts"); - STAT(intrcoal, "interrupts coalesced"); - STAT(tx_mgmt, "tx management frames"); - STAT(tx_discard, "tx frames discarded prior to association"); - STAT(tx_qstop, "tx stopped 'cuz no xmit buffer"); - STAT(tx_encap, "tx encapsulation failed"); - STAT(tx_nonode, "tx failed 'cuz no node"); - STAT(tx_nombuf, "tx failed 'cuz no mbuf"); - STAT(tx_nomcl, "tx failed 'cuz no cluster"); - STAT(tx_linear, "tx linearized to cluster"); - STAT(tx_nodata, "tx discarded empty frame"); - STAT(tx_busdma, "tx failed for dma resrcs"); - STAT(tx_xretries, "tx failed 'cuz too many retries"); - STAT(tx_fifoerr, "tx failed 'cuz FIFO underrun"); - STAT(tx_filtered, "tx failed 'cuz xmit filtered"); - STAT(tx_shortretry, "short on-chip tx retries"); - STAT(tx_longretry, "long on-chip tx retries"); - STAT(tx_badrate, "tx failed 'cuz 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(tx_raw, "tx frames through raw api"); - STAT(rx_nombuf, "rx setup failed 'cuz no mbuf"); - STAT(rx_busdma, "rx setup failed for dma resrcs"); - STAT(rx_orn, "rx failed 'cuz of desc overrun"); - STAT(rx_crcerr, "rx failed 'cuz of bad CRC"); - STAT(rx_fifoerr, "rx failed 'cuz of FIFO overrun"); - STAT(rx_badcrypt, "rx failed 'cuz decryption"); - STAT(rx_badmic, "rx failed 'cuz MIC failure"); - STAT(rx_tooshort, "rx failed 'cuz frame too short"); - STAT(rx_toobig, "rx failed 'cuz frame too large"); - STAT(rx_mgt, "rx management frames"); - STAT(rx_ctl, "rx control frames"); - STAT(rx_phyerr, "rx failed 'cuz of PHY err"); - if (stats->ast_rx_phyerr != 0) { - for (i = 0; i < 32; i++) { - if (stats->ast_rx_phy[i] == 0) - continue; - for (j = 0; j < N(phyerrdescriptions); j++) - if (phyerrdescriptions[j].phyerr == i) - break; - if (j == N(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_nombuf, "beacon setup failed 'cuz no mbuf"); - STAT(be_xmit, "beacons transmitted"); - STAT(cabq_xmit, "cabq frames transmitted"); - STAT(cabq_busy, "cabq xmit overflowed beacon interval"); - 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, "avg recv rssi: %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 N + strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name)); } -static u_int -getifrate(int s, const char* ifname) +static void +ath_collect(struct athstatfoo_p *wf, struct ath_stats *stats) { -#define N(a) (sizeof(a) / sizeof(a[0])) - static const int rates[] = { - 0, /* IFM_AUTO */ - 0, /* IFM_MANUAL */ - 0, /* IFM_NONE */ - 1, /* IFM_IEEE80211_FH1 */ - 2, /* IFM_IEEE80211_FH2 */ - 1, /* IFM_IEEE80211_DS1 */ - 2, /* IFM_IEEE80211_DS2 */ - 5, /* IFM_IEEE80211_DS5 */ - 11, /* IFM_IEEE80211_DS11 */ - 22, /* IFM_IEEE80211_DS22 */ - 6, /* IFM_IEEE80211_OFDM6 */ - 9, /* IFM_IEEE80211_OFDM9 */ - 12, /* IFM_IEEE80211_OFDM12 */ - 18, /* IFM_IEEE80211_OFDM18 */ - 24, /* IFM_IEEE80211_OFDM24 */ - 36, /* IFM_IEEE80211_OFDM36 */ - 48, /* IFM_IEEE80211_OFDM48 */ - 54, /* IFM_IEEE80211_OFDM54 */ - 72, /* IFM_IEEE80211_OFDM72 */ - }; - struct ifmediareq ifmr; - int *media_list, i; + wf->ifr.ifr_data = (caddr_t) stats; + if (ioctl(wf->s, SIOCGATHSTATS, &wf->ifr) < 0) + err(1, wf->ifr.ifr_name); +} - (void) memset(&ifmr, 0, sizeof(ifmr)); - (void) strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); +static void +ath_collect_cur(struct statfoo *sf) +{ + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; - if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) - return 0; - return IFM_SUBTYPE(ifmr.ifm_active) < N(rates) ? - rates[IFM_SUBTYPE(ifmr.ifm_active)] : 0; -#undef N + ath_collect(wf, &wf->cur); } -static int signalled; +static void +ath_collect_tot(struct statfoo *sf) +{ + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; + + ath_collect(wf, &wf->total); +} static void -catchalarm(int signo __unused) +ath_update_tot(struct statfoo *sf) { - signalled = 1; + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; + + wf->total = wf->cur; } -int -main(int argc, char *argv[]) +static int +ath_get_curstat(struct statfoo *sf, int s, char b[], size_t bs) { - int s; - struct ifreq ifr; + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->cur.ast_##x - wf->total.ast_##x); return 1 +#define PHY(x) \ + snprintf(b, bs, "%u", wf->cur.ast_rx_phy[x] - wf->total.ast_rx_phy[x]); return 1 +#define TXANT(x) \ + snprintf(b, bs, "%u", wf->cur.ast_ant_tx[x] - wf->total.ast_ant_tx[x]); return 1 +#define RXANT(x) \ + snprintf(b, bs, "%u", wf->cur.ast_ant_rx[x] - wf->total.ast_ant_rx[x]); return 1 - 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); - } - strncpy(ifr.ifr_name, argv[2], sizeof (ifr.ifr_name)); - argc -= 2, argv += 2; - } else - strncpy(ifr.ifr_name, "ath0", sizeof (ifr.ifr_name)); - if (argc > 1) { - u_long interval = strtoul(argv[1], NULL, 0); - int line, omask; - u_int rate = getifrate(s, ifr.ifr_name); - struct ath_stats cur, total; + switch (s) { + case S_INPUT: + snprintf(b, bs, "%lu", + (wf->cur.ast_rx_packets - wf->total.ast_rx_packets) - + (wf->cur.ast_rx_mgt - wf->total.ast_rx_mgt)); + return 1; + case S_OUTPUT: + snprintf(b, bs, "%lu", + wf->cur.ast_tx_packets - wf->total.ast_tx_packets); + return 1; + case S_RATE: + snprintf(b, bs, "%uM", wf->cur.ast_tx_rate / 2); + return 1; + case S_WATCHDOG: STAT(watchdog); + case S_FATAL: STAT(hardware); + case S_BMISS: STAT(bmiss); + case S_BMISS_PHANTOM: STAT(bmiss_phantom); +#ifdef S_BSTUCK + case S_BSTUCK: STAT(bstuck); +#endif + case S_RXORN: STAT(rxorn); + case S_RXEOL: STAT(rxeol); + case S_TXURN: STAT(txurn); + case S_MIB: STAT(mib); +#ifdef S_INTRCOAL + case S_INTRCOAL: STAT(intrcoal); +#endif + case S_TX_MGMT: STAT(tx_mgmt); + case S_TX_DISCARD: STAT(tx_discard); + case S_TX_QSTOP: STAT(tx_qstop); + case S_TX_ENCAP: STAT(tx_encap); + case S_TX_NONODE: STAT(tx_nonode); + case S_TX_NOMBUF: STAT(tx_nombuf); +#ifdef S_TX_NOMCL + case S_TX_NOMCL: STAT(tx_nomcl); + case S_TX_LINEAR: STAT(tx_linear); + case S_TX_NODATA: STAT(tx_nodata); + case S_TX_BUSDMA: STAT(tx_busdma); +#endif + case S_TX_XRETRIES: STAT(tx_xretries); + case S_TX_FIFOERR: STAT(tx_fifoerr); + case S_TX_FILTERED: STAT(tx_filtered); + case S_TX_SHORTRETRY: STAT(tx_shortretry); + case S_TX_LONGRETRY: STAT(tx_longretry); + case S_TX_BADRATE: STAT(tx_badrate); + case S_TX_NOACK: STAT(tx_noack); + case S_TX_RTS: STAT(tx_rts); + case S_TX_CTS: STAT(tx_cts); + case S_TX_SHORTPRE: STAT(tx_shortpre); + case S_TX_ALTRATE: STAT(tx_altrate); + case S_TX_PROTECT: STAT(tx_protect); + case S_RX_NOMBUF: STAT(rx_nombuf); +#ifdef S_RX_BUSDMA + case S_RX_BUSDMA: STAT(rx_busdma); +#endif + case S_RX_ORN: STAT(rx_orn); + case S_RX_CRC_ERR: STAT(rx_crcerr); + case S_RX_FIFO_ERR: STAT(rx_fifoerr); + case S_RX_CRYPTO_ERR: STAT(rx_badcrypt); + case S_RX_MIC_ERR: STAT(rx_badmic); + case S_RX_PHY_ERR: STAT(rx_phyerr); + case S_RX_PHY_UNDERRUN: PHY(HAL_PHYERR_UNDERRUN); + case S_RX_PHY_TIMING: PHY(HAL_PHYERR_TIMING); + case S_RX_PHY_PARITY: PHY(HAL_PHYERR_PARITY); + case S_RX_PHY_RATE: PHY(HAL_PHYERR_RATE); + case S_RX_PHY_LENGTH: PHY(HAL_PHYERR_LENGTH); + case S_RX_PHY_RADAR: PHY(HAL_PHYERR_RADAR); + case S_RX_PHY_SERVICE: PHY(HAL_PHYERR_SERVICE); + case S_RX_PHY_TOR: PHY(HAL_PHYERR_TOR); + case S_RX_PHY_OFDM_TIMING: PHY(HAL_PHYERR_OFDM_TIMING); + case S_RX_PHY_OFDM_SIGNAL_PARITY: PHY(HAL_PHYERR_OFDM_SIGNAL_PARITY); + case S_RX_PHY_OFDM_RATE_ILLEGAL: PHY(HAL_PHYERR_OFDM_RATE_ILLEGAL); + case S_RX_PHY_OFDM_POWER_DROP: PHY(HAL_PHYERR_OFDM_POWER_DROP); + case S_RX_PHY_OFDM_SERVICE: PHY(HAL_PHYERR_OFDM_SERVICE); + case S_RX_PHY_OFDM_RESTART: PHY(HAL_PHYERR_OFDM_RESTART); + case S_RX_PHY_CCK_TIMING: PHY(HAL_PHYERR_CCK_TIMING); + case S_RX_PHY_CCK_HEADER_CRC: PHY(HAL_PHYERR_CCK_HEADER_CRC); + case S_RX_PHY_CCK_RATE_ILLEGAL: PHY(HAL_PHYERR_CCK_RATE_ILLEGAL); + case S_RX_PHY_CCK_SERVICE: PHY(HAL_PHYERR_CCK_SERVICE); + case S_RX_PHY_CCK_RESTART: PHY(HAL_PHYERR_CCK_RESTART); + case S_RX_TOOSHORT: STAT(rx_tooshort); + case S_RX_TOOBIG: STAT(rx_toobig); + case S_RX_MGT: STAT(rx_mgt); + case S_RX_CTL: STAT(rx_ctl); + case S_TX_RSSI: + snprintf(b, bs, "%d", wf->cur.ast_tx_rssi); + return 1; + case S_RX_RSSI: + snprintf(b, bs, "%d", wf->cur.ast_rx_rssi); + return 1; + case S_BE_XMIT: STAT(be_xmit); + case S_BE_NOMBUF: STAT(be_nombuf); + case S_PER_CAL: STAT(per_cal); + case S_PER_CALFAIL: STAT(per_calfail); + case S_PER_RFGAIN: STAT(per_rfgain); +#ifdef S_TDMA_UPDATE + case S_TDMA_UPDATE: STAT(tdma_update); + case S_TDMA_TIMERS: STAT(tdma_timers); + case S_TDMA_TSF: STAT(tdma_tsf); +#endif + case S_RATE_CALLS: STAT(rate_calls); + case S_RATE_RAISE: STAT(rate_raise); + case S_RATE_DROP: STAT(rate_drop); + case S_ANT_DEFSWITCH: STAT(ant_defswitch); + case S_ANT_TXSWITCH: STAT(ant_txswitch); + case S_ANT_TX0: TXANT(0); + case S_ANT_TX1: TXANT(1); + case S_ANT_TX2: TXANT(2); + case S_ANT_TX3: TXANT(3); + case S_ANT_TX4: TXANT(4); + case S_ANT_TX5: TXANT(5); + case S_ANT_TX6: TXANT(6); + case S_ANT_TX7: TXANT(7); + case S_ANT_RX0: RXANT(0); + case S_ANT_RX1: RXANT(1); + case S_ANT_RX2: RXANT(2); + case S_ANT_RX3: RXANT(3); + case S_ANT_RX4: RXANT(4); + case S_ANT_RX5: RXANT(5); + case S_ANT_RX6: RXANT(6); + case S_ANT_RX7: RXANT(7); +#ifdef S_CABQ_XMIT + case S_CABQ_XMIT: STAT(cabq_xmit); + case S_CABQ_BUSY: STAT(cabq_busy); +#endif +#ifdef S_FF_TXOK + case S_FF_TXOK: STAT(ff_txok); + case S_FF_TXERR: STAT(ff_txerr); + case S_FF_FLUSH: STAT(ff_flush); + case S_FF_QFULL: STAT(ff_qfull); +#endif + case S_RX_NOISE: + snprintf(b, bs, "%d", wf->cur.ast_rx_noise); + return 1; + case S_TX_SIGNAL: + snprintf(b, bs, "%d", + wf->cur.ast_tx_rssi + wf->cur.ast_rx_noise); + return 1; + case S_RX_SIGNAL: + snprintf(b, bs, "%d", + wf->cur.ast_rx_rssi + wf->cur.ast_rx_noise); + return 1; + } + b[0] = '\0'; + return 0; +#undef RXANT +#undef TXANT +#undef PHY +#undef STAT +} - if (interval < 1) - interval = 1; - signal(SIGALRM, catchalarm); - signalled = 0; - alarm(interval); - banner: - printf("%8s %8s %7s %7s %7s %6s %6s %5s %7s %4s %4s" - , "input" - , "output" - , "altrate" - , "short" - , "long" - , "xretry" - , "crcerr" - , "crypt" - , "phyerr" - , "rssi" - , "rate" - ); - putchar('\n'); - fflush(stdout); - line = 0; - loop: - if (line != 0) { - ifr.ifr_data = (caddr_t) &cur; - if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) - err(1, ifr.ifr_name); - rate = getifrate(s, ifr.ifr_name); - printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n" - , cur.ast_rx_packets - total.ast_rx_packets - , cur.ast_tx_packets - total.ast_tx_packets - , 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; - } else { - ifr.ifr_data = (caddr_t) &total; - if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) - err(1, ifr.ifr_name); - rate = getifrate(s, ifr.ifr_name); - printf("%8u %8u %7u %7u %7u %6u %6u %5u %7u %4u %3uM\n" - , total.ast_rx_packets - , total.ast_tx_packets - , 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); - omask = sigblock(sigmask(SIGALRM)); - if (!signalled) - sigpause(0); - sigsetmask(omask); - signalled = 0; - alarm(interval); - line++; - if (line == 21) /* XXX tty line count */ - goto banner; - else - goto loop; - /*NOTREACHED*/ - } else { - struct ath_stats stats; +static int +ath_get_totstat(struct statfoo *sf, int s, char b[], size_t bs) +{ + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->total.ast_##x); return 1 +#define PHY(x) \ + snprintf(b, bs, "%u", wf->total.ast_rx_phy[x]); return 1 +#define TXANT(x) \ + snprintf(b, bs, "%u", wf->total.ast_ant_tx[x]); return 1 +#define RXANT(x) \ + snprintf(b, bs, "%u", wf->total.ast_ant_rx[x]); return 1 - ifr.ifr_data = (caddr_t) &stats; - if (ioctl(s, SIOCGATHSTATS, &ifr) < 0) - err(1, ifr.ifr_name); - printstats(stdout, &stats); + switch (s) { + case S_INPUT: + snprintf(b, bs, "%lu", + wf->total.ast_rx_packets - wf->total.ast_rx_mgt); + return 1; + case S_OUTPUT: + snprintf(b, bs, "%lu", wf->total.ast_tx_packets); + return 1; + case S_RATE: + snprintf(b, bs, "%uM", wf->total.ast_tx_rate / 2); + return 1; + case S_WATCHDOG: STAT(watchdog); + case S_FATAL: STAT(hardware); + case S_BMISS: STAT(bmiss); + case S_BMISS_PHANTOM: STAT(bmiss_phantom); +#ifdef S_BSTUCK + case S_BSTUCK: STAT(bstuck); +#endif + case S_RXORN: STAT(rxorn); + case S_RXEOL: STAT(rxeol); + case S_TXURN: STAT(txurn); + case S_MIB: STAT(mib); +#ifdef S_INTRCOAL + case S_INTRCOAL: STAT(intrcoal); +#endif + case S_TX_MGMT: STAT(tx_mgmt); + case S_TX_DISCARD: STAT(tx_discard); + case S_TX_QSTOP: STAT(tx_qstop); + case S_TX_ENCAP: STAT(tx_encap); + case S_TX_NONODE: STAT(tx_nonode); + case S_TX_NOMBUF: STAT(tx_nombuf); +#ifdef S_TX_NOMCL + case S_TX_NOMCL: STAT(tx_nomcl); + case S_TX_LINEAR: STAT(tx_linear); + case S_TX_NODATA: STAT(tx_nodata); + case S_TX_BUSDMA: STAT(tx_busdma); +#endif + case S_TX_XRETRIES: STAT(tx_xretries); + case S_TX_FIFOERR: STAT(tx_fifoerr); + case S_TX_FILTERED: STAT(tx_filtered); + case S_TX_SHORTRETRY: STAT(tx_shortretry); + case S_TX_LONGRETRY: STAT(tx_longretry); + case S_TX_BADRATE: STAT(tx_badrate); + case S_TX_NOACK: STAT(tx_noack); + case S_TX_RTS: STAT(tx_rts); + case S_TX_CTS: STAT(tx_cts); + case S_TX_SHORTPRE: STAT(tx_shortpre); + case S_TX_ALTRATE: STAT(tx_altrate); + case S_TX_PROTECT: STAT(tx_protect); + case S_RX_NOMBUF: STAT(rx_nombuf); +#ifdef S_RX_BUSDMA + case S_RX_BUSDMA: STAT(rx_busdma); +#endif + case S_RX_ORN: STAT(rx_orn); + case S_RX_CRC_ERR: STAT(rx_crcerr); + case S_RX_FIFO_ERR: STAT(rx_fifoerr); + case S_RX_CRYPTO_ERR: STAT(rx_badcrypt); + case S_RX_MIC_ERR: STAT(rx_badmic); + case S_RX_PHY_ERR: STAT(rx_phyerr); + case S_RX_PHY_UNDERRUN: PHY(HAL_PHYERR_UNDERRUN); + case S_RX_PHY_TIMING: PHY(HAL_PHYERR_TIMING); + case S_RX_PHY_PARITY: PHY(HAL_PHYERR_PARITY); + case S_RX_PHY_RATE: PHY(HAL_PHYERR_RATE); + case S_RX_PHY_LENGTH: PHY(HAL_PHYERR_LENGTH); + case S_RX_PHY_RADAR: PHY(HAL_PHYERR_RADAR); + case S_RX_PHY_SERVICE: PHY(HAL_PHYERR_SERVICE); + case S_RX_PHY_TOR: PHY(HAL_PHYERR_TOR); + case S_RX_PHY_OFDM_TIMING: PHY(HAL_PHYERR_OFDM_TIMING); + case S_RX_PHY_OFDM_SIGNAL_PARITY: PHY(HAL_PHYERR_OFDM_SIGNAL_PARITY); + case S_RX_PHY_OFDM_RATE_ILLEGAL: PHY(HAL_PHYERR_OFDM_RATE_ILLEGAL); + case S_RX_PHY_OFDM_POWER_DROP: PHY(HAL_PHYERR_OFDM_POWER_DROP); + case S_RX_PHY_OFDM_SERVICE: PHY(HAL_PHYERR_OFDM_SERVICE); + case S_RX_PHY_OFDM_RESTART: PHY(HAL_PHYERR_OFDM_RESTART); + case S_RX_PHY_CCK_TIMING: PHY(HAL_PHYERR_CCK_TIMING); + case S_RX_PHY_CCK_HEADER_CRC: PHY(HAL_PHYERR_CCK_HEADER_CRC); + case S_RX_PHY_CCK_RATE_ILLEGAL: PHY(HAL_PHYERR_CCK_RATE_ILLEGAL); + case S_RX_PHY_CCK_SERVICE: PHY(HAL_PHYERR_CCK_SERVICE); + case S_RX_PHY_CCK_RESTART: PHY(HAL_PHYERR_CCK_RESTART); + case S_RX_TOOSHORT: STAT(rx_tooshort); + case S_RX_TOOBIG: STAT(rx_toobig); + case S_RX_MGT: STAT(rx_mgt); + case S_RX_CTL: STAT(rx_ctl); + case S_TX_RSSI: + snprintf(b, bs, "%d", wf->total.ast_tx_rssi); + return 1; + case S_RX_RSSI: + snprintf(b, bs, "%d", wf->total.ast_rx_rssi); + return 1; + case S_BE_XMIT: STAT(be_xmit); + case S_BE_NOMBUF: STAT(be_nombuf); + case S_PER_CAL: STAT(per_cal); + case S_PER_CALFAIL: STAT(per_calfail); + case S_PER_RFGAIN: STAT(per_rfgain); +#ifdef S_TDMA_UPDATE + case S_TDMA_UPDATE: STAT(tdma_update); + case S_TDMA_TIMERS: STAT(tdma_timers); + case S_TDMA_TSF: STAT(tdma_tsf); +#endif + case S_RATE_CALLS: STAT(rate_calls); + case S_RATE_RAISE: STAT(rate_raise); + case S_RATE_DROP: STAT(rate_drop); + case S_ANT_DEFSWITCH: STAT(ant_defswitch); + case S_ANT_TXSWITCH: STAT(ant_txswitch); + case S_ANT_TX0: TXANT(0); + case S_ANT_TX1: TXANT(1); + case S_ANT_TX2: TXANT(2); + case S_ANT_TX3: TXANT(3); + case S_ANT_TX4: TXANT(4); + case S_ANT_TX5: TXANT(5); + case S_ANT_TX6: TXANT(6); + case S_ANT_TX7: TXANT(7); + case S_ANT_RX0: RXANT(0); + case S_ANT_RX1: RXANT(1); + case S_ANT_RX2: RXANT(2); + case S_ANT_RX3: RXANT(3); + case S_ANT_RX4: RXANT(4); + case S_ANT_RX5: RXANT(5); + case S_ANT_RX6: RXANT(6); + case S_ANT_RX7: RXANT(7); +#ifdef S_CABQ_XMIT + case S_CABQ_XMIT: STAT(cabq_xmit); + case S_CABQ_BUSY: STAT(cabq_busy); +#endif +#ifdef S_FF_TXOK + case S_FF_TXOK: STAT(ff_txok); + case S_FF_TXERR: STAT(ff_txerr); + case S_FF_FLUSH: STAT(ff_flush); + case S_FF_QFULL: STAT(ff_qfull); +#endif + case S_RX_NOISE: + snprintf(b, bs, "%d", wf->total.ast_rx_noise); + return 1; + case S_TX_SIGNAL: + snprintf(b, bs, "%d", + wf->total.ast_tx_rssi + wf->total.ast_rx_noise); + return 1; + case S_RX_SIGNAL: + snprintf(b, bs, "%d", + wf->total.ast_rx_rssi + wf->total.ast_rx_noise); + return 1; } + b[0] = '\0'; return 0; +#undef RXANT +#undef TXANT +#undef PHY +#undef STAT +} + +static void +ath_print_verbose(struct statfoo *sf, FILE *fd) +{ + struct athstatfoo_p *wf = (struct athstatfoo_p *) sf; +#define isphyerr(i) (S_PHY_MIN <= i && i <= S_PHY_MAX) + char s[32]; + const char *indent; + int i; + + for (i = 0; i < S_LAST; i++) { + if (ath_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) { + if (isphyerr(i)) + indent = " "; + else + indent = ""; + fprintf(fd, "%s%s %s\n", indent, s, athstats[i].desc); + } + } + fprintf(fd, "Antenna profile:\n"); + for (i = 0; i < 8; i++) + if (wf->total.ast_ant_rx[i] || wf->total.ast_ant_tx[i]) + fprintf(fd, "[%u] tx %8u rx %8u\n", i, + wf->total.ast_ant_tx[i], + wf->total.ast_ant_rx[i]); +#undef isphyerr +} + +STATFOO_DEFINE_BOUNCE(athstatfoo) + +struct athstatfoo * +athstats_new(const char *ifname, const char *fmtstring) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + struct athstatfoo_p *wf; + + wf = calloc(1, sizeof(struct athstatfoo_p)); + if (wf != NULL) { + statfoo_init(&wf->base.base, "athstats", athstats, N(athstats)); + /* override base methods */ + wf->base.base.collect_cur = ath_collect_cur; + wf->base.base.collect_tot = ath_collect_tot; + wf->base.base.get_curstat = ath_get_curstat; + wf->base.base.get_totstat = ath_get_totstat; + wf->base.base.update_tot = ath_update_tot; + wf->base.base.print_verbose = ath_print_verbose; + + /* setup bounce functions for public methods */ + STATFOO_BOUNCE(wf, athstatfoo); + + /* setup our public methods */ + wf->base.setifname = ath_setifname; +#if 0 + wf->base.setstamac = wlan_setstamac; +#endif + wf->s = socket(AF_INET, SOCK_DGRAM, 0); + if (wf->s < 0) + err(1, "socket"); + + ath_setifname(&wf->base, ifname); + wf->base.setfmt(&wf->base, fmtstring); + } + return &wf->base; +#undef N } diff --git a/tools/tools/ath/athstats/athstats.h b/tools/tools/ath/athstats/athstats.h new file mode 100644 index 0000000..03a9b7c --- /dev/null +++ b/tools/tools/ath/athstats/athstats.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _ATHSTATS_H_ +#define _ATHSTATS_H_ + +#include "statfoo.h" + +/* + * ath statistics class. + */ +struct athstatfoo { + struct statfoo base; + + STATFOO_DECL_METHODS(struct athstatfoo *); + + /* set the network interface name for collection */ + void (*setifname)(struct athstatfoo *, const char *ifname); + /* set the mac address of the associated station/ap */ + void (*setstamac)(struct athstatfoo *, const uint8_t mac[]); +}; + +struct athstatfoo *athstats_new(const char *ifname, const char *fmtstring); +#endif /* _ATHSTATS_H_ */ diff --git a/tools/tools/ath/athstats/main.c b/tools/tools/ath/athstats/main.c new file mode 100644 index 0000000..b775b1a --- /dev/null +++ b/tools/tools/ath/athstats/main.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * $FreeBSD$ + */ + +/* + * Simple Atheros-specific tool to inspect and monitor network traffic + * statistics. + * + * athstats [-i interface] [-l] [-o fmtstring] [interval] + * + * (default interface is ath0). If interval is specified a rolling output + * a la netstat -i is displayed every interval seconds. The format of + * the rolling display can be controlled a la ps. The -l option will + * print a list of all possible statistics for use with the -o option. + */ + +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <err.h> + +#include "athstats.h" + +#define S_DEFAULT \ + "input,output,altrate,short,long,xretry,crcerr,crypt,phyerr,rssi,rate" + +static int signalled; + +static void +catchalarm(int signo __unused) +{ + signalled = 1; +} + +int +main(int argc, char *argv[]) +{ + struct athstatfoo *wf; + int c; + + wf = athstats_new("ath0", S_DEFAULT); + while ((c = getopt(argc, argv, "i:lo:")) != -1) { + switch (c) { + case 'i': + wf->setifname(wf, optarg); + break; + case 'l': + wf->print_fields(wf, stdout); + return 0; + case 'o': + wf->setfmt(wf, optarg); + break; + default: + errx(-1, "usage: %s [-a] [-i ifname] [-l] [-o fmt] [interval]\n", argv[0]); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (argc > 0) { + u_long interval = strtoul(argv[0], NULL, 0); + int line, omask; + + if (interval < 1) + interval = 1; + signal(SIGALRM, catchalarm); + signalled = 0; + alarm(interval); + banner: + wf->print_header(wf, stdout); + line = 0; + loop: + if (line != 0) { + wf->collect_cur(wf); + wf->print_current(wf, stdout); + wf->update_tot(wf); + } else { + wf->collect_tot(wf); + wf->print_total(wf, stdout); + } + fflush(stdout); + omask = sigblock(sigmask(SIGALRM)); + if (!signalled) + sigpause(0); + sigsetmask(omask); + signalled = 0; + alarm(interval); + line++; + if (line == 21) /* XXX tty line count */ + goto banner; + else + goto loop; + /*NOTREACHED*/ + } else { + wf->collect_tot(wf); + wf->print_verbose(wf, stdout); + } + return 0; +} diff --git a/tools/tools/ath/athstats/statfoo.c b/tools/tools/ath/athstats/statfoo.c new file mode 100644 index 0000000..99c616b --- /dev/null +++ b/tools/tools/ath/athstats/statfoo.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * $FreeBSD$ + */ + +#include <stdio.h> +#include <string.h> + +#include "statfoo.h" + +static void +statfoo_setfmt(struct statfoo *sf, const char *fmt0) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + char fmt[4096]; + char *fp, *tok; + int i, j; + + j = 0; + strlcpy(fmt, fmt0, sizeof(fmt)); + for (fp = fmt; (tok = strsep(&fp, ", ")) != NULL;) { + for (i = 0; i < sf->nstats; i++) + if (strcasecmp(tok, sf->stats[i].name) == 0) + break; + if (i >= sf->nstats) { + fprintf(stderr, "%s: unknown statistic name \"%s\" " + "skipped\n", sf->name, tok); + continue; + } + if (j+3 > sizeof(sf->fmts)) { + fprintf(stderr, "%s: not enough room for all stats; " + "stopped at %s\n", sf->name, tok); + break; + } + if (j != 0) + sf->fmts[j++] = ' '; + sf->fmts[j++] = 0x80 | i; + } + sf->fmts[j] = '\0'; +#undef N +} + +static void +statfoo_collect(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to collect data\n", sf->name); +} + +static void +statfoo_update_tot(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to update total data\n", sf->name); +} + +static int +statfoo_get(struct statfoo *sf, int s, char b[], size_t bs) +{ + fprintf(stderr, "%s: don't know how to get stat #%u\n", sf->name, s); + return 0; +} + +static void +statfoo_print_header(struct statfoo *sf, FILE *fd) +{ + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + fprintf(fd, "%*s", f->width, f->label); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_current(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_curstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_total(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_totstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_verbose(struct statfoo *sf, FILE *fd) +{ + char s[32]; + int i; + + for (i = 0; i < sf->nstats; i++) { + if (sf->get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) + fprintf(fd, "%s %s\n", s, sf->stats[i].desc); + } +} + +static void +statfoo_print_fields(struct statfoo *sf, FILE *fd) +{ + int i, w, width; + + width = 0; + for (i = 0; i < sf->nstats; i++) { + w = strlen(sf->stats[i].name); + if (w > width) + width = w; + } + for (i = 0; i < sf->nstats; i++) { + const struct fmt *f = &sf->stats[i]; + if (f->width != 0) + fprintf(fd, "%-*s %s\n", width, f->name, f->desc); + } +} + +void +statfoo_init(struct statfoo *sf, const char *name, const struct fmt *stats, int nstats) +{ + sf->name = name; + sf->stats = stats; + sf->nstats = nstats; + sf->setfmt = statfoo_setfmt; + sf->collect_cur = statfoo_collect; + sf->collect_tot = statfoo_collect; + sf->update_tot = statfoo_update_tot; + sf->get_curstat = statfoo_get; + sf->get_totstat = statfoo_get; + sf->print_header = statfoo_print_header; + sf->print_current = statfoo_print_current; + sf->print_total = statfoo_print_total; + sf->print_verbose = statfoo_print_verbose; + sf->print_fields = statfoo_print_fields; +} diff --git a/tools/tools/ath/athstats/statfoo.h b/tools/tools/ath/athstats/statfoo.h new file mode 100644 index 0000000..4575946 --- /dev/null +++ b/tools/tools/ath/athstats/statfoo.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _STATFOO_H_ +#define _STATFOO_H_ +/* + * Base class for managing+displaying periodically collected statistics. + */ + +/* + * Statistic definition/description. The are defined + * for stats that correspond 1-1 w/ a collected stat + * and for stats that are calculated indirectly. + */ +struct fmt { + int width; /* printed field width */ + const char* name; /* stat field name referenced by user */ + const char* label; /* printed header label */ + const char* desc; /* verbose description */ +}; + +#define STATFOO_DECL_METHODS(_p) \ + /* set the format of the statistics to display */ \ + void (*setfmt)(_p, const char *); \ + /* collect+store ``current statistics'' */ \ + void (*collect_cur)(_p); \ + /* collect+store ``total statistics'' */ \ + void (*collect_tot)(_p); \ + /* update ``total statistics'' if necessary from current */ \ + void (*update_tot)(_p); \ + /* format a statistic from the current stats */ \ + int (*get_curstat)(_p, int, char [], size_t); \ + /* format a statistic from the total stats */ \ + int (*get_totstat)(_p, int, char [], size_t); \ + /* print field headers terminated by a \n */ \ + void (*print_header)(_p, FILE *); \ + /* print current statistics terminated by a \n */ \ + void (*print_current)(_p, FILE *); \ + /* print total statistics terminated by a \n */ \ + void (*print_total)(_p, FILE *); \ + /* print total statistics in a verbose (1 stat/line) format */ \ + void (*print_verbose)(_p, FILE *); \ + /* print available statistics */ \ + void (*print_fields)(_p, FILE *) + +/* + * Statistics base class. This class is not usable; only + * classes derived from it are useful. + */ +struct statfoo { + const char *name; /* statistics name, e.g. wlanstats */ + const struct fmt *stats; /* statistics in class */ + int nstats; /* number of stats */ + unsigned char fmts[4096]; /* private: compiled stats to display */ + + STATFOO_DECL_METHODS(struct statfoo *); +}; + +void statfoo_init(struct statfoo *, const char *name, + const struct fmt *stats, int nstats); + +#define STATFOO_DEFINE_BOUNCE(_t) \ +static void _t##_setfmt(struct _t *wf, const char *fmt0) \ + { wf->base.setfmt(&wf->base, fmt0); } \ +static void _t##_collect_cur(struct _t *wf) \ + { wf->base.collect_cur(&wf->base); } \ +static void _t##_collect_tot(struct _t *wf) \ + { wf->base.collect_tot(&wf->base); } \ +static void _t##_update_tot(struct _t *wf) \ + { wf->base.update_tot(&wf->base); } \ +static int _t##_get_curstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_curstat(&wf->base, s, b, bs); } \ +static int _t##_get_totstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_totstat(&wf->base, s, b, bs); } \ +static void _t##_print_header(struct _t *wf, FILE *fd) \ + { wf->base.print_header(&wf->base, fd); } \ +static void _t##_print_current(struct _t *wf, FILE *fd) \ + { wf->base.print_current(&wf->base, fd); } \ +static void _t##_print_total(struct _t *wf, FILE *fd) \ + { wf->base.print_total(&wf->base, fd); } \ +static void _t##_print_verbose(struct _t *wf, FILE *fd) \ + { wf->base.print_verbose(&wf->base, fd); } \ +static void _t##_print_fields(struct _t *wf, FILE *fd) \ + { wf->base.print_fields(&wf->base, fd); } + +#define STATFOO_BOUNCE(_p, _t) do { \ + _p->base.setfmt = _t##_setfmt; \ + _p->base.collect_cur = _t##_collect_cur; \ + _p->base.collect_tot = _t##_collect_tot; \ + _p->base.update_tot = _t##_update_tot; \ + _p->base.get_curstat = _t##_get_curstat; \ + _p->base.get_totstat = _t##_get_totstat; \ + _p->base.print_header = _t##_print_header; \ + _p->base.print_current = _t##_print_current; \ + _p->base.print_total = _t##_print_total; \ + _p->base.print_verbose = _t##_print_verbose; \ + _p->base.print_fields = _t##_print_fields; \ +} while (0) +#endif /* _STATFOO_H_ */ diff --git a/tools/tools/net80211/wlanstats/Makefile b/tools/tools/net80211/wlanstats/Makefile index 678a988..da36495 100644 --- a/tools/tools/net80211/wlanstats/Makefile +++ b/tools/tools/net80211/wlanstats/Makefile @@ -4,4 +4,6 @@ PROG= wlanstats BINDIR= /usr/local/bin NO_MAN= +SRCS= statfoo.c wlanstats.c main.c + .include <bsd.prog.mk> diff --git a/tools/tools/net80211/wlanstats/main.c b/tools/tools/net80211/wlanstats/main.c new file mode 100644 index 0000000..f3276d1 --- /dev/null +++ b/tools/tools/net80211/wlanstats/main.c @@ -0,0 +1,255 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * $FreeBSD$ + */ + +/* + * wlanstats [-i interface] + * (default interface is ath0). + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/ethernet.h> +#include <net80211/_ieee80211.h> + +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <err.h> + +#include "wlanstats.h" + +#define S_DEFAULT \ + "input,output,rx_ucast,rx_mcast,tx_ucast,tx_mcast,signal,noise,rate" + +static int signalled; + +static void +catchalarm(int signo __unused) +{ + signalled = 1; +} + +#if 0 +static void +print_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN]) +{ +#define STAT(x,fmt) \ + if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; } + struct ieee80211req ireq; + struct ieee80211req_sta_stats stats; + const struct ieee80211_nodestats *ns = &stats.is_stats; + const char *sep; + + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_STA_STATS; + ireq.i_data = &stats; + ireq.i_len = sizeof(stats); + memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN); + if (ioctl(s, SIOCG80211, &ireq) < 0) + err(1, "unable to get station stats for %s", + ether_ntoa((const struct ether_addr*) macaddr)); + + fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr)); + + sep = "\t"; + STAT(rx_data, "%u"); + STAT(rx_mgmt, "%u"); + STAT(rx_ctrl, "%u"); + STAT(rx_beacons, "%u"); + STAT(rx_proberesp, "%u"); + STAT(rx_ucast, "%u"); + STAT(rx_mcast, "%u"); + STAT(rx_bytes, "%llu"); + STAT(rx_dup, "%u"); + STAT(rx_noprivacy, "%u"); + STAT(rx_wepfail, "%u"); + STAT(rx_demicfail, "%u"); + STAT(rx_decap, "%u"); + STAT(rx_defrag, "%u"); + STAT(rx_disassoc, "%u"); + STAT(rx_deauth, "%u"); + STAT(rx_decryptcrc, "%u"); + STAT(rx_unauth, "%u"); + STAT(rx_unencrypted, "%u"); + fprintf(fd, "\n"); + + sep = "\t"; + STAT(tx_data, "%u"); + STAT(tx_mgmt, "%u"); + STAT(tx_probereq, "%u"); + STAT(tx_ucast, "%u"); + STAT(tx_mcast, "%u"); + STAT(tx_bytes, "%llu"); + STAT(tx_novlantag, "%u"); + STAT(tx_vlanmismatch, "%u"); + fprintf(fd, "\n"); + + sep = "\t"; + STAT(tx_assoc, "%u"); + STAT(tx_assoc_fail, "%u"); + STAT(tx_auth, "%u"); + STAT(tx_auth_fail, "%u"); + STAT(tx_deauth, "%u"); + STAT(tx_deauth_code, "%llu"); + STAT(tx_disassoc, "%u"); + STAT(tx_disassoc_code, "%u"); + fprintf(fd, "\n"); + +#undef STAT +} +#endif + +int +main(int argc, char *argv[]) +{ + struct wlanstatfoo *wf; + struct ether_addr *ea; + const uint8_t *mac = NULL; + int allnodes = 0; + int c, mode; + + wf = wlanstats_new("ath0", S_DEFAULT); + while ((c = getopt(argc, argv, "ai:lm:o:")) != -1) { + switch (c) { + case 'a': + allnodes++; + break; + case 'i': + wf->setifname(wf, optarg); + break; + case 'l': + wf->print_fields(wf, stdout); + return 0; + case 'm': + ea = ether_aton(optarg); + if (!ea) + errx(1, "%s: invalid ethernet address", optarg); + mac = ea->octet; + break; + case 'o': + wf->setfmt(wf, optarg); + break; + default: + errx(-1, "usage: %s [-a] [-i ifname] [-l] [-o fmt] [interval]\n", argv[0]); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + mode = wf->getopmode(wf); + wf->setstamac(wf, mac); + + if (argc > 0) { + u_long interval = strtoul(argv[0], NULL, 0); + int line, omask; + + if (interval < 1) + interval = 1; + signal(SIGALRM, catchalarm); + signalled = 0; + alarm(interval); + banner: + wf->print_header(wf, stdout); + line = 0; + loop: + if (line != 0) { + wf->collect_cur(wf); + wf->print_current(wf, stdout); + wf->update_tot(wf); + } else { + wf->collect_tot(wf); + wf->print_total(wf, stdout); + } + fflush(stdout); + omask = sigblock(sigmask(SIGALRM)); + if (!signalled) + sigpause(0); + sigsetmask(omask); + signalled = 0; + alarm(interval); + line++; + /* refresh every display in case sta roams */ + if (mac == NULL && mode == IEEE80211_M_STA) + wf->setstamac(wf, NULL); + if (line == 21) /* XXX tty line count */ + goto banner; + else + goto loop; + /*NOTREACHED*/ +#if 0 + } else if (allnodes) { + struct ieee80211req_sta_info *si; + union { + struct ieee80211req_sta_req req; + uint8_t buf[24*1024]; + } u; + uint8_t *cp; + struct ieee80211req ireq; + int len; + + /* + * Retrieve station/neighbor table and print stats for each. + */ + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_STA_INFO; + memset(&u.req.macaddr, 0xff, sizeof(u.req.macaddr)); + ireq.i_data = &u; + ireq.i_len = sizeof(u); + if (ioctl(s, SIOCG80211, &ireq) < 0) + err(1, "unable to get station information"); + len = ireq.i_len; + if (len >= sizeof(struct ieee80211req_sta_info)) { + cp = u.req.info; + do { + si = (struct ieee80211req_sta_info *) cp; + if (si->isi_len < sizeof(*si)) + break; + print_sta_stats(stdout, si->isi_macaddr); + cp += si->isi_len, len -= si->isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); + } +#endif + } else { + wf->collect_tot(wf); + wf->print_verbose(wf, stdout); + } + return 0; +} diff --git a/tools/tools/net80211/wlanstats/statfoo.c b/tools/tools/net80211/wlanstats/statfoo.c new file mode 100644 index 0000000..99c616b --- /dev/null +++ b/tools/tools/net80211/wlanstats/statfoo.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * $FreeBSD$ + */ + +#include <stdio.h> +#include <string.h> + +#include "statfoo.h" + +static void +statfoo_setfmt(struct statfoo *sf, const char *fmt0) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + char fmt[4096]; + char *fp, *tok; + int i, j; + + j = 0; + strlcpy(fmt, fmt0, sizeof(fmt)); + for (fp = fmt; (tok = strsep(&fp, ", ")) != NULL;) { + for (i = 0; i < sf->nstats; i++) + if (strcasecmp(tok, sf->stats[i].name) == 0) + break; + if (i >= sf->nstats) { + fprintf(stderr, "%s: unknown statistic name \"%s\" " + "skipped\n", sf->name, tok); + continue; + } + if (j+3 > sizeof(sf->fmts)) { + fprintf(stderr, "%s: not enough room for all stats; " + "stopped at %s\n", sf->name, tok); + break; + } + if (j != 0) + sf->fmts[j++] = ' '; + sf->fmts[j++] = 0x80 | i; + } + sf->fmts[j] = '\0'; +#undef N +} + +static void +statfoo_collect(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to collect data\n", sf->name); +} + +static void +statfoo_update_tot(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to update total data\n", sf->name); +} + +static int +statfoo_get(struct statfoo *sf, int s, char b[], size_t bs) +{ + fprintf(stderr, "%s: don't know how to get stat #%u\n", sf->name, s); + return 0; +} + +static void +statfoo_print_header(struct statfoo *sf, FILE *fd) +{ + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + fprintf(fd, "%*s", f->width, f->label); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_current(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_curstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_total(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_totstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_verbose(struct statfoo *sf, FILE *fd) +{ + char s[32]; + int i; + + for (i = 0; i < sf->nstats; i++) { + if (sf->get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) + fprintf(fd, "%s %s\n", s, sf->stats[i].desc); + } +} + +static void +statfoo_print_fields(struct statfoo *sf, FILE *fd) +{ + int i, w, width; + + width = 0; + for (i = 0; i < sf->nstats; i++) { + w = strlen(sf->stats[i].name); + if (w > width) + width = w; + } + for (i = 0; i < sf->nstats; i++) { + const struct fmt *f = &sf->stats[i]; + if (f->width != 0) + fprintf(fd, "%-*s %s\n", width, f->name, f->desc); + } +} + +void +statfoo_init(struct statfoo *sf, const char *name, const struct fmt *stats, int nstats) +{ + sf->name = name; + sf->stats = stats; + sf->nstats = nstats; + sf->setfmt = statfoo_setfmt; + sf->collect_cur = statfoo_collect; + sf->collect_tot = statfoo_collect; + sf->update_tot = statfoo_update_tot; + sf->get_curstat = statfoo_get; + sf->get_totstat = statfoo_get; + sf->print_header = statfoo_print_header; + sf->print_current = statfoo_print_current; + sf->print_total = statfoo_print_total; + sf->print_verbose = statfoo_print_verbose; + sf->print_fields = statfoo_print_fields; +} diff --git a/tools/tools/net80211/wlanstats/statfoo.h b/tools/tools/net80211/wlanstats/statfoo.h new file mode 100644 index 0000000..4575946 --- /dev/null +++ b/tools/tools/net80211/wlanstats/statfoo.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _STATFOO_H_ +#define _STATFOO_H_ +/* + * Base class for managing+displaying periodically collected statistics. + */ + +/* + * Statistic definition/description. The are defined + * for stats that correspond 1-1 w/ a collected stat + * and for stats that are calculated indirectly. + */ +struct fmt { + int width; /* printed field width */ + const char* name; /* stat field name referenced by user */ + const char* label; /* printed header label */ + const char* desc; /* verbose description */ +}; + +#define STATFOO_DECL_METHODS(_p) \ + /* set the format of the statistics to display */ \ + void (*setfmt)(_p, const char *); \ + /* collect+store ``current statistics'' */ \ + void (*collect_cur)(_p); \ + /* collect+store ``total statistics'' */ \ + void (*collect_tot)(_p); \ + /* update ``total statistics'' if necessary from current */ \ + void (*update_tot)(_p); \ + /* format a statistic from the current stats */ \ + int (*get_curstat)(_p, int, char [], size_t); \ + /* format a statistic from the total stats */ \ + int (*get_totstat)(_p, int, char [], size_t); \ + /* print field headers terminated by a \n */ \ + void (*print_header)(_p, FILE *); \ + /* print current statistics terminated by a \n */ \ + void (*print_current)(_p, FILE *); \ + /* print total statistics terminated by a \n */ \ + void (*print_total)(_p, FILE *); \ + /* print total statistics in a verbose (1 stat/line) format */ \ + void (*print_verbose)(_p, FILE *); \ + /* print available statistics */ \ + void (*print_fields)(_p, FILE *) + +/* + * Statistics base class. This class is not usable; only + * classes derived from it are useful. + */ +struct statfoo { + const char *name; /* statistics name, e.g. wlanstats */ + const struct fmt *stats; /* statistics in class */ + int nstats; /* number of stats */ + unsigned char fmts[4096]; /* private: compiled stats to display */ + + STATFOO_DECL_METHODS(struct statfoo *); +}; + +void statfoo_init(struct statfoo *, const char *name, + const struct fmt *stats, int nstats); + +#define STATFOO_DEFINE_BOUNCE(_t) \ +static void _t##_setfmt(struct _t *wf, const char *fmt0) \ + { wf->base.setfmt(&wf->base, fmt0); } \ +static void _t##_collect_cur(struct _t *wf) \ + { wf->base.collect_cur(&wf->base); } \ +static void _t##_collect_tot(struct _t *wf) \ + { wf->base.collect_tot(&wf->base); } \ +static void _t##_update_tot(struct _t *wf) \ + { wf->base.update_tot(&wf->base); } \ +static int _t##_get_curstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_curstat(&wf->base, s, b, bs); } \ +static int _t##_get_totstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_totstat(&wf->base, s, b, bs); } \ +static void _t##_print_header(struct _t *wf, FILE *fd) \ + { wf->base.print_header(&wf->base, fd); } \ +static void _t##_print_current(struct _t *wf, FILE *fd) \ + { wf->base.print_current(&wf->base, fd); } \ +static void _t##_print_total(struct _t *wf, FILE *fd) \ + { wf->base.print_total(&wf->base, fd); } \ +static void _t##_print_verbose(struct _t *wf, FILE *fd) \ + { wf->base.print_verbose(&wf->base, fd); } \ +static void _t##_print_fields(struct _t *wf, FILE *fd) \ + { wf->base.print_fields(&wf->base, fd); } + +#define STATFOO_BOUNCE(_p, _t) do { \ + _p->base.setfmt = _t##_setfmt; \ + _p->base.collect_cur = _t##_collect_cur; \ + _p->base.collect_tot = _t##_collect_tot; \ + _p->base.update_tot = _t##_update_tot; \ + _p->base.get_curstat = _t##_get_curstat; \ + _p->base.get_totstat = _t##_get_totstat; \ + _p->base.print_header = _t##_print_header; \ + _p->base.print_current = _t##_print_current; \ + _p->base.print_total = _t##_print_total; \ + _p->base.print_verbose = _t##_print_verbose; \ + _p->base.print_fields = _t##_print_fields; \ +} while (0) +#endif /* _STATFOO_H_ */ diff --git a/tools/tools/net80211/wlanstats/wlanstats.c b/tools/tools/net80211/wlanstats/wlanstats.c index 118f9c0..3f5f372 100644 --- a/tools/tools/net80211/wlanstats/wlanstats.c +++ b/tools/tools/net80211/wlanstats/wlanstats.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,264 +37,690 @@ */ /* - * wlanstats [-i interface] - * (default interface is ath0). + * net80211 statistics class. */ #include <sys/types.h> #include <sys/file.h> #include <sys/sockio.h> #include <sys/socket.h> #include <net/if.h> +#include <net/if_dl.h> #include <net/if_media.h> #include <net/if_var.h> #include <net/ethernet.h> #include <stdio.h> #include <signal.h> +#include <string.h> #include <unistd.h> #include <err.h> +#include <ifaddrs.h> #include "../../../../sys/net80211/ieee80211_ioctl.h" -const char *progname; +#include "wlanstats.h" + +#ifndef IEEE80211_ADDR_COPY +#define IEEE80211_ADDR_COPY(dst, src) memcpy(dst, src, IEEE80211_ADDR_LEN) +#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0) +#endif + +static const struct fmt wlanstats[] = { +#define S_RX_BADVERSION 0 + { 5, "rx_badversion", "badversion", "rx frame with bad version" }, +#define S_RX_TOOSHORT 1 + { 5, "rx_tooshort", "tooshort", "rx frame too short" }, +#define S_RX_WRONGBSS 2 + { 5, "rx_wrongbss", "wrongbss", "rx from wrong bssid" }, +#define S_RX_DUP 3 + { 5, "rx_dup", "rx_dup", "rx discard 'cuz dup" }, +#define S_RX_WRONGDIR 4 + { 5, "rx_wrongdir", "wrongdir", "rx w/ wrong direction" }, +#define S_RX_MCASTECHO 5 + { 5, "rx_mcastecho", "mcastecho", "rx discard 'cuz mcast echo" }, +#define S_RX_NOTASSOC 6 + { 5, "rx_notassoc", "notassoc", "rx discard 'cuz sta !assoc" }, +#define S_RX_NOPRIVACY 7 + { 5, "rx_noprivacy", "noprivacy", "rx w/ wep but privacy off" }, +#define S_RX_UNENCRYPTED 8 + { 5, "rx_unencrypted", "unencrypted", "rx w/o wep and privacy on" }, +#define S_RX_WEPFAIL 9 + { 5, "rx_wepfail", "wepfail", "rx wep processing failed" }, +#define S_RX_DECAP 10 + { 5, "rx_decap", "decap", "rx decapsulation failed" }, +#define S_RX_MGTDISCARD 11 + { 5, "rx_mgtdiscard", "mgtdiscard", "rx discard mgt frames" }, +#define S_RX_CTL 12 + { 5, "rx_ctl", "ctl", "rx discard ctrl frames" }, +#define S_RX_BEACON 13 + { 5, "rx_beacon", "beacon", "rx beacon frames" }, +#define S_RX_RSTOOBIG 14 + { 5, "rx_rstoobig", "rstoobig", "rx rate set truncated" }, +#define S_RX_ELEM_MISSING 15 + { 5, "rx_elem_missing","elem_missing", "rx required element missing" }, +#define S_RX_ELEM_TOOBIG 16 + { 5, "rx_elem_toobig", "elem_toobig", "rx element too big" }, +#define S_RX_ELEM_TOOSMALL 17 + { 5, "rx_elem_toosmall","elem_toosmall","rx element too small" }, +#define S_RX_ELEM_UNKNOWN 18 + { 5, "rx_elem_unknown","elem_unknown", "rx element unknown" }, +#define S_RX_BADCHAN 19 + { 5, "rx_badchan", "badchan", "rx frame w/ invalid chan" }, +#define S_RX_CHANMISMATCH 20 + { 5, "rx_chanmismatch","chanmismatch", "rx frame chan mismatch" }, +#define S_RX_NODEALLOC 21 + { 5, "rx_nodealloc", "nodealloc", "nodes allocated (rx)" }, +#define S_RX_SSIDMISMATCH 22 + { 5, "rx_ssidmismatch","ssidmismatch", "rx frame ssid mismatch" }, +#define S_RX_AUTH_UNSUPPORTED 23 + { 5, "rx_auth_unsupported","auth_unsupported", + "rx w/ unsupported auth alg" }, +#define S_RX_AUTH_FAIL 24 + { 5, "rx_auth_fail", "auth_fail", "rx sta auth failure" }, +#define S_RX_AUTH_COUNTERMEASURES 25 + { 5, "rx_auth_countermeasures", "auth_countermeasures", + "rx sta auth failure 'cuz of TKIP countermeasures" }, +#define S_RX_ASSOC_BSS 26 + { 5, "rx_assoc_bss", "assoc_bss", "rx assoc from wrong bssid" }, +#define S_RX_ASSOC_NOTAUTH 27 + { 5, "rx_assoc_notauth","assoc_notauth", "rx assoc w/o auth" }, +#define S_RX_ASSOC_CAPMISMATCH 28 + { 5, "rx_assoc_capmismatch","assoc_capmismatch", + "rx assoc w/ cap mismatch" }, +#define S_RX_ASSOC_NORATE 29 + { 5, "rx_assoc_norate","assoc_norate", "rx assoc w/ no rate match" }, +#define S_RX_ASSOC_BADWPAIE 30 + { 5, "rx_assoc_badwpaie","assoc_badwpaie", + "rx assoc w/ bad WPA IE" }, +#define S_RX_DEAUTH 31 + { 5, "rx_deauth", "deauth", "rx deauthentication" }, +#define S_RX_DISASSOC 32 + { 5, "rx_disassoc", "disassoc", "rx disassociation" }, +#define S_RX_BADSUBTYPE 33 + { 5, "rx_badsubtype", "badsubtype", "rx frame w/ unknown subtype" }, +#define S_RX_NOBUF 34 + { 5, "rx_nobuf", "nobuf", "rx failed for lack of mbuf" }, +#define S_RX_DECRYPTCRC 35 + { 5, "rx_decryptcrc", "decryptcrc", "rx decrypt failed on crc" }, +#define S_RX_AHDEMO_MGT 36 + { 5, "rx_ahdemo_mgt", "ahdemo_mgt", + "rx discard mgmt frame received in ahdoc demo mode" }, +#define S_RX_BAD_AUTH 37 + { 5, "rx_bad_auth", "bad_auth", "rx bad authentication request" }, +#define S_RX_UNAUTH 38 + { 5, "rx_unauth", "unauth", + "rx discard 'cuz port unauthorized" }, +#define S_RX_BADKEYID 39 + { 5, "rx_badkeyid", "badkeyid", "rx w/ incorrect keyid" }, +#define S_RX_CCMPREPLAY 40 + { 5, "rx_ccmpreplay", "ccmpreplay", "rx seq# violation (CCMP)" }, +#define S_RX_CCMPFORMAT 41 + { 5, "rx_ccmpformat", "ccmpformat", "rx format bad (CCMP)" }, +#define S_RX_CCMPMIC 42 + { 5, "rx_ccmpmic", "ccmpmic", "rx MIC check failed (CCMP)" }, +#define S_RX_TKIPREPLAY 43 + { 5, "rx_tkipreplay", "tkipreplay", "rx seq# violation (TKIP)" }, +#define S_RX_TKIPFORMAT 44 + { 5, "rx_tkipformat", "tkipformat", "rx format bad (TKIP)" }, +#define S_RX_TKIPMIC 45 + { 5, "rx_tkipmic", "tkipmic", "rx MIC check failed (TKIP)" }, +#define S_RX_TKIPICV 46 + { 5, "rx_tkipicv", "tkipicv", "rx ICV check failed (TKIP)" }, +#define S_RX_BADCIPHER 47 + { 5, "rx_badcipher", "badcipher", "rx failed 'cuz bad cipher/key type" }, +#define S_RX_NOCIPHERCTX 48 + { 5, "rx_nocipherctx", "nocipherctx", "rx failed 'cuz key/cipher ctx not setup" }, +#define S_RX_ACL 49 + { 5, "rx_acl", "acl", "rx discard 'cuz acl policy" }, +#define S_TX_NOBUF 50 + { 5, "tx_nobuf", "nobuf", "tx failed for lack of mbuf" }, +#define S_TX_NONODE 51 + { 5, "tx_nonode", "nonode", "tx failed for no node" }, +#define S_TX_UNKNOWNMGT 52 + { 5, "tx_unknownmgt", "unknownmgt", "tx of unknown mgt frame" }, +#define S_TX_BADCIPHER 53 + { 5, "tx_badcipher", "badcipher", "tx failed 'cuz bad ciper/key type" }, +#define S_TX_NODEFKEY 54 + { 5, "tx_nodefkey", "nodefkey", "tx failed 'cuz no defkey" }, +#define S_TX_NOHEADROOM 55 + { 5, "tx_noheadroom", "noheadroom", "tx failed 'cuz no space for crypto hdrs" }, +#define S_TX_FRAGFRAMES 56 + { 5, "tx_fragframes", "fragframes", "tx frames fragmented" }, +#define S_TX_FRAGS 57 + { 5, "tx_frags", "frags", "tx frags generated" }, +#define S_SCAN_ACTIVE 58 + { 5, "scan_active", "scan_active", "active scans started" }, +#define S_SCAN_PASSIVE 59 + { 5, "scan_passive", "scan_passive", "passive scans started" }, +#define S_NODE_TIMEOUT 60 + { 5, "node_timeout", "node_timeout", "nodes timed out inactivity" }, +#define S_CRYPTO_NOMEM 61 + { 5, "crypto_nomem", "crypto_nomem", "cipher context malloc failed" }, +#define S_CRYPTO_TKIP 62 + { 5, "crypto_tkip", "crypto_tkip", "tkip crypto done in s/w" }, +#define S_CRYPTO_TKIPENMIC 63 + { 5, "crypto_tkipenmic","crypto_tkipenmic", "tkip tx MIC done in s/w" }, +#define S_CRYPTO_TKIPDEMIC 64 + { 5, "crypto_tkipdemic","crypto_tkipdemic", "tkip rx MIC done in s/w" }, +#define S_CRYPTO_TKIPCM 65 + { 5, "crypto_tkipcm", "crypto_tkipcm", "tkip dropped frames 'cuz of countermeasures" }, +#define S_CRYPTO_CCMP 66 + { 5, "crypto_ccmp", "crypto_ccmp", "ccmp crypto done in s/w" }, +#define S_CRYPTO_WEP 67 + { 5, "crypto_wep", "crypto_wep", "wep crypto done in s/w" }, +#define S_CRYPTO_SETKEY_CIPHER 68 + { 5, "crypto_setkey_cipher", "crypto_setkey_cipher","setkey failed 'cuz cipher rejected data" }, +#define S_CRYPTO_SETKEY_NOKEY 69 + { 5, "crypto_setkey_nokey", "crypto_setkey_nokey","setkey failed 'cuz no key index" }, +#define S_CRYPTO_DELKEY 70 + { 5, "crypto_delkey", "crypto_delkey", "driver key delete failed" }, +#define S_CRYPTO_BADCIPHER 71 + { 5, "crypto_badcipher","crypto_badcipher", "setkey failed 'cuz unknown cipher" }, +#define S_CRYPTO_NOCIPHER 72 + { 5, "crypto_nocipher","crypto_nocipher", "setkey failed 'cuz cipher module unavailable" }, +#define S_CRYPTO_ATTACHFAIL 73 + { 5, "crypto_attachfail","crypto_attachfail", "setkey failed 'cuz cipher attach failed" }, +#define S_CRYPTO_SWFALLBACK 74 + { 5, "crypto_swfallback","crypto_swfallback", "crypto fell back to s/w implementation" }, +#define S_CRYPTO_KEYFAIL 75 + { 5, "crypto_keyfail", "crypto_keyfail", "setkey failed 'cuz driver key alloc failed" }, +#define S_CRYPTO_ENMICFAIL 76 + { 5, "crypto_enmicfail","crypto_enmicfail", "enmic failed (may be mbuf exhaustion)" }, +#define S_IBSS_CAPMISMATCH 77 + { 5, "ibss_capmismatch","ibss_capmismatch", "ibss merge faied 'cuz capabilities mismatch" }, +#define S_IBSS_NORATE 78 + { 5, "ibss_norate", "ibss_norate", "ibss merge faied 'cuz rate set mismatch" }, +#define S_PS_UNASSOC 79 + { 5, "ps_unassoc", "ps_unassoc", "ps-poll received for unassociated station" }, +#define S_PS_BADAID 80 + { 5, "ps_badaid", "ps_badaid", "ps-poll received with invalid association id" }, +#define S_PS_QEMPTY 81 + { 5, "ps_qempty", "ps_qempty", "ps-poll received with nothing to send" }, +#define S_FF_BADHDR 82 + { 5, "ff_badhdr", "ff_badhdr", "fast frame rx'd w/ bad hdr" }, +#define S_FF_TOOSHORT 83 + { 5, "ff_tooshort", "ff_tooshort", "fast frame rx decap error" }, +#define S_FF_SPLIT 84 + { 5, "ff_split", "ff_split", "fast frame rx split error" }, +#define S_FF_DECAP 85 + { 5, "ff_decap", "ff_decap", "fast frames decap'd" }, +#define S_FF_ENCAP 86 + { 5, "ff_encap", "ff_encap", "fast frames encap'd for tx" }, +#define S_FF_ENCAPFAIL 87 + { 5, "ff_encapfail", "ff_encapfail", "fast frames encap failed" }, +#define S_RX_BADBINTVAL 88 + { 5, "rx_badbintval", "rx_badbintval","rx frame with bogus beacon interval" }, +#define S_RX_MGMT 89 + { 5, "rx_mgmt", "rx_mgmt", "rx management frames" }, +#define S_RX_DEMICFAIL 90 + { 5, "rx_demicfail", "rx_demicfail", "rx demic failed" }, +#define S_RX_DEFRAG 91 + { 5, "rx_defrag", "rx_defrag", "rx defragmentation failed" }, +#define S_INPUT 92 + { 8, "input", "input", "data frames received" }, +#define S_OUTPUT 93 + { 8, "output", "output", "data frames transmit" }, +#define S_RATE 94 + { 4, "rate", "rate", "current transmit rate" }, +#define S_RSSI 95 + { 4, "rssi", "rssi", "current rssi" }, +#define S_NOISE 96 + { 4, "noise", "noise", "current noise floor (dBm)" }, +#define S_RX_UCAST 97 + { 8, "rx_ucast", "rx_ucast", "unicast data frames received" }, +#define S_RX_MCAST 98 + { 8, "rx_mcast", "rx_mcast", "multicast data frames received" }, +#define S_TX_UCAST 99 + { 8, "tx_ucast", "tx_ucast", "unicast data frames sent" }, +#define S_TX_MCAST 100 + { 8, "tx_mcast", "tx_mcast", "multicast data frames sent" }, +#define S_SIGNAL 101 + { 4, "signal", "sig", "current signal (dBm)" }, +}; +#define S_LAST S_RX_DEFRAG +#define S_MAX S_LAST+1 + +struct wlanstatfoo_p { + struct wlanstatfoo base; + int s; + int opmode; + uint8_t mac[IEEE80211_ADDR_LEN]; + struct ifreq ifr; + struct ieee80211_stats cur; + struct ieee80211_stats total; + struct ieee80211req ireq; + union { + struct ieee80211req_sta_req info; + char buf[1024]; + } u_info; + struct ieee80211req_sta_stats ncur; + struct ieee80211req_sta_stats ntotal; +}; static void -printstats(FILE *fd, const struct ieee80211_stats *stats) +wlan_setifname(struct wlanstatfoo *wf0, const char *ifname) { -#define N(a) (sizeof(a) / sizeof(a[0])) -#define STAT(x,fmt) \ - if (stats->is_##x) fprintf(fd, "%u " fmt "\n", stats->is_##x) - STAT(rx_badversion, "rx frame with bad version"); - STAT(rx_tooshort, "rx frame too short"); - STAT(rx_wrongbss, "rx from wrong bssid"); - STAT(rx_dup, "rx discard 'cuz dup"); - STAT(rx_wrongdir, "rx w/ wrong direction"); - STAT(rx_mcastecho, "rx discard 'cuz mcast echo"); - STAT(rx_notassoc, "rx discard 'cuz sta !assoc"); - STAT(rx_noprivacy, "rx w/ wep but privacy off"); - STAT(rx_unencrypted, "rx w/o wep and privacy on"); - STAT(rx_wepfail, "rx wep processing failed"); - STAT(rx_decap, "rx decapsulation failed"); - STAT(rx_mgtdiscard, "rx discard mgt frames"); - STAT(rx_ctl, "rx discard ctrl frames"); - STAT(rx_beacon, "rx beacon frames"); - STAT(rx_rstoobig, "rx rate set truncated"); - STAT(rx_elem_missing, "rx required element missing"); - STAT(rx_elem_toobig, "rx element too big"); - STAT(rx_elem_toosmall, "rx element too small"); - STAT(rx_elem_unknown, "rx element unknown"); - STAT(rx_badchan, "rx frame w/ invalid chan"); - STAT(rx_chanmismatch, "rx frame chan mismatch"); - STAT(rx_nodealloc, "nodes allocated (rx)"); - STAT(rx_ssidmismatch, "rx frame ssid mismatch"); - STAT(rx_auth_unsupported,"rx w/ unsupported auth alg"); - STAT(rx_auth_fail, "rx sta auth failure"); - STAT(rx_auth_countermeasures, - "rx sta auth failure 'cuz of TKIP countermeasures"); - STAT(rx_assoc_bss, "rx assoc from wrong bssid"); - STAT(rx_assoc_notauth, "rx assoc w/o auth"); - STAT(rx_assoc_capmismatch,"rx assoc w/ cap mismatch"); - STAT(rx_assoc_norate, "rx assoc w/ no rate match"); - STAT(rx_assoc_badwpaie, "rx assoc w/ bad WPA IE"); - STAT(rx_deauth, "rx deauthentication"); - STAT(rx_disassoc, "rx disassociation"); - STAT(rx_badsubtype, "rx frame w/ unknown subtype"); - STAT(rx_nobuf, "rx failed for lack of sk_buffer"); - STAT(rx_decryptcrc, "rx decrypt failed on crc"); - STAT(rx_ahdemo_mgt, - "rx discard mgmt frame received in ahdoc demo mode"); - STAT(rx_bad_auth, "rx bad authentication request"); - STAT(rx_unauth, "rx discard 'cuz port unauthorized"); - STAT(rx_badkeyid, "rx w/ incorrect keyid"); - STAT(rx_ccmpreplay, "rx seq# violation (CCMP)"); - STAT(rx_ccmpformat, "rx format bad (CCMP)"); - STAT(rx_ccmpmic, "rx MIC check failed (CCMP)"); - STAT(rx_tkipreplay, "rx seq# violation (TKIP)"); - STAT(rx_tkipformat, "rx format bad (TKIP)"); - STAT(rx_tkipmic, "rx MIC check failed (TKIP)"); - STAT(rx_tkipicv, "rx ICV check failed (TKIP)"); - STAT(rx_badcipher, "rx failed 'cuz bad cipher/key type"); - STAT(rx_nocipherctx, "rx failed 'cuz key/cipher ctx not setup"); - STAT(rx_acl, "rx discard 'cuz acl policy"); - STAT(tx_nobuf, "tx failed for lack of sk_buffer"); - STAT(tx_nonode, "tx failed for no node"); - STAT(tx_unknownmgt, "tx of unknown mgt frame"); - STAT(tx_badcipher, "tx failed 'cuz bad ciper/key type"); - STAT(tx_nodefkey, "tx failed 'cuz no defkey"); - STAT(tx_noheadroom, "tx failed 'cuz no space for crypto hdrs"); - STAT(tx_fragframes, "tx frames fragmented"); - STAT(tx_frags, "tx frags generated"); - STAT(scan_active, "active scans started"); - STAT(scan_passive, "passive scans started"); - STAT(node_timeout, "nodes timed out inactivity"); - STAT(crypto_nomem, "cipher context malloc failed"); - STAT(crypto_tkip, "tkip crypto done in s/w"); - STAT(crypto_tkipenmic, "tkip tx MIC done in s/w"); - STAT(crypto_tkipdemic, "tkip rx MIC done in s/w"); - STAT(crypto_tkipcm, "tkip dropped frames 'cuz of countermeasures"); - STAT(crypto_ccmp, "ccmp crypto done in s/w"); - STAT(crypto_wep, "wep crypto done in s/w"); - STAT(crypto_setkey_cipher,"setkey failed 'cuz cipher rejected data"); - STAT(crypto_setkey_nokey,"setkey failed 'cuz no key index"); - STAT(crypto_delkey, "driver key delete failed"); - STAT(crypto_badcipher, "setkey failed 'cuz unknown cipher"); - STAT(crypto_nocipher, "setkey failed 'cuz cipher module unavailable"); - STAT(crypto_attachfail, "setkey failed 'cuz cipher attach failed"); - STAT(crypto_swfallback, "crypto fell back to s/w implementation"); - STAT(crypto_keyfail, "setkey failed 'cuz driver key alloc failed"); - STAT(crypto_enmicfail, "enmic failed (may be mbuf exhaustion)"); - STAT(ibss_capmismatch, "ibss merge faied 'cuz capabilities mismatch"); - STAT(ibss_norate, "ibss merge faied 'cuz rate set mismatch"); - STAT(ps_unassoc, "ps-poll received for unassociated station"); - STAT(ps_badaid, "ps-poll received with invalid association id"); - STAT(ps_qempty, "ps-poll received with nothing to send"); - STAT(ff_badhdr, "fast frame rx'd w/ bad hdr"); - STAT(ff_tooshort, "fast frame rx decap error"); - STAT(ff_split, "fast frame rx split error"); - STAT(ff_decap, "fast frames decap'd"); - STAT(ff_encap, "fast frames encap'd for tx"); -#undef STAT -#undef N + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0; + + strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name)); + strncpy(wf->ireq.i_name, ifname, sizeof (wf->ireq.i_name)); +} + +static const char * +wlan_getifname(struct wlanstatfoo *wf0) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0; + + return wf->ifr.ifr_name; } -struct ifreq ifr; -int s; +static int +wlan_getopmode(struct wlanstatfoo *wf0) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0; + + if (wf->opmode == -1) { + struct ifmediareq ifmr; + + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, wf->ifr.ifr_name, sizeof(ifmr.ifm_name)); + if (ioctl(wf->s, SIOCGIFMEDIA, &ifmr) < 0) + err(1, "%s (SIOCGIFMEDIA)", wf->ifr.ifr_name); + if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) + wf->opmode = IEEE80211_M_IBSS; /* XXX ahdemo */ + else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) + wf->opmode = IEEE80211_M_HOSTAP; + else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) + wf->opmode = IEEE80211_M_MONITOR; + else + wf->opmode = IEEE80211_M_STA; + } + return wf->opmode; +} static void -print_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN]) +getlladdr(struct wlanstatfoo_p *wf) { -#define STAT(x,fmt) \ - if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; } - struct ieee80211req ireq; - struct ieee80211req_sta_stats stats; - const struct ieee80211_nodestats *ns = &stats.is_stats; - const char *sep; - - (void) memset(&ireq, 0, sizeof(ireq)); - (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); - ireq.i_type = IEEE80211_IOC_STA_STATS; - ireq.i_data = &stats; - ireq.i_len = sizeof(stats); - memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN); - if (ioctl(s, SIOCG80211, &ireq) < 0) - err(1, "unable to get station stats for %s", - ether_ntoa((const struct ether_addr*) macaddr)); - - fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr)); - - sep = "\t"; - STAT(rx_data, "%u"); - STAT(rx_mgmt, "%u"); - STAT(rx_ctrl, "%u"); - STAT(rx_beacons, "%u"); - STAT(rx_proberesp, "%u"); - STAT(rx_ucast, "%u"); - STAT(rx_mcast, "%u"); - STAT(rx_bytes, "%llu"); - STAT(rx_dup, "%u"); - STAT(rx_noprivacy, "%u"); - STAT(rx_wepfail, "%u"); - STAT(rx_demicfail, "%u"); - STAT(rx_decap, "%u"); - STAT(rx_defrag, "%u"); - STAT(rx_disassoc, "%u"); - STAT(rx_deauth, "%u"); - STAT(rx_decryptcrc, "%u"); - STAT(rx_unauth, "%u"); - STAT(rx_unencrypted, "%u"); - fprintf(fd, "\n"); - - sep = "\t"; - STAT(tx_data, "%u"); - STAT(tx_mgmt, "%u"); - STAT(tx_probereq, "%u"); - STAT(tx_ucast, "%u"); - STAT(tx_mcast, "%u"); - STAT(tx_bytes, "%llu"); - STAT(tx_novlantag, "%u"); - STAT(tx_vlanmismatch, "%u"); - fprintf(fd, "\n"); - - sep = "\t"; - STAT(tx_assoc, "%u"); - STAT(tx_assoc_fail, "%u"); - STAT(tx_auth, "%u"); - STAT(tx_auth_fail, "%u"); - STAT(tx_deauth, "%u"); - STAT(tx_deauth_code, "%llu"); - STAT(tx_disassoc, "%u"); - STAT(tx_disassoc_code, "%u"); - fprintf(fd, "\n"); + const struct sockaddr_dl *sdl; + struct ifaddrs *ifp, *p; -#undef STAT + if (getifaddrs(&ifp) != 0) + err(1, "getifaddrs"); + for (p = ifp; p != NULL; p = p->ifa_next) + if (strcmp(p->ifa_name, wf->ifr.ifr_name) == 0 && + p->ifa_addr->sa_family == AF_LINK) + break; + if (p == NULL) + errx(1, "did not find link layer address for interface %s", + wf->ifr.ifr_name); + sdl = (const struct sockaddr_dl *) p->ifa_addr; + IEEE80211_ADDR_COPY(wf->mac, LLADDR(sdl)); + freeifaddrs(ifp); } -int -main(int argc, char *argv[]) +static void +wlan_setstamac(struct wlanstatfoo *wf0, const uint8_t *mac) { - int c, len; - struct ieee80211req_sta_info *si; - uint8_t buf[24*1024], *cp; - struct ieee80211req ireq; - int allnodes = 0; - - progname = argv[0]; - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - err(1, "socket"); - strncpy(ifr.ifr_name, "ath0", sizeof (ifr.ifr_name)); - while ((c = getopt(argc, argv, "ai:")) != -1) - switch (c) { - case 'a': - allnodes++; + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0; + + if (mac == NULL) { + switch (wlan_getopmode(wf0)) { + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MONITOR: + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + getlladdr(wf); break; - case 'i': - strncpy(ifr.ifr_name, optarg, sizeof (ifr.ifr_name)); + case IEEE80211_M_STA: + wf->ireq.i_type = IEEE80211_IOC_BSSID; + wf->ireq.i_data = wf->mac; + wf->ireq.i_len = IEEE80211_ADDR_LEN; + if (ioctl(wf->s, SIOCG80211, &wf->ireq) <0) + err(1, wf->ireq.i_name); break; - default: - errx(1, "usage: %s [-a] [-i device] [mac...]\n", progname); - /*NOTREACHED*/ } + } else + IEEE80211_ADDR_COPY(wf->mac, mac); +} + +/* XXX only fetch what's needed to do reports */ +static void +wlan_collect(struct wlanstatfoo_p *wf, + struct ieee80211_stats *stats, struct ieee80211req_sta_stats *nstats) +{ + + IEEE80211_ADDR_COPY(wf->u_info.info.is_u.macaddr, wf->mac); + wf->ireq.i_type = IEEE80211_IOC_STA_INFO; + wf->ireq.i_data = (caddr_t) &wf->u_info; + wf->ireq.i_len = sizeof(wf->u_info); + if (ioctl(wf->s, SIOCG80211, &wf->ireq) < 0) + err(1, wf->ireq.i_name); + + IEEE80211_ADDR_COPY(nstats->is_u.macaddr, wf->mac); + wf->ireq.i_type = IEEE80211_IOC_STA_STATS; + wf->ireq.i_data = (caddr_t) nstats; + wf->ireq.i_len = sizeof(*nstats); + if (ioctl(wf->s, SIOCG80211, &wf->ireq) < 0) + err(1, wf->ireq.i_name); + + wf->ifr.ifr_data = (caddr_t) stats; + if (ioctl(wf->s, SIOCG80211STATS, &wf->ifr) < 0) + err(1, wf->ifr.ifr_name); +} + +static void +wlan_collect_cur(struct statfoo *sf) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf; + + wlan_collect(wf, &wf->cur, &wf->ncur); +} - if (argc == optind && !allnodes) { - struct ieee80211_stats stats; +static void +wlan_collect_tot(struct statfoo *sf) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf; + + wlan_collect(wf, &wf->total, &wf->ntotal); +} + +static void +wlan_update_tot(struct statfoo *sf) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf; + + wf->total = wf->cur; + wf->ntotal = wf->ncur; +} - /* no args, just show global stats */ - ifr.ifr_data = (caddr_t) &stats; - if (ioctl(s, SIOCG80211STATS, &ifr) < 0) - err(1, ifr.ifr_name); - printstats(stdout, &stats); - return 0; +static int +wlan_getinfo(struct wlanstatfoo_p *wf, int s, char b[], size_t bs) +{ + const struct ieee80211req_sta_info *si = &wf->u_info.info.info[0]; + uint8_t r; + + switch (s) { + case S_RATE: + r = si->isi_rates[si->isi_txrate]; + snprintf(b, bs, "%uM", (r &~ 0x80) / 2); + return 1; + case S_RSSI: + snprintf(b, bs, "%d", si->isi_rssi); + return 1; + case S_NOISE: + snprintf(b, bs, "%d", si->isi_noise); + return 1; + case S_SIGNAL: + snprintf(b, bs, "%d", si->isi_rssi + si->isi_noise); + return 1; } - if (allnodes) { - /* - * Retrieve station/neighbor table and print stats for each. - */ - (void) memset(&ireq, 0, sizeof(ireq)); - (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); - ireq.i_type = IEEE80211_IOC_STA_INFO; - ireq.i_data = buf; - ireq.i_len = sizeof(buf); - if (ioctl(s, SIOCG80211, &ireq) < 0) - err(1, "unable to get station information"); - len = ireq.i_len; - if (len >= sizeof(struct ieee80211req_sta_info)) { - cp = buf; - do { - si = (struct ieee80211req_sta_info *) cp; - print_sta_stats(stdout, si->isi_macaddr); - cp += si->isi_len, len -= si->isi_len; - } while (len >= sizeof(struct ieee80211req_sta_info)); - } - } else { - /* - * Print stats for specified stations. - */ - for (c = optind; c < argc; c++) { - const struct ether_addr *ea = ether_aton(argv[c]); - if (ea != NULL) - print_sta_stats(stdout, ea->octet); - } + b[0] = '\0'; + return 0; +} + +static int +wlan_get_curstat(struct statfoo *sf, int s, char b[], size_t bs) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->cur.is_##x - wf->total.is_##x); return 1 +#define NSTAT(x) \ + snprintf(b, bs, "%u", \ + wf->ncur.is_stats.ns_##x - wf->ntotal.is_stats.ns_##x); \ + return 1 + + switch (s) { + case S_RX_BADVERSION: STAT(rx_badversion); + case S_RX_TOOSHORT: STAT(rx_tooshort); + case S_RX_WRONGBSS: STAT(rx_wrongbss); + case S_RX_DUP: STAT(rx_dup); + case S_RX_WRONGDIR: STAT(rx_wrongdir); + case S_RX_MCASTECHO: STAT(rx_mcastecho); + case S_RX_NOTASSOC: STAT(rx_notassoc); + case S_RX_NOPRIVACY: STAT(rx_noprivacy); + case S_RX_UNENCRYPTED: STAT(rx_unencrypted); + case S_RX_WEPFAIL: STAT(rx_wepfail); + case S_RX_DECAP: STAT(rx_decap); + case S_RX_MGTDISCARD: STAT(rx_mgtdiscard); + case S_RX_CTL: STAT(rx_ctl); + case S_RX_BEACON: STAT(rx_beacon); + case S_RX_RSTOOBIG: STAT(rx_rstoobig); + case S_RX_ELEM_MISSING: STAT(rx_elem_missing); + case S_RX_ELEM_TOOBIG: STAT(rx_elem_toobig); + case S_RX_ELEM_TOOSMALL: STAT(rx_elem_toosmall); + case S_RX_ELEM_UNKNOWN: STAT(rx_elem_unknown); + case S_RX_BADCHAN: STAT(rx_badchan); + case S_RX_CHANMISMATCH: STAT(rx_chanmismatch); + case S_RX_NODEALLOC: STAT(rx_nodealloc); + case S_RX_SSIDMISMATCH: STAT(rx_ssidmismatch); + case S_RX_AUTH_UNSUPPORTED: STAT(rx_auth_unsupported); + case S_RX_AUTH_FAIL: STAT(rx_auth_fail); + case S_RX_AUTH_COUNTERMEASURES: STAT(rx_auth_countermeasures); + case S_RX_ASSOC_BSS: STAT(rx_assoc_bss); + case S_RX_ASSOC_NOTAUTH: STAT(rx_assoc_notauth); + case S_RX_ASSOC_CAPMISMATCH: STAT(rx_assoc_capmismatch); + case S_RX_ASSOC_NORATE: STAT(rx_assoc_norate); + case S_RX_ASSOC_BADWPAIE: STAT(rx_assoc_badwpaie); + case S_RX_DEAUTH: STAT(rx_deauth); + case S_RX_DISASSOC: STAT(rx_disassoc); + case S_RX_BADSUBTYPE: STAT(rx_badsubtype); + case S_RX_NOBUF: STAT(rx_nobuf); + case S_RX_DECRYPTCRC: STAT(rx_decryptcrc); + case S_RX_AHDEMO_MGT: STAT(rx_ahdemo_mgt); + case S_RX_BAD_AUTH: STAT(rx_bad_auth); + case S_RX_UNAUTH: STAT(rx_unauth); + case S_RX_BADKEYID: STAT(rx_badkeyid); + case S_RX_CCMPREPLAY: STAT(rx_ccmpreplay); + case S_RX_CCMPFORMAT: STAT(rx_ccmpformat); + case S_RX_CCMPMIC: STAT(rx_ccmpmic); + case S_RX_TKIPREPLAY: STAT(rx_tkipreplay); + case S_RX_TKIPFORMAT: STAT(rx_tkipformat); + case S_RX_TKIPMIC: STAT(rx_tkipmic); + case S_RX_TKIPICV: STAT(rx_tkipicv); + case S_RX_BADCIPHER: STAT(rx_badcipher); + case S_RX_NOCIPHERCTX: STAT(rx_nocipherctx); + case S_RX_ACL: STAT(rx_acl); + case S_TX_NOBUF: STAT(tx_nobuf); + case S_TX_NONODE: STAT(tx_nonode); + case S_TX_UNKNOWNMGT: STAT(tx_unknownmgt); + case S_TX_BADCIPHER: STAT(tx_badcipher); + case S_TX_NODEFKEY: STAT(tx_nodefkey); + case S_TX_NOHEADROOM: STAT(tx_noheadroom); + case S_TX_FRAGFRAMES: STAT(tx_fragframes); + case S_TX_FRAGS: STAT(tx_frags); + case S_SCAN_ACTIVE: STAT(scan_active); + case S_SCAN_PASSIVE: STAT(scan_passive); + case S_NODE_TIMEOUT: STAT(node_timeout); + case S_CRYPTO_NOMEM: STAT(crypto_nomem); + case S_CRYPTO_TKIP: STAT(crypto_tkip); + case S_CRYPTO_TKIPENMIC: STAT(crypto_tkipenmic); + case S_CRYPTO_TKIPDEMIC: STAT(crypto_tkipdemic); + case S_CRYPTO_TKIPCM: STAT(crypto_tkipcm); + case S_CRYPTO_CCMP: STAT(crypto_ccmp); + case S_CRYPTO_WEP: STAT(crypto_wep); + case S_CRYPTO_SETKEY_CIPHER: STAT(crypto_setkey_cipher); + case S_CRYPTO_SETKEY_NOKEY: STAT(crypto_setkey_nokey); + case S_CRYPTO_DELKEY: STAT(crypto_delkey); + case S_CRYPTO_BADCIPHER: STAT(crypto_badcipher); + case S_CRYPTO_NOCIPHER: STAT(crypto_nocipher); + case S_CRYPTO_ATTACHFAIL: STAT(crypto_attachfail); + case S_CRYPTO_SWFALLBACK: STAT(crypto_swfallback); + case S_CRYPTO_KEYFAIL: STAT(crypto_keyfail); + case S_CRYPTO_ENMICFAIL: STAT(crypto_enmicfail); + case S_IBSS_CAPMISMATCH: STAT(ibss_capmismatch); + case S_IBSS_NORATE: STAT(ibss_norate); + case S_PS_UNASSOC: STAT(ps_unassoc); + case S_PS_BADAID: STAT(ps_badaid); + case S_PS_QEMPTY: STAT(ps_qempty); + case S_FF_BADHDR: STAT(ff_badhdr); + case S_FF_TOOSHORT: STAT(ff_tooshort); + case S_FF_SPLIT: STAT(ff_split); + case S_FF_DECAP: STAT(ff_decap); + case S_FF_ENCAP: STAT(ff_encap); + case S_RX_BADBINTVAL: STAT(rx_badbintval); + case S_RX_MGMT: STAT(rx_mgmt); + case S_RX_DEMICFAIL: STAT(rx_demicfail); + case S_RX_DEFRAG: STAT(rx_defrag); + case S_INPUT: NSTAT(rx_data); + case S_OUTPUT: NSTAT(tx_data); + case S_RX_UCAST: NSTAT(rx_ucast); + case S_RX_MCAST: NSTAT(rx_mcast); + case S_TX_UCAST: NSTAT(tx_ucast); + case S_TX_MCAST: NSTAT(tx_mcast); + } + return wlan_getinfo(wf, s, b, bs); +#undef NSTAT +#undef STAT +} + +static int +wlan_get_totstat(struct statfoo *sf, int s, char b[], size_t bs) +{ + struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->total.is_##x); return 1 +#define NSTAT(x) \ + snprintf(b, bs, "%u", wf->ntotal.is_stats.ns_##x); return 1 + + switch (s) { + case S_RX_BADVERSION: STAT(rx_badversion); + case S_RX_TOOSHORT: STAT(rx_tooshort); + case S_RX_WRONGBSS: STAT(rx_wrongbss); + case S_RX_DUP: STAT(rx_dup); + case S_RX_WRONGDIR: STAT(rx_wrongdir); + case S_RX_MCASTECHO: STAT(rx_mcastecho); + case S_RX_NOTASSOC: STAT(rx_notassoc); + case S_RX_NOPRIVACY: STAT(rx_noprivacy); + case S_RX_UNENCRYPTED: STAT(rx_unencrypted); + case S_RX_WEPFAIL: STAT(rx_wepfail); + case S_RX_DECAP: STAT(rx_decap); + case S_RX_MGTDISCARD: STAT(rx_mgtdiscard); + case S_RX_CTL: STAT(rx_ctl); + case S_RX_BEACON: STAT(rx_beacon); + case S_RX_RSTOOBIG: STAT(rx_rstoobig); + case S_RX_ELEM_MISSING: STAT(rx_elem_missing); + case S_RX_ELEM_TOOBIG: STAT(rx_elem_toobig); + case S_RX_ELEM_TOOSMALL: STAT(rx_elem_toosmall); + case S_RX_ELEM_UNKNOWN: STAT(rx_elem_unknown); + case S_RX_BADCHAN: STAT(rx_badchan); + case S_RX_CHANMISMATCH: STAT(rx_chanmismatch); + case S_RX_NODEALLOC: STAT(rx_nodealloc); + case S_RX_SSIDMISMATCH: STAT(rx_ssidmismatch); + case S_RX_AUTH_UNSUPPORTED: STAT(rx_auth_unsupported); + case S_RX_AUTH_FAIL: STAT(rx_auth_fail); + case S_RX_AUTH_COUNTERMEASURES: STAT(rx_auth_countermeasures); + case S_RX_ASSOC_BSS: STAT(rx_assoc_bss); + case S_RX_ASSOC_NOTAUTH: STAT(rx_assoc_notauth); + case S_RX_ASSOC_CAPMISMATCH: STAT(rx_assoc_capmismatch); + case S_RX_ASSOC_NORATE: STAT(rx_assoc_norate); + case S_RX_ASSOC_BADWPAIE: STAT(rx_assoc_badwpaie); + case S_RX_DEAUTH: STAT(rx_deauth); + case S_RX_DISASSOC: STAT(rx_disassoc); + case S_RX_BADSUBTYPE: STAT(rx_badsubtype); + case S_RX_NOBUF: STAT(rx_nobuf); + case S_RX_DECRYPTCRC: STAT(rx_decryptcrc); + case S_RX_AHDEMO_MGT: STAT(rx_ahdemo_mgt); + case S_RX_BAD_AUTH: STAT(rx_bad_auth); + case S_RX_UNAUTH: STAT(rx_unauth); + case S_RX_BADKEYID: STAT(rx_badkeyid); + case S_RX_CCMPREPLAY: STAT(rx_ccmpreplay); + case S_RX_CCMPFORMAT: STAT(rx_ccmpformat); + case S_RX_CCMPMIC: STAT(rx_ccmpmic); + case S_RX_TKIPREPLAY: STAT(rx_tkipreplay); + case S_RX_TKIPFORMAT: STAT(rx_tkipformat); + case S_RX_TKIPMIC: STAT(rx_tkipmic); + case S_RX_TKIPICV: STAT(rx_tkipicv); + case S_RX_BADCIPHER: STAT(rx_badcipher); + case S_RX_NOCIPHERCTX: STAT(rx_nocipherctx); + case S_RX_ACL: STAT(rx_acl); + case S_TX_NOBUF: STAT(tx_nobuf); + case S_TX_NONODE: STAT(tx_nonode); + case S_TX_UNKNOWNMGT: STAT(tx_unknownmgt); + case S_TX_BADCIPHER: STAT(tx_badcipher); + case S_TX_NODEFKEY: STAT(tx_nodefkey); + case S_TX_NOHEADROOM: STAT(tx_noheadroom); + case S_TX_FRAGFRAMES: STAT(tx_fragframes); + case S_TX_FRAGS: STAT(tx_frags); + case S_SCAN_ACTIVE: STAT(scan_active); + case S_SCAN_PASSIVE: STAT(scan_passive); + case S_NODE_TIMEOUT: STAT(node_timeout); + case S_CRYPTO_NOMEM: STAT(crypto_nomem); + case S_CRYPTO_TKIP: STAT(crypto_tkip); + case S_CRYPTO_TKIPENMIC: STAT(crypto_tkipenmic); + case S_CRYPTO_TKIPDEMIC: STAT(crypto_tkipdemic); + case S_CRYPTO_TKIPCM: STAT(crypto_tkipcm); + case S_CRYPTO_CCMP: STAT(crypto_ccmp); + case S_CRYPTO_WEP: STAT(crypto_wep); + case S_CRYPTO_SETKEY_CIPHER: STAT(crypto_setkey_cipher); + case S_CRYPTO_SETKEY_NOKEY: STAT(crypto_setkey_nokey); + case S_CRYPTO_DELKEY: STAT(crypto_delkey); + case S_CRYPTO_BADCIPHER: STAT(crypto_badcipher); + case S_CRYPTO_NOCIPHER: STAT(crypto_nocipher); + case S_CRYPTO_ATTACHFAIL: STAT(crypto_attachfail); + case S_CRYPTO_SWFALLBACK: STAT(crypto_swfallback); + case S_CRYPTO_KEYFAIL: STAT(crypto_keyfail); + case S_CRYPTO_ENMICFAIL: STAT(crypto_enmicfail); + case S_IBSS_CAPMISMATCH: STAT(ibss_capmismatch); + case S_IBSS_NORATE: STAT(ibss_norate); + case S_PS_UNASSOC: STAT(ps_unassoc); + case S_PS_BADAID: STAT(ps_badaid); + case S_PS_QEMPTY: STAT(ps_qempty); + case S_FF_BADHDR: STAT(ff_badhdr); + case S_FF_TOOSHORT: STAT(ff_tooshort); + case S_FF_SPLIT: STAT(ff_split); + case S_FF_DECAP: STAT(ff_decap); + case S_FF_ENCAP: STAT(ff_encap); + case S_RX_BADBINTVAL: STAT(rx_badbintval); + case S_RX_MGMT: STAT(rx_mgmt); + case S_RX_DEMICFAIL: STAT(rx_demicfail); + case S_RX_DEFRAG: STAT(rx_defrag); + case S_INPUT: NSTAT(rx_data); + case S_OUTPUT: NSTAT(tx_data); + case S_RX_UCAST: NSTAT(rx_ucast); + case S_RX_MCAST: NSTAT(rx_mcast); + case S_TX_UCAST: NSTAT(tx_ucast); + case S_TX_MCAST: NSTAT(tx_mcast); + } + return wlan_getinfo(wf, s, b, bs); +#undef NSTAT +#undef STAT +} + +STATFOO_DEFINE_BOUNCE(wlanstatfoo) + +struct wlanstatfoo * +wlanstats_new(const char *ifname, const char *fmtstring) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + struct wlanstatfoo_p *wf; + + wf = calloc(1, sizeof(struct wlanstatfoo_p)); + if (wf != NULL) { + statfoo_init(&wf->base.base, "wlanstats", wlanstats, N(wlanstats)); + /* override base methods */ + wf->base.base.collect_cur = wlan_collect_cur; + wf->base.base.collect_tot = wlan_collect_tot; + wf->base.base.get_curstat = wlan_get_curstat; + wf->base.base.get_totstat = wlan_get_totstat; + wf->base.base.update_tot = wlan_update_tot; + + /* setup bounce functions for public methods */ + STATFOO_BOUNCE(wf, wlanstatfoo); + + /* setup our public methods */ + wf->base.setifname = wlan_setifname; + wf->base.getifname = wlan_getifname; + wf->base.getopmode = wlan_getopmode; + wf->base.setstamac = wlan_setstamac; + wf->opmode = -1; + + wf->s = socket(AF_INET, SOCK_DGRAM, 0); + if (wf->s < 0) + err(1, "socket"); + + wlan_setifname(&wf->base, ifname); + wf->base.setfmt(&wf->base, fmtstring); } + return &wf->base; +#undef N } diff --git a/tools/tools/net80211/wlanstats/wlanstats.h b/tools/tools/net80211/wlanstats/wlanstats.h new file mode 100644 index 0000000..9f38098 --- /dev/null +++ b/tools/tools/net80211/wlanstats/wlanstats.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2002-2006 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. + * + * 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. + * + * $FreeBSD$ + */ + +#ifndef _WLANSTATS_H_ +#define _WLANSTATS_H_ + +#include "statfoo.h" + +/* + * wlan statistics class. + */ +struct wlanstatfoo { + struct statfoo base; + + STATFOO_DECL_METHODS(struct wlanstatfoo *); + + /* set the network interface name for collection */ + void (*setifname)(struct wlanstatfoo *, const char *ifname); + /* get the network interface name */ + const char *(*getifname)(struct wlanstatfoo *); + /* get the wireless operating mode */ + int (*getopmode)(struct wlanstatfoo *); + /* set the mac address of the associated station/ap */ + void (*setstamac)(struct wlanstatfoo *, const uint8_t mac[]); +}; + +struct wlanstatfoo *wlanstats_new(const char *ifname, const char *fmtstring); +#endif /* _WLANSTATS_H_ */ |