12f549d72SSam Leffler /*-
253d4724bSSam Leffler * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
32f549d72SSam Leffler * All rights reserved.
42f549d72SSam Leffler *
52f549d72SSam Leffler * Redistribution and use in source and binary forms, with or without
62f549d72SSam Leffler * modification, are permitted provided that the following conditions
72f549d72SSam Leffler * are met:
82f549d72SSam Leffler * 1. Redistributions of source code must retain the above copyright
92f549d72SSam Leffler * notice, this list of conditions and the following disclaimer,
102f549d72SSam Leffler * without modification.
112f549d72SSam Leffler * 2. Redistributions in binary form must reproduce at minimum a disclaimer
122f549d72SSam Leffler * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
132f549d72SSam Leffler * redistribution must be conditioned upon including a substantially
142f549d72SSam Leffler * similar Disclaimer requirement for further binary redistribution.
152f549d72SSam Leffler *
162f549d72SSam Leffler * NO WARRANTY
172f549d72SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182f549d72SSam Leffler * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192f549d72SSam Leffler * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
202f549d72SSam Leffler * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
212f549d72SSam Leffler * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
222f549d72SSam Leffler * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232f549d72SSam Leffler * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242f549d72SSam Leffler * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
252f549d72SSam Leffler * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262f549d72SSam Leffler * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
272f549d72SSam Leffler * THE POSSIBILITY OF SUCH DAMAGES.
282f549d72SSam Leffler */
292f549d72SSam Leffler
302f549d72SSam Leffler /*
312f549d72SSam Leffler * wlanstats [-i interface]
32525de97eSSam Leffler * (default interface is wlan0).
332f549d72SSam Leffler */
342f549d72SSam Leffler
3560caf0c9SCraig Rodrigues #include <sys/param.h>
362f549d72SSam Leffler #include <sys/socket.h>
3760caf0c9SCraig Rodrigues
382f549d72SSam Leffler #include <net/ethernet.h>
392f549d72SSam Leffler #include <net80211/_ieee80211.h>
402f549d72SSam Leffler
412f549d72SSam Leffler #include <err.h>
4260caf0c9SCraig Rodrigues #include <signal.h>
4360caf0c9SCraig Rodrigues #include <stdio.h>
4460caf0c9SCraig Rodrigues #include <stdlib.h>
45525de97eSSam Leffler #include <strings.h>
4660caf0c9SCraig Rodrigues #include <unistd.h>
472f549d72SSam Leffler
482f549d72SSam Leffler #include "wlanstats.h"
492f549d72SSam Leffler
50ab28e516SSam Leffler static struct {
51ab28e516SSam Leffler const char *tag;
52ab28e516SSam Leffler const char *fmt;
53ab28e516SSam Leffler } tags[] = {
54ab28e516SSam Leffler { "default",
5551a5da15SSam Leffler "input,rx_mgmt,output,rx_badkeyid,scan_active,scan_bg,bmiss,rssi,noise,rate"
56ab28e516SSam Leffler },
57ab28e516SSam Leffler { "ampdu",
58ab28e516SSam Leffler "input,output,ampdu_reorder,ampdu_oor,rx_dup,ampdu_flush,ampdu_move,"
597e7f083fSAdrian Chadd "ampdu_drop,ampdu_bar,ampdu_baroow,ampdu_barmove,ampdu_bartx,"
607e7f083fSAdrian Chadd "ampdu_bartxfail,ampdu_bartxretry,rssi,rate"
61ab28e516SSam Leffler },
62fb232cbfSAdrian Chadd {
63fb232cbfSAdrian Chadd "amsdu",
6426a6f76aSAdrian Chadd "input,output,amsdu_tooshort,amsdu_split,amsdu_decap,amsdu_encap,rx_amsdu_more,rx_amsdu_more_end,rssi,rate"
65fb232cbfSAdrian Chadd },
66ab28e516SSam Leffler };
67ab28e516SSam Leffler
68ab28e516SSam Leffler static const char *
getfmt(const char * tag)69ab28e516SSam Leffler getfmt(const char *tag)
70ab28e516SSam Leffler {
71ff7c2c5aSAdrian Chadd unsigned int i;
7260caf0c9SCraig Rodrigues for (i = 0; i < nitems(tags); i++)
73ab28e516SSam Leffler if (strcasecmp(tags[i].tag, tag) == 0)
74ab28e516SSam Leffler return tags[i].fmt;
75ab28e516SSam Leffler return tag;
76ab28e516SSam Leffler }
772f549d72SSam Leffler
782f549d72SSam Leffler static int signalled;
792f549d72SSam Leffler
802f549d72SSam Leffler static void
catchalarm(int signo __unused)812f549d72SSam Leffler catchalarm(int signo __unused)
822f549d72SSam Leffler {
832f549d72SSam Leffler signalled = 1;
842f549d72SSam Leffler }
852f549d72SSam Leffler
862f549d72SSam Leffler #if 0
872f549d72SSam Leffler static void
882f549d72SSam Leffler print_sta_stats(FILE *fd, const u_int8_t macaddr[IEEE80211_ADDR_LEN])
892f549d72SSam Leffler {
902f549d72SSam Leffler #define STAT(x,fmt) \
912f549d72SSam Leffler if (ns->ns_##x) { fprintf(fd, "%s" #x " " fmt, sep, ns->ns_##x); sep = " "; }
922f549d72SSam Leffler struct ieee80211req ireq;
932f549d72SSam Leffler struct ieee80211req_sta_stats stats;
942f549d72SSam Leffler const struct ieee80211_nodestats *ns = &stats.is_stats;
952f549d72SSam Leffler const char *sep;
962f549d72SSam Leffler
972f549d72SSam Leffler (void) memset(&ireq, 0, sizeof(ireq));
982f549d72SSam Leffler (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name));
992f549d72SSam Leffler ireq.i_type = IEEE80211_IOC_STA_STATS;
1002f549d72SSam Leffler ireq.i_data = &stats;
1012f549d72SSam Leffler ireq.i_len = sizeof(stats);
1022f549d72SSam Leffler memcpy(stats.is_u.macaddr, macaddr, IEEE80211_ADDR_LEN);
1032f549d72SSam Leffler if (ioctl(s, SIOCG80211, &ireq) < 0)
1042f549d72SSam Leffler err(1, "unable to get station stats for %s",
1052f549d72SSam Leffler ether_ntoa((const struct ether_addr*) macaddr));
1062f549d72SSam Leffler
1072f549d72SSam Leffler fprintf(fd, "%s:\n", ether_ntoa((const struct ether_addr*) macaddr));
1082f549d72SSam Leffler
1092f549d72SSam Leffler sep = "\t";
1102f549d72SSam Leffler STAT(rx_data, "%u");
1112f549d72SSam Leffler STAT(rx_mgmt, "%u");
1122f549d72SSam Leffler STAT(rx_ctrl, "%u");
1132f549d72SSam Leffler STAT(rx_beacons, "%u");
1142f549d72SSam Leffler STAT(rx_proberesp, "%u");
1152f549d72SSam Leffler STAT(rx_ucast, "%u");
1162f549d72SSam Leffler STAT(rx_mcast, "%u");
1172f549d72SSam Leffler STAT(rx_bytes, "%llu");
1182f549d72SSam Leffler STAT(rx_dup, "%u");
1192f549d72SSam Leffler STAT(rx_noprivacy, "%u");
1202f549d72SSam Leffler STAT(rx_wepfail, "%u");
1212f549d72SSam Leffler STAT(rx_demicfail, "%u");
1222f549d72SSam Leffler STAT(rx_decap, "%u");
1232f549d72SSam Leffler STAT(rx_defrag, "%u");
1242f549d72SSam Leffler STAT(rx_disassoc, "%u");
1252f549d72SSam Leffler STAT(rx_deauth, "%u");
1262f549d72SSam Leffler STAT(rx_decryptcrc, "%u");
1272f549d72SSam Leffler STAT(rx_unauth, "%u");
1282f549d72SSam Leffler STAT(rx_unencrypted, "%u");
1292f549d72SSam Leffler fprintf(fd, "\n");
1302f549d72SSam Leffler
1312f549d72SSam Leffler sep = "\t";
1322f549d72SSam Leffler STAT(tx_data, "%u");
1332f549d72SSam Leffler STAT(tx_mgmt, "%u");
1342f549d72SSam Leffler STAT(tx_probereq, "%u");
1352f549d72SSam Leffler STAT(tx_ucast, "%u");
1362f549d72SSam Leffler STAT(tx_mcast, "%u");
1372f549d72SSam Leffler STAT(tx_bytes, "%llu");
1382f549d72SSam Leffler STAT(tx_novlantag, "%u");
1392f549d72SSam Leffler STAT(tx_vlanmismatch, "%u");
1402f549d72SSam Leffler fprintf(fd, "\n");
1412f549d72SSam Leffler
1422f549d72SSam Leffler sep = "\t";
1432f549d72SSam Leffler STAT(tx_assoc, "%u");
1442f549d72SSam Leffler STAT(tx_assoc_fail, "%u");
1452f549d72SSam Leffler STAT(tx_auth, "%u");
1462f549d72SSam Leffler STAT(tx_auth_fail, "%u");
1472f549d72SSam Leffler STAT(tx_deauth, "%u");
1482f549d72SSam Leffler STAT(tx_deauth_code, "%llu");
1492f549d72SSam Leffler STAT(tx_disassoc, "%u");
1502f549d72SSam Leffler STAT(tx_disassoc_code, "%u");
1512f549d72SSam Leffler fprintf(fd, "\n");
1522f549d72SSam Leffler
1532f549d72SSam Leffler #undef STAT
1542f549d72SSam Leffler }
1552f549d72SSam Leffler #endif
1562f549d72SSam Leffler
157ff7c2c5aSAdrian Chadd static void
usage(void)158ff7c2c5aSAdrian Chadd usage(void)
159ff7c2c5aSAdrian Chadd {
160ff7c2c5aSAdrian Chadd
161c2863c0aSAdrian Chadd printf("wlanstats: [-ah] [-i ifname] [-l] [-m station MAC address] [-o fmt] [interval]\n");
162fb7aab99SEitan Adler }
163fb7aab99SEitan Adler
1642f549d72SSam Leffler int
main(int argc,char * argv[])1652f549d72SSam Leffler main(int argc, char *argv[])
1662f549d72SSam Leffler {
1672f549d72SSam Leffler struct wlanstatfoo *wf;
1682f549d72SSam Leffler struct ether_addr *ea;
1692f549d72SSam Leffler const uint8_t *mac = NULL;
170ab28e516SSam Leffler const char *ifname;
171530c13c5SBjoern A. Zeeb #if 0
1722f549d72SSam Leffler int allnodes = 0;
173530c13c5SBjoern A. Zeeb #endif
1742f549d72SSam Leffler int c, mode;
1752f549d72SSam Leffler
176ab28e516SSam Leffler ifname = getenv("WLAN");
177ab28e516SSam Leffler if (ifname == NULL)
178ab28e516SSam Leffler ifname = "wlan0";
179ab28e516SSam Leffler wf = wlanstats_new(ifname, getfmt("default"));
180530c13c5SBjoern A. Zeeb #if 0
181fb7aab99SEitan Adler while ((c = getopt(argc, argv, "ahi:lm:o:")) != -1) {
182530c13c5SBjoern A. Zeeb #else
183530c13c5SBjoern A. Zeeb while ((c = getopt(argc, argv, "hi:lm:o:")) != -1) {
184530c13c5SBjoern A. Zeeb #endif
1852f549d72SSam Leffler switch (c) {
186530c13c5SBjoern A. Zeeb #if 0
1872f549d72SSam Leffler case 'a':
1882f549d72SSam Leffler allnodes++;
1892f549d72SSam Leffler break;
190530c13c5SBjoern A. Zeeb #endif
191fb7aab99SEitan Adler case 'h':
192fb7aab99SEitan Adler usage();
193fb7aab99SEitan Adler exit(0);
1942f549d72SSam Leffler case 'i':
1952f549d72SSam Leffler wf->setifname(wf, optarg);
1962f549d72SSam Leffler break;
1972f549d72SSam Leffler case 'l':
1982f549d72SSam Leffler wf->print_fields(wf, stdout);
1992f549d72SSam Leffler return 0;
2002f549d72SSam Leffler case 'm':
2012f549d72SSam Leffler ea = ether_aton(optarg);
2022f549d72SSam Leffler if (!ea)
2032f549d72SSam Leffler errx(1, "%s: invalid ethernet address", optarg);
2042f549d72SSam Leffler mac = ea->octet;
2052f549d72SSam Leffler break;
2062f549d72SSam Leffler case 'o':
207ab28e516SSam Leffler wf->setfmt(wf, getfmt(optarg));
2082f549d72SSam Leffler break;
2092f549d72SSam Leffler default:
210fb7aab99SEitan Adler usage();
211fb7aab99SEitan Adler exit(1);
2122f549d72SSam Leffler /*NOTREACHED*/
2132f549d72SSam Leffler }
2142f549d72SSam Leffler }
2152f549d72SSam Leffler argc -= optind;
2162f549d72SSam Leffler argv += optind;
2172f549d72SSam Leffler
2182f549d72SSam Leffler mode = wf->getopmode(wf);
2192f549d72SSam Leffler wf->setstamac(wf, mac);
2202f549d72SSam Leffler
2212f549d72SSam Leffler if (argc > 0) {
2222f549d72SSam Leffler u_long interval = strtoul(argv[0], NULL, 0);
2232f549d72SSam Leffler int line, omask;
2242f549d72SSam Leffler
2252f549d72SSam Leffler if (interval < 1)
2262f549d72SSam Leffler interval = 1;
2272f549d72SSam Leffler signal(SIGALRM, catchalarm);
2282f549d72SSam Leffler signalled = 0;
2292f549d72SSam Leffler alarm(interval);
2302f549d72SSam Leffler banner:
2312f549d72SSam Leffler wf->print_header(wf, stdout);
2322f549d72SSam Leffler line = 0;
2332f549d72SSam Leffler loop:
2342f549d72SSam Leffler if (line != 0) {
2352f549d72SSam Leffler wf->collect_cur(wf);
2362f549d72SSam Leffler wf->print_current(wf, stdout);
2372f549d72SSam Leffler wf->update_tot(wf);
2382f549d72SSam Leffler } else {
2392f549d72SSam Leffler wf->collect_tot(wf);
2402f549d72SSam Leffler wf->print_total(wf, stdout);
2412f549d72SSam Leffler }
2422f549d72SSam Leffler fflush(stdout);
2432f549d72SSam Leffler omask = sigblock(sigmask(SIGALRM));
2442f549d72SSam Leffler if (!signalled)
2452f549d72SSam Leffler sigpause(0);
2462f549d72SSam Leffler sigsetmask(omask);
2472f549d72SSam Leffler signalled = 0;
2482f549d72SSam Leffler alarm(interval);
2492f549d72SSam Leffler line++;
2502f549d72SSam Leffler /* refresh every display in case sta roams */
2512f549d72SSam Leffler if (mac == NULL && mode == IEEE80211_M_STA)
2522f549d72SSam Leffler wf->setstamac(wf, NULL);
2532f549d72SSam Leffler if (line == 21) /* XXX tty line count */
2542f549d72SSam Leffler goto banner;
2552f549d72SSam Leffler else
2562f549d72SSam Leffler goto loop;
2572f549d72SSam Leffler /*NOTREACHED*/
2582f549d72SSam Leffler #if 0
2592f549d72SSam Leffler } else if (allnodes) {
2602f549d72SSam Leffler struct ieee80211req_sta_info *si;
2612f549d72SSam Leffler union {
2622f549d72SSam Leffler struct ieee80211req_sta_req req;
2632f549d72SSam Leffler uint8_t buf[24*1024];
2642f549d72SSam Leffler } u;
2652f549d72SSam Leffler uint8_t *cp;
2662f549d72SSam Leffler struct ieee80211req ireq;
2672f549d72SSam Leffler int len;
2682f549d72SSam Leffler
2692f549d72SSam Leffler /*
2702f549d72SSam Leffler * Retrieve station/neighbor table and print stats for each.
2712f549d72SSam Leffler */
2722f549d72SSam Leffler (void) memset(&ireq, 0, sizeof(ireq));
2732f549d72SSam Leffler (void) strncpy(ireq.i_name, ifr.ifr_name, sizeof(ireq.i_name));
2742f549d72SSam Leffler ireq.i_type = IEEE80211_IOC_STA_INFO;
2752f549d72SSam Leffler memset(&u.req.macaddr, 0xff, sizeof(u.req.macaddr));
2762f549d72SSam Leffler ireq.i_data = &u;
2772f549d72SSam Leffler ireq.i_len = sizeof(u);
2782f549d72SSam Leffler if (ioctl(s, SIOCG80211, &ireq) < 0)
2792f549d72SSam Leffler err(1, "unable to get station information");
2802f549d72SSam Leffler len = ireq.i_len;
2812f549d72SSam Leffler if (len >= sizeof(struct ieee80211req_sta_info)) {
2822f549d72SSam Leffler cp = u.req.info;
2832f549d72SSam Leffler do {
2842f549d72SSam Leffler si = (struct ieee80211req_sta_info *) cp;
2852f549d72SSam Leffler if (si->isi_len < sizeof(*si))
2862f549d72SSam Leffler break;
2872f549d72SSam Leffler print_sta_stats(stdout, si->isi_macaddr);
2882f549d72SSam Leffler cp += si->isi_len, len -= si->isi_len;
2892f549d72SSam Leffler } while (len >= sizeof(struct ieee80211req_sta_info));
2902f549d72SSam Leffler }
2912f549d72SSam Leffler #endif
2922f549d72SSam Leffler } else {
2932f549d72SSam Leffler wf->collect_tot(wf);
2942f549d72SSam Leffler wf->print_verbose(wf, stdout);
2952f549d72SSam Leffler }
2962f549d72SSam Leffler return 0;
2972f549d72SSam Leffler }
298