1262423Sadrian/*- 2262423Sadrian * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org> 3262423Sadrian * All rights reserved. 4262423Sadrian * 5262423Sadrian * Redistribution and use in source and binary forms, with or without 6262423Sadrian * modification, are permitted provided that the following conditions 7262423Sadrian * are met: 8262423Sadrian * 1. Redistributions of source code must retain the above copyright 9262423Sadrian * notice, this list of conditions and the following disclaimer, 10262423Sadrian * without modification. 11262423Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12262423Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13262423Sadrian * redistribution must be conditioned upon including a substantially 14262423Sadrian * similar Disclaimer requirement for further binary redistribution. 15262423Sadrian * 16262423Sadrian * NO WARRANTY 17262423Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18262423Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19262423Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20262423Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21262423Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22262423Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23262423Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24262423Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25262423Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26262423Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27262423Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28262423Sadrian * 29262423Sadrian * $FreeBSD$ 30262423Sadrian */ 31262423Sadrian 32262766Seadler#include <stdbool.h> 33262423Sadrian#include <stdio.h> 34262423Sadrian#include <stdlib.h> 35262423Sadrian#include <signal.h> 36287313Sadrian#include <fcntl.h> 37262423Sadrian#include <unistd.h> 38262423Sadrian#include <string.h> 39262423Sadrian#include <err.h> 40262423Sadrian#include <net/if.h> 41262423Sadrian#include <sys/endian.h> 42263093Seadler#include <sys/time.h> 43262893Seadler#include <sys/types.h> 44262893Seadler#include <sys/sysctl.h> 45262423Sadrian 46262423Sadrian#include "net80211/ieee80211_ioctl.h" 47262423Sadrian#include "net80211/ieee80211_radiotap.h" 48262423Sadrian 49262423Sadrian#include "if_iwn_ioctl.h" 50262423Sadrian#include "if_iwnreg.h" 51262423Sadrian#include "iwnstats.h" 52262423Sadrian#include "iwn_ioctl.h" 53262423Sadrian 54287313Sadrian#define IWN_DEFAULT_IF "iwn0" 55262423Sadrian 56262768Seadlerstatic struct iwnstats * 57262423Sadrianiwnstats_new(const char *ifname) 58262423Sadrian{ 59262423Sadrian struct iwnstats *is; 60287313Sadrian char buf[128]; 61262423Sadrian 62262423Sadrian is = calloc(1, sizeof(struct iwnstats)); 63262423Sadrian if (is == NULL) 64262423Sadrian return (NULL); 65262423Sadrian 66287313Sadrian snprintf(buf, sizeof(buf), "/dev/%s", ifname); 67287313Sadrian is->s = open(buf, O_RDWR); 68262423Sadrian if (is->s < 0) 69287313Sadrian err(1, "open"); 70262423Sadrian 71262423Sadrian return (is); 72262423Sadrian} 73262423Sadrian 74262423Sadrianstatic void 75262423Sadrianiwn_stats_phy_print(struct iwnstats *is, struct iwn_rx_phy_stats *rxphy, 76262423Sadrian const char *prefix) 77262423Sadrian{ 78262423Sadrian 79262423Sadrian printf("%s: %s: ina=%d, fina=%d, bad_plcp=%d, bad_crc32=%d, overrun=%d, eoverrun=%d\n", 80262423Sadrian __func__, 81262423Sadrian prefix, 82262423Sadrian le32toh(rxphy->ina), 83262423Sadrian le32toh(rxphy->fina), 84262423Sadrian le32toh(rxphy->bad_plcp), 85262423Sadrian le32toh(rxphy->bad_crc32), 86262423Sadrian le32toh(rxphy->overrun), 87262423Sadrian le32toh(rxphy->eoverrun)); 88262423Sadrian 89262423Sadrian printf("%s: %s: fa=%d, bad_fina_sync=%d, sfd_timeout=%d, fina_timeout=%d, no_rts_ack=%d\n", 90262423Sadrian __func__, 91262423Sadrian prefix, 92262423Sadrian le32toh(rxphy->fa), 93262423Sadrian le32toh(rxphy->bad_fina_sync), 94262423Sadrian le32toh(rxphy->sfd_timeout), 95262423Sadrian le32toh(rxphy->fina_timeout), 96262423Sadrian le32toh(rxphy->no_rts_ack)); 97262423Sadrian 98262423Sadrian printf("%s: %s: rxe_limit=%d, ack=%d, cts=%d, ba_resp=%d, dsp_kill=%d, bad_mh=%d, rssi_sum=%d\n", 99262423Sadrian __func__, 100262423Sadrian prefix, 101262423Sadrian le32toh(rxphy->rxe_limit), 102262423Sadrian le32toh(rxphy->ack), 103262423Sadrian le32toh(rxphy->cts), 104262423Sadrian le32toh(rxphy->ba_resp), 105262423Sadrian le32toh(rxphy->dsp_kill), 106262423Sadrian le32toh(rxphy->bad_mh), 107262423Sadrian le32toh(rxphy->rssi_sum)); 108262423Sadrian} 109262423Sadrian 110262423Sadrianstatic void 111262423Sadrianiwn_stats_rx_general_print(struct iwnstats *is, struct iwn_rx_general_stats *g) 112262423Sadrian{ 113262423Sadrian 114262423Sadrian printf("%s: bad_cts=%d, bad_ack=%d, not_bss=%d, filtered=%d, bad_chan=%d, beacons=%d\n", 115262423Sadrian __func__, 116262423Sadrian le32toh(g->bad_cts), 117262423Sadrian le32toh(g->bad_ack), 118262423Sadrian le32toh(g->not_bss), 119262423Sadrian le32toh(g->filtered), 120262423Sadrian le32toh(g->bad_chan), 121262423Sadrian le32toh(g->beacons)); 122262423Sadrian 123262423Sadrian /* XXX it'd be nice to have adc/ina saturated as a % of time */ 124262423Sadrian printf("%s: missed_beacons=%d, adc_saturated=%d, ina_searched=%d\n", 125262423Sadrian __func__, 126262423Sadrian le32toh(g->missed_beacons), 127262423Sadrian le32toh(g->adc_saturated), 128262423Sadrian le32toh(g->ina_searched)); 129262423Sadrian 130262423Sadrian printf("%s: noise=[%d, %d, %d] flags=0x%08x, load=%d, fa=%d\n", 131262423Sadrian __func__, 132262423Sadrian le32toh(g->noise[0]), 133262423Sadrian le32toh(g->noise[1]), 134262423Sadrian le32toh(g->noise[2]), 135262423Sadrian le32toh(g->flags), 136262423Sadrian le32toh(g->load), 137262423Sadrian le32toh(g->fa)); 138262423Sadrian 139262423Sadrian printf("%s: rssi=[%d, %d, %d] energy=[%d %d %d]\n", 140262423Sadrian __func__, 141262423Sadrian le32toh(g->rssi[0]), 142262423Sadrian le32toh(g->rssi[1]), 143262423Sadrian le32toh(g->rssi[2]), 144262423Sadrian le32toh(g->energy[0]), 145262423Sadrian le32toh(g->energy[1]), 146262423Sadrian le32toh(g->energy[2])); 147262423Sadrian} 148262423Sadrian 149262423Sadrianstatic void 150262423Sadrianiwn_stats_tx_print(struct iwnstats *is, struct iwn_tx_stats *tx) 151262423Sadrian{ 152262423Sadrian 153262423Sadrian printf("%s: preamble=%d, rx_detected=%d, bt_defer=%d, bt_kill=%d, short_len=%d\n", 154262423Sadrian __func__, 155262423Sadrian le32toh(tx->preamble), 156262423Sadrian le32toh(tx->rx_detected), 157262423Sadrian le32toh(tx->bt_defer), 158262423Sadrian le32toh(tx->bt_kill), 159262423Sadrian le32toh(tx->short_len)); 160262423Sadrian 161262423Sadrian printf("%s: cts_timeout=%d, ack_timeout=%d, exp_ack=%d, ack=%d, msdu=%d\n", 162262423Sadrian __func__, 163262423Sadrian le32toh(tx->cts_timeout), 164262423Sadrian le32toh(tx->ack_timeout), 165262423Sadrian le32toh(tx->exp_ack), 166262423Sadrian le32toh(tx->ack), 167262423Sadrian le32toh(tx->msdu)); 168262423Sadrian 169262423Sadrian printf("%s: burst_err1=%d, burst_err2=%d, cts_collision=%d, ack_collision=%d\n", 170262423Sadrian __func__, 171262423Sadrian le32toh(tx->burst_err1), 172262423Sadrian le32toh(tx->burst_err2), 173262423Sadrian le32toh(tx->cts_collision), 174262423Sadrian le32toh(tx->ack_collision)); 175262423Sadrian 176262423Sadrian printf("%s: ba_timeout=%d, ba_resched=%d, query_ampdu=%d, query=%d, query_ampdu_frag=%d\n", 177262423Sadrian __func__, 178262423Sadrian le32toh(tx->ba_timeout), 179262423Sadrian le32toh(tx->ba_resched), 180262423Sadrian le32toh(tx->query_ampdu), 181262423Sadrian le32toh(tx->query), 182262423Sadrian le32toh(tx->query_ampdu_frag)); 183262423Sadrian 184262423Sadrian printf("%s: query_mismatch=%d, not_ready=%d, underrun=%d, bt_ht_kill=%d, rx_ba_resp=%d\n", 185262423Sadrian __func__, 186262423Sadrian le32toh(tx->query_mismatch), 187262423Sadrian le32toh(tx->not_ready), 188262423Sadrian le32toh(tx->underrun), 189262423Sadrian le32toh(tx->bt_ht_kill), 190262423Sadrian le32toh(tx->rx_ba_resp)); 191262423Sadrian} 192262423Sadrian 193262423Sadrianstatic void 194262423Sadrianiwn_stats_ht_phy_print(struct iwnstats *is, struct iwn_rx_ht_phy_stats *ht) 195262423Sadrian{ 196262423Sadrian 197262423Sadrian printf("%s: bad_plcp=%d, overrun=%d, eoverrun=%d, good_crc32=%d, bad_crc32=%d\n", 198262423Sadrian __func__, 199262423Sadrian le32toh(ht->bad_plcp), 200262423Sadrian le32toh(ht->overrun), 201262423Sadrian le32toh(ht->eoverrun), 202262423Sadrian le32toh(ht->good_crc32), 203262423Sadrian le32toh(ht->bad_crc32)); 204262423Sadrian 205262423Sadrian printf("%s: bad_mh=%d, good_ampdu_crc32=%d, ampdu=%d, fragment=%d\n", 206262423Sadrian __func__, 207262423Sadrian le32toh(ht->bad_plcp), 208262423Sadrian le32toh(ht->good_ampdu_crc32), 209262423Sadrian le32toh(ht->ampdu), 210262423Sadrian le32toh(ht->fragment)); 211262423Sadrian} 212262423Sadrian 213262423Sadrian 214262423Sadrianstatic void 215262423Sadrianiwn_stats_general_print(struct iwnstats *is, struct iwn_stats *stats) 216262423Sadrian{ 217262423Sadrian 218262423Sadrian /* General */ 219262423Sadrian printf("%s: temp=%d, temp_m=%d, burst_check=%d, burst=%d, sleep=%d, slot_out=%d, slot_idle=%d\n", 220262423Sadrian __func__, 221262423Sadrian le32toh(stats->general.temp), 222262423Sadrian le32toh(stats->general.temp_m), 223262423Sadrian le32toh(stats->general.burst_check), 224262423Sadrian le32toh(stats->general.burst), 225262423Sadrian le32toh(stats->general.sleep), 226262423Sadrian le32toh(stats->general.slot_out), 227262423Sadrian le32toh(stats->general.slot_idle)); 228262423Sadrian printf("%s: slot_out=%d, ttl_tstamp=0x%08x, tx_ant_a=%d, tx_ant_b=%d, exec=%d, probe=%d\n", 229262423Sadrian __func__, 230262423Sadrian le32toh(stats->general.slot_out), 231262423Sadrian le32toh(stats->general.ttl_tstamp), 232262423Sadrian le32toh(stats->general.tx_ant_a), 233262423Sadrian le32toh(stats->general.tx_ant_b), 234262423Sadrian le32toh(stats->general.exec), 235262423Sadrian le32toh(stats->general.probe)); 236262423Sadrian printf("%s: rx_enabled=%d\n", 237262423Sadrian __func__, 238262423Sadrian le32toh(stats->general.rx_enabled)); 239262423Sadrian} 240262423Sadrian 241262423Sadrianstatic void 242262423Sadrianiwn_print(struct iwnstats *is) 243262423Sadrian{ 244262423Sadrian struct iwn_stats *s; 245263093Seadler struct timeval tv; 246262423Sadrian 247262423Sadrian s = &is->st; 248262423Sadrian 249263093Seadler gettimeofday(&tv, NULL); 250263093Seadler printf("time=%ld.%.6ld\n", (long)tv.tv_sec, (long)tv.tv_usec); 251263093Seadler 252262423Sadrian iwn_stats_general_print(is, s); 253262423Sadrian 254262423Sadrian /* RX */ 255262423Sadrian iwn_stats_phy_print(is, &s->rx.ofdm, "ofdm"); 256262423Sadrian iwn_stats_phy_print(is, &s->rx.cck, "cck"); 257262423Sadrian iwn_stats_ht_phy_print(is, &s->rx.ht); 258262423Sadrian iwn_stats_rx_general_print(is, &s->rx.general); 259262423Sadrian 260262423Sadrian /* TX */ 261262423Sadrian iwn_stats_tx_print(is, &s->tx); 262262423Sadrian printf("--\n"); 263262423Sadrian} 264262423Sadrian 265262759Sadrianstatic void 266262759Sadrianusage(void) 267262759Sadrian{ 268262759Sadrian printf("Usage: iwnstats [-h] [-i ifname]\n"); 269262759Sadrian printf(" -h: Help\n"); 270262759Sadrian printf(" -i <ifname>: Use ifname (default %s)\n", 271262759Sadrian IWN_DEFAULT_IF); 272262759Sadrian} 273262759Sadrian 274262423Sadrianint 275262759Sadrianmain(int argc, char *argv[]) 276262423Sadrian{ 277262423Sadrian struct iwnstats *is; 278262759Sadrian int ch; 279262759Sadrian char *ifname; 280262766Seadler bool first; 281262893Seadler char *sysctlname; 282262893Seadler size_t len; 283262893Seadler int ret; 284262423Sadrian 285262759Sadrian ifname = strdup(IWN_DEFAULT_IF); 286262423Sadrian 287262759Sadrian /* Parse command line arguments */ 288262759Sadrian while ((ch = getopt(argc, argv, 289262759Sadrian "hi:")) != -1) { 290262759Sadrian switch (ch) { 291262759Sadrian case 'i': 292262759Sadrian if (ifname) 293262759Sadrian free(ifname); 294262759Sadrian ifname = strdup(optarg); 295262759Sadrian break; 296262759Sadrian default: 297262759Sadrian case '?': 298262759Sadrian case 'h': 299262759Sadrian usage(); 300262759Sadrian exit(1); 301262759Sadrian } 302262759Sadrian } 303262759Sadrian 304262759Sadrian is = iwnstats_new(ifname); 305262759Sadrian 306262423Sadrian if (is == NULL) { 307262423Sadrian fprintf(stderr, "%s: couldn't allocate new stats structure\n", 308262423Sadrian argv[0]); 309262423Sadrian exit(127); 310262423Sadrian } 311262423Sadrian 312262423Sadrian /* begin fetching data */ 313262766Seadler first = true; 314262423Sadrian while (1) { 315262423Sadrian if (iwn_collect(is) != 0) { 316262423Sadrian fprintf(stderr, "%s: fetch failed\n", argv[0]); 317262766Seadler if (first) 318262766Seadler return 1; 319262423Sadrian goto next; 320262423Sadrian } 321262423Sadrian 322262423Sadrian iwn_print(is); 323262423Sadrian 324262423Sadrian next: 325262423Sadrian usleep(100 * 1000); 326262766Seadler first = false; 327262423Sadrian } 328262423Sadrian 329262423Sadrian exit(0); 330262423Sadrian} 331