2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
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.
32 #include <sys/param.h>
37 * ath statistics class.
39 #include <sys/types.h>
41 #include <sys/sockio.h>
42 #include <sys/socket.h>
44 #include <net/if_media.h>
45 #include <net/if_var.h>
56 #include "net80211/ieee80211_ioctl.h"
57 #include "net80211/ieee80211_radiotap.h"
58 #include "if_athioctl.h"
60 #include "athaggrstats.h"
62 #define NOTPRESENT { 0, "", "" }
64 #define AFTER(prev) ((prev)+1)
66 static const struct fmt athaggrstats[] = {
68 #define S_SINGLE_PKT 0
69 { 4, "singlepkt", "spkt", "single frames scheduled" },
70 #define S_NONBAW_PKT AFTER(S_SINGLE_PKT)
71 { 5, "nonbawpkt", "nbpkt", "frames outside of the BAW" },
72 #define S_AGGR_PKT AFTER(S_NONBAW_PKT)
73 { 6, "aggrpkt", "aggpkt", "aggregate frames scheduled" },
74 #define S_BAW_CLOSED_SINGLE_PKT AFTER(S_AGGR_PKT)
75 { 8, "bawclosedpkt", "bawclpkt", "single frames due to closed BAW" },
76 #define S_LOW_HWQ_SINGLE_PKT AFTER(S_BAW_CLOSED_SINGLE_PKT)
77 { 6, "lhsinglepkt", "lhspkt", "single frames scheduled due to low HWQ depth" },
78 #define S_SCHED_NOPKT AFTER(S_LOW_HWQ_SINGLE_PKT)
79 { 6, "schednopkt", "snopkt", "sched called with no frames" },
80 #define S_RTS_AGGR_LIMITED AFTER(S_SCHED_NOPKT)
81 { 8, "rtsaggrlimit", "rtslimit", "RTS limited aggregates" },
82 #define S_PKT0 AFTER(S_RTS_AGGR_LIMITED)
83 { 2, "p0", "p0", "" },
84 #define S_PKT1 AFTER(S_PKT0)
85 { 2, "p1", "p1", "" },
86 #define S_PKT2 AFTER(S_PKT1)
87 { 2, "p2", "p2", "" },
88 #define S_PKT3 AFTER(S_PKT2)
89 { 2, "p3", "p3", "" },
90 #define S_PKT4 AFTER(S_PKT3)
91 { 2, "p4", "p4", "" },
92 #define S_PKT5 AFTER(S_PKT4)
93 { 2, "p5", "p5", "" },
94 #define S_PKT6 AFTER(S_PKT5)
95 { 2, "p6", "p6", "" },
96 #define S_PKT7 AFTER(S_PKT6)
97 { 2, "p7", "p7", "" },
98 #define S_PKT8 AFTER(S_PKT7)
99 { 2, "p8", "p8", "" },
100 #define S_PKT9 AFTER(S_PKT8)
101 { 2, "p9", "p9", "" },
102 #define S_PKT10 AFTER(S_PKT9)
103 { 3, "p10", "p10", "" },
104 #define S_PKT11 AFTER(S_PKT10)
105 { 3, "p11", "p11", "" },
106 #define S_PKT12 AFTER(S_PKT11)
107 { 3, "p12", "p12", "" },
108 #define S_PKT13 AFTER(S_PKT12)
109 { 3, "p13", "p13", "" },
110 #define S_PKT14 AFTER(S_PKT13)
111 { 3, "p14", "p14", "" },
112 #define S_PKT15 AFTER(S_PKT14)
113 { 3, "p15", "p15", "" },
114 #define S_PKT16 AFTER(S_PKT15)
115 { 3, "p16", "p16", "" },
116 #define S_PKT17 AFTER(S_PKT16)
117 { 3, "p17", "p17", "" },
118 #define S_PKT18 AFTER(S_PKT17)
119 { 3, "p18", "p18", "" },
120 #define S_PKT19 AFTER(S_PKT18)
121 { 3, "p19", "p19", "" },
122 #define S_PKT20 AFTER(S_PKT19)
123 { 3, "p20", "p20", "" },
124 #define S_PKT21 AFTER(S_PKT20)
125 { 3, "p21", "p21", "" },
126 #define S_PKT22 AFTER(S_PKT21)
127 { 3, "p22", "p22", "" },
128 #define S_PKT23 AFTER(S_PKT22)
129 { 3, "p23", "p23", "" },
130 #define S_PKT24 AFTER(S_PKT23)
131 { 3, "p24", "p24", "" },
132 #define S_PKT25 AFTER(S_PKT24)
133 { 3, "p25", "p25", "" },
134 #define S_PKT26 AFTER(S_PKT25)
135 { 3, "p26", "p26", "" },
136 #define S_PKT27 AFTER(S_PKT26)
137 { 3, "p27", "p27", "" },
138 #define S_PKT28 AFTER(S_PKT27)
139 { 3, "p28", "p28", "" },
140 #define S_PKT29 AFTER(S_PKT28)
141 { 3, "p29", "p29", "" },
142 #define S_PKT30 AFTER(S_PKT29)
143 { 3, "p30", "p30", "" },
144 #define S_PKT31 AFTER(S_PKT30)
145 { 3, "p31", "p31", "" },
148 #define S_LAST S_RTS_AGGR_LIMITED
149 #define S_MAX (S_PKT31 + 1)
151 struct athaggrstatfoo_p {
152 struct athaggrstatfoo base;
157 struct ath_tx_aggr_stats cur;
158 struct ath_tx_aggr_stats total;
162 ath_setifname(struct athaggrstatfoo *wf0, const char *ifname)
164 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) wf0;
166 strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name));
170 ath_zerostats(struct athaggrstatfoo *wf0)
173 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) wf0;
175 if (ioctl(wf->s, SIOCZATHSTATS, &wf->ifr) < 0)
176 err(-1, wf->ifr.ifr_name);
181 ath_collect(struct athaggrstatfoo_p *wf, struct ath_tx_aggr_stats *stats)
183 wf->ifr.ifr_data = (caddr_t) stats;
184 if (ioctl(wf->s, SIOCGATHAGSTATS, &wf->ifr) < 0)
185 err(1, "%s: ioctl: %s", __func__, wf->ifr.ifr_name);
189 ath_collect_cur(struct bsdstat *sf)
191 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
193 ath_collect(wf, &wf->cur);
197 ath_collect_tot(struct bsdstat *sf)
199 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
201 ath_collect(wf, &wf->total);
205 ath_update_tot(struct bsdstat *sf)
207 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
213 snprintrate(char b[], size_t bs, int rate)
215 if (rate & IEEE80211_RATE_MCS)
216 snprintf(b, bs, "MCS%u", rate &~ IEEE80211_RATE_MCS);
218 snprintf(b, bs, "%u.5M", rate / 2);
220 snprintf(b, bs, "%uM", rate / 2);
224 ath_get_curstat(struct bsdstat *sf, int s, char b[], size_t bs)
226 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
228 snprintf(b, bs, "%u", wf->cur.aggr_##x - wf->total.aggr_##x); return 1
230 snprintf(b, bs, "%u", wf->cur.aggr_pkts[x] - wf->total.aggr_pkts[x]); return 1
233 case S_SINGLE_PKT: STAT(single_pkt);
234 case S_NONBAW_PKT: STAT(nonbaw_pkt);
235 case S_AGGR_PKT: STAT(aggr_pkt);
236 case S_BAW_CLOSED_SINGLE_PKT: STAT(baw_closed_single_pkt);
237 case S_LOW_HWQ_SINGLE_PKT: STAT(low_hwq_single_pkt);
238 case S_SCHED_NOPKT: STAT(sched_nopkt);
239 case S_RTS_AGGR_LIMITED: STAT(rts_aggr_limited);
250 case S_PKT10: PKT(10);
251 case S_PKT11: PKT(11);
252 case S_PKT12: PKT(12);
253 case S_PKT13: PKT(13);
254 case S_PKT14: PKT(14);
255 case S_PKT15: PKT(15);
256 case S_PKT16: PKT(16);
257 case S_PKT17: PKT(17);
258 case S_PKT18: PKT(18);
259 case S_PKT19: PKT(19);
260 case S_PKT20: PKT(20);
261 case S_PKT21: PKT(21);
262 case S_PKT22: PKT(22);
263 case S_PKT23: PKT(23);
264 case S_PKT24: PKT(24);
265 case S_PKT25: PKT(25);
266 case S_PKT26: PKT(26);
267 case S_PKT27: PKT(27);
268 case S_PKT28: PKT(28);
269 case S_PKT29: PKT(29);
270 case S_PKT30: PKT(30);
271 case S_PKT31: PKT(31);
280 ath_get_totstat(struct bsdstat *sf, int s, char b[], size_t bs)
282 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
284 snprintf(b, bs, "%u", wf->total.aggr_##x); return 1
286 snprintf(b, bs, "%u", wf->total.aggr_pkts[x]); return 1
289 case S_SINGLE_PKT: STAT(single_pkt);
290 case S_NONBAW_PKT: STAT(nonbaw_pkt);
291 case S_AGGR_PKT: STAT(aggr_pkt);
292 case S_BAW_CLOSED_SINGLE_PKT: STAT(baw_closed_single_pkt);
293 case S_LOW_HWQ_SINGLE_PKT: STAT(low_hwq_single_pkt);
294 case S_SCHED_NOPKT: STAT(sched_nopkt);
295 case S_RTS_AGGR_LIMITED: STAT(rts_aggr_limited);
306 case S_PKT10: PKT(10);
307 case S_PKT11: PKT(11);
308 case S_PKT12: PKT(12);
309 case S_PKT13: PKT(13);
310 case S_PKT14: PKT(14);
311 case S_PKT15: PKT(15);
312 case S_PKT16: PKT(16);
313 case S_PKT17: PKT(17);
314 case S_PKT18: PKT(18);
315 case S_PKT19: PKT(19);
316 case S_PKT20: PKT(20);
317 case S_PKT21: PKT(21);
318 case S_PKT22: PKT(22);
319 case S_PKT23: PKT(23);
320 case S_PKT24: PKT(24);
321 case S_PKT25: PKT(25);
322 case S_PKT26: PKT(26);
323 case S_PKT27: PKT(27);
324 case S_PKT28: PKT(28);
325 case S_PKT29: PKT(29);
326 case S_PKT30: PKT(30);
327 case S_PKT31: PKT(31);
336 ath_print_verbose(struct bsdstat *sf, FILE *fd)
338 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf;
345 for (i = 0; i < S_LAST; i++) {
347 if (f->width > width)
350 for (i = 0; i < S_LAST; i++) {
351 if (ath_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) {
353 fprintf(fd, "%s%-*s %s\n", indent, width, s,
354 athaggrstats[i].desc);
358 fprintf(fd, "\nAggregate size profile:\n\n");
359 for (i = 0; i < 64; i++) {
360 fprintf(fd, "%2d: %12u%s",
362 wf->total.aggr_pkts[i],
363 (i % 4 == 3) ? "\n" : " ");
368 BSDSTAT_DEFINE_BOUNCE(athaggrstatfoo)
370 struct athaggrstatfoo *
371 athaggrstats_new(const char *ifname, const char *fmtstring)
373 struct athaggrstatfoo_p *wf;
375 wf = calloc(1, sizeof(struct athaggrstatfoo_p));
377 bsdstat_init(&wf->base.base, "athaggrstats",
378 athaggrstats, nitems(athaggrstats));
379 /* override base methods */
380 wf->base.base.collect_cur = ath_collect_cur;
381 wf->base.base.collect_tot = ath_collect_tot;
382 wf->base.base.get_curstat = ath_get_curstat;
383 wf->base.base.get_totstat = ath_get_totstat;
384 wf->base.base.update_tot = ath_update_tot;
385 wf->base.base.print_verbose = ath_print_verbose;
387 /* setup bounce functions for public methods */
388 BSDSTAT_BOUNCE(wf, athaggrstatfoo);
390 /* setup our public methods */
391 wf->base.setifname = ath_setifname;
393 wf->base.setstamac = wlan_setstamac;
395 wf->base.zerostats = ath_zerostats;
396 wf->s = socket(AF_INET, SOCK_DGRAM, 0);
400 ath_setifname(&wf->base, ifname);
401 wf->base.setfmt(&wf->base, fmtstring);