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