]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/ath/athratestats/main.c
MFS r365608:
[FreeBSD/FreeBSD.git] / tools / tools / ath / athratestats / main.c
1 /*-
2  * Copyright (c) 2012, Adrian Chadd.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
15  *
16  * NO WARRANTY
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.
28  *
29  * $FreeBSD$
30  */
31
32 #include "opt_ah.h"
33
34 #include <sys/types.h>
35 #include <sys/file.h>
36 #include <sys/sockio.h>
37 #include <sys/socket.h>
38 #include <net/ethernet.h>
39 #include <net/if.h>
40 #include <net/if_media.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdint.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <err.h>
49
50 #include <curses.h>
51
52 #include "ah.h"
53 #include "ah_desc.h"
54 #include "net80211/ieee80211_ioctl.h"
55 #include "net80211/ieee80211_radiotap.h"
56 #include "if_athioctl.h"
57 #include "if_athrate.h"
58
59 #include "ath_rate/sample/sample.h"
60
61 static int do_loop = 0;
62
63 /*
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.
66  */
67 #define STATS_BUF_SIZE  65536
68
69 #define PRINTMSG(...) do {                      \
70         if (do_loop == 0)                       \
71                 printf(__VA_ARGS__);            \
72         else                                    \
73                 printw(__VA_ARGS__);            \
74         } while (0)
75
76 #define PRINTATTR_ON(_x) do {                   \
77         if (do_loop)                            \
78                 attron(_x);                     \
79         } while(0)
80
81
82 #define PRINTATTR_OFF(_x) do {                  \
83         if (do_loop)                            \
84                 attroff(_x);                    \
85         } while(0)
86
87 struct ath_ratestats {
88         int s;
89         struct ath_rateioctl re;
90 };
91
92 static inline int
93 dot11rate(struct ath_rateioctl_rt *rt, int rix)
94 {
95
96         if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
97                 return rt->ratecode[rix] & ~(IEEE80211_RATE_MCS);
98         else
99                 return (rt->ratecode[rix] / 2);
100 }
101
102 static const char *
103 dot11str(struct ath_rateioctl_rt *rt, int rix)
104 {
105         if (rix == -1)
106                 return "";
107         else if (rt->ratecode[rix] & IEEE80211_RATE_MCS)
108                 return "MCS";
109         else
110                 return " Mb";
111 }
112
113 static void
114 ath_sample_stats(struct ath_ratestats *r, struct ath_rateioctl_rt *rt,
115     struct sample_node *sn)
116 {
117         uint64_t mask;
118         int rix, y;
119
120         PRINTMSG("static_rix (%d) ratemask 0x%llx\n",
121             sn->static_rix,
122             (long long) sn->ratemask);
123
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 ",
128                     bin_to_size(y),
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]);
133
134                 PRINTMSG("last sample (%d %s) cur sample (%d %s) "
135                     "packets sent %d ",
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);
142                 
143                 PRINTATTR_ON(COLOR_PAIR(1) | A_BOLD);
144                 PRINTMSG("packets since sample %d sample tt %u\n",
145                     sn->packets_since_sample[y],
146                     sn->sample_tt[y]);
147                 PRINTATTR_OFF(COLOR_PAIR(3) | A_BOLD);
148         }
149         PRINTMSG("   TX Rate      TXTOTAL:TXOK       EWMA          T/   F"
150             "     avg last xmit  ");
151         PRINTMSG("   TX Rate      TXTOTAL:TXOK       EWMA          T/   F"
152             "     avg last xmit\n");
153         for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
154                 int c = 0;
155                 if ((mask & 1) == 0)
156                                 continue;
157                 for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
158                         if (sn->stats[y][rix].total_packets == 0)
159                                 continue;
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);
164 #if 0
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);
169 #endif
170                         PRINTMSG("[%2u %s:%5u] %8ju:%-8ju "
171                             "(%3d.%1d%%) %8ju/%4d %5uuS %u ",
172                             dot11rate(rt, rix),
173                             dot11str(rt, rix),
174                             bin_to_size(y),
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);
187 #if 0
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);
192 #endif
193                         c++;
194                         if (c == 2) {
195                                 PRINTMSG("\n");
196                                 c = 0;
197                         }
198                 }
199                 if (c != 0)
200                         PRINTMSG("\n");
201         }
202 }
203
204 static void
205 ath_setifname(struct ath_ratestats *r, const char *ifname)
206 {
207
208         strncpy(r->re.if_name, ifname, sizeof (r->re.if_name));
209 }
210
211 static void
212 ath_setsta(struct ath_ratestats *r, uint8_t *mac)
213 {
214
215         memcpy(&r->re.is_u.macaddr, mac, sizeof(r->re.is_u.macaddr));
216 }
217
218 static void
219 ath_rate_ioctl(struct ath_ratestats *r)
220 {
221
222         if (ioctl(r->s, SIOCGATHNODERATESTATS, &r->re) < 0)
223                 err(1, "ioctl");
224 }
225
226 static int
227 rate_node_stats(struct ath_ratestats *r, struct ether_addr *e)
228 {
229         struct ath_rateioctl_tlv *av;
230         struct sample_node *sn = NULL;
231         struct ath_rateioctl_rt *rt = NULL;
232         int error = 0;
233         uint8_t *buf = (uint8_t *) r->re.buf;
234
235         /*
236          * For now, hard-code the TLV order and contents.  Ew!
237          */
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, "
241                     "expected 0x%x\n",
242                     av->tlv_id,
243                     ATH_RATE_TLV_RATETABLE);
244                 exit(127);
245         }
246         if (av->tlv_len != sizeof(struct ath_rateioctl_rt)) {
247                 fprintf(stderr, "unexpected TLV len (got %d bytes, "
248                     "expected %d bytes\n",
249                     av->tlv_len,
250                     (int) sizeof(struct ath_rateioctl_rt));
251                 exit(127);
252         }
253         rt = (void *) (buf + sizeof(struct ath_rateioctl_tlv));
254
255         /* Next */
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, "
260                     "expected 0x%x\n",
261                     av->tlv_id,
262                     ATH_RATE_TLV_SAMPLENODE);
263                 exit(127);
264         }
265         if (av->tlv_len != sizeof(struct sample_node)) {
266                 fprintf(stderr, "unexpected TLV len (got %d bytes, "
267                     "expected %d bytes\n",
268                     av->tlv_len,
269                     (int) sizeof(struct sample_node));
270                 exit(127);
271         }
272         sn = (void *) (buf + sizeof(struct ath_rateioctl_tlv) +
273             sizeof(struct ath_rateioctl_rt) +
274             sizeof(struct ath_rateioctl_tlv));
275
276         ath_sample_stats(r, rt, sn);
277
278         return (0);
279 }
280
281 static void
282 fetch_and_print_stats(struct ath_ratestats *r, struct ether_addr *e,
283     uint8_t *buf)
284 {
285
286         /* Zero the buffer before it's passed in */
287         memset(buf, '\0', STATS_BUF_SIZE);
288
289         /*
290          * Set the station address for this lookup.
291          */
292         ath_setsta(r, e->octet);
293
294         /*
295          * Fetch the data from the driver.
296          */
297         ath_rate_ioctl(r);
298
299         /*
300          * Decode and parse statistics.
301          */
302         rate_node_stats(r, e);
303 }
304
305 int
306 main(int argc, char *argv[])
307 {
308         char const *ifname = NULL, *macaddr = NULL;
309         int c;
310         int do_all = 0;
311         struct ether_addr *e;
312         struct ath_ratestats r;
313         uint8_t *buf;
314         useconds_t sleep_period;
315         float f;
316         short cf, cb;
317
318         ifname = getenv("ATH");
319         if (ifname == NULL)
320                 ifname = ATH_DEFAULT;
321
322         while ((c = getopt(argc, argv, "ahi:m:s:")) != -1) {
323                 switch (c) {
324                 case 'a':
325                         do_all = 1;
326                         break;
327                 case 'i':
328                         ifname = optarg;
329                         break;
330                 case 'm':
331                         macaddr = optarg;
332                         break;
333                 case 's':
334                         sscanf(optarg, "%f", &f);
335                         do_loop = 1;
336                         sleep_period = (useconds_t) (f * 1000000.0);
337                         break;
338                 default:
339                         errx(1,
340                             "usage: %s [-h] [-i ifname] [-a] [-m macaddr] [-s sleep period]\n",
341                             argv[0]);
342                         /* NOTREACHED */
343                 }
344         }
345
346         if (macaddr == NULL) {
347                 errx(1, "%s: macaddress wasn't supplied and no -a given\n",
348                     argv[0]);
349                 /* NOTREACHED */
350         }
351         e = ether_aton(macaddr);
352         if (e == NULL)
353                 err(1, "ether_aton");
354
355         bzero(&r, sizeof(r));
356
357         /*
358          * Persistent buffer for each lookup
359          */
360         buf = malloc(STATS_BUF_SIZE);
361         if (buf == NULL)
362                 err(1, "calloc");
363
364         r.re.buf = (char *) buf;
365         r.re.len = STATS_BUF_SIZE;
366
367         r.s = socket(AF_INET, SOCK_DGRAM, 0);
368         if (r.s < 0) {
369                 err(1, "socket");
370         }
371
372         /* XXX error check */
373         ath_setifname(&r, ifname);
374
375         if (do_loop) {
376                 initscr();
377                 start_color();
378                 use_default_colors();
379                 pair_content(0, &cf, &cb);
380                 /* Error - medium */
381                 init_pair(1, COLOR_YELLOW, cb);
382                 /* Error - high */
383                 init_pair(2, COLOR_RED, cb);
384                 /* Sample */
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);
390                 cbreak();
391                 noecho();
392                 nonl();
393                 nodelay(stdscr, 1);
394                 intrflush(stdscr, FALSE);
395                 keypad(stdscr, TRUE);
396
397                 while (1) {
398                         clear();
399                         move(0, 0);
400                         fetch_and_print_stats(&r, e, buf);
401                         refresh();
402                         usleep(sleep_period);
403                 }
404         } else
405                 fetch_and_print_stats(&r, e, buf);
406
407         exit(0);
408 }