xref: /freebsd/tools/tools/net80211/wlanstats/main.c (revision 530c13c5)
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