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