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