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