xref: /freebsd-src/tools/tools/ath/athratestats/main.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
178c166feSAdrian Chadd /*-
278c166feSAdrian Chadd  * Copyright (c) 2012, Adrian Chadd.
378c166feSAdrian Chadd  * All rights reserved.
478c166feSAdrian Chadd  *
578c166feSAdrian Chadd  * Redistribution and use in source and binary forms, with or without
678c166feSAdrian Chadd  * modification, are permitted provided that the following conditions
778c166feSAdrian Chadd  * are met:
878c166feSAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
978c166feSAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
1078c166feSAdrian Chadd  *    without modification.
1178c166feSAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1278c166feSAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1378c166feSAdrian Chadd  *    redistribution must be conditioned upon including a substantially
1478c166feSAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
1578c166feSAdrian Chadd  *
1678c166feSAdrian Chadd  * NO WARRANTY
1778c166feSAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1878c166feSAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1978c166feSAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2078c166feSAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2178c166feSAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2278c166feSAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2378c166feSAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2478c166feSAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2578c166feSAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2678c166feSAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2778c166feSAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
2878c166feSAdrian Chadd  */
2978c166feSAdrian Chadd 
3078c166feSAdrian Chadd #include "opt_ah.h"
3178c166feSAdrian Chadd 
3278c166feSAdrian Chadd #include <sys/types.h>
3378c166feSAdrian Chadd #include <sys/file.h>
3478c166feSAdrian Chadd #include <sys/sockio.h>
3578c166feSAdrian Chadd #include <sys/socket.h>
3678c166feSAdrian Chadd #include <net/ethernet.h>
3778c166feSAdrian Chadd #include <net/if.h>
3878c166feSAdrian Chadd #include <net/if_media.h>
3978c166feSAdrian Chadd 
4078c166feSAdrian Chadd #include <stdio.h>
4178c166feSAdrian Chadd #include <stdlib.h>
4278c166feSAdrian Chadd #include <stdint.h>
4378c166feSAdrian Chadd #include <signal.h>
4478c166feSAdrian Chadd #include <string.h>
4578c166feSAdrian Chadd #include <unistd.h>
4678c166feSAdrian Chadd #include <err.h>
4778c166feSAdrian Chadd 
48b1dcd0fbSAdrian Chadd #include <curses.h>
49b1dcd0fbSAdrian Chadd 
5078c166feSAdrian Chadd #include "ah.h"
5178c166feSAdrian Chadd #include "ah_desc.h"
5278c166feSAdrian Chadd #include "net80211/ieee80211_ioctl.h"
5378c166feSAdrian Chadd #include "net80211/ieee80211_radiotap.h"
5478c166feSAdrian Chadd #include "if_athioctl.h"
5578c166feSAdrian Chadd #include "if_athrate.h"
5678c166feSAdrian Chadd 
5778c166feSAdrian Chadd #include "ath_rate/sample/sample.h"
5878c166feSAdrian Chadd 
59b1dcd0fbSAdrian Chadd static int do_loop = 0;
60b1dcd0fbSAdrian Chadd 
61422866dfSAdrian Chadd /*
62422866dfSAdrian Chadd  * This needs to be big enough to fit the two TLVs, the rate table
63422866dfSAdrian Chadd  * and the rate statistics table for a single node.
64422866dfSAdrian Chadd  */
657072a501SAdrian Chadd #define	STATS_BUF_SIZE	65536
66422866dfSAdrian Chadd 
67b1dcd0fbSAdrian Chadd #define	PRINTMSG(...) do {			\
68b1dcd0fbSAdrian Chadd 	if (do_loop == 0)			\
69b1dcd0fbSAdrian Chadd 		printf(__VA_ARGS__);		\
70b1dcd0fbSAdrian Chadd 	else					\
71b1dcd0fbSAdrian Chadd 		printw(__VA_ARGS__);		\
72b1dcd0fbSAdrian Chadd 	} while (0)
73b1dcd0fbSAdrian Chadd 
74e65889e6SAdrian Chadd #define	PRINTATTR_ON(_x) do {			\
75e65889e6SAdrian Chadd 	if (do_loop)				\
76e65889e6SAdrian Chadd 		attron(_x);			\
77e65889e6SAdrian Chadd 	} while(0)
78e65889e6SAdrian Chadd 
79e65889e6SAdrian Chadd 
80e65889e6SAdrian Chadd #define	PRINTATTR_OFF(_x) do {			\
81e65889e6SAdrian Chadd 	if (do_loop)				\
82e65889e6SAdrian Chadd 		attroff(_x);			\
83e65889e6SAdrian Chadd 	} while(0)
84e65889e6SAdrian Chadd 
8578c166feSAdrian Chadd struct ath_ratestats {
8678c166feSAdrian Chadd 	int s;
8778c166feSAdrian Chadd 	struct ath_rateioctl re;
8878c166feSAdrian Chadd };
8978c166feSAdrian Chadd 
90ef80e034SAdrian Chadd static inline int
dot11rate(struct ath_rateioctl_rt * rt,int rix)91ef80e034SAdrian Chadd dot11rate(struct ath_rateioctl_rt *rt, int rix)
9278c166feSAdrian Chadd {
93ef80e034SAdrian Chadd 
94ef80e034SAdrian Chadd 	if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
95ef80e034SAdrian Chadd 		return rt->ratecode[rix] & ~(IEEE80211_RATE_MCS);
96ef80e034SAdrian Chadd 	else
97ef80e034SAdrian Chadd 		return (rt->ratecode[rix] / 2);
98ef80e034SAdrian Chadd }
99ef80e034SAdrian Chadd 
100ef80e034SAdrian Chadd static const char *
dot11str(struct ath_rateioctl_rt * rt,int rix)101ef80e034SAdrian Chadd dot11str(struct ath_rateioctl_rt *rt, int rix)
102ef80e034SAdrian Chadd {
103ef80e034SAdrian Chadd 	if (rix == -1)
104ef80e034SAdrian Chadd 		return "";
105ef80e034SAdrian Chadd 	else if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
106ef80e034SAdrian Chadd 		return "MCS";
107ef80e034SAdrian Chadd 	else
108ef80e034SAdrian Chadd 		return " Mb";
109ef80e034SAdrian Chadd }
110ef80e034SAdrian Chadd 
111ef80e034SAdrian Chadd static void
ath_sample_stats(struct ath_ratestats * r,struct ath_rateioctl_rt * rt,struct sample_node * sn)112ef80e034SAdrian Chadd ath_sample_stats(struct ath_ratestats *r, struct ath_rateioctl_rt *rt,
113ef80e034SAdrian Chadd     struct sample_node *sn)
114ef80e034SAdrian Chadd {
115d2b384c4SAdrian Chadd 	uint64_t mask;
11678c166feSAdrian Chadd 	int rix, y;
11778c166feSAdrian Chadd 
1185e951af2SAdrian Chadd 	PRINTMSG("static_rix (%d) ratemask 0x%llx\n",
11978c166feSAdrian Chadd 	    sn->static_rix,
1205e951af2SAdrian Chadd 	    (long long) sn->ratemask);
12178c166feSAdrian Chadd 
12278c166feSAdrian Chadd 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
1233347e196SAdrian Chadd 		PRINTATTR_ON(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
124b1dcd0fbSAdrian Chadd 		PRINTMSG("[%4u] cur rate %d %s since switch: "
1257072a501SAdrian Chadd 		    "packets %d ticks %u ",
12678c166feSAdrian Chadd 		    bin_to_size(y),
127ef80e034SAdrian Chadd 		    dot11rate(rt, sn->current_rix[y]),
128ef80e034SAdrian Chadd 		    dot11str(rt, sn->current_rix[y]),
12978c166feSAdrian Chadd 		    sn->packets_since_switch[y],
13078c166feSAdrian Chadd 		    sn->ticks_since_switch[y]);
13178c166feSAdrian Chadd 
1327072a501SAdrian Chadd 		PRINTMSG("last sample (%d %s) cur sample (%d %s) "
1333347e196SAdrian Chadd 		    "packets sent %d ",
134ef80e034SAdrian Chadd 		    dot11rate(rt, sn->last_sample_rix[y]),
135ef80e034SAdrian Chadd 		    dot11str(rt, sn->last_sample_rix[y]),
136ef80e034SAdrian Chadd 		    dot11rate(rt, sn->current_sample_rix[y]),
137ef80e034SAdrian Chadd 		    dot11str(rt, sn->current_sample_rix[y]),
13878c166feSAdrian Chadd 		    sn->packets_sent[y]);
1393347e196SAdrian Chadd 		PRINTATTR_OFF(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
14078c166feSAdrian Chadd 
1413347e196SAdrian Chadd 		PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
1423347e196SAdrian Chadd 		PRINTMSG("packets since sample %d sample tt %u\n",
14378c166feSAdrian Chadd 		    sn->packets_since_sample[y],
14478c166feSAdrian Chadd 		    sn->sample_tt[y]);
145e65889e6SAdrian Chadd 		PRINTATTR_OFF(COLOR_PAIR(3) | A_BOLD);
14678c166feSAdrian Chadd 	}
147b1dcd0fbSAdrian Chadd 	PRINTMSG("   TX Rate      TXTOTAL:TXOK       EWMA          T/   F"
148*8d3361e9SAdrian Chadd 	    "     avg last xmit  ");
149*8d3361e9SAdrian Chadd 	PRINTMSG("   TX Rate      TXTOTAL:TXOK       EWMA          T/   F"
1503ed3dcb6SAdrian Chadd 	    "     avg last xmit\n");
15178c166feSAdrian Chadd 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
152*8d3361e9SAdrian Chadd 		int c = 0;
15378c166feSAdrian Chadd 		if ((mask & 1) == 0)
15478c166feSAdrian Chadd 				continue;
15578c166feSAdrian Chadd 		for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
15678c166feSAdrian Chadd 			if (sn->stats[y][rix].total_packets == 0)
15778c166feSAdrian Chadd 				continue;
158e65889e6SAdrian Chadd 			if (rix == sn->current_rix[y])
1593347e196SAdrian Chadd 				PRINTATTR_ON(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
160e65889e6SAdrian Chadd 			else if (rix == sn->last_sample_rix[y])
1613347e196SAdrian Chadd 				PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
162e65889e6SAdrian Chadd #if 0
163e65889e6SAdrian Chadd 			else if (sn->stats[y][rix].ewma_pct / 10 < 50)
164e65889e6SAdrian Chadd 				PRINTATTR_ON(COLOR_PAIR(2) | A_BOLD);
165e65889e6SAdrian Chadd 			else if (sn->stats[y][rix].ewma_pct / 10 < 75)
166e65889e6SAdrian Chadd 				PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
167e65889e6SAdrian Chadd #endif
168e2d18daeSAdrian Chadd 			PRINTMSG("[%2u %s:%5u] %8ju:%-8ju "
169*8d3361e9SAdrian Chadd 			    "(%3d.%1d%%) %8ju/%4d %5uuS %u ",
170ef80e034SAdrian Chadd 			    dot11rate(rt, rix),
171ef80e034SAdrian Chadd 			    dot11str(rt, rix),
17278c166feSAdrian Chadd 			    bin_to_size(y),
17378c166feSAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].total_packets,
17478c166feSAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].packets_acked,
17578c166feSAdrian Chadd 			    sn->stats[y][rix].ewma_pct / 10,
17678c166feSAdrian Chadd 			    sn->stats[y][rix].ewma_pct % 10,
17778c166feSAdrian Chadd 			    (uintmax_t) sn->stats[y][rix].tries,
17878c166feSAdrian Chadd 			    sn->stats[y][rix].successive_failures,
17978c166feSAdrian Chadd 			    sn->stats[y][rix].average_tx_time,
18078c166feSAdrian Chadd 			    sn->stats[y][rix].last_tx);
181e65889e6SAdrian Chadd 			if (rix == sn->current_rix[y])
1823347e196SAdrian Chadd 				PRINTATTR_OFF(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
183e65889e6SAdrian Chadd 			else if (rix == sn->last_sample_rix[y])
1843347e196SAdrian Chadd 				PRINTATTR_OFF(COLOR_PAIR(1) | A_BOLD);
185e65889e6SAdrian Chadd #if 0
186e65889e6SAdrian Chadd 			else if (sn->stats[y][rix].ewma_pct / 10 < 50)
187e65889e6SAdrian Chadd 				PRINTATTR_OFF(COLOR_PAIR(2) | A_BOLD);
188e65889e6SAdrian Chadd 			else if (sn->stats[y][rix].ewma_pct / 10 < 75)
189e65889e6SAdrian Chadd 				PRINTATTR_OFF(COLOR_PAIR(1) | A_BOLD);
190e65889e6SAdrian Chadd #endif
191*8d3361e9SAdrian Chadd 			c++;
192*8d3361e9SAdrian Chadd 			if (c == 2) {
193*8d3361e9SAdrian Chadd 				PRINTMSG("\n");
194*8d3361e9SAdrian Chadd 				c = 0;
19578c166feSAdrian Chadd 			}
19678c166feSAdrian Chadd 		}
197*8d3361e9SAdrian Chadd 		if (c != 0)
198*8d3361e9SAdrian Chadd 			PRINTMSG("\n");
199*8d3361e9SAdrian Chadd 	}
20078c166feSAdrian Chadd }
20178c166feSAdrian Chadd 
20278c166feSAdrian Chadd static void
ath_setifname(struct ath_ratestats * r,const char * ifname)20378c166feSAdrian Chadd ath_setifname(struct ath_ratestats *r, const char *ifname)
20478c166feSAdrian Chadd {
20578c166feSAdrian Chadd 
20678c166feSAdrian Chadd 	strncpy(r->re.if_name, ifname, sizeof (r->re.if_name));
20778c166feSAdrian Chadd }
20878c166feSAdrian Chadd 
20978c166feSAdrian Chadd static void
ath_setsta(struct ath_ratestats * r,uint8_t * mac)210b920ab48SAdrian Chadd ath_setsta(struct ath_ratestats *r, uint8_t *mac)
21178c166feSAdrian Chadd {
21278c166feSAdrian Chadd 
21378c166feSAdrian Chadd 	memcpy(&r->re.is_u.macaddr, mac, sizeof(r->re.is_u.macaddr));
21478c166feSAdrian Chadd }
21578c166feSAdrian Chadd 
21678c166feSAdrian Chadd static void
ath_rate_ioctl(struct ath_ratestats * r)21778c166feSAdrian Chadd ath_rate_ioctl(struct ath_ratestats *r)
21878c166feSAdrian Chadd {
219422866dfSAdrian Chadd 
22078c166feSAdrian Chadd 	if (ioctl(r->s, SIOCGATHNODERATESTATS, &r->re) < 0)
22178c166feSAdrian Chadd 		err(1, "ioctl");
22278c166feSAdrian Chadd }
22378c166feSAdrian Chadd 
224a30a9352SAdrian Chadd static int
rate_node_stats(struct ath_ratestats * r,struct ether_addr * e)225a30a9352SAdrian Chadd rate_node_stats(struct ath_ratestats *r, struct ether_addr *e)
22678c166feSAdrian Chadd {
22778c166feSAdrian Chadd 	struct ath_rateioctl_tlv *av;
228ef80e034SAdrian Chadd 	struct sample_node *sn = NULL;
229ef80e034SAdrian Chadd 	struct ath_rateioctl_rt *rt = NULL;
230a30a9352SAdrian Chadd 	int error = 0;
231b920ab48SAdrian Chadd 	uint8_t *buf = (uint8_t *) r->re.buf;
23278c166feSAdrian Chadd 
23378c166feSAdrian Chadd 	/*
234ef80e034SAdrian Chadd 	 * For now, hard-code the TLV order and contents.  Ew!
23578c166feSAdrian Chadd 	 */
23678c166feSAdrian Chadd 	av = (struct ath_rateioctl_tlv *) buf;
237ef80e034SAdrian Chadd 	if (av->tlv_id != ATH_RATE_TLV_RATETABLE) {
238ef80e034SAdrian Chadd 		fprintf(stderr, "unexpected rate control TLV (got 0x%x, "
239ef80e034SAdrian Chadd 		    "expected 0x%x\n",
240ef80e034SAdrian Chadd 		    av->tlv_id,
241ef80e034SAdrian Chadd 		    ATH_RATE_TLV_RATETABLE);
242ef80e034SAdrian Chadd 		exit(127);
243ef80e034SAdrian Chadd 	}
244ef80e034SAdrian Chadd 	if (av->tlv_len != sizeof(struct ath_rateioctl_rt)) {
245ef80e034SAdrian Chadd 		fprintf(stderr, "unexpected TLV len (got %d bytes, "
246ef80e034SAdrian Chadd 		    "expected %d bytes\n",
247ef80e034SAdrian Chadd 		    av->tlv_len,
2485e951af2SAdrian Chadd 		    (int) sizeof(struct ath_rateioctl_rt));
249ef80e034SAdrian Chadd 		exit(127);
250ef80e034SAdrian Chadd 	}
251ef80e034SAdrian Chadd 	rt = (void *) (buf + sizeof(struct ath_rateioctl_tlv));
25278c166feSAdrian Chadd 
253ef80e034SAdrian Chadd 	/* Next */
254ef80e034SAdrian Chadd 	av = (void *) (buf + sizeof(struct ath_rateioctl_tlv) +
255ef80e034SAdrian Chadd 	    sizeof(struct ath_rateioctl_rt));
25678c166feSAdrian Chadd 	if (av->tlv_id != ATH_RATE_TLV_SAMPLENODE) {
25778c166feSAdrian Chadd 		fprintf(stderr, "unexpected rate control TLV (got 0x%x, "
25878c166feSAdrian Chadd 		    "expected 0x%x\n",
25978c166feSAdrian Chadd 		    av->tlv_id,
26078c166feSAdrian Chadd 		    ATH_RATE_TLV_SAMPLENODE);
26178c166feSAdrian Chadd 		exit(127);
26278c166feSAdrian Chadd 	}
26378c166feSAdrian Chadd 	if (av->tlv_len != sizeof(struct sample_node)) {
26478c166feSAdrian Chadd 		fprintf(stderr, "unexpected TLV len (got %d bytes, "
26578c166feSAdrian Chadd 		    "expected %d bytes\n",
26678c166feSAdrian Chadd 		    av->tlv_len,
2675e951af2SAdrian Chadd 		    (int) sizeof(struct sample_node));
26878c166feSAdrian Chadd 		exit(127);
26978c166feSAdrian Chadd 	}
270ef80e034SAdrian Chadd 	sn = (void *) (buf + sizeof(struct ath_rateioctl_tlv) +
271ef80e034SAdrian Chadd 	    sizeof(struct ath_rateioctl_rt) +
272ef80e034SAdrian Chadd 	    sizeof(struct ath_rateioctl_tlv));
27378c166feSAdrian Chadd 
274a30a9352SAdrian Chadd 	ath_sample_stats(r, rt, sn);
2755e951af2SAdrian Chadd 
2765e951af2SAdrian Chadd 	return (0);
27778c166feSAdrian Chadd }
27878c166feSAdrian Chadd 
279b1dcd0fbSAdrian Chadd static void
fetch_and_print_stats(struct ath_ratestats * r,struct ether_addr * e,uint8_t * buf)280b1dcd0fbSAdrian Chadd fetch_and_print_stats(struct ath_ratestats *r, struct ether_addr *e,
281b1dcd0fbSAdrian Chadd     uint8_t *buf)
282b1dcd0fbSAdrian Chadd {
283b1dcd0fbSAdrian Chadd 
284b1dcd0fbSAdrian Chadd 	/* Zero the buffer before it's passed in */
285b1dcd0fbSAdrian Chadd 	memset(buf, '\0', STATS_BUF_SIZE);
286b1dcd0fbSAdrian Chadd 
287b1dcd0fbSAdrian Chadd 	/*
288b1dcd0fbSAdrian Chadd 	 * Set the station address for this lookup.
289b1dcd0fbSAdrian Chadd 	 */
290b1dcd0fbSAdrian Chadd 	ath_setsta(r, e->octet);
291b1dcd0fbSAdrian Chadd 
292b1dcd0fbSAdrian Chadd 	/*
293b1dcd0fbSAdrian Chadd 	 * Fetch the data from the driver.
294b1dcd0fbSAdrian Chadd 	 */
295b1dcd0fbSAdrian Chadd 	ath_rate_ioctl(r);
296b1dcd0fbSAdrian Chadd 
297b1dcd0fbSAdrian Chadd 	/*
298b1dcd0fbSAdrian Chadd 	 * Decode and parse statistics.
299b1dcd0fbSAdrian Chadd 	 */
300b1dcd0fbSAdrian Chadd 	rate_node_stats(r, e);
301b1dcd0fbSAdrian Chadd }
302a30a9352SAdrian Chadd 
303a30a9352SAdrian Chadd int
main(int argc,char * argv[])304a30a9352SAdrian Chadd main(int argc, char *argv[])
305a30a9352SAdrian Chadd {
306a30a9352SAdrian Chadd 	char const *ifname = NULL, *macaddr = NULL;
307a30a9352SAdrian Chadd 	int c;
308a30a9352SAdrian Chadd 	int do_all = 0;
309a30a9352SAdrian Chadd 	struct ether_addr *e;
310a30a9352SAdrian Chadd 	struct ath_ratestats r;
311a30a9352SAdrian Chadd 	uint8_t *buf;
312b1dcd0fbSAdrian Chadd 	useconds_t sleep_period;
313b1dcd0fbSAdrian Chadd 	float f;
314e65889e6SAdrian Chadd 	short cf, cb;
315a30a9352SAdrian Chadd 
316a30a9352SAdrian Chadd 	ifname = getenv("ATH");
317a30a9352SAdrian Chadd 	if (ifname == NULL)
31865f41e58SAdrian Chadd 		ifname = ATH_DEFAULT;
319a30a9352SAdrian Chadd 
320b1dcd0fbSAdrian Chadd 	while ((c = getopt(argc, argv, "ahi:m:s:")) != -1) {
321a30a9352SAdrian Chadd 		switch (c) {
322a30a9352SAdrian Chadd 		case 'a':
323a30a9352SAdrian Chadd 			do_all = 1;
324a30a9352SAdrian Chadd 			break;
325a30a9352SAdrian Chadd 		case 'i':
326a30a9352SAdrian Chadd 			ifname = optarg;
327a30a9352SAdrian Chadd 			break;
328a30a9352SAdrian Chadd 		case 'm':
329a30a9352SAdrian Chadd 			macaddr = optarg;
330a30a9352SAdrian Chadd 			break;
331b1dcd0fbSAdrian Chadd 		case 's':
332b1dcd0fbSAdrian Chadd 			sscanf(optarg, "%f", &f);
333b1dcd0fbSAdrian Chadd 			do_loop = 1;
334b1dcd0fbSAdrian Chadd 			sleep_period = (useconds_t) (f * 1000000.0);
335b1dcd0fbSAdrian Chadd 			break;
336a30a9352SAdrian Chadd 		default:
337a30a9352SAdrian Chadd 			errx(1,
338b1dcd0fbSAdrian Chadd 			    "usage: %s [-h] [-i ifname] [-a] [-m macaddr] [-s sleep period]\n",
339a30a9352SAdrian Chadd 			    argv[0]);
340a30a9352SAdrian Chadd 			/* NOTREACHED */
341a30a9352SAdrian Chadd 		}
342a30a9352SAdrian Chadd 	}
343a30a9352SAdrian Chadd 
344a30a9352SAdrian Chadd 	if (macaddr == NULL) {
345a30a9352SAdrian Chadd 		errx(1, "%s: macaddress wasn't supplied and no -a given\n",
346a30a9352SAdrian Chadd 		    argv[0]);
347a30a9352SAdrian Chadd 		/* NOTREACHED */
348a30a9352SAdrian Chadd 	}
349a30a9352SAdrian Chadd 	e = ether_aton(macaddr);
350a30a9352SAdrian Chadd 	if (e == NULL)
351a30a9352SAdrian Chadd 		err(1, "ether_aton");
352a30a9352SAdrian Chadd 
353a30a9352SAdrian Chadd 	bzero(&r, sizeof(r));
354a30a9352SAdrian Chadd 
355a30a9352SAdrian Chadd 	/*
356a30a9352SAdrian Chadd 	 * Persistent buffer for each lookup
357a30a9352SAdrian Chadd 	 */
358a30a9352SAdrian Chadd 	buf = malloc(STATS_BUF_SIZE);
359a30a9352SAdrian Chadd 	if (buf == NULL)
360a30a9352SAdrian Chadd 		err(1, "calloc");
361a30a9352SAdrian Chadd 
362b920ab48SAdrian Chadd 	r.re.buf = (char *) buf;
363a30a9352SAdrian Chadd 	r.re.len = STATS_BUF_SIZE;
364a30a9352SAdrian Chadd 
365a30a9352SAdrian Chadd 	r.s = socket(AF_INET, SOCK_DGRAM, 0);
366a30a9352SAdrian Chadd 	if (r.s < 0) {
367a30a9352SAdrian Chadd 		err(1, "socket");
368a30a9352SAdrian Chadd 	}
369b1dcd0fbSAdrian Chadd 
370a30a9352SAdrian Chadd 	/* XXX error check */
371a30a9352SAdrian Chadd 	ath_setifname(&r, ifname);
372a30a9352SAdrian Chadd 
373b1dcd0fbSAdrian Chadd 	if (do_loop) {
374b1dcd0fbSAdrian Chadd 		initscr();
375b1dcd0fbSAdrian Chadd 		start_color();
376b1dcd0fbSAdrian Chadd 		use_default_colors();
377e65889e6SAdrian Chadd 		pair_content(0, &cf, &cb);
378e65889e6SAdrian Chadd 		/* Error - medium */
379e65889e6SAdrian Chadd 		init_pair(1, COLOR_YELLOW, cb);
380e65889e6SAdrian Chadd 		/* Error - high */
381e65889e6SAdrian Chadd 		init_pair(2, COLOR_RED, cb);
382e65889e6SAdrian Chadd 		/* Sample */
383e65889e6SAdrian Chadd 		init_pair(3, COLOR_CYAN, cb);
384e65889e6SAdrian Chadd 		/* 250 byte frames */
385e65889e6SAdrian Chadd 		init_pair(4, COLOR_BLUE, cb);
386e65889e6SAdrian Chadd 		/* 1600 byte frames */
387e65889e6SAdrian Chadd 		init_pair(5, COLOR_MAGENTA, cb);
388b1dcd0fbSAdrian Chadd 		cbreak();
389b1dcd0fbSAdrian Chadd 		noecho();
390b1dcd0fbSAdrian Chadd 		nonl();
391b1dcd0fbSAdrian Chadd 		nodelay(stdscr, 1);
392b1dcd0fbSAdrian Chadd 		intrflush(stdscr, FALSE);
393b1dcd0fbSAdrian Chadd 		keypad(stdscr, TRUE);
394a30a9352SAdrian Chadd 
395b1dcd0fbSAdrian Chadd 		while (1) {
396b1dcd0fbSAdrian Chadd 			clear();
397b1dcd0fbSAdrian Chadd 			move(0, 0);
398b1dcd0fbSAdrian Chadd 			fetch_and_print_stats(&r, e, buf);
399b1dcd0fbSAdrian Chadd 			refresh();
400b1dcd0fbSAdrian Chadd 			usleep(sleep_period);
401b1dcd0fbSAdrian Chadd 		}
402b1dcd0fbSAdrian Chadd 	} else
403b1dcd0fbSAdrian Chadd 		fetch_and_print_stats(&r, e, buf);
404a30a9352SAdrian Chadd 
405b1dcd0fbSAdrian Chadd 	exit(0);
406a30a9352SAdrian Chadd }
407