bring in ath-specific test tool; more to follow

This commit is contained in:
Sam Leffler 2003-06-28 18:26:23 +00:00
parent 11484af448
commit 64125f9866
3 changed files with 446 additions and 1 deletions

View File

@ -8,11 +8,12 @@ the other categories.
Please make a subdir per program, and add a brief description to this
file.
ath Tools specific to the Atheros 802.11 support
backout_commit A tool for reading in a commit message and generating
a script that will backout the commit.
commitsdb A tool for reconstructing commit history using md5
checksums of the commit logs.
crypto Exercise the crypto framework through /dev/crypto
crypto Test and exercise tools related to the crypto framework
diffburst OBSOLETE: equivalent functionality is available via split -p.
For example: "split -p ^diff < patchfile". See split(1).
editing Editor modes and the like to help editing FreeBSD code.

35
tools/tools/ath/Makefile Normal file
View File

@ -0,0 +1,35 @@
# $FreeBSD$
#
# Copyright (c) 2002, 2003 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.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
#
ALL= athstats
all: ${ALL}
athstats: athstats.c
${CC} -o athstats athstats.c -lkvm
clean:
rm -f ${ALL} core a.out

409
tools/tools/ath/athstats.c Normal file
View File

@ -0,0 +1,409 @@
/*-
* Copyright (c) 2002, 2003 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] [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
*/
#include <sys/types.h>
#include <sys/file.h>
#include <sys/sockio.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_var.h>
#include <stdio.h>
#include <signal.h>
#include <kvm.h>
#include <nlist.h>
#include "../../../sys/contrib/dev/ath/ah_desc.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" },
};
static void
printstats(FILE *fd, const struct ath_stats *stats)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
#define STAT(x,fmt) \
if (stats->ast_##x) fprintf(fd, "%u " fmt "\n", stats->ast_##x)
STAT(watchdog, "watchdog timeouts");
STAT(hardware, "hardware error interrupts");
STAT(bmiss, "beacon miss interrupts");
STAT(rxorn, "recv overrun interrupts");
STAT(rxeol, "recv eol interrupts");
STAT(txurn, "txmit underrun interrupts");
STAT(intrcoal, "interrupts coalesced");
STAT(rx_orn, "rx overrun interrupts");
STAT(tx_mgmt, "tx management frames");
STAT(tx_discard, "tx frames discarded prior to association");
STAT(tx_encap, "tx encapsulation failed");
STAT(tx_nonode, "tx failed 'cuz no node");
STAT(tx_qstop, "tx stopped 'cuz no xmit buffer");
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(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_tooshort, "rx failed 'cuz frame too short");
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_phyerr, "rx failed 'cuz of PHY err");
if (stats->ast_rx_phyerr != 0) {
int i, j;
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(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");
#undef STAT
#undef N
}
static u_int
getifrate(int s, const char* ifname)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
static const int rates[] = {
-1, /* 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 kvm_t *kvmd;
static char *nlistf = NULL;
static char *memf = NULL;
static struct nlist nl[] = {
#define N_IFNET 0
{ "_ifnet" },
};
/*
* Read kernel memory, return 0 on success.
*/
static int
kread(u_long addr, void *buf, int size)
{
if (kvmd == 0) {
/*
* XXX.
*/
kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
setgid(getgid());
if (kvmd != NULL) {
if (kvm_nlist(kvmd, nl) < 0) {
if(nlistf)
errx(1, "%s: kvm_nlist: %s", nlistf,
kvm_geterr(kvmd));
else
errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
}
if (nl[0].n_type == 0) {
if(nlistf)
errx(1, "%s: no namelist", nlistf);
else
errx(1, "no namelist");
}
} else {
warnx("kvm not available");
return(-1);
}
}
if (!buf)
return (0);
if (kvm_read(kvmd, addr, buf, size) != size) {
warnx("%s", kvm_geterr(kvmd));
return (-1);
}
return (0);
}
static u_long
ifnetsetup(const char *interface, u_long off)
{
struct ifnet ifnet;
u_long firstifnet;
struct ifnethead ifnethead;
if (kread(off, (char *)&ifnethead, sizeof ifnethead))
return;
firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
for (off = firstifnet; off;) {
char name[16], tname[16];
if (kread(off, (char *)&ifnet, sizeof ifnet))
break;
if (kread((u_long)ifnet.if_name, tname, sizeof(tname)))
break;
tname[sizeof(tname) - 1] = '\0';
snprintf(name, sizeof(name), "%s%d", tname, ifnet.if_unit);
if (interface && strcmp(name, interface) == 0)
return off;
off = (u_long)TAILQ_NEXT(&ifnet, if_link);
}
return 0;
}
static int signalled;
static void
catchalarm(int signo __unused)
{
signalled = 1;
}
int
main(int argc, char *argv[])
{
int s;
struct ifreq ifr;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
err(1, "socket");
if (argc > 1 && strcmp(argv[1], "-i") == 0) {
if (argc < 2) {
fprintf(stderr, "%s: missing interface name for -i\n",
argv[0]);
exit(-1);
}
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);
u_long off;
int line, omask;
u_int rate = getifrate(s, ifr.ifr_name);
u_int32_t rate_raise, rate_drop, mgmt;
struct ath_stats cur, total;
struct ifnet ifcur, iftot;
kread(0, 0, 0);
off = ifnetsetup(ifr.ifr_name, nl[N_IFNET].n_value);
if (interval < 1)
interval = 1;
signal(SIGALRM, catchalarm);
signalled = 0;
alarm(interval);
banner:
printf("%8s %8s %7s %7s %6s %6s %6s %6s %6s"
, "input"
, "output"
, "short"
, "long"
, "xretry"
, "crcerr"
, "crypt"
, "phyerr"
, "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);
if (total.ast_rate_raise != rate_raise ||
total.ast_rate_drop != rate_drop ||
total.ast_tx_mgmt != mgmt) {
rate = getifrate(s, ifr.ifr_name);
rate_raise = total.ast_rate_raise;
rate_drop = total.ast_rate_drop;
mgmt = total.ast_tx_mgmt;
}
if (kread(off, &ifcur, sizeof(ifcur)))
err(1, ifr.ifr_name);
printf("%8u %8u %7u %7u %6u %6u %6u %6u %5uM\n"
, ifcur.if_ipackets - iftot.if_ipackets
, ifcur.if_opackets - iftot.if_opackets
, 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
, rate
);
total = cur;
iftot = ifcur;
} else {
ifr.ifr_data = (caddr_t) &total;
if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
err(1, ifr.ifr_name);
if (total.ast_rate_raise != rate_raise ||
total.ast_rate_drop != rate_drop ||
total.ast_tx_mgmt != mgmt) {
rate = getifrate(s, ifr.ifr_name);
rate_raise = total.ast_rate_raise;
rate_drop = total.ast_rate_drop;
mgmt = total.ast_tx_mgmt;
}
if (kread(off, &iftot, sizeof(iftot)))
err(1, ifr.ifr_name);
printf("%8u %8u %7u %7u %6u %6u %6u %6u %5uM\n"
, iftot.if_ipackets
, iftot.if_opackets
, total.ast_tx_shortretry
, total.ast_tx_longretry
, total.ast_tx_xretries
, total.ast_rx_crcerr
, total.ast_rx_badcrypt
, total.ast_rx_phyerr
, 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;
ifr.ifr_data = (caddr_t) &stats;
if (ioctl(s, SIOCGATHSTATS, &ifr) < 0)
err(1, ifr.ifr_name);
printstats(stdout, &stats);
}
return 0;
}