2 * Copyright (c) 2012, Adrian Chadd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13 * redistribution must be conditioned upon including a substantially
14 * similar Disclaimer requirement for further binary redistribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGES.
34 #include <sys/types.h>
36 #include <sys/sockio.h>
37 #include <sys/socket.h>
38 #include <net/ethernet.h>
40 #include <net/if_media.h>
54 #include "net80211/ieee80211_ioctl.h"
55 #include "net80211/ieee80211_radiotap.h"
56 #include "if_athioctl.h"
57 #include "if_athrate.h"
59 #include "ath_rate/sample/sample.h"
61 static int do_loop = 0;
64 * This needs to be big enough to fit the two TLVs, the rate table
65 * and the rate statistics table for a single node.
67 #define STATS_BUF_SIZE 65536
69 #define PRINTMSG(...) do { \
71 printf(__VA_ARGS__); \
73 printw(__VA_ARGS__); \
76 #define PRINTATTR_ON(_x) do { \
82 #define PRINTATTR_OFF(_x) do { \
87 struct ath_ratestats {
89 struct ath_rateioctl re;
93 dot11rate(struct ath_rateioctl_rt *rt, int rix)
96 if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
97 return rt->ratecode[rix] & ~(IEEE80211_RATE_MCS);
99 return (rt->ratecode[rix] / 2);
103 dot11str(struct ath_rateioctl_rt *rt, int rix)
107 else if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
114 ath_sample_stats(struct ath_ratestats *r, struct ath_rateioctl_rt *rt,
115 struct sample_node *sn)
120 PRINTMSG("static_rix (%d) ratemask 0x%llx\n",
122 (long long) sn->ratemask);
124 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
125 PRINTATTR_ON(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
126 PRINTMSG("[%4u] cur rate %d %s since switch: "
127 "packets %d ticks %u ",
129 dot11rate(rt, sn->current_rix[y]),
130 dot11str(rt, sn->current_rix[y]),
131 sn->packets_since_switch[y],
132 sn->ticks_since_switch[y]);
134 PRINTMSG("last sample (%d %s) cur sample (%d %s) "
136 dot11rate(rt, sn->last_sample_rix[y]),
137 dot11str(rt, sn->last_sample_rix[y]),
138 dot11rate(rt, sn->current_sample_rix[y]),
139 dot11str(rt, sn->current_sample_rix[y]),
140 sn->packets_sent[y]);
141 PRINTATTR_OFF(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
143 PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
144 PRINTMSG("packets since sample %d sample tt %u\n",
145 sn->packets_since_sample[y],
147 PRINTATTR_OFF(COLOR_PAIR(3) | A_BOLD);
149 PRINTMSG(" TX Rate TXTOTAL:TXOK EWMA T/ F"
151 PRINTMSG(" TX Rate TXTOTAL:TXOK EWMA T/ F"
153 for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
157 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
158 if (sn->stats[y][rix].total_packets == 0)
160 if (rix == sn->current_rix[y])
161 PRINTATTR_ON(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
162 else if (rix == sn->last_sample_rix[y])
163 PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
165 else if (sn->stats[y][rix].ewma_pct / 10 < 50)
166 PRINTATTR_ON(COLOR_PAIR(2) | A_BOLD);
167 else if (sn->stats[y][rix].ewma_pct / 10 < 75)
168 PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
170 PRINTMSG("[%2u %s:%5u] %8ju:%-8ju "
171 "(%3d.%1d%%) %8ju/%4d %5uuS %u ",
175 (uintmax_t) sn->stats[y][rix].total_packets,
176 (uintmax_t) sn->stats[y][rix].packets_acked,
177 sn->stats[y][rix].ewma_pct / 10,
178 sn->stats[y][rix].ewma_pct % 10,
179 (uintmax_t) sn->stats[y][rix].tries,
180 sn->stats[y][rix].successive_failures,
181 sn->stats[y][rix].average_tx_time,
182 sn->stats[y][rix].last_tx);
183 if (rix == sn->current_rix[y])
184 PRINTATTR_OFF(COLOR_PAIR(2 + (y % 4)) | A_BOLD);
185 else if (rix == sn->last_sample_rix[y])
186 PRINTATTR_OFF(COLOR_PAIR(1) | A_BOLD);
188 else if (sn->stats[y][rix].ewma_pct / 10 < 50)
189 PRINTATTR_OFF(COLOR_PAIR(2) | A_BOLD);
190 else if (sn->stats[y][rix].ewma_pct / 10 < 75)
191 PRINTATTR_OFF(COLOR_PAIR(1) | A_BOLD);
205 ath_setifname(struct ath_ratestats *r, const char *ifname)
208 strncpy(r->re.if_name, ifname, sizeof (r->re.if_name));
212 ath_setsta(struct ath_ratestats *r, uint8_t *mac)
215 memcpy(&r->re.is_u.macaddr, mac, sizeof(r->re.is_u.macaddr));
219 ath_rate_ioctl(struct ath_ratestats *r)
222 if (ioctl(r->s, SIOCGATHNODERATESTATS, &r->re) < 0)
227 rate_node_stats(struct ath_ratestats *r, struct ether_addr *e)
229 struct ath_rateioctl_tlv *av;
230 struct sample_node *sn = NULL;
231 struct ath_rateioctl_rt *rt = NULL;
233 uint8_t *buf = (uint8_t *) r->re.buf;
236 * For now, hard-code the TLV order and contents. Ew!
238 av = (struct ath_rateioctl_tlv *) buf;
239 if (av->tlv_id != ATH_RATE_TLV_RATETABLE) {
240 fprintf(stderr, "unexpected rate control TLV (got 0x%x, "
243 ATH_RATE_TLV_RATETABLE);
246 if (av->tlv_len != sizeof(struct ath_rateioctl_rt)) {
247 fprintf(stderr, "unexpected TLV len (got %d bytes, "
248 "expected %d bytes\n",
250 (int) sizeof(struct ath_rateioctl_rt));
253 rt = (void *) (buf + sizeof(struct ath_rateioctl_tlv));
256 av = (void *) (buf + sizeof(struct ath_rateioctl_tlv) +
257 sizeof(struct ath_rateioctl_rt));
258 if (av->tlv_id != ATH_RATE_TLV_SAMPLENODE) {
259 fprintf(stderr, "unexpected rate control TLV (got 0x%x, "
262 ATH_RATE_TLV_SAMPLENODE);
265 if (av->tlv_len != sizeof(struct sample_node)) {
266 fprintf(stderr, "unexpected TLV len (got %d bytes, "
267 "expected %d bytes\n",
269 (int) sizeof(struct sample_node));
272 sn = (void *) (buf + sizeof(struct ath_rateioctl_tlv) +
273 sizeof(struct ath_rateioctl_rt) +
274 sizeof(struct ath_rateioctl_tlv));
276 ath_sample_stats(r, rt, sn);
282 fetch_and_print_stats(struct ath_ratestats *r, struct ether_addr *e,
286 /* Zero the buffer before it's passed in */
287 memset(buf, '\0', STATS_BUF_SIZE);
290 * Set the station address for this lookup.
292 ath_setsta(r, e->octet);
295 * Fetch the data from the driver.
300 * Decode and parse statistics.
302 rate_node_stats(r, e);
306 main(int argc, char *argv[])
308 char const *ifname = NULL, *macaddr = NULL;
311 struct ether_addr *e;
312 struct ath_ratestats r;
314 useconds_t sleep_period;
318 ifname = getenv("ATH");
320 ifname = ATH_DEFAULT;
322 while ((c = getopt(argc, argv, "ahi:m:s:")) != -1) {
334 sscanf(optarg, "%f", &f);
336 sleep_period = (useconds_t) (f * 1000000.0);
340 "usage: %s [-h] [-i ifname] [-a] [-m macaddr] [-s sleep period]\n",
346 if (macaddr == NULL) {
347 errx(1, "%s: macaddress wasn't supplied and no -a given\n",
351 e = ether_aton(macaddr);
353 err(1, "ether_aton");
355 bzero(&r, sizeof(r));
358 * Persistent buffer for each lookup
360 buf = malloc(STATS_BUF_SIZE);
364 r.re.buf = (char *) buf;
365 r.re.len = STATS_BUF_SIZE;
367 r.s = socket(AF_INET, SOCK_DGRAM, 0);
372 /* XXX error check */
373 ath_setifname(&r, ifname);
378 use_default_colors();
379 pair_content(0, &cf, &cb);
381 init_pair(1, COLOR_YELLOW, cb);
383 init_pair(2, COLOR_RED, cb);
385 init_pair(3, COLOR_CYAN, cb);
386 /* 250 byte frames */
387 init_pair(4, COLOR_BLUE, cb);
388 /* 1600 byte frames */
389 init_pair(5, COLOR_MAGENTA, cb);
394 intrflush(stdscr, FALSE);
395 keypad(stdscr, TRUE);
400 fetch_and_print_stats(&r, e, buf);
402 usleep(sleep_period);
405 fetch_and_print_stats(&r, e, buf);