1161200Ssam/*- 2174244Ssam * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting 3161200Ssam * All rights reserved. 4161200Ssam * 5161200Ssam * Redistribution and use in source and binary forms, with or without 6161200Ssam * modification, are permitted provided that the following conditions 7161200Ssam * are met: 8161200Ssam * 1. Redistributions of source code must retain the above copyright 9161200Ssam * notice, this list of conditions and the following disclaimer, 10161200Ssam * without modification. 11161200Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12161200Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13161200Ssam * redistribution must be conditioned upon including a substantially 14161200Ssam * similar Disclaimer requirement for further binary redistribution. 15161200Ssam * 16161200Ssam * NO WARRANTY 17161200Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18161200Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19161200Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20161200Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21161200Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22161200Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23161200Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24161200Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25161200Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26161200Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27161200Ssam * THE POSSIBILITY OF SUCH DAMAGES. 28161200Ssam * 29161200Ssam * $FreeBSD$ 30161200Ssam */ 31161200Ssam 32161200Ssam/* 33161200Ssam * wlanstats [-i interface] 34178359Ssam * (default interface is wlan0). 35161200Ssam */ 36161200Ssam 37161200Ssam#include <sys/types.h> 38161200Ssam#include <sys/socket.h> 39161200Ssam#include <net/ethernet.h> 40161200Ssam#include <net80211/_ieee80211.h> 41161200Ssam 42178359Ssam#include <stdlib.h> 43161200Ssam#include <stdio.h> 44161200Ssam#include <signal.h> 45161200Ssam#include <unistd.h> 46161200Ssam#include <err.h> 47178359Ssam#include <strings.h> 48161200Ssam 49161200Ssam#include "wlanstats.h" 50161200Ssam 51188206Ssamstatic struct { 52188206Ssam const char *tag; 53188206Ssam const char *fmt; 54188206Ssam} tags[] = { 55188206Ssam { "default", 56188206Ssam "input,rx_mgmt,output,rx_badkeyid,scan_active,scan_bg,bmiss,rssi,noise,rate" 57188206Ssam }, 58188206Ssam { "ampdu", 59188206Ssam "input,output,ampdu_reorder,ampdu_oor,rx_dup,ampdu_flush,ampdu_move," 60237129Sadrian "ampdu_drop,ampdu_bar,ampdu_baroow,ampdu_barmove,ampdu_bartx," 61237129Sadrian "ampdu_bartxfail,ampdu_bartxretry,rssi,rate" 62188206Ssam }, 63188206Ssam}; 64161200Ssam 65188206Ssamstatic const char * 66188206Ssamgetfmt(const char *tag) 67188206Ssam{ 68188206Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 69188206Ssam int i; 70188206Ssam for (i = 0; i < N(tags); i++) 71188206Ssam if (strcasecmp(tags[i].tag, tag) == 0) 72188206Ssam return tags[i].fmt; 73188206Ssam return tag; 74188206Ssam#undef N 75188206Ssam} 76188206Ssam 77161200Ssamstatic int signalled; 78161200Ssam 79161200Ssamstatic void 80161200Ssamcatchalarm(int signo __unused) 81161200Ssam{ 82161200Ssam signalled = 1; 83161200Ssam} 84161200Ssam 85161200Ssam#if 0 86161200Ssamstatic void 87161200Ssamprint_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN]) 88161200Ssam{ 89161200Ssam#define STAT(x,fmt) \ 90161200Ssam if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; } 91161200Ssam struct ieee80211req ireq; 92161200Ssam struct ieee80211req_sta_stats stats; 93161200Ssam const struct ieee80211_nodestats *ns = &stats.is_stats; 94161200Ssam const char *sep; 95161200Ssam 96161200Ssam (void) memset(&ireq, 0, sizeof(ireq)); 97161200Ssam (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); 98161200Ssam ireq.i_type = IEEE80211_IOC_STA_STATS; 99161200Ssam ireq.i_data = &stats; 100161200Ssam ireq.i_len = sizeof(stats); 101161200Ssam memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN); 102161200Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 103161200Ssam err(1, "unable to get station stats for %s", 104161200Ssam ether_ntoa((const struct ether_addr*) macaddr)); 105161200Ssam 106161200Ssam fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr)); 107161200Ssam 108161200Ssam sep = "\t"; 109161200Ssam STAT(rx_data, "%u"); 110161200Ssam STAT(rx_mgmt, "%u"); 111161200Ssam STAT(rx_ctrl, "%u"); 112161200Ssam STAT(rx_beacons, "%u"); 113161200Ssam STAT(rx_proberesp, "%u"); 114161200Ssam STAT(rx_ucast, "%u"); 115161200Ssam STAT(rx_mcast, "%u"); 116161200Ssam STAT(rx_bytes, "%llu"); 117161200Ssam STAT(rx_dup, "%u"); 118161200Ssam STAT(rx_noprivacy, "%u"); 119161200Ssam STAT(rx_wepfail, "%u"); 120161200Ssam STAT(rx_demicfail, "%u"); 121161200Ssam STAT(rx_decap, "%u"); 122161200Ssam STAT(rx_defrag, "%u"); 123161200Ssam STAT(rx_disassoc, "%u"); 124161200Ssam STAT(rx_deauth, "%u"); 125161200Ssam STAT(rx_decryptcrc, "%u"); 126161200Ssam STAT(rx_unauth, "%u"); 127161200Ssam STAT(rx_unencrypted, "%u"); 128161200Ssam fprintf(fd, "\n"); 129161200Ssam 130161200Ssam sep = "\t"; 131161200Ssam STAT(tx_data, "%u"); 132161200Ssam STAT(tx_mgmt, "%u"); 133161200Ssam STAT(tx_probereq, "%u"); 134161200Ssam STAT(tx_ucast, "%u"); 135161200Ssam STAT(tx_mcast, "%u"); 136161200Ssam STAT(tx_bytes, "%llu"); 137161200Ssam STAT(tx_novlantag, "%u"); 138161200Ssam STAT(tx_vlanmismatch, "%u"); 139161200Ssam fprintf(fd, "\n"); 140161200Ssam 141161200Ssam sep = "\t"; 142161200Ssam STAT(tx_assoc, "%u"); 143161200Ssam STAT(tx_assoc_fail, "%u"); 144161200Ssam STAT(tx_auth, "%u"); 145161200Ssam STAT(tx_auth_fail, "%u"); 146161200Ssam STAT(tx_deauth, "%u"); 147161200Ssam STAT(tx_deauth_code, "%llu"); 148161200Ssam STAT(tx_disassoc, "%u"); 149161200Ssam STAT(tx_disassoc_code, "%u"); 150161200Ssam fprintf(fd, "\n"); 151161200Ssam 152161200Ssam#undef STAT 153161200Ssam} 154161200Ssam#endif 155161200Ssam 156161200Ssamint 157161200Ssammain(int argc, char *argv[]) 158161200Ssam{ 159161200Ssam struct wlanstatfoo *wf; 160161200Ssam struct ether_addr *ea; 161161200Ssam const uint8_t *mac = NULL; 162188206Ssam const char *ifname; 163161200Ssam int allnodes = 0; 164161200Ssam int c, mode; 165161200Ssam 166188206Ssam ifname = getenv("WLAN"); 167188206Ssam if (ifname == NULL) 168188206Ssam ifname = "wlan0"; 169188206Ssam wf = wlanstats_new(ifname, getfmt("default")); 170161200Ssam while ((c = getopt(argc, argv, "ai:lm:o:")) != -1) { 171161200Ssam switch (c) { 172161200Ssam case 'a': 173161200Ssam allnodes++; 174161200Ssam break; 175161200Ssam case 'i': 176161200Ssam wf->setifname(wf, optarg); 177161200Ssam break; 178161200Ssam case 'l': 179161200Ssam wf->print_fields(wf, stdout); 180161200Ssam return 0; 181161200Ssam case 'm': 182161200Ssam ea = ether_aton(optarg); 183161200Ssam if (!ea) 184161200Ssam errx(1, "%s: invalid ethernet address", optarg); 185161200Ssam mac = ea->octet; 186161200Ssam break; 187161200Ssam case 'o': 188188206Ssam wf->setfmt(wf, getfmt(optarg)); 189161200Ssam break; 190161200Ssam default: 191161200Ssam errx(-1, "usage: %s [-a] [-i ifname] [-l] [-o fmt] [interval]\n", argv[0]); 192161200Ssam /*NOTREACHED*/ 193161200Ssam } 194161200Ssam } 195161200Ssam argc -= optind; 196161200Ssam argv += optind; 197161200Ssam 198161200Ssam mode = wf->getopmode(wf); 199161200Ssam wf->setstamac(wf, mac); 200161200Ssam 201161200Ssam if (argc > 0) { 202161200Ssam u_long interval = strtoul(argv[0], NULL, 0); 203161200Ssam int line, omask; 204161200Ssam 205161200Ssam if (interval < 1) 206161200Ssam interval = 1; 207161200Ssam signal(SIGALRM, catchalarm); 208161200Ssam signalled = 0; 209161200Ssam alarm(interval); 210161200Ssam banner: 211161200Ssam wf->print_header(wf, stdout); 212161200Ssam line = 0; 213161200Ssam loop: 214161200Ssam if (line != 0) { 215161200Ssam wf->collect_cur(wf); 216161200Ssam wf->print_current(wf, stdout); 217161200Ssam wf->update_tot(wf); 218161200Ssam } else { 219161200Ssam wf->collect_tot(wf); 220161200Ssam wf->print_total(wf, stdout); 221161200Ssam } 222161200Ssam fflush(stdout); 223161200Ssam omask = sigblock(sigmask(SIGALRM)); 224161200Ssam if (!signalled) 225161200Ssam sigpause(0); 226161200Ssam sigsetmask(omask); 227161200Ssam signalled = 0; 228161200Ssam alarm(interval); 229161200Ssam line++; 230161200Ssam /* refresh every display in case sta roams */ 231161200Ssam if (mac == NULL && mode == IEEE80211_M_STA) 232161200Ssam wf->setstamac(wf, NULL); 233161200Ssam if (line == 21) /* XXX tty line count */ 234161200Ssam goto banner; 235161200Ssam else 236161200Ssam goto loop; 237161200Ssam /*NOTREACHED*/ 238161200Ssam#if 0 239161200Ssam } else if (allnodes) { 240161200Ssam struct ieee80211req_sta_info *si; 241161200Ssam union { 242161200Ssam struct ieee80211req_sta_req req; 243161200Ssam uint8_t buf[24*1024]; 244161200Ssam } u; 245161200Ssam uint8_t *cp; 246161200Ssam struct ieee80211req ireq; 247161200Ssam int len; 248161200Ssam 249161200Ssam /* 250161200Ssam * Retrieve station/neighbor table and print stats for each. 251161200Ssam */ 252161200Ssam (void) memset(&ireq, 0, sizeof(ireq)); 253161200Ssam (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); 254161200Ssam ireq.i_type = IEEE80211_IOC_STA_INFO; 255161200Ssam memset(&u.req.macaddr, 0xff, sizeof(u.req.macaddr)); 256161200Ssam ireq.i_data = &u; 257161200Ssam ireq.i_len = sizeof(u); 258161200Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 259161200Ssam err(1, "unable to get station information"); 260161200Ssam len = ireq.i_len; 261161200Ssam if (len >= sizeof(struct ieee80211req_sta_info)) { 262161200Ssam cp = u.req.info; 263161200Ssam do { 264161200Ssam si = (struct ieee80211req_sta_info *) cp; 265161200Ssam if (si->isi_len < sizeof(*si)) 266161200Ssam break; 267161200Ssam print_sta_stats(stdout, si->isi_macaddr); 268161200Ssam cp += si->isi_len, len -= si->isi_len; 269161200Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 270161200Ssam } 271161200Ssam#endif 272161200Ssam } else { 273161200Ssam wf->collect_tot(wf); 274161200Ssam wf->print_verbose(wf, stdout); 275161200Ssam } 276161200Ssam return 0; 277161200Ssam} 278