1 /*- 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 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 <sys/param.h> 33 34 #include "opt_ah.h" 35 36 /* 37 * ath statistics class. 38 */ 39 #include <sys/types.h> 40 #include <sys/file.h> 41 #include <sys/sockio.h> 42 #include <sys/socket.h> 43 #include <net/if.h> 44 #include <net/if_media.h> 45 #include <net/if_var.h> 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <signal.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <err.h> 53 54 #include "ah.h" 55 #include "ah_desc.h" 56 #include "net80211/ieee80211_ioctl.h" 57 #include "net80211/ieee80211_radiotap.h" 58 #include "if_athioctl.h" 59 60 #include "athaggrstats.h" 61 62 #define NOTPRESENT { 0, "", "" } 63 64 #define AFTER(prev) ((prev)+1) 65 66 static const struct fmt athaggrstats[] = { 67 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", "" }, 146 }; 147 148 #define S_LAST S_RTS_AGGR_LIMITED 149 #define S_MAX (S_PKT31 + 1) 150 151 struct athaggrstatfoo_p { 152 struct athaggrstatfoo base; 153 int s; 154 int optstats; 155 struct ifreq ifr; 156 struct ath_diag atd; 157 struct ath_tx_aggr_stats cur; 158 struct ath_tx_aggr_stats total; 159 }; 160 161 static void 162 ath_setifname(struct athaggrstatfoo *wf0, const char *ifname) 163 { 164 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) wf0; 165 166 strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name)); 167 } 168 169 static void 170 ath_zerostats(struct athaggrstatfoo *wf0) 171 { 172 #if 0 173 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) wf0; 174 175 if (ioctl(wf->s, SIOCZATHSTATS, &wf->ifr) < 0) 176 err(-1, wf->ifr.ifr_name); 177 #endif 178 } 179 180 static void 181 ath_collect(struct athaggrstatfoo_p *wf, struct ath_tx_aggr_stats *stats) 182 { 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); 186 } 187 188 static void 189 ath_collect_cur(struct bsdstat *sf) 190 { 191 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 192 193 ath_collect(wf, &wf->cur); 194 } 195 196 static void 197 ath_collect_tot(struct bsdstat *sf) 198 { 199 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 200 201 ath_collect(wf, &wf->total); 202 } 203 204 static void 205 ath_update_tot(struct bsdstat *sf) 206 { 207 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 208 209 wf->total = wf->cur; 210 } 211 212 static void 213 snprintrate(char b[], size_t bs, int rate) 214 { 215 if (rate & IEEE80211_RATE_MCS) 216 snprintf(b, bs, "MCS%u", rate &~ IEEE80211_RATE_MCS); 217 else if (rate & 1) 218 snprintf(b, bs, "%u.5M", rate / 2); 219 else 220 snprintf(b, bs, "%uM", rate / 2); 221 } 222 223 static int 224 ath_get_curstat(struct bsdstat *sf, int s, char b[], size_t bs) 225 { 226 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 227 #define STAT(x) \ 228 snprintf(b, bs, "%u", wf->cur.aggr_##x - wf->total.aggr_##x); return 1 229 #define PKT(x) \ 230 snprintf(b, bs, "%u", wf->cur.aggr_pkts[x] - wf->total.aggr_pkts[x]); return 1 231 232 switch (s) { 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); 240 case S_PKT0: PKT(0); 241 case S_PKT1: PKT(1); 242 case S_PKT2: PKT(2); 243 case S_PKT3: PKT(3); 244 case S_PKT4: PKT(4); 245 case S_PKT5: PKT(5); 246 case S_PKT6: PKT(6); 247 case S_PKT7: PKT(7); 248 case S_PKT8: PKT(8); 249 case S_PKT9: PKT(9); 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); 272 } 273 b[0] = '\0'; 274 return 0; 275 #undef PKT 276 #undef STAT 277 } 278 279 static int 280 ath_get_totstat(struct bsdstat *sf, int s, char b[], size_t bs) 281 { 282 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 283 #define STAT(x) \ 284 snprintf(b, bs, "%u", wf->total.aggr_##x); return 1 285 #define PKT(x) \ 286 snprintf(b, bs, "%u", wf->total.aggr_pkts[x]); return 1 287 288 switch (s) { 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); 296 case S_PKT0: PKT(0); 297 case S_PKT1: PKT(1); 298 case S_PKT2: PKT(2); 299 case S_PKT3: PKT(3); 300 case S_PKT4: PKT(4); 301 case S_PKT5: PKT(5); 302 case S_PKT6: PKT(6); 303 case S_PKT7: PKT(7); 304 case S_PKT8: PKT(8); 305 case S_PKT9: PKT(9); 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); 328 } 329 b[0] = '\0'; 330 return 0; 331 #undef PKT 332 #undef STAT 333 } 334 335 static void 336 ath_print_verbose(struct bsdstat *sf, FILE *fd) 337 { 338 struct athaggrstatfoo_p *wf = (struct athaggrstatfoo_p *) sf; 339 const struct fmt *f; 340 char s[32]; 341 const char *indent; 342 int i, width; 343 344 width = 0; 345 for (i = 0; i < S_LAST; i++) { 346 f = &sf->stats[i]; 347 if (f->width > width) 348 width = f->width; 349 } 350 for (i = 0; i < S_LAST; i++) { 351 if (ath_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) { 352 indent = ""; 353 fprintf(fd, "%s%-*s %s\n", indent, width, s, 354 athaggrstats[i].desc); 355 } 356 } 357 358 fprintf(fd, "\nAggregate size profile:\n\n"); 359 for (i = 0; i < 64; i++) { 360 fprintf(fd, "%2d: %12u%s", 361 i, 362 wf->total.aggr_pkts[i], 363 (i % 4 == 3) ? "\n" : " "); 364 } 365 fprintf(fd, "\n"); 366 } 367 368 BSDSTAT_DEFINE_BOUNCE(athaggrstatfoo) 369 370 struct athaggrstatfoo * 371 athaggrstats_new(const char *ifname, const char *fmtstring) 372 { 373 struct athaggrstatfoo_p *wf; 374 375 wf = calloc(1, sizeof(struct athaggrstatfoo_p)); 376 if (wf != NULL) { 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; 386 387 /* setup bounce functions for public methods */ 388 BSDSTAT_BOUNCE(wf, athaggrstatfoo); 389 390 /* setup our public methods */ 391 wf->base.setifname = ath_setifname; 392 #if 0 393 wf->base.setstamac = wlan_setstamac; 394 #endif 395 wf->base.zerostats = ath_zerostats; 396 wf->s = socket(AF_INET, SOCK_DGRAM, 0); 397 if (wf->s < 0) 398 err(1, "socket"); 399 400 ath_setifname(&wf->base, ifname); 401 wf->base.setfmt(&wf->base, fmtstring); 402 } 403 return &wf->base; 404 } 405