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 52 static 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 66 static const char * 67 getfmt(const char *tag) 68 { 69 int i; 70 for (i = 0; i < nitems(tags); i++) 71 if (strcasecmp(tags[i].tag, tag) == 0) 72 return tags[i].fmt; 73 return tag; 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 void 156 usage(void) { 157 printf("wlanstats: [-ah] [-i ifname] [-l] [-o fmt] [interval]\n"); 158 } 159 160 int 161 main(int argc, char *argv[]) 162 { 163 struct wlanstatfoo *wf; 164 struct ether_addr *ea; 165 const uint8_t *mac = NULL; 166 const char *ifname; 167 int allnodes = 0; 168 int c, mode; 169 170 ifname = getenv("WLAN"); 171 if (ifname == NULL) 172 ifname = "wlan0"; 173 wf = wlanstats_new(ifname, getfmt("default")); 174 while ((c = getopt(argc, argv, "ahi:lm:o:")) != -1) { 175 switch (c) { 176 case 'a': 177 allnodes++; 178 break; 179 case 'h': 180 usage(); 181 exit(0); 182 case 'i': 183 wf->setifname(wf, optarg); 184 break; 185 case 'l': 186 wf->print_fields(wf, stdout); 187 return 0; 188 case 'm': 189 ea = ether_aton(optarg); 190 if (!ea) 191 errx(1, "%s: invalid ethernet address", optarg); 192 mac = ea->octet; 193 break; 194 case 'o': 195 wf->setfmt(wf, getfmt(optarg)); 196 break; 197 default: 198 usage(); 199 exit(1); 200 /*NOTREACHED*/ 201 } 202 } 203 argc -= optind; 204 argv += optind; 205 206 mode = wf->getopmode(wf); 207 wf->setstamac(wf, mac); 208 209 if (argc > 0) { 210 u_long interval = strtoul(argv[0], NULL, 0); 211 int line, omask; 212 213 if (interval < 1) 214 interval = 1; 215 signal(SIGALRM, catchalarm); 216 signalled = 0; 217 alarm(interval); 218 banner: 219 wf->print_header(wf, stdout); 220 line = 0; 221 loop: 222 if (line != 0) { 223 wf->collect_cur(wf); 224 wf->print_current(wf, stdout); 225 wf->update_tot(wf); 226 } else { 227 wf->collect_tot(wf); 228 wf->print_total(wf, stdout); 229 } 230 fflush(stdout); 231 omask = sigblock(sigmask(SIGALRM)); 232 if (!signalled) 233 sigpause(0); 234 sigsetmask(omask); 235 signalled = 0; 236 alarm(interval); 237 line++; 238 /* refresh every display in case sta roams */ 239 if (mac == NULL && mode == IEEE80211_M_STA) 240 wf->setstamac(wf, NULL); 241 if (line == 21) /* XXX tty line count */ 242 goto banner; 243 else 244 goto loop; 245 /*NOTREACHED*/ 246 #if 0 247 } else if (allnodes) { 248 struct ieee80211req_sta_info *si; 249 union { 250 struct ieee80211req_sta_req req; 251 uint8_t buf[24*1024]; 252 } u; 253 uint8_t *cp; 254 struct ieee80211req ireq; 255 int len; 256 257 /* 258 * Retrieve station/neighbor table and print stats for each. 259 */ 260 (void) memset(&ireq, 0, sizeof(ireq)); 261 (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name)); 262 ireq.i_type = IEEE80211_IOC_STA_INFO; 263 memset(&u.req.macaddr, 0xff, sizeof(u.req.macaddr)); 264 ireq.i_data = &u; 265 ireq.i_len = sizeof(u); 266 if (ioctl(s, SIOCG80211, &ireq) < 0) 267 err(1, "unable to get station information"); 268 len = ireq.i_len; 269 if (len >= sizeof(struct ieee80211req_sta_info)) { 270 cp = u.req.info; 271 do { 272 si = (struct ieee80211req_sta_info *) cp; 273 if (si->isi_len < sizeof(*si)) 274 break; 275 print_sta_stats(stdout, si->isi_macaddr); 276 cp += si->isi_len, len -= si->isi_len; 277 } while (len >= sizeof(struct ieee80211req_sta_info)); 278 } 279 #endif 280 } else { 281 wf->collect_tot(wf); 282 wf->print_verbose(wf, stdout); 283 } 284 return 0; 285 } 286