checkpoint new version
This commit is contained in:
parent
8440b5885d
commit
2f549d72a2
@ -4,4 +4,6 @@ PROG= athstats
|
||||
BINDIR= /usr/local/bin
|
||||
NO_MAN=
|
||||
|
||||
SRCS= main.c statfoo.c athstats.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -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)
|
||||
{
|
||||
#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;
|
||||
|
||||
(void) memset(&ifmr, 0, sizeof(ifmr));
|
||||
(void) strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
static int signalled;
|
||||
|
||||
static void
|
||||
catchalarm(int signo __unused)
|
||||
ath_collect(struct athstatfoo_p *wf, struct ath_stats *stats)
|
||||
{
|
||||
signalled = 1;
|
||||
wf->ifr.ifr_data = (caddr_t) stats;
|
||||
if (ioctl(wf->s, SIOCGATHSTATS, &wf->ifr) < 0)
|
||||
err(1, wf->ifr.ifr_name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
static void
|
||||
ath_collect_cur(struct statfoo *sf)
|
||||
{
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
struct athstatfoo_p *wf = (struct athstatfoo_p *) sf;
|
||||
|
||||
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;
|
||||
ath_collect(wf, &wf->cur);
|
||||
}
|
||||
|
||||
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 void
|
||||
ath_collect_tot(struct statfoo *sf)
|
||||
{
|
||||
struct athstatfoo_p *wf = (struct athstatfoo_p *) sf;
|
||||
|
||||
ifr.ifr_data = (caddr_t) &stats;
|
||||
if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
|
||||
err(1, ifr.ifr_name);
|
||||
printstats(stdout, &stats);
|
||||
ath_collect(wf, &wf->total);
|
||||
}
|
||||
|
||||
static void
|
||||
ath_update_tot(struct statfoo *sf)
|
||||
{
|
||||
struct athstatfoo_p *wf = (struct athstatfoo_p *) sf;
|
||||
|
||||
wf->total = wf->cur;
|
||||
}
|
||||
|
||||
static int
|
||||
ath_get_curstat(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->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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
|
52
tools/tools/ath/athstats/athstats.h
Normal file
52
tools/tools/ath/athstats/athstats.h
Normal file
@ -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_ */
|
134
tools/tools/ath/athstats/main.c
Normal file
134
tools/tools/ath/athstats/main.c
Normal file
@ -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;
|
||||
}
|
191
tools/tools/ath/athstats/statfoo.c
Normal file
191
tools/tools/ath/athstats/statfoo.c
Normal file
@ -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;
|
||||
}
|
127
tools/tools/ath/athstats/statfoo.h
Normal file
127
tools/tools/ath/athstats/statfoo.h
Normal file
@ -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_ */
|
@ -4,4 +4,6 @@ PROG= wlanstats
|
||||
BINDIR= /usr/local/bin
|
||||
NO_MAN=
|
||||
|
||||
SRCS= statfoo.c wlanstats.c main.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
255
tools/tools/net80211/wlanstats/main.c
Normal file
255
tools/tools/net80211/wlanstats/main.c
Normal file
@ -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;
|
||||
}
|
191
tools/tools/net80211/wlanstats/statfoo.c
Normal file
191
tools/tools/net80211/wlanstats/statfoo.c
Normal file
@ -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;
|
||||
}
|
127
tools/tools/net80211/wlanstats/statfoo.h
Normal file
127
tools/tools/net80211/wlanstats/statfoo.h
Normal file
@ -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_ */
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
getlladdr(struct wlanstatfoo_p *wf)
|
||||
{
|
||||
const struct sockaddr_dl *sdl;
|
||||
struct ifaddrs *ifp, *p;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
wlan_setstamac(struct wlanstatfoo *wf0, const uint8_t *mac)
|
||||
{
|
||||
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 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;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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]))
|
||||
#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
|
||||
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
|
||||
}
|
||||
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
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++;
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(ifr.ifr_name, optarg, sizeof (ifr.ifr_name));
|
||||
break;
|
||||
default:
|
||||
errx(1, "usage: %s [-a] [-i device] [mac...]\n", progname);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
if (argc == optind && !allnodes) {
|
||||
struct ieee80211_stats stats;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
tools/tools/net80211/wlanstats/wlanstats.h
Normal file
56
tools/tools/net80211/wlanstats/wlanstats.h
Normal file
@ -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_ */
|
Loading…
Reference in New Issue
Block a user