1 /*- 2 * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org> 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 <stdbool.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <signal.h> 36 #include <unistd.h> 37 #include <string.h> 38 #include <err.h> 39 #include <net/if.h> 40 #include <sys/endian.h> 41 #include <sys/time.h> 42 #include <sys/types.h> 43 #include <sys/sysctl.h> 44 45 #include "net80211/ieee80211_ioctl.h" 46 #include "net80211/ieee80211_radiotap.h" 47 48 #include "if_iwn_ioctl.h" 49 #include "if_iwnreg.h" 50 #include "iwnstats.h" 51 #include "iwn_ioctl.h" 52 53 #define IWN_DEFAULT_IF "iwn0" 54 55 static struct iwnstats * 56 iwnstats_new(const char *ifname) 57 { 58 struct iwnstats *is; 59 60 is = calloc(1, sizeof(struct iwnstats)); 61 if (is == NULL) 62 return (NULL); 63 64 is->s = socket(AF_INET, SOCK_DGRAM, 0); 65 if (is->s < 0) 66 err(1, "socket"); 67 68 iwn_setifname(is, ifname); 69 return (is); 70 } 71 72 static void 73 iwn_stats_phy_print(struct iwnstats *is, struct iwn_rx_phy_stats *rxphy, 74 const char *prefix) 75 { 76 77 printf("%s: %s: ina=%d, fina=%d, bad_plcp=%d, bad_crc32=%d, overrun=%d, eoverrun=%d\n", 78 __func__, 79 prefix, 80 le32toh(rxphy->ina), 81 le32toh(rxphy->fina), 82 le32toh(rxphy->bad_plcp), 83 le32toh(rxphy->bad_crc32), 84 le32toh(rxphy->overrun), 85 le32toh(rxphy->eoverrun)); 86 87 printf("%s: %s: fa=%d, bad_fina_sync=%d, sfd_timeout=%d, fina_timeout=%d, no_rts_ack=%d\n", 88 __func__, 89 prefix, 90 le32toh(rxphy->fa), 91 le32toh(rxphy->bad_fina_sync), 92 le32toh(rxphy->sfd_timeout), 93 le32toh(rxphy->fina_timeout), 94 le32toh(rxphy->no_rts_ack)); 95 96 printf("%s: %s: rxe_limit=%d, ack=%d, cts=%d, ba_resp=%d, dsp_kill=%d, bad_mh=%d, rssi_sum=%d\n", 97 __func__, 98 prefix, 99 le32toh(rxphy->rxe_limit), 100 le32toh(rxphy->ack), 101 le32toh(rxphy->cts), 102 le32toh(rxphy->ba_resp), 103 le32toh(rxphy->dsp_kill), 104 le32toh(rxphy->bad_mh), 105 le32toh(rxphy->rssi_sum)); 106 } 107 108 static void 109 iwn_stats_rx_general_print(struct iwnstats *is, struct iwn_rx_general_stats *g) 110 { 111 112 printf("%s: bad_cts=%d, bad_ack=%d, not_bss=%d, filtered=%d, bad_chan=%d, beacons=%d\n", 113 __func__, 114 le32toh(g->bad_cts), 115 le32toh(g->bad_ack), 116 le32toh(g->not_bss), 117 le32toh(g->filtered), 118 le32toh(g->bad_chan), 119 le32toh(g->beacons)); 120 121 /* XXX it'd be nice to have adc/ina saturated as a % of time */ 122 printf("%s: missed_beacons=%d, adc_saturated=%d, ina_searched=%d\n", 123 __func__, 124 le32toh(g->missed_beacons), 125 le32toh(g->adc_saturated), 126 le32toh(g->ina_searched)); 127 128 printf("%s: noise=[%d, %d, %d] flags=0x%08x, load=%d, fa=%d\n", 129 __func__, 130 le32toh(g->noise[0]), 131 le32toh(g->noise[1]), 132 le32toh(g->noise[2]), 133 le32toh(g->flags), 134 le32toh(g->load), 135 le32toh(g->fa)); 136 137 printf("%s: rssi=[%d, %d, %d] energy=[%d %d %d]\n", 138 __func__, 139 le32toh(g->rssi[0]), 140 le32toh(g->rssi[1]), 141 le32toh(g->rssi[2]), 142 le32toh(g->energy[0]), 143 le32toh(g->energy[1]), 144 le32toh(g->energy[2])); 145 } 146 147 static void 148 iwn_stats_tx_print(struct iwnstats *is, struct iwn_tx_stats *tx) 149 { 150 151 printf("%s: preamble=%d, rx_detected=%d, bt_defer=%d, bt_kill=%d, short_len=%d\n", 152 __func__, 153 le32toh(tx->preamble), 154 le32toh(tx->rx_detected), 155 le32toh(tx->bt_defer), 156 le32toh(tx->bt_kill), 157 le32toh(tx->short_len)); 158 159 printf("%s: cts_timeout=%d, ack_timeout=%d, exp_ack=%d, ack=%d, msdu=%d\n", 160 __func__, 161 le32toh(tx->cts_timeout), 162 le32toh(tx->ack_timeout), 163 le32toh(tx->exp_ack), 164 le32toh(tx->ack), 165 le32toh(tx->msdu)); 166 167 printf("%s: burst_err1=%d, burst_err2=%d, cts_collision=%d, ack_collision=%d\n", 168 __func__, 169 le32toh(tx->burst_err1), 170 le32toh(tx->burst_err2), 171 le32toh(tx->cts_collision), 172 le32toh(tx->ack_collision)); 173 174 printf("%s: ba_timeout=%d, ba_resched=%d, query_ampdu=%d, query=%d, query_ampdu_frag=%d\n", 175 __func__, 176 le32toh(tx->ba_timeout), 177 le32toh(tx->ba_resched), 178 le32toh(tx->query_ampdu), 179 le32toh(tx->query), 180 le32toh(tx->query_ampdu_frag)); 181 182 printf("%s: query_mismatch=%d, not_ready=%d, underrun=%d, bt_ht_kill=%d, rx_ba_resp=%d\n", 183 __func__, 184 le32toh(tx->query_mismatch), 185 le32toh(tx->not_ready), 186 le32toh(tx->underrun), 187 le32toh(tx->bt_ht_kill), 188 le32toh(tx->rx_ba_resp)); 189 } 190 191 static void 192 iwn_stats_ht_phy_print(struct iwnstats *is, struct iwn_rx_ht_phy_stats *ht) 193 { 194 195 printf("%s: bad_plcp=%d, overrun=%d, eoverrun=%d, good_crc32=%d, bad_crc32=%d\n", 196 __func__, 197 le32toh(ht->bad_plcp), 198 le32toh(ht->overrun), 199 le32toh(ht->eoverrun), 200 le32toh(ht->good_crc32), 201 le32toh(ht->bad_crc32)); 202 203 printf("%s: bad_mh=%d, good_ampdu_crc32=%d, ampdu=%d, fragment=%d\n", 204 __func__, 205 le32toh(ht->bad_plcp), 206 le32toh(ht->good_ampdu_crc32), 207 le32toh(ht->ampdu), 208 le32toh(ht->fragment)); 209 } 210 211 212 static void 213 iwn_stats_general_print(struct iwnstats *is, struct iwn_stats *stats) 214 { 215 216 /* General */ 217 printf("%s: temp=%d, temp_m=%d, burst_check=%d, burst=%d, sleep=%d, slot_out=%d, slot_idle=%d\n", 218 __func__, 219 le32toh(stats->general.temp), 220 le32toh(stats->general.temp_m), 221 le32toh(stats->general.burst_check), 222 le32toh(stats->general.burst), 223 le32toh(stats->general.sleep), 224 le32toh(stats->general.slot_out), 225 le32toh(stats->general.slot_idle)); 226 printf("%s: slot_out=%d, ttl_tstamp=0x%08x, tx_ant_a=%d, tx_ant_b=%d, exec=%d, probe=%d\n", 227 __func__, 228 le32toh(stats->general.slot_out), 229 le32toh(stats->general.ttl_tstamp), 230 le32toh(stats->general.tx_ant_a), 231 le32toh(stats->general.tx_ant_b), 232 le32toh(stats->general.exec), 233 le32toh(stats->general.probe)); 234 printf("%s: rx_enabled=%d\n", 235 __func__, 236 le32toh(stats->general.rx_enabled)); 237 } 238 239 static void 240 iwn_print(struct iwnstats *is) 241 { 242 struct iwn_stats *s; 243 struct timeval tv; 244 245 s = &is->st; 246 247 gettimeofday(&tv, NULL); 248 printf("time=%ld.%.6ld\n", (long)tv.tv_sec, (long)tv.tv_usec); 249 250 iwn_stats_general_print(is, s); 251 252 /* RX */ 253 iwn_stats_phy_print(is, &s->rx.ofdm, "ofdm"); 254 iwn_stats_phy_print(is, &s->rx.cck, "cck"); 255 iwn_stats_ht_phy_print(is, &s->rx.ht); 256 iwn_stats_rx_general_print(is, &s->rx.general); 257 258 /* TX */ 259 iwn_stats_tx_print(is, &s->tx); 260 printf("--\n"); 261 } 262 263 static void 264 usage(void) 265 { 266 printf("Usage: iwnstats [-h] [-i ifname]\n"); 267 printf(" -h: Help\n"); 268 printf(" -i <ifname>: Use ifname (default %s)\n", 269 IWN_DEFAULT_IF); 270 } 271 272 int 273 main(int argc, char *argv[]) 274 { 275 struct iwnstats *is; 276 int ch; 277 char *ifname; 278 bool first; 279 char *sysctlname; 280 size_t len; 281 int ret; 282 283 ifname = strdup(IWN_DEFAULT_IF); 284 285 /* Parse command line arguments */ 286 while ((ch = getopt(argc, argv, 287 "hi:")) != -1) { 288 switch (ch) { 289 case 'i': 290 if (ifname) 291 free(ifname); 292 ifname = strdup(optarg); 293 if (strncmp(ifname, "wlan", 4) == 0) { 294 free(ifname); 295 len = 0; 296 asprintf(&sysctlname, "net.wlan.%s.%%parent", ifname + 4); 297 ret = sysctlbyname(sysctlname, NULL, &len, NULL, 0); 298 if (ret != 0) 299 err(1, "sysctl failed"); 300 ifname = calloc(len, 1); 301 ret = sysctlbyname(sysctlname, ifname, &len, NULL, 0); 302 if (ret != 0) 303 err(1, "sysctl failed"); 304 free(sysctlname); 305 } 306 break; 307 default: 308 case '?': 309 case 'h': 310 usage(); 311 exit(1); 312 } 313 } 314 315 is = iwnstats_new(ifname); 316 317 if (is == NULL) { 318 fprintf(stderr, "%s: couldn't allocate new stats structure\n", 319 argv[0]); 320 exit(127); 321 } 322 323 /* begin fetching data */ 324 first = true; 325 while (1) { 326 if (iwn_collect(is) != 0) { 327 fprintf(stderr, "%s: fetch failed\n", argv[0]); 328 if (first) 329 return 1; 330 goto next; 331 } 332 333 iwn_print(is); 334 335 next: 336 usleep(100 * 1000); 337 first = false; 338 } 339 340 exit(0); 341 } 342