diff --git a/tools/tools/README b/tools/tools/README index ef934651907c..6e5014ed529a 100644 --- a/tools/tools/README +++ b/tools/tools/README @@ -46,6 +46,7 @@ mctest A multicast test program mfc Merge a directory from HEAD to a branch where it does not already exist and other MFC related script(s). mid Create a Message-ID database for mailing lists. +mwl Tools specific to the Marvell 88W8363 support ncpus Count the number of processors npe Tools specific to the Intel IXP4XXX NPE device nxge A diagnostic tool for the nxge(4) driver diff --git a/tools/tools/mwl/Makefile b/tools/tools/mwl/Makefile new file mode 100644 index 000000000000..64161c3897cc --- /dev/null +++ b/tools/tools/mwl/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= mwlstats mwldebug + +.include diff --git a/tools/tools/mwl/mwldebug/Makefile b/tools/tools/mwl/mwldebug/Makefile new file mode 100644 index 000000000000..a2caf1a6e415 --- /dev/null +++ b/tools/tools/mwl/mwldebug/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= mwldebug +BINDIR= /usr/local/bin +NO_MAN= + +.include diff --git a/tools/tools/mwl/mwldebug/mwldebug.c b/tools/tools/mwl/mwldebug/mwldebug.c new file mode 100644 index 000000000000..4e97b6d8cdcc --- /dev/null +++ b/tools/tools/mwl/mwldebug/mwldebug.c @@ -0,0 +1,212 @@ +/*- + * Copyright (c) 2007 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$ + */ + +/* + * mwldebug [-i interface] flags + * (default interface is mwl0). + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define N(a) (sizeof(a)/sizeof(a[0])) + +const char *progname; + +enum { + MWL_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + MWL_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */ + MWL_DEBUG_RECV = 0x00000004, /* basic recv operation */ + MWL_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */ + MWL_DEBUG_RESET = 0x00000010, /* reset processing */ + MWL_DEBUG_BEACON = 0x00000020, /* beacon handling */ + MWL_DEBUG_INTR = 0x00000040, /* ISR */ + MWL_DEBUG_TX_PROC = 0x00000080, /* tx ISR proc */ + MWL_DEBUG_RX_PROC = 0x00000100, /* rx ISR proc */ + MWL_DEBUG_KEYCACHE = 0x00000200, /* key cache management */ + MWL_DEBUG_STATE = 0x00000400, /* 802.11 state transitions */ + MWL_DEBUG_NODE = 0x00000800, /* node management */ + MWL_DEBUG_RECV_ALL = 0x00001000, /* trace all frames (beacons) */ + MWL_DEBUG_TSO = 0x00002000, /* TSO processing */ + MWL_DEBUG_AMPDU = 0x00004000, /* BA stream handling */ + MWL_DEBUG_ANY = 0xffffffff +}; + +static struct { + const char *name; + u_int bit; +} flags[] = { + { "xmit", MWL_DEBUG_XMIT }, + { "xmit_desc", MWL_DEBUG_XMIT_DESC }, + { "recv", MWL_DEBUG_RECV }, + { "recv_desc", MWL_DEBUG_RECV_DESC }, + { "reset", MWL_DEBUG_RESET }, + { "beacon", MWL_DEBUG_BEACON }, + { "intr", MWL_DEBUG_INTR }, + { "xmit_proc", MWL_DEBUG_TX_PROC }, + { "recv_proc", MWL_DEBUG_RX_PROC }, + { "keycache", MWL_DEBUG_KEYCACHE }, + { "state", MWL_DEBUG_STATE }, + { "node", MWL_DEBUG_NODE }, + { "recv_all", MWL_DEBUG_RECV_ALL }, + { "tso", MWL_DEBUG_TSO }, + { "ampdu", MWL_DEBUG_AMPDU }, + /* XXX these are a hack; there should be a separate sysctl knob */ + { "hal", 0x02000000 }, /* cmd-completion processing */ + { "hal2", 0x01000000 }, /* cmd submission processing */ + { "halhang", 0x04000000 }, /* disable fw hang stuff */ +}; + +static u_int +getflag(const char *name, int len) +{ + int i; + + for (i = 0; i < N(flags); i++) + if (strncasecmp(flags[i].name, name, len) == 0) + return flags[i].bit; + return 0; +} + +#if 0 +static const char * +getflagname(u_int flag) +{ + int i; + + for (i = 0; i < N(flags); i++) + if (flags[i].bit == flag) + return flags[i].name; + return "???"; +} +#endif + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage: %s [-i device] [flags]\n", progname); + fprintf(stderr, "where flags are:\n"); + for (i = 0; i < N(flags); i++) + printf("%s\n", flags[i].name); + exit(-1); +} + +int +main(int argc, char *argv[]) +{ + const char *ifname = "mwl0"; + const char *cp, *tp; + const char *sep; + int c, op, i; + u_int32_t debug, ndebug; + size_t debuglen; + char oid[256]; + + progname = argv[0]; + if (argc > 1) { + if (strcmp(argv[1], "-i") == 0) { + if (argc < 2) + errx(1, "missing interface name for -i option"); + ifname = argv[2]; + if (strncmp(ifname, "mv", 2) != 0) + errx(2, "huh, this is for mv devices?"); + argc -= 2, argv += 2; + } else if (strcmp(argv[1], "-?") == 0) + usage(); + } + + snprintf(oid, sizeof(oid), "dev.mwl.%s.debug", ifname+3); + debuglen = sizeof(debug); + if (sysctlbyname(oid, &debug, &debuglen, NULL, 0) < 0) + err(1, "sysctl-get(%s)", oid); + ndebug = debug; + for (; argc > 1; argc--, argv++) { + cp = argv[1]; + do { + u_int bit; + + if (*cp == '-') { + cp++; + op = -1; + } else if (*cp == '+') { + cp++; + op = 1; + } else + op = 0; + for (tp = cp; *tp != '\0' && *tp != '+' && *tp != '-';) + tp++; + bit = getflag(cp, tp-cp); + if (op < 0) + ndebug &= ~bit; + else if (op > 0) + ndebug |= bit; + else { + if (bit == 0) { + c = *cp; + if (isdigit(c)) + bit = strtoul(cp, NULL, 0); + else + errx(1, "unknown flag %.*s", + (int)(tp-cp), cp); + } + ndebug = bit; + } + } while (*(cp = tp) != '\0'); + } + if (debug != ndebug) { + printf("%s: 0x%x => ", oid, debug); + if (sysctlbyname(oid, NULL, NULL, &ndebug, sizeof(ndebug)) < 0) + err(1, "sysctl-set(%s)", oid); + printf("0x%x", ndebug); + debug = ndebug; + } else + printf("%s: 0x%x", oid, debug); + sep = "<"; + for (i = 0; i < N(flags); i++) + if (debug & flags[i].bit) { + printf("%s%s", sep, flags[i].name); + sep = ","; + } + printf("%s\n", *sep != '<' ? ">" : ""); + return 0; +} diff --git a/tools/tools/mwl/mwlstats/Makefile b/tools/tools/mwl/mwlstats/Makefile new file mode 100644 index 000000000000..b3e22d539ddd --- /dev/null +++ b/tools/tools/mwl/mwlstats/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +PROG= mwlstats +BINDIR= /usr/local/bin +NO_MAN= + +SRCS= main.c statfoo.c mwlstats.c + +.include + +CFLAGS+= -I. diff --git a/tools/tools/mwl/mwlstats/main.c b/tools/tools/mwl/mwlstats/main.c new file mode 100644 index 000000000000..025c410f5723 --- /dev/null +++ b/tools/tools/mwl/mwlstats/main.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 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$ + */ + +/* + * Simple Marvell-specific tool to inspect and monitor network traffic + * statistics. + * + * mwlstats [-i interface] [-l] [-o fmtstring] [interval] + * + * (default interface is mv0). 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 +#include +#include +#include +#include + +#include "mwlstats.h" + +#define S_DEFAULT \ + "input,output,txtry,txretry,txmretry,txdoneput,rxfcs,rxcrypt,rxicv,rssi,rate" + +static int signalled; + +static void +catchalarm(int signo __unused) +{ + signalled = 1; +} + +int +main(int argc, char *argv[]) +{ + struct mwlstatfoo *wf; + int c; + + wf = mwlstats_new("mwl0", S_DEFAULT); + while ((c = getopt(argc, argv, "i:lo:")) != -1) { + switch (c) { + case 'i': + wf->setifname(wf, optarg); + break; + case 'l': + wf->print_fields(wf, stdout); + return 0; + case 'o': + wf->setfmt(wf, optarg); + break; + default: + errx(-1, "usage: %s [-a] [-i ifname] [-l] [-o fmt] [interval]\n", argv[0]); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (argc > 0) { + u_long interval = strtoul(argv[0], NULL, 0); + int line, omask; + + if (interval < 1) + interval = 1; + signal(SIGALRM, catchalarm); + signalled = 0; + alarm(interval); + banner: + wf->print_header(wf, stdout); + line = 0; + loop: + if (line != 0) { + wf->collect_cur(wf); + wf->print_current(wf, stdout); + wf->update_tot(wf); + } else { + wf->collect_tot(wf); + wf->print_total(wf, stdout); + } + fflush(stdout); + omask = sigblock(sigmask(SIGALRM)); + if (!signalled) + sigpause(0); + sigsetmask(omask); + signalled = 0; + alarm(interval); + line++; + if (line == 21) /* XXX tty line count */ + goto banner; + else + goto loop; + /*NOTREACHED*/ + } else { + wf->collect_tot(wf); + wf->print_verbose(wf, stdout); + } + return 0; +} diff --git a/tools/tools/mwl/mwlstats/mwlstats.c b/tools/tools/mwl/mwlstats/mwlstats.c new file mode 100644 index 000000000000..e92b790e4b48 --- /dev/null +++ b/tools/tools/mwl/mwlstats/mwlstats.c @@ -0,0 +1,578 @@ +/*- + * Copyright (c) 2007 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$ + */ + +/* + * mwl statistics class. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../sys/net80211/ieee80211_ioctl.h" +#include "../../sys/net80211/ieee80211_radiotap.h" + +/* + * Get Hardware Statistics. + */ +struct mwl_hal_hwstats { + uint32_t TxRetrySuccesses; + uint32_t TxMultipleRetrySuccesses; + uint32_t TxFailures; + uint32_t RTSSuccesses; + uint32_t RTSFailures; + uint32_t AckFailures; + uint32_t RxDuplicateFrames; + uint32_t FCSErrorCount; + uint32_t TxWatchDogTimeouts; + uint32_t RxOverflows; + uint32_t RxFragErrors; + uint32_t RxMemErrors; + uint32_t PointerErrors; + uint32_t TxUnderflows; + uint32_t TxDone; + uint32_t TxDoneBufTryPut; + uint32_t TxDoneBufPut; + uint32_t Wait4TxBuf; + uint32_t TxAttempts; + uint32_t TxSuccesses; + uint32_t TxFragments; + uint32_t TxMulticasts; + uint32_t RxNonCtlPkts; + uint32_t RxMulticasts; + uint32_t RxUndecryptableFrames; + uint32_t RxICVErrors; + uint32_t RxExcludedFrames; +}; +#include "../../../../sys/dev/mwl/if_mwlioctl.h" + +#include "mwlstats.h" + +#define AFTER(prev) ((prev)+1) + +static const struct fmt mwlstats[] = { +#define S_INPUT 0 + { 8, "input", "input", "total frames received" }, +#define S_RX_MCAST AFTER(S_INPUT) + { 7, "rxmcast", "rxmcast", "rx multicast frames" }, +#define S_RX_NONCTL AFTER(S_RX_MCAST) + { 8, "rxnonctl", "rxnonctl" "rx non control frames" }, +#define S_RX_MGT AFTER(S_RX_NONCTL) + { 5, "rxmgt", "rxmgt", "rx management frames" }, +#define S_RX_CTL AFTER(S_RX_MGT) + { 5, "rxctl", "rxctl", "rx control frames" }, +#define S_OUTPUT AFTER(S_RX_CTL) + { 8, "output", "output", "total frames transmit" }, +#define S_TX_MCAST AFTER(S_OUTPUT) + { 7, "txmcast", "txmcast", "tx multicast frames" }, +#define S_TX_MGMT AFTER(S_TX_MCAST) + { 5, "txmgt", "txmgt", "tx management frames" }, +#define S_TX_RETRY AFTER(S_TX_MGMT) + { 7, "txretry", "txretry", "tx success with 1 retry" }, +#define S_TX_MRETRY AFTER(S_TX_RETRY) + { 8, "txmretry", "txmretry", "tx success with >1 retry" }, +#define S_TX_RTSGOOD AFTER(S_TX_MRETRY) + { 7, "rtsgood", "rtsgood", "RTS tx success" }, +#define S_TX_RTSBAD AFTER(S_TX_RTSGOOD) + { 6, "rtsbad", "rtsbad", "RTS tx failed" }, +#define S_TX_NOACK AFTER(S_TX_RTSBAD) + { 5, "noack", "noack", "tx failed because no ACK was received" }, +#define S_RX_DUPLICATE AFTER(S_TX_NOACK) + { 5, "rxdup", "rxdup", "rx discarded by f/w as dup" }, +#define S_RX_FCS AFTER(S_RX_DUPLICATE) + { 5, "rxfcs", "rxfcs", "rx discarded by f/w for bad FCS" }, +#define S_TX_WATCHDOG AFTER(S_RX_FCS) + { 7, "txwatch", "txwatch", "MAC tx hang (f/w recovery)" }, +#define S_RX_OVERFLOW AFTER(S_TX_WATCHDOG) + { 6, "rxover", "rxover", "no f/w buffer for rx" }, +#define S_RX_FRAGERROR AFTER(S_RX_OVERFLOW) + { 6, "rxfrag", "rxfrag", "rx failed in f/w due to defrag" }, +#define S_RX_MEMERROR AFTER(S_RX_FRAGERROR) + { 5, "rxmem", "rxmem", "rx failed in f/w 'cuz out of of memory" }, +#define S_PTRERROR AFTER(S_RX_MEMERROR) + { 6, "badptr", "badptr", "MAC internal pointer problem" }, +#define S_TX_UNDERFLOW AFTER(S_PTRERROR) + { 7, "txunder", "txunder", "tx failed in f/w 'cuz of underflow" }, +#define S_TX_DONE AFTER(S_TX_UNDERFLOW) + { 6, "txdone", "txdone", "MAC tx ops completed" }, +#define S_TX_DONEBUFPUT AFTER(S_TX_DONE) + { 9, "txdoneput", "txdoneput", "tx buffers returned by f/w to host" }, +#define S_TX_WAIT4BUF AFTER(S_TX_DONEBUFPUT) + { 6, "txwait", "txwait", "no f/w buffers available when supplied a tx descriptor" }, +#define S_TX_ATTEMPTS AFTER(S_TX_WAIT4BUF) + { 5, "txtry", "txtry", "tx descriptors processed by f/w" }, +#define S_TX_SUCCESS AFTER(S_TX_ATTEMPTS) + { 4, "txok", "txok", "tx attempts successful" }, +#define S_TX_FRAGS AFTER(S_TX_SUCCESS) + { 6, "txfrag", "txfrag", "tx attempts with fragmentation" }, +#define S_RX_UNDECRYPT AFTER(S_TX_FRAGS) + { 7, "rxcrypt", "rxcrypt", "rx failed in f/w 'cuz decrypt failed" }, +#define S_RX_ICVERROR AFTER(S_RX_UNDECRYPT) + { 5, "rxicv", "rxicv", "rx failed in f/w 'cuz ICV check" }, +#define S_RX_EXCLUDE AFTER(S_RX_ICVERROR) + { 8, "rxfilter", "rxfilter", "rx frames filtered in f/w" }, +#define S_TX_LINEAR AFTER(S_RX_EXCLUDE) + { 5, "txlinear", "txlinear", "tx linearized to cluster" }, +#define S_TX_DISCARD AFTER(S_TX_LINEAR) + { 5, "txdisc", "txdisc", "tx frames discarded prior to association" }, +#define S_TX_QSTOP AFTER(S_TX_DISCARD) + { 5, "qstop", "qstop", "tx stopped 'cuz no xmit buffer" }, +#define S_TX_ENCAP AFTER(S_TX_QSTOP) + { 5, "txencode", "txencode", "tx encapsulation failed" }, +#define S_TX_NOMBUF AFTER(S_TX_ENCAP) + { 5, "txnombuf", "txnombuf", "tx failed 'cuz mbuf allocation failed" }, +#define S_TX_SHORTPRE AFTER(S_TX_NOMBUF) + { 5, "shpre", "shpre", "tx frames with short preamble" }, +#define S_TX_NOHEADROOM AFTER(S_TX_SHORTPRE) + { 5, "nohead", "nohead", "tx frames discarded for lack of headroom" }, +#define S_TX_BADFRAMETYPE AFTER(S_TX_NOHEADROOM) + { 5, "badtxtype", "badtxtype", "tx frames discarded for invalid/unknown 802.11 frame type" }, +#define S_RX_CRYPTO_ERR AFTER(S_TX_BADFRAMETYPE) + { 5, "crypt", "crypt", "rx failed 'cuz decryption" }, +#define S_RX_NOMBUF AFTER(S_RX_CRYPTO_ERR) + { 5, "rxnombuf", "rxnombuf", "rx setup failed 'cuz no mbuf" }, +#define S_RX_TKIPMIC AFTER(S_RX_NOMBUF) + { 5, "rxtkipmic", "rxtkipmic", "rx failed 'cuz TKIP MIC error" }, +#define S_RX_NODMABUF AFTER(S_RX_TKIPMIC) + { 5, "rxnodmabuf", "rxnodmabuf", "rx failed 'cuz no DMA buffer available" }, +#define S_RX_DMABUFMISSING AFTER(S_RX_NODMABUF) + { 5, "rxdmabufmissing", "rxdmabufmissing", "rx descriptor with no DMA buffer attached" }, +#define S_TX_NODATA AFTER(S_RX_DMABUFMISSING) + { 5, "txnodata", "txnodata", "tx discarded empty frame" }, +#define S_TX_BUSDMA AFTER(S_TX_NODATA) + { 5, "txbusdma", "txbusdma", "tx failed for dma resources" }, +#define S_RX_BUSDMA AFTER(S_TX_BUSDMA) + { 5, "rxbusdma", "rxbusdma", "rx setup failed for dma resources" }, +#define S_AMPDU_NOSTREAM AFTER(S_RX_BUSDMA) + { 5, "ampdu_nostream","ampdu_nostream","ADDBA request failed 'cuz all BA streams in use" }, +#define S_AMPDU_REJECT AFTER(S_AMPDU_NOSTREAM) + { 5, "ampdu_reject","ampdu_reject","ADDBA request failed 'cuz station already has one BA stream" }, +#define S_ADDBA_NOSTREAM AFTER(S_AMPDU_REJECT) + { 5, "addba_nostream","addba_nostream","ADDBA response processed but no BA stream present" }, +#define S_TX_TSO AFTER(S_ADDBA_NOSTREAM) + { 8, "txtso", "tso", "tx frames using TSO" }, +#define S_TSO_BADETH AFTER(S_TX_TSO) + { 5, "tsoeth", "tsoeth", "TSO failed 'cuz ether header type not IPv4" }, +#define S_TSO_NOHDR AFTER(S_TSO_BADETH) + { 5, "tsonohdr", "tsonohdr", "TSO failed 'cuz header not in first mbuf" }, +#define S_TSO_BADSPLIT AFTER(S_TSO_NOHDR) + { 5, "tsobadsplit", "tsobadsplit", "TSO failed 'cuz payload split failed" }, +#define S_BAWATCHDOG AFTER(S_TSO_BADSPLIT) + { 5, "bawatchdog", "bawatchdog", "BA watchdog interrupts" }, +#define S_BAWATCHDOG_NOTFOUND AFTER(S_BAWATCHDOG) + { 5, "bawatchdog_notfound", "bawatchdog_notfound", + "BA watchdog for unknown stream" }, +#define S_BAWATCHDOG_EMPTY AFTER(S_BAWATCHDOG_NOTFOUND) + { 5, "bawatchdog_empty", "bawatchdog_empty", + "BA watchdog on all streams but none found" }, +#define S_BAWATCHDOG_FAILED AFTER(S_BAWATCHDOG_EMPTY) + { 5, "bawatchdog_failed", "bawatchdog_failed", + "BA watchdog processing failed to get bitmap from f/w" }, +#define S_RADARDETECT AFTER(S_BAWATCHDOG_FAILED) + { 5, "radardetect", "radardetect", "radar detect interrupts" }, +#define S_RATE AFTER(S_RADARDETECT) + { 4, "rate", "rate", "rate of last transmit" }, +#define S_TX_RSSI AFTER(S_RATE) + { 4, "arssi", "arssi", "rssi of last ack" }, +#define S_RX_RSSI AFTER(S_TX_RSSI) + { 4, "rssi", "rssi", "avg recv rssi" }, +#define S_RX_NOISE AFTER(S_RX_RSSI) + { 5, "noise", "noise", "rx noise floor" }, +#define S_TX_SIGNAL AFTER(S_RX_NOISE) + { 4, "asignal", "asig", "signal of last ack (dBm)" }, +#define S_RX_SIGNAL AFTER(S_TX_SIGNAL) + { 4, "signal", "sig", "avg recv signal (dBm)" }, +#define S_ANT_TX0 AFTER(S_RX_SIGNAL) + { 8, "tx0", "ant0(tx)", "frames tx on antenna 0" }, +#define S_ANT_TX1 (S_RX_SIGNAL+2) + { 8, "tx1", "ant1(tx)", "frames tx on antenna 1" }, +#define S_ANT_TX2 (S_RX_SIGNAL+3) + { 8, "tx2", "ant2(tx)", "frames tx on antenna 2" }, +#define S_ANT_TX3 (S_RX_SIGNAL+4) + { 8, "tx3", "ant3(tx)", "frames tx on antenna 3" }, +#define S_ANT_RX0 AFTER(S_ANT_TX3) + { 8, "rx0", "ant0(rx)", "frames rx on antenna 0" }, +#define S_ANT_RX1 (S_ANT_TX3+2) + { 8, "rx1", "ant1(rx)", "frames rx on antenna 1" }, +#define S_ANT_RX2 (S_ANT_TX3+3) + { 8, "rx2", "ant2(rx)", "frames rx on antenna 2" }, +#define S_ANT_RX3 (S_ANT_TX3+4) + { 8, "rx3", "ant3(rx)", "frames rx on antenna 3" }, +}; +/* NB: this intentionally avoids per-antenna stats */ +#define S_LAST (S_RX_SIGNAL+1) + +struct mwlstatfoo_p { + struct mwlstatfoo base; + int s; + struct ifreq ifr; + struct mwl_stats cur; + struct mwl_stats total; +}; + +static void +mwl_setifname(struct mwlstatfoo *wf0, const char *ifname) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) wf0; + + strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name)); +} + +static void +mwl_collect(struct mwlstatfoo_p *wf, struct mwl_stats *stats) +{ + wf->ifr.ifr_data = (caddr_t) stats; + if (ioctl(wf->s, SIOCGMVSTATS, &wf->ifr) < 0) + err(1, wf->ifr.ifr_name); +} + +static void +mwl_collect_cur(struct statfoo *sf) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; + + mwl_collect(wf, &wf->cur); +} + +static void +mwl_collect_tot(struct statfoo *sf) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; + + mwl_collect(wf, &wf->total); +} + +static void +mwl_update_tot(struct statfoo *sf) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; + + wf->total = wf->cur; +} + +static void +setrate(char b[], size_t bs, uint8_t rate) +{ + if (rate & IEEE80211_RATE_MCS) + snprintf(b, bs, "MCS%u", rate & IEEE80211_RATE_VAL); + else if (rate & 1) + snprintf(b, bs, "%u.5M", rate / 2); + else + snprintf(b, bs, "%uM", rate / 2); +} + +static int +mwl_get_curstat(struct statfoo *sf, int s, char b[], size_t bs) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->cur.mst_##x - wf->total.mst_##x); return 1 +#define HWSTAT(x) \ + snprintf(b, bs, "%u", wf->cur.hw_stats.x - wf->total.hw_stats.x); return 1 +#define RXANT(x) \ + snprintf(b, bs, "%u", wf->cur.mst_ant_rx[x] - wf->total.mst_ant_rx[x]); return 1 +#define TXANT(x) \ + snprintf(b, bs, "%u", wf->cur.mst_ant_tx[x] - wf->total.mst_ant_tx[x]); return 1 + + switch (s) { + case S_INPUT: + snprintf(b, bs, "%lu", (u_long)( + (wf->cur.mst_rx_packets - wf->total.mst_rx_packets))); + return 1; + case S_OUTPUT: + snprintf(b, bs, "%lu", (u_long)( + wf->cur.mst_tx_packets - wf->total.mst_tx_packets)); + return 1; + case S_RATE: + setrate(b, bs, wf->cur.mst_tx_rate); + return 1; + case S_TX_RETRY: HWSTAT(TxRetrySuccesses); + case S_TX_MRETRY: HWSTAT(TxMultipleRetrySuccesses); + case S_TX_RTSGOOD: HWSTAT(RTSSuccesses); + case S_TX_RTSBAD: HWSTAT(RTSFailures); + case S_TX_NOACK: HWSTAT(AckFailures); + case S_RX_DUPLICATE: HWSTAT(RxDuplicateFrames); + case S_RX_FCS: HWSTAT(FCSErrorCount); + case S_TX_WATCHDOG: HWSTAT(TxWatchDogTimeouts); + case S_RX_OVERFLOW: HWSTAT(RxOverflows); + case S_RX_FRAGERROR: HWSTAT(RxFragErrors); + case S_RX_MEMERROR: HWSTAT(RxMemErrors); + case S_PTRERROR: HWSTAT(PointerErrors); + case S_TX_UNDERFLOW: HWSTAT(TxUnderflows); + case S_TX_DONE: HWSTAT(TxDone); + case S_TX_DONEBUFPUT: HWSTAT(TxDoneBufPut); + case S_TX_WAIT4BUF: HWSTAT(Wait4TxBuf); + case S_TX_ATTEMPTS: HWSTAT(TxAttempts); + case S_TX_SUCCESS: HWSTAT(TxSuccesses); + case S_TX_FRAGS: HWSTAT(TxFragments); + case S_TX_MCAST: HWSTAT(TxMulticasts); + case S_RX_NONCTL: HWSTAT(RxNonCtlPkts); + case S_RX_MCAST: HWSTAT(RxMulticasts); + case S_RX_UNDECRYPT: HWSTAT(RxUndecryptableFrames); + case S_RX_ICVERROR: HWSTAT(RxICVErrors); + case S_RX_EXCLUDE: HWSTAT(RxExcludedFrames); + 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_NOMBUF: STAT(tx_nombuf); + case S_TX_LINEAR: STAT(tx_linear); + case S_TX_NODATA: STAT(tx_nodata); + case S_TX_BUSDMA: STAT(tx_busdma); + case S_TX_SHORTPRE: STAT(tx_shortpre); + case S_TX_NOHEADROOM: STAT(tx_noheadroom); + case S_TX_BADFRAMETYPE: STAT(tx_badframetype); + case S_RX_CRYPTO_ERR: STAT(rx_crypto); + case S_RX_TKIPMIC: STAT(rx_tkipmic); + case S_RX_NODMABUF: STAT(rx_nodmabuf); + case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing); + case S_RX_NOMBUF: STAT(rx_nombuf); + case S_RX_BUSDMA: STAT(rx_busdma); + case S_AMPDU_NOSTREAM: STAT(ampdu_nostream); + case S_AMPDU_REJECT: STAT(ampdu_reject); + case S_ADDBA_NOSTREAM: STAT(addba_nostream); + case S_TX_TSO: STAT(tx_tso); + case S_TSO_BADETH: STAT(tso_badeth); + case S_TSO_NOHDR: STAT(tso_nohdr); + case S_TSO_BADSPLIT: STAT(tso_badsplit); + case S_BAWATCHDOG: STAT(bawatchdog); + case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound); + case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty); + case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed); + case S_RADARDETECT: STAT(radardetect); + case S_RX_RSSI: + snprintf(b, bs, "%d", wf->cur.mst_rx_rssi); + return 1; + 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_RX0: RXANT(0); + case S_ANT_RX1: RXANT(1); + case S_ANT_RX2: RXANT(2); + case S_ANT_RX3: RXANT(3); + case S_RX_NOISE: + snprintf(b, bs, "%d", wf->cur.mst_rx_noise); + return 1; + case S_RX_SIGNAL: + snprintf(b, bs, "%d", + wf->cur.mst_rx_rssi + wf->cur.mst_rx_noise); + return 1; + } + b[0] = '\0'; + return 0; +#undef RXANT +#undef TXANT +#undef HWSTAT +#undef STAT +} + +static int +mwl_get_totstat(struct statfoo *sf, int s, char b[], size_t bs) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; +#define STAT(x) \ + snprintf(b, bs, "%u", wf->total.mst_##x); return 1 +#define HWSTAT(x) \ + snprintf(b, bs, "%u", wf->total.hw_stats.x); return 1 +#define TXANT(x) \ + snprintf(b, bs, "%u", wf->total.mst_ant_tx[x]); return 1 +#define RXANT(x) \ + snprintf(b, bs, "%u", wf->total.mst_ant_rx[x]); return 1 + + switch (s) { + case S_INPUT: + snprintf(b, bs, "%lu", (u_long)wf->total.mst_rx_packets); + return 1; + case S_OUTPUT: + snprintf(b, bs, "%lu", (u_long) wf->total.mst_tx_packets); + return 1; + case S_RATE: + setrate(b, bs, wf->total.mst_tx_rate); + return 1; + case S_TX_RETRY: HWSTAT(TxRetrySuccesses); + case S_TX_MRETRY: HWSTAT(TxMultipleRetrySuccesses); + case S_TX_RTSGOOD: HWSTAT(RTSSuccesses); + case S_TX_RTSBAD: HWSTAT(RTSFailures); + case S_TX_NOACK: HWSTAT(AckFailures); + case S_RX_DUPLICATE: HWSTAT(RxDuplicateFrames); + case S_RX_FCS: HWSTAT(FCSErrorCount); + case S_TX_WATCHDOG: HWSTAT(TxWatchDogTimeouts); + case S_RX_OVERFLOW: HWSTAT(RxOverflows); + case S_RX_FRAGERROR: HWSTAT(RxFragErrors); + case S_RX_MEMERROR: HWSTAT(RxMemErrors); + case S_PTRERROR: HWSTAT(PointerErrors); + case S_TX_UNDERFLOW: HWSTAT(TxUnderflows); + case S_TX_DONE: HWSTAT(TxDone); + case S_TX_DONEBUFPUT: HWSTAT(TxDoneBufPut); + case S_TX_WAIT4BUF: HWSTAT(Wait4TxBuf); + case S_TX_ATTEMPTS: HWSTAT(TxAttempts); + case S_TX_SUCCESS: HWSTAT(TxSuccesses); + case S_TX_FRAGS: HWSTAT(TxFragments); + case S_TX_MCAST: HWSTAT(TxMulticasts); + case S_RX_NONCTL: HWSTAT(RxNonCtlPkts); + case S_RX_MCAST: HWSTAT(RxMulticasts); + case S_RX_UNDECRYPT: HWSTAT(RxUndecryptableFrames); + case S_RX_ICVERROR: HWSTAT(RxICVErrors); + case S_RX_EXCLUDE: HWSTAT(RxExcludedFrames); + 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_NOMBUF: STAT(tx_nombuf); + case S_TX_LINEAR: STAT(tx_linear); + case S_TX_NODATA: STAT(tx_nodata); + case S_TX_BUSDMA: STAT(tx_busdma); + case S_TX_SHORTPRE: STAT(tx_shortpre); + case S_TX_NOHEADROOM: STAT(tx_noheadroom); + case S_TX_BADFRAMETYPE: STAT(tx_badframetype); + case S_RX_CRYPTO_ERR: STAT(rx_crypto); + case S_RX_TKIPMIC: STAT(rx_tkipmic); + case S_RX_NODMABUF: STAT(rx_nodmabuf); + case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing); + case S_RX_NOMBUF: STAT(rx_nombuf); + case S_RX_BUSDMA: STAT(rx_busdma); + case S_AMPDU_NOSTREAM: STAT(ampdu_nostream); + case S_AMPDU_REJECT: STAT(ampdu_reject); + case S_ADDBA_NOSTREAM: STAT(addba_nostream); + case S_TX_TSO: STAT(tx_tso); + case S_TSO_BADETH: STAT(tso_badeth); + case S_TSO_NOHDR: STAT(tso_nohdr); + case S_TSO_BADSPLIT: STAT(tso_badsplit); + case S_BAWATCHDOG: STAT(bawatchdog); + case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound); + case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty); + case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed); + case S_RADARDETECT: STAT(radardetect); + case S_RX_RSSI: + snprintf(b, bs, "%d", wf->total.mst_rx_rssi); + return 1; + 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_RX0: RXANT(0); + case S_ANT_RX1: RXANT(1); + case S_ANT_RX2: RXANT(2); + case S_ANT_RX3: RXANT(3); + case S_RX_NOISE: + snprintf(b, bs, "%d", wf->total.mst_rx_noise); + return 1; + case S_RX_SIGNAL: + snprintf(b, bs, "%d", + wf->total.mst_rx_rssi + wf->total.mst_rx_noise); + return 1; + } + b[0] = '\0'; + return 0; +#undef RXANT +#undef TXANT +#undef HWSTAT +#undef STAT +} + +static void +mwl_print_verbose(struct statfoo *sf, FILE *fd) +{ + struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf; + const struct fmt *f; + char s[32]; + const char *indent; + int i, width; + + width = 0; + for (i = 0; i < S_LAST; i++) { + f = &sf->stats[i]; + if (f->width > width) + width = f->width; + } + for (i = 0; i < S_LAST; i++) { + f = &sf->stats[i]; + if (mwl_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) { + indent = ""; + fprintf(fd, "%s%-*s %s\n", indent, width, s, f->desc); + } + } + fprintf(fd, "Antenna profile:\n"); + for (i = 0; i < 4; i++) + if (wf->total.mst_ant_rx[i] || wf->total.mst_ant_tx[i]) + fprintf(fd, "[%u] tx %8u rx %8u\n", i, + wf->total.mst_ant_tx[i], + wf->total.mst_ant_rx[i]); +} + +STATFOO_DEFINE_BOUNCE(mwlstatfoo) + +struct mwlstatfoo * +mwlstats_new(const char *ifname, const char *fmtstring) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + struct mwlstatfoo_p *wf; + + wf = calloc(1, sizeof(struct mwlstatfoo_p)); + if (wf != NULL) { + statfoo_init(&wf->base.base, "mwlstats", mwlstats, N(mwlstats)); + /* override base methods */ + wf->base.base.collect_cur = mwl_collect_cur; + wf->base.base.collect_tot = mwl_collect_tot; + wf->base.base.get_curstat = mwl_get_curstat; + wf->base.base.get_totstat = mwl_get_totstat; + wf->base.base.update_tot = mwl_update_tot; + wf->base.base.print_verbose = mwl_print_verbose; + + /* setup bounce functions for public methods */ + STATFOO_BOUNCE(wf, mwlstatfoo); + + /* setup our public methods */ + wf->base.setifname = mwl_setifname; +#if 0 + wf->base.setstamac = wlan_setstamac; +#endif + wf->s = socket(AF_INET, SOCK_DGRAM, 0); + if (wf->s < 0) + err(1, "socket"); + + mwl_setifname(&wf->base, ifname); + wf->base.setfmt(&wf->base, fmtstring); + } + return &wf->base; +#undef N +} diff --git a/tools/tools/mwl/mwlstats/mwlstats.h b/tools/tools/mwl/mwlstats/mwlstats.h new file mode 100644 index 000000000000..60ff4bb49411 --- /dev/null +++ b/tools/tools/mwl/mwlstats/mwlstats.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2007 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 _MWLSTATS_H_ +#define _MWLSTATS_H_ + +#include "statfoo.h" + +/* + * mv statistics class. + */ +struct mwlstatfoo { + struct statfoo base; + + STATFOO_DECL_METHODS(struct mwlstatfoo *); + + /* set the network interface name for collection */ + void (*setifname)(struct mwlstatfoo *, const char *ifname); + /* set the mac address of the associated station/ap */ + void (*setstamac)(struct mwlstatfoo *, const uint8_t mac[]); +}; + +struct mwlstatfoo *mwlstats_new(const char *ifname, const char *fmtstring); +#endif /* _MWLSTATS_H_ */ diff --git a/tools/tools/mwl/mwlstats/statfoo.c b/tools/tools/mwl/mwlstats/statfoo.c new file mode 100644 index 000000000000..0fa0c37c8a67 --- /dev/null +++ b/tools/tools/mwl/mwlstats/statfoo.c @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2007 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$ + */ + +#include +#include + +#include "statfoo.h" + +static void +statfoo_setfmt(struct statfoo *sf, const char *fmt0) +{ +#define N(a) (sizeof(a)/sizeof(a[0])) + char fmt[4096]; + char *fp, *tok; + int i, j; + + j = 0; + strlcpy(fmt, fmt0, sizeof(fmt)); + for (fp = fmt; (tok = strsep(&fp, ", ")) != NULL;) { + for (i = 0; i < sf->nstats; i++) + if (strcasecmp(tok, sf->stats[i].name) == 0) + break; + if (i >= sf->nstats) { + fprintf(stderr, "%s: unknown statistic name \"%s\" " + "skipped\n", sf->name, tok); + continue; + } + if (j+3 > sizeof(sf->fmts)) { + fprintf(stderr, "%s: not enough room for all stats; " + "stopped at %s\n", sf->name, tok); + break; + } + if (j != 0) + sf->fmts[j++] = ' '; + sf->fmts[j++] = 0x80 | i; + } + sf->fmts[j] = '\0'; +#undef N +} + +static void +statfoo_collect(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to collect data\n", sf->name); +} + +static void +statfoo_update_tot(struct statfoo *sf) +{ + fprintf(stderr, "%s: don't know how to update total data\n", sf->name); +} + +static int +statfoo_get(struct statfoo *sf, int s, char b[], size_t bs) +{ + fprintf(stderr, "%s: don't know how to get stat #%u\n", sf->name, s); + return 0; +} + +static void +statfoo_print_header(struct statfoo *sf, FILE *fd) +{ + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + fprintf(fd, "%*s", f->width, f->label); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_current(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_curstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_total(struct statfoo *sf, FILE *fd) +{ + char buf[32]; + const unsigned char *cp; + + for (cp = sf->fmts; *cp != '\0'; cp++) { + if (*cp & 0x80) { + const struct fmt *f = &sf->stats[*cp &~ 0x80]; + if (sf->get_totstat(sf, *cp &~ 0x80, buf, sizeof(buf))) + fprintf(fd, "%*s", f->width, buf); + } else + putc(*cp, fd); + } + putc('\n', fd); +} + +static void +statfoo_print_verbose(struct statfoo *sf, FILE *fd) +{ + char s[32]; + int i; + + for (i = 0; i < sf->nstats; i++) { + if (sf->get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) + fprintf(fd, "%s %s\n", s, sf->stats[i].desc); + } +} + +static void +statfoo_print_fields(struct statfoo *sf, FILE *fd) +{ + int i, w, width; + + width = 0; + for (i = 0; i < sf->nstats; i++) { + w = strlen(sf->stats[i].name); + if (w > width) + width = w; + } + for (i = 0; i < sf->nstats; i++) { + const struct fmt *f = &sf->stats[i]; + if (f->width != 0) + fprintf(fd, "%-*s %s\n", width, f->name, f->desc); + } +} + +void +statfoo_init(struct statfoo *sf, const char *name, const struct fmt *stats, int nstats) +{ + sf->name = name; + sf->stats = stats; + sf->nstats = nstats; + sf->setfmt = statfoo_setfmt; + sf->collect_cur = statfoo_collect; + sf->collect_tot = statfoo_collect; + sf->update_tot = statfoo_update_tot; + sf->get_curstat = statfoo_get; + sf->get_totstat = statfoo_get; + sf->print_header = statfoo_print_header; + sf->print_current = statfoo_print_current; + sf->print_total = statfoo_print_total; + sf->print_verbose = statfoo_print_verbose; + sf->print_fields = statfoo_print_fields; +} diff --git a/tools/tools/mwl/mwlstats/statfoo.h b/tools/tools/mwl/mwlstats/statfoo.h new file mode 100644 index 000000000000..4575946bceed --- /dev/null +++ b/tools/tools/mwl/mwlstats/statfoo.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _STATFOO_H_ +#define _STATFOO_H_ +/* + * Base class for managing+displaying periodically collected statistics. + */ + +/* + * Statistic definition/description. The are defined + * for stats that correspond 1-1 w/ a collected stat + * and for stats that are calculated indirectly. + */ +struct fmt { + int width; /* printed field width */ + const char* name; /* stat field name referenced by user */ + const char* label; /* printed header label */ + const char* desc; /* verbose description */ +}; + +#define STATFOO_DECL_METHODS(_p) \ + /* set the format of the statistics to display */ \ + void (*setfmt)(_p, const char *); \ + /* collect+store ``current statistics'' */ \ + void (*collect_cur)(_p); \ + /* collect+store ``total statistics'' */ \ + void (*collect_tot)(_p); \ + /* update ``total statistics'' if necessary from current */ \ + void (*update_tot)(_p); \ + /* format a statistic from the current stats */ \ + int (*get_curstat)(_p, int, char [], size_t); \ + /* format a statistic from the total stats */ \ + int (*get_totstat)(_p, int, char [], size_t); \ + /* print field headers terminated by a \n */ \ + void (*print_header)(_p, FILE *); \ + /* print current statistics terminated by a \n */ \ + void (*print_current)(_p, FILE *); \ + /* print total statistics terminated by a \n */ \ + void (*print_total)(_p, FILE *); \ + /* print total statistics in a verbose (1 stat/line) format */ \ + void (*print_verbose)(_p, FILE *); \ + /* print available statistics */ \ + void (*print_fields)(_p, FILE *) + +/* + * Statistics base class. This class is not usable; only + * classes derived from it are useful. + */ +struct statfoo { + const char *name; /* statistics name, e.g. wlanstats */ + const struct fmt *stats; /* statistics in class */ + int nstats; /* number of stats */ + unsigned char fmts[4096]; /* private: compiled stats to display */ + + STATFOO_DECL_METHODS(struct statfoo *); +}; + +void statfoo_init(struct statfoo *, const char *name, + const struct fmt *stats, int nstats); + +#define STATFOO_DEFINE_BOUNCE(_t) \ +static void _t##_setfmt(struct _t *wf, const char *fmt0) \ + { wf->base.setfmt(&wf->base, fmt0); } \ +static void _t##_collect_cur(struct _t *wf) \ + { wf->base.collect_cur(&wf->base); } \ +static void _t##_collect_tot(struct _t *wf) \ + { wf->base.collect_tot(&wf->base); } \ +static void _t##_update_tot(struct _t *wf) \ + { wf->base.update_tot(&wf->base); } \ +static int _t##_get_curstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_curstat(&wf->base, s, b, bs); } \ +static int _t##_get_totstat(struct _t *wf, int s, char b[], size_t bs) \ + { return wf->base.get_totstat(&wf->base, s, b, bs); } \ +static void _t##_print_header(struct _t *wf, FILE *fd) \ + { wf->base.print_header(&wf->base, fd); } \ +static void _t##_print_current(struct _t *wf, FILE *fd) \ + { wf->base.print_current(&wf->base, fd); } \ +static void _t##_print_total(struct _t *wf, FILE *fd) \ + { wf->base.print_total(&wf->base, fd); } \ +static void _t##_print_verbose(struct _t *wf, FILE *fd) \ + { wf->base.print_verbose(&wf->base, fd); } \ +static void _t##_print_fields(struct _t *wf, FILE *fd) \ + { wf->base.print_fields(&wf->base, fd); } + +#define STATFOO_BOUNCE(_p, _t) do { \ + _p->base.setfmt = _t##_setfmt; \ + _p->base.collect_cur = _t##_collect_cur; \ + _p->base.collect_tot = _t##_collect_tot; \ + _p->base.update_tot = _t##_update_tot; \ + _p->base.get_curstat = _t##_get_curstat; \ + _p->base.get_totstat = _t##_get_totstat; \ + _p->base.print_header = _t##_print_header; \ + _p->base.print_current = _t##_print_current; \ + _p->base.print_total = _t##_print_total; \ + _p->base.print_verbose = _t##_print_verbose; \ + _p->base.print_fields = _t##_print_fields; \ +} while (0) +#endif /* _STATFOO_H_ */