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