1/*- 2 * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting 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/* 33 * wlanstats [-i interface] 34 * (default interface is wlan0). 35 */ 36 37#include <sys/types.h> 38#include <sys/socket.h> 39#include <net/ethernet.h> 40#include <net80211/_ieee80211.h> 41 42#include <stdlib.h> 43#include <stdio.h> 44#include <signal.h> 45#include <unistd.h> 46#include <err.h> 47#include <strings.h> 48 49#include "wlanstats.h" 50 51static struct { 52 const char *tag; 53 const char *fmt; 54} tags[] = { 55 { "default", 56 "input,rx_mgmt,output,rx_badkeyid,scan_active,scan_bg,bmiss,rssi,noise,rate" 57 }, 58 { "ampdu", 59 "input,output,ampdu_reorder,ampdu_oor,rx_dup,ampdu_flush,ampdu_move," 60 "ampdu_drop,ampdu_bar,ampdu_baroow,ampdu_barmove,ampdu_bartx," 61 "ampdu_bartxfail,ampdu_bartxretry,rssi,rate" 62 }, 63}; 64 65static const char * 66getfmt(const char *tag) 67{ 68#define N(a) (sizeof(a)/sizeof(a[0])) 69 int i; 70 for (i = 0; i < N(tags); i++) 71 if (strcasecmp(tags[i].tag, tag) == 0) 72 return tags[i].fmt; 73 return tag; 74#undef N 75} 76 77static int signalled; 78 79static void 80catchalarm(int signo __unused) 81{ 82 signalled = 1; 83} 84 85#if 0 86static void 87print_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN]) 88{ 89#define STAT(x,fmt) \ 90 if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; } 91 struct ieee80211req ireq; 92 struct ieee80211req_sta_stats stats; 93 const struct ieee80211_nodestats *ns = &stats.is_stats; 94 const char *sep; 95 96 (void) memset(&ireq, 0, sizeof(ireq)); 97 (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); 98 ireq.i_type = IEEE80211_IOC_STA_STATS; 99 ireq.i_data = &stats; 100 ireq.i_len = sizeof(stats); 101 memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN); 102 if (ioctl(s, SIOCG80211, &ireq) < 0) 103 err(1, "unable to get station stats for %s", 104 ether_ntoa((const struct ether_addr*) macaddr)); 105 106 fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr)); 107 108 sep = "\t"; 109 STAT(rx_data, "%u"); 110 STAT(rx_mgmt, "%u"); 111 STAT(rx_ctrl, "%u"); 112 STAT(rx_beacons, "%u"); 113 STAT(rx_proberesp, "%u"); 114 STAT(rx_ucast, "%u"); 115 STAT(rx_mcast, "%u"); 116 STAT(rx_bytes, "%llu"); 117 STAT(rx_dup, "%u"); 118 STAT(rx_noprivacy, "%u"); 119 STAT(rx_wepfail, "%u"); 120 STAT(rx_demicfail, "%u"); 121 STAT(rx_decap, "%u"); 122 STAT(rx_defrag, "%u"); 123 STAT(rx_disassoc, "%u"); 124 STAT(rx_deauth, "%u"); 125 STAT(rx_decryptcrc, "%u"); 126 STAT(rx_unauth, "%u"); 127 STAT(rx_unencrypted, "%u"); 128 fprintf(fd, "\n"); 129 130 sep = "\t"; 131 STAT(tx_data, "%u"); 132 STAT(tx_mgmt, "%u"); 133 STAT(tx_probereq, "%u"); 134 STAT(tx_ucast, "%u"); 135 STAT(tx_mcast, "%u"); 136 STAT(tx_bytes, "%llu"); 137 STAT(tx_novlantag, "%u"); 138 STAT(tx_vlanmismatch, "%u"); 139 fprintf(fd, "\n"); 140 141 sep = "\t"; 142 STAT(tx_assoc, "%u"); 143 STAT(tx_assoc_fail, "%u"); 144 STAT(tx_auth, "%u"); 145 STAT(tx_auth_fail, "%u"); 146 STAT(tx_deauth, "%u"); 147 STAT(tx_deauth_code, "%llu"); 148 STAT(tx_disassoc, "%u"); 149 STAT(tx_disassoc_code, "%u"); 150 fprintf(fd, "\n"); 151 152#undef STAT 153} 154#endif 155 156int 157main(int argc, char *argv[]) 158{ 159 struct wlanstatfoo *wf; 160 struct ether_addr *ea; 161 const uint8_t *mac = NULL; 162 const char *ifname; 163 int allnodes = 0; 164 int c, mode; 165 166 ifname = getenv("WLAN"); 167 if (ifname == NULL) 168 ifname = "wlan0"; 169 wf = wlanstats_new(ifname, getfmt("default")); 170 while ((c = getopt(argc, argv, "ai:lm:o:")) != -1) { 171 switch (c) { 172 case 'a': 173 allnodes++; 174 break; 175 case 'i': 176 wf->setifname(wf, optarg); 177 break; 178 case 'l': 179 wf->print_fields(wf, stdout); 180 return 0; 181 case 'm': 182 ea = ether_aton(optarg); 183 if (!ea) 184 errx(1, "%s: invalid ethernet address", optarg); 185 mac = ea->octet; 186 break; 187 case 'o': 188 wf->setfmt(wf, getfmt(optarg)); 189 break; 190 default: 191 errx(-1, "usage: %s [-a] [-i ifname] [-l] [-o fmt] [interval]\n", argv[0]); 192 /*NOTREACHED*/ 193 } 194 } 195 argc -= optind; 196 argv += optind; 197 198 mode = wf->getopmode(wf); 199 wf->setstamac(wf, mac); 200 201 if (argc > 0) { 202 u_long interval = strtoul(argv[0], NULL, 0); 203 int line, omask; 204 205 if (interval < 1) 206 interval = 1; 207 signal(SIGALRM, catchalarm); 208 signalled = 0; 209 alarm(interval); 210 banner: 211 wf->print_header(wf, stdout); 212 line = 0; 213 loop: 214 if (line != 0) { 215 wf->collect_cur(wf); 216 wf->print_current(wf, stdout); 217 wf->update_tot(wf); 218 } else { 219 wf->collect_tot(wf); 220 wf->print_total(wf, stdout); 221 } 222 fflush(stdout); 223 omask = sigblock(sigmask(SIGALRM)); 224 if (!signalled) 225 sigpause(0); 226 sigsetmask(omask); 227 signalled = 0; 228 alarm(interval); 229 line++; 230 /* refresh every display in case sta roams */ 231 if (mac == NULL && mode == IEEE80211_M_STA) 232 wf->setstamac(wf, NULL); 233 if (line == 21) /* XXX tty line count */ 234 goto banner; 235 else 236 goto loop; 237 /*NOTREACHED*/ 238#if 0 239 } else if (allnodes) { 240 struct ieee80211req_sta_info *si; 241 union { 242 struct ieee80211req_sta_req req; 243 uint8_t buf[24*1024]; 244 } u; 245 uint8_t *cp; 246 struct ieee80211req ireq; 247 int len; 248 249 /* 250 * Retrieve station/neighbor table and print stats for each. 251 */ 252 (void) memset(&ireq, 0, sizeof(ireq)); 253 (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); 254 ireq.i_type = IEEE80211_IOC_STA_INFO; 255 memset(&u.req.macaddr, 0xff, sizeof(u.req.macaddr)); 256 ireq.i_data = &u; 257 ireq.i_len = sizeof(u); 258 if (ioctl(s, SIOCG80211, &ireq) < 0) 259 err(1, "unable to get station information"); 260 len = ireq.i_len; 261 if (len >= sizeof(struct ieee80211req_sta_info)) { 262 cp = u.req.info; 263 do { 264 si = (struct ieee80211req_sta_info *) cp; 265 if (si->isi_len < sizeof(*si)) 266 break; 267 print_sta_stats(stdout, si->isi_macaddr); 268 cp += si->isi_len, len -= si->isi_len; 269 } while (len >= sizeof(struct ieee80211req_sta_info)); 270 } 271#endif 272 } else { 273 wf->collect_tot(wf); 274 wf->print_verbose(wf, stdout); 275 } 276 return 0; 277} 278