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