1153317Ssam/*-
2174244Ssam * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
3153317Ssam * All rights reserved.
4153317Ssam *
5153317Ssam * Redistribution and use in source and binary forms, with or without
6153317Ssam * modification, are permitted provided that the following conditions
7153317Ssam * are met:
8153317Ssam * 1. Redistributions of source code must retain the above copyright
9153317Ssam *    notice, this list of conditions and the following disclaimer,
10153317Ssam *    without modification.
11153317Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12153317Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13153317Ssam *    redistribution must be conditioned upon including a substantially
14153317Ssam *    similar Disclaimer requirement for further binary redistribution.
15153317Ssam *
16153317Ssam * NO WARRANTY
17153317Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18153317Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19153317Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20153317Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21153317Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22153317Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23153317Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24153317Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25153317Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26153317Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27153317Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28153317Ssam *
29153317Ssam * $FreeBSD$
30153317Ssam */
31153317Ssam
32153317Ssam/*
33161200Ssam * net80211 statistics class.
34153317Ssam */
35153317Ssam#include <sys/types.h>
36153317Ssam#include <sys/file.h>
37153317Ssam#include <sys/sockio.h>
38153317Ssam#include <sys/socket.h>
39153317Ssam#include <net/if.h>
40161200Ssam#include <net/if_dl.h>
41153317Ssam#include <net/if_media.h>
42153317Ssam#include <net/if_var.h>
43153317Ssam#include <net/ethernet.h>
44153317Ssam
45153317Ssam#include <stdio.h>
46170535Ssam#include <stdlib.h>
47153317Ssam#include <signal.h>
48161200Ssam#include <string.h>
49153317Ssam#include <unistd.h>
50153317Ssam#include <err.h>
51161200Ssam#include <ifaddrs.h>
52153317Ssam
53153392Ssam#include "../../../../sys/net80211/ieee80211_ioctl.h"
54153317Ssam
55161200Ssam#include "wlanstats.h"
56153317Ssam
57161200Ssam#ifndef IEEE80211_ADDR_COPY
58161200Ssam#define	IEEE80211_ADDR_COPY(dst, src)	memcpy(dst, src, IEEE80211_ADDR_LEN)
59161200Ssam#define	IEEE80211_ADDR_EQ(a1,a2)	(memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0)
60161200Ssam#endif
61161200Ssam
62173306Ssam#define	AFTER(prev)	((prev)+1)
63173306Ssam
64161200Ssamstatic const struct fmt wlanstats[] = {
65173306Ssam#define	S_RX_BADVERSION		0
66173306Ssam	{ 5,  "rx_badversion",	"bvers",	"rx frame with bad version" },
67173306Ssam#define	S_RX_TOOSHORT		AFTER(S_RX_BADVERSION)
68173306Ssam	{ 5,  "rx_tooshort",	"2short",	"rx frame too short" },
69173306Ssam#define	S_RX_WRONGBSS		AFTER(S_RX_TOOSHORT)
70173306Ssam	{ 5,  "rx_wrongbss",	"wrbss",	"rx from wrong bssid" },
71173306Ssam#define	S_RX_DUP		AFTER(S_RX_WRONGBSS)
72173306Ssam	{ 5,  "rx_dup",		"rxdup",	"rx discard 'cuz dup" },
73173306Ssam#define	S_RX_WRONGDIR		AFTER(S_RX_DUP)
74173306Ssam	{ 5,  "rx_wrongdir",	"wrdir",	"rx w/ wrong direction" },
75173306Ssam#define	S_RX_MCASTECHO		AFTER(S_RX_WRONGDIR)
76173306Ssam	{ 5,  "rx_mcastecho",	"mecho",	"rx discard 'cuz mcast echo" },
77173306Ssam#define	S_RX_NOTASSOC		AFTER(S_RX_MCASTECHO)
78173306Ssam	{ 6,  "rx_notassoc",	"!assoc",	"rx discard 'cuz sta !assoc" },
79173306Ssam#define	S_RX_NOPRIVACY		AFTER(S_RX_NOTASSOC)
80173306Ssam	{ 6,  "rx_noprivacy",	"nopriv",	"rx w/ wep but privacy off" },
81173306Ssam#define	S_RX_UNENCRYPTED	AFTER(S_RX_NOPRIVACY)
82173306Ssam	{ 6,  "rx_unencrypted",	"unencr",	"rx w/o wep and privacy on" },
83173306Ssam#define	S_RX_WEPFAIL		AFTER(S_RX_UNENCRYPTED)
84173306Ssam	{ 7,  "rx_wepfail",	"wepfail",	"rx wep processing failed" },
85173306Ssam#define	S_RX_DECAP		AFTER(S_RX_WEPFAIL)
86161200Ssam	{ 5,  "rx_decap",	"decap",	"rx decapsulation failed" },
87173306Ssam#define	S_RX_MGTDISCARD		AFTER(S_RX_DECAP)
88173306Ssam	{ 8,  "rx_mgtdiscard",	"mgtdiscard",	"rx discard mgt frames" },
89173306Ssam#define	S_RX_CTL		AFTER(S_RX_MGTDISCARD)
90170535Ssam	{ 5,  "rx_ctl",		"ctl",		"rx ctrl frames" },
91173306Ssam#define	S_RX_BEACON		AFTER(S_RX_CTL)
92173306Ssam	{ 6,  "rx_beacon",	"beacon",	"rx beacon frames" },
93173306Ssam#define	S_RX_RSTOOBIG		AFTER(S_RX_BEACON)
94173306Ssam	{ 6,  "rx_rstoobig",	"rs2big",	"rx rate set truncated" },
95173306Ssam#define	S_RX_ELEM_MISSING	AFTER(S_RX_RSTOOBIG)
96173306Ssam	{ 6,  "rx_elem_missing","iemiss",	"rx required element missing" },
97173306Ssam#define	S_RX_ELEM_TOOBIG	AFTER(S_RX_ELEM_MISSING)
98173306Ssam	{ 6,  "rx_elem_toobig",	"ie2big",	"rx element too big" },
99173306Ssam#define	S_RX_ELEM_TOOSMALL	AFTER(S_RX_ELEM_TOOBIG)
100173306Ssam	{ 7,  "rx_elem_toosmall","ie2small","rx element too small" },
101173306Ssam#define	S_RX_ELEM_UNKNOWN 	AFTER(S_RX_ELEM_TOOSMALL)
102173306Ssam	{ 5,  "rx_elem_unknown","ieunk",	"rx element unknown" },
103173306Ssam#define	S_RX_BADCHAN		AFTER(S_RX_ELEM_UNKNOWN)
104173306Ssam	{ 6,  "rx_badchan",	"badchan",	"rx frame w/ invalid chan" },
105173306Ssam#define	S_RX_CHANMISMATCH	AFTER(S_RX_BADCHAN)
106161200Ssam	{ 5,  "rx_chanmismatch","chanmismatch",	"rx frame chan mismatch" },
107173306Ssam#define	S_RX_NODEALLOC		AFTER(S_RX_CHANMISMATCH)
108161200Ssam	{ 5,  "rx_nodealloc",	"nodealloc",	"nodes allocated (rx)" },
109173306Ssam#define	S_RX_SSIDMISMATCH	AFTER(S_RX_NODEALLOC)
110161200Ssam	{ 5,  "rx_ssidmismatch","ssidmismatch",	"rx frame ssid mismatch" },
111173306Ssam#define	S_RX_AUTH_UNSUPPORTED	AFTER(S_RX_SSIDMISMATCH)
112161200Ssam	{ 5,  "rx_auth_unsupported","auth_unsupported",
113161200Ssam		"rx w/ unsupported auth alg" },
114173306Ssam#define	S_RX_AUTH_FAIL		AFTER(S_RX_AUTH_UNSUPPORTED)
115161200Ssam	{ 5,  "rx_auth_fail",	"auth_fail",	"rx sta auth failure" },
116178359Ssam#define	S_RX_AUTH_FAIL_CODE	AFTER(S_RX_AUTH_FAIL)
117178359Ssam	{ 5,  "rx_auth_fail_code","auth_fail_code",
118178359Ssam		"last rx auth failure reason" },
119178359Ssam#define	S_RX_AUTH_COUNTERMEASURES	AFTER(S_RX_AUTH_FAIL_CODE)
120161200Ssam	{ 5,  "rx_auth_countermeasures",	"auth_countermeasures",
121161200Ssam		"rx sta auth failure 'cuz of TKIP countermeasures" },
122173306Ssam#define	S_RX_ASSOC_BSS		AFTER(S_RX_AUTH_COUNTERMEASURES)
123161200Ssam	{ 5,  "rx_assoc_bss",	"assoc_bss",	"rx assoc from wrong bssid" },
124173306Ssam#define	S_RX_ASSOC_NOTAUTH	AFTER(S_RX_ASSOC_BSS)
125161200Ssam	{ 5,  "rx_assoc_notauth","assoc_notauth",	"rx assoc w/o auth" },
126173306Ssam#define	S_RX_ASSOC_CAPMISMATCH	AFTER(S_RX_ASSOC_NOTAUTH)
127161200Ssam	{ 5,  "rx_assoc_capmismatch","assoc_capmismatch",
128161200Ssam		"rx assoc w/ cap mismatch" },
129173306Ssam#define	S_RX_ASSOC_NORATE	AFTER(S_RX_ASSOC_CAPMISMATCH)
130161200Ssam	{ 5,  "rx_assoc_norate","assoc_norate",	"rx assoc w/ no rate match" },
131173306Ssam#define	S_RX_ASSOC_BADWPAIE	AFTER(S_RX_ASSOC_NORATE)
132161200Ssam	{ 5,  "rx_assoc_badwpaie","assoc_badwpaie",
133161200Ssam		"rx assoc w/ bad WPA IE" },
134173306Ssam#define	S_RX_DEAUTH		AFTER(S_RX_ASSOC_BADWPAIE)
135161200Ssam	{ 5,  "rx_deauth",	"deauth",	"rx deauthentication" },
136178359Ssam#define	S_RX_DEAUTH_CODE	AFTER(S_RX_DEAUTH)
137178359Ssam	{ 5,  "rx_deauth_code","deauth_code",	"last rx deauth reason" },
138178359Ssam#define	S_RX_DISASSOC		AFTER(S_RX_DEAUTH_CODE)
139161200Ssam	{ 5,  "rx_disassoc",	"disassoc",	"rx disassociation" },
140178359Ssam#define	S_RX_DISASSOC_CODE	AFTER(S_RX_DISASSOC)
141178359Ssam	{ 5,  "rx_disassoc_code","disassoc_code",
142178359Ssam		"last rx disassoc reason" },
143178359Ssam#define	S_BMISS			AFTER(S_RX_DISASSOC_CODE)
144178359Ssam	{ 5,  "bmiss",		"bmiss",	"beacon miss events handled" },
145178359Ssam#define	S_RX_BADSUBTYPE		AFTER(S_BMISS)
146161200Ssam	{ 5,  "rx_badsubtype",	"badsubtype",	"rx frame w/ unknown subtype" },
147173306Ssam#define	S_RX_NOBUF		AFTER(S_RX_BADSUBTYPE)
148161200Ssam	{ 5,  "rx_nobuf",	"nobuf",	"rx failed for lack of mbuf" },
149173306Ssam#define	S_RX_DECRYPTCRC		AFTER(S_RX_NOBUF)
150161200Ssam	{ 5,  "rx_decryptcrc",	"decryptcrc",	"rx decrypt failed on crc" },
151173306Ssam#define	S_RX_AHDEMO_MGT		AFTER(S_RX_DECRYPTCRC)
152161200Ssam	{ 5,  "rx_ahdemo_mgt",	"ahdemo_mgt",
153161200Ssam		"rx discard mgmt frame received in ahdoc demo mode" },
154173306Ssam#define	S_RX_BAD_AUTH		AFTER(S_RX_AHDEMO_MGT)
155161200Ssam	{ 5,  "rx_bad_auth",	"bad_auth",	"rx bad authentication request" },
156173306Ssam#define	S_RX_UNAUTH		AFTER(S_RX_BAD_AUTH)
157161200Ssam	{ 5,  "rx_unauth",	"unauth",
158161200Ssam		"rx discard 'cuz port unauthorized" },
159173306Ssam#define	S_RX_BADKEYID		AFTER(S_RX_UNAUTH)
160178699Ssam	{ 5,  "rx_badkeyid",	"rxkid",	"rx w/ incorrect keyid" },
161173306Ssam#define	S_RX_CCMPREPLAY		AFTER(S_RX_BADKEYID)
162161200Ssam	{ 5,  "rx_ccmpreplay",	"ccmpreplay",	"rx seq# violation (CCMP)" },
163173306Ssam#define	S_RX_CCMPFORMAT		AFTER(S_RX_CCMPREPLAY)
164161200Ssam	{ 5,  "rx_ccmpformat",	"ccmpformat",	"rx format bad (CCMP)" },
165173306Ssam#define	S_RX_CCMPMIC		AFTER(S_RX_CCMPFORMAT)
166161200Ssam	{ 5,  "rx_ccmpmic",	"ccmpmic",	"rx MIC check failed (CCMP)" },
167173306Ssam#define	S_RX_TKIPREPLAY		AFTER(S_RX_CCMPMIC)
168161200Ssam	{ 5,  "rx_tkipreplay",	"tkipreplay",	"rx seq# violation (TKIP)" },
169173306Ssam#define	S_RX_TKIPFORMAT		AFTER(S_RX_TKIPREPLAY)
170161200Ssam	{ 5,  "rx_tkipformat",	"tkipformat",	"rx format bad (TKIP)" },
171173306Ssam#define	S_RX_TKIPMIC		AFTER(S_RX_TKIPFORMAT)
172161200Ssam	{ 5,  "rx_tkipmic",	"tkipmic",	"rx MIC check failed (TKIP)" },
173173306Ssam#define	S_RX_TKIPICV		AFTER(S_RX_TKIPMIC)
174161200Ssam	{ 5,  "rx_tkipicv",	"tkipicv",	"rx ICV check failed (TKIP)" },
175173306Ssam#define	S_RX_BADCIPHER		AFTER(S_RX_TKIPICV)
176161200Ssam	{ 5,  "rx_badcipher",	"badcipher",	"rx failed 'cuz bad cipher/key type" },
177173306Ssam#define	S_RX_NOCIPHERCTX	AFTER(S_RX_BADCIPHER)
178161200Ssam	{ 5,  "rx_nocipherctx",	"nocipherctx",	"rx failed 'cuz key/cipher ctx not setup" },
179173306Ssam#define	S_RX_ACL		AFTER(S_RX_NOCIPHERCTX)
180161200Ssam	{ 5,  "rx_acl",		"acl",		"rx discard 'cuz acl policy" },
181173306Ssam#define	S_TX_NOBUF		AFTER(S_RX_ACL)
182161200Ssam	{ 5,  "tx_nobuf",	"nobuf",	"tx failed for lack of mbuf" },
183173306Ssam#define	S_TX_NONODE		AFTER(S_TX_NOBUF)
184161200Ssam	{ 5,  "tx_nonode",	"nonode",	"tx failed for no node" },
185173306Ssam#define	S_TX_UNKNOWNMGT		AFTER(S_TX_NONODE)
186161200Ssam	{ 5,  "tx_unknownmgt",	"unknownmgt",	"tx of unknown mgt frame" },
187173306Ssam#define	S_TX_BADCIPHER		AFTER(S_TX_UNKNOWNMGT)
188161200Ssam	{ 5,  "tx_badcipher",	"badcipher",	"tx failed 'cuz bad ciper/key type" },
189173306Ssam#define	S_TX_NODEFKEY		AFTER(S_TX_BADCIPHER)
190161200Ssam	{ 5,  "tx_nodefkey",	"nodefkey",	"tx failed 'cuz no defkey" },
191173306Ssam#define	S_TX_NOHEADROOM		AFTER(S_TX_NODEFKEY)
192161200Ssam	{ 5,  "tx_noheadroom",	"noheadroom",	"tx failed 'cuz no space for crypto hdrs" },
193173306Ssam#define	S_TX_FRAGFRAMES		AFTER(S_TX_NOHEADROOM)
194161200Ssam	{ 5,  "tx_fragframes",	"fragframes",	"tx frames fragmented" },
195173306Ssam#define	S_TX_FRAGS		AFTER(S_TX_FRAGFRAMES)
196161200Ssam	{ 5,  "tx_frags",	"frags",		"tx frags generated" },
197173306Ssam#define	S_SCAN_ACTIVE		AFTER(S_TX_FRAGS)
198178699Ssam	{ 5,  "scan_active",	"ascan",	"active scans started" },
199173306Ssam#define	S_SCAN_PASSIVE		AFTER(S_SCAN_ACTIVE)
200178699Ssam	{ 5,  "scan_passive",	"pscan",	"passive scans started" },
201178359Ssam#define	S_SCAN_BG		AFTER(S_SCAN_PASSIVE)
202178699Ssam	{ 5,  "scan_bg",	"bgscn",	"background scans started" },
203178359Ssam#define	S_NODE_TIMEOUT		AFTER(S_SCAN_BG)
204173306Ssam	{ 5,  "node_timeout",	"node_timeout",	"nodes timed out for inactivity" },
205173306Ssam#define	S_CRYPTO_NOMEM		AFTER(S_NODE_TIMEOUT)
206161200Ssam	{ 5,  "crypto_nomem",	"crypto_nomem",	"cipher context malloc failed" },
207173306Ssam#define	S_CRYPTO_TKIP		AFTER(S_CRYPTO_NOMEM)
208161200Ssam	{ 5,  "crypto_tkip",	"crypto_tkip",	"tkip crypto done in s/w" },
209173306Ssam#define	S_CRYPTO_TKIPENMIC	AFTER(S_CRYPTO_TKIP)
210161200Ssam	{ 5,  "crypto_tkipenmic","crypto_tkipenmic",	"tkip tx MIC done in s/w" },
211173306Ssam#define	S_CRYPTO_TKIPDEMIC	AFTER(S_CRYPTO_TKIPENMIC)
212161200Ssam	{ 5,  "crypto_tkipdemic","crypto_tkipdemic",	"tkip rx MIC done in s/w" },
213173306Ssam#define	S_CRYPTO_TKIPCM		AFTER(S_CRYPTO_TKIPDEMIC)
214161200Ssam	{ 5,  "crypto_tkipcm",	"crypto_tkipcm",	"tkip dropped frames 'cuz of countermeasures" },
215173306Ssam#define	S_CRYPTO_CCMP		AFTER(S_CRYPTO_TKIPCM)
216161200Ssam	{ 5,  "crypto_ccmp",	"crypto_ccmp",	"ccmp crypto done in s/w" },
217173306Ssam#define	S_CRYPTO_WEP		AFTER(S_CRYPTO_CCMP)
218161200Ssam	{ 5,  "crypto_wep",	"crypto_wep",	"wep crypto done in s/w" },
219173306Ssam#define	S_CRYPTO_SETKEY_CIPHER	AFTER(S_CRYPTO_WEP)
220161200Ssam	{ 5,  "crypto_setkey_cipher",	"crypto_setkey_cipher","setkey failed 'cuz cipher rejected data" },
221173306Ssam#define	S_CRYPTO_SETKEY_NOKEY	AFTER(S_CRYPTO_SETKEY_CIPHER)
222161200Ssam	{ 5,  "crypto_setkey_nokey",	"crypto_setkey_nokey","setkey failed 'cuz no key index" },
223173306Ssam#define	S_CRYPTO_DELKEY		AFTER(S_CRYPTO_SETKEY_NOKEY)
224161200Ssam	{ 5,  "crypto_delkey",	"crypto_delkey",	"driver key delete failed" },
225173306Ssam#define	S_CRYPTO_BADCIPHER	AFTER(S_CRYPTO_DELKEY)
226161200Ssam	{ 5,  "crypto_badcipher","crypto_badcipher",	"setkey failed 'cuz unknown cipher" },
227173306Ssam#define	S_CRYPTO_NOCIPHER	AFTER(S_CRYPTO_BADCIPHER)
228161200Ssam	{ 5,  "crypto_nocipher","crypto_nocipher",	"setkey failed 'cuz cipher module unavailable" },
229173306Ssam#define	S_CRYPTO_ATTACHFAIL	AFTER(S_CRYPTO_NOCIPHER)
230161200Ssam	{ 5,  "crypto_attachfail","crypto_attachfail",	"setkey failed 'cuz cipher attach failed" },
231173306Ssam#define	S_CRYPTO_SWFALLBACK	AFTER(S_CRYPTO_ATTACHFAIL)
232161200Ssam	{ 5,  "crypto_swfallback","crypto_swfallback",	"crypto fell back to s/w implementation" },
233173306Ssam#define	S_CRYPTO_KEYFAIL	AFTER(S_CRYPTO_SWFALLBACK)
234161200Ssam	{ 5,  "crypto_keyfail",	"crypto_keyfail",	"setkey failed 'cuz driver key alloc failed" },
235173306Ssam#define	S_CRYPTO_ENMICFAIL	AFTER(S_CRYPTO_KEYFAIL)
236161200Ssam	{ 5,  "crypto_enmicfail","crypto_enmicfail",	"enmic failed (may be mbuf exhaustion)" },
237173306Ssam#define	S_IBSS_CAPMISMATCH	AFTER(S_CRYPTO_ENMICFAIL)
238161200Ssam	{ 5,  "ibss_capmismatch","ibss_capmismatch",	"ibss merge faied 'cuz capabilities mismatch" },
239173306Ssam#define	S_IBSS_NORATE		AFTER(S_IBSS_CAPMISMATCH)
240161200Ssam	{ 5,  "ibss_norate",	"ibss_norate",	"ibss merge faied 'cuz rate set mismatch" },
241173306Ssam#define	S_PS_UNASSOC		AFTER(S_IBSS_NORATE)
242161200Ssam	{ 5,  "ps_unassoc",	"ps_unassoc",	"ps-poll received for unassociated station" },
243173306Ssam#define	S_PS_BADAID		AFTER(S_PS_UNASSOC)
244161200Ssam	{ 5,  "ps_badaid",	"ps_badaid",	"ps-poll received with invalid association id" },
245173306Ssam#define	S_PS_QEMPTY		AFTER(S_PS_BADAID)
246161200Ssam	{ 5,  "ps_qempty",	"ps_qempty",	"ps-poll received with nothing to send" },
247173306Ssam#define	S_FF_BADHDR		AFTER(S_PS_QEMPTY)
248161200Ssam	{ 5,  "ff_badhdr",	"ff_badhdr",	"fast frame rx'd w/ bad hdr" },
249173306Ssam#define	S_FF_TOOSHORT		AFTER(S_FF_BADHDR)
250161200Ssam	{ 5,  "ff_tooshort",	"ff_tooshort",	"fast frame rx decap error" },
251173306Ssam#define	S_FF_SPLIT		AFTER(S_FF_TOOSHORT)
252161200Ssam	{ 5,  "ff_split",	"ff_split",	"fast frame rx split error" },
253173306Ssam#define	S_FF_DECAP		AFTER(S_FF_SPLIT)
254161200Ssam	{ 5,  "ff_decap",	"ff_decap",	"fast frames decap'd" },
255173306Ssam#define	S_FF_ENCAP		AFTER(S_FF_DECAP)
256161200Ssam	{ 5,  "ff_encap",	"ff_encap",	"fast frames encap'd for tx" },
257173306Ssam#define	S_FF_ENCAPFAIL		AFTER(S_FF_ENCAP)
258161200Ssam	{ 5,  "ff_encapfail",	"ff_encapfail",	"fast frames encap failed" },
259173306Ssam#define	S_RX_BADBINTVAL		AFTER(S_FF_ENCAPFAIL)
260161200Ssam	{ 5,  "rx_badbintval",	"rx_badbintval","rx frame with bogus beacon interval" },
261173306Ssam#define	S_RX_MGMT		AFTER(S_RX_BADBINTVAL)
262178699Ssam	{ 8,  "rx_mgmt",	"mgmt",		"rx management frames" },
263173306Ssam#define	S_RX_DEMICFAIL		AFTER(S_RX_MGMT)
264161200Ssam	{ 5,  "rx_demicfail",	"rx_demicfail",	"rx demic failed" },
265173306Ssam#define	S_RX_DEFRAG		AFTER(S_RX_DEMICFAIL)
266161200Ssam	{ 5,  "rx_defrag",	"rx_defrag",	"rx defragmentation failed" },
267173306Ssam#define	S_RX_ACTION		AFTER(S_RX_DEFRAG)
268170535Ssam	{ 5,  "rx_action",	"rx_action",	"rx action frames" },
269173306Ssam#define	S_AMSDU_TOOSHORT	AFTER(S_RX_ACTION)
270173306Ssam	{ 8,  "amsdu_tooshort",	"tooshort","A-MSDU rx decap error" },
271173306Ssam#define	S_AMSDU_SPLIT		AFTER(S_AMSDU_TOOSHORT)
272173306Ssam	{ 8,  "amsdu_split",	"split",	"A-MSDU rx failed on frame split" },
273173306Ssam#define	S_AMSDU_DECAP		AFTER(S_AMSDU_SPLIT)
274173306Ssam	{ 8,  "amsdu_decap",	"decap",	"A-MSDU frames received" },
275173306Ssam#define	S_AMSDU_ENCAP		AFTER(S_AMSDU_DECAP)
276173306Ssam	{ 8,  "amsdu_encap",	"encap",	"A-MSDU frames transmitted" },
277173306Ssam#define	S_AMPDU_REORDER		AFTER(S_AMSDU_ENCAP)
278173306Ssam	{ 8,  "ampdu_reorder",	"reorder","A-MPDU frames held in reorder q" },
279173306Ssam#define	S_AMPDU_FLUSH		AFTER(S_AMPDU_REORDER)
280173306Ssam	{ 8,  "ampdu_flush",	"flush",	"A-MPDU frames sent up from reorder q" },
281173306Ssam#define	S_AMPDU_BARBAD		AFTER(S_AMPDU_FLUSH)
282173306Ssam	{ 6,  "ampdu_barbad",	"barbad",	"A-MPDU BAR rx before ADDBA exchange (or disabled with net.link.ieee80211)" },
283173306Ssam#define	S_AMPDU_BAROOW		AFTER(S_AMPDU_BARBAD)
284173306Ssam	{ 6,  "ampdu_baroow",	"baroow",	"A-MPDU BAR rx out of BA window" },
285173306Ssam#define	S_AMPDU_BARMOVE		AFTER(S_AMPDU_BAROOW)
286173306Ssam	{ 8,  "ampdu_barmove",	"barmove","A-MPDU BAR rx moved BA window" },
287173306Ssam#define	S_AMPDU_BAR		AFTER(S_AMPDU_BARMOVE)
288173306Ssam	{ 8,  "ampdu_bar",	"rxbar",	"A-MPDU BAR rx successful" },
289173306Ssam#define	S_AMPDU_MOVE		AFTER(S_AMPDU_BAR)
290173306Ssam	{ 5,  "ampdu_move",	"move",	"A-MPDU frame moved BA window" },
291173306Ssam#define	S_AMPDU_OOR		AFTER(S_AMPDU_MOVE)
292173306Ssam	{ 8,  "ampdu_oor",	"oorx",	"A-MPDU frames rx out-of-order" },
293173306Ssam#define	S_AMPDU_COPY		AFTER(S_AMPDU_OOR)
294173306Ssam	{ 8,  "ampdu_copy",	"copy",	"A-MPDU rx window slots copied" },
295173306Ssam#define	S_AMPDU_DROP		AFTER(S_AMPDU_COPY)
296173306Ssam	{ 5,  "ampdu_drop",	"drop",	"A-MPDU frames discarded for out of range seqno" },
297173306Ssam#define	S_AMPDU_AGE		AFTER(S_AMPDU_DROP)
298173306Ssam	{ 5,  "ampdu_age",	"age",	"A-MPDU frames sent up due to old age" },
299173306Ssam#define	S_AMPDU_STOP		AFTER(S_AMPDU_AGE)
300173306Ssam	{ 5,  "ampdu_stop",	"stop",	"A-MPDU streams stopped" },
301173306Ssam#define	S_AMPDU_STOP_FAILED	AFTER(S_AMPDU_STOP)
302173306Ssam	{ 5,  "ampdu_stop_failed","!stop",	"A-MPDU stop requests failed 'cuz stream not running" },
303173306Ssam#define	S_ADDBA_REJECT		AFTER(S_AMPDU_STOP_FAILED)
304173306Ssam	{ 5,  "addba_reject",	"reject",	"ADDBA requests rejected 'cuz A-MPDU rx is disabled" },
305173306Ssam#define	S_ADDBA_NOREQUEST	AFTER(S_ADDBA_REJECT)
306173306Ssam	{ 5,  "addba_norequest","norequest","ADDBA response frames discarded because no ADDBA request was pending" },
307173306Ssam#define	S_ADDBA_BADTOKEN	AFTER(S_ADDBA_NOREQUEST)
308173306Ssam	{ 5,  "addba_badtoken",	"badtoken","ADDBA response frames discarded 'cuz rx'd dialog token is wrong" },
309173306Ssam#define	S_TX_BADSTATE		AFTER(S_ADDBA_BADTOKEN)
310173306Ssam	{ 4,  "tx_badstate",	"badstate",	"tx failed 'cuz vap not in RUN state" },
311173306Ssam#define	S_TX_NOTASSOC		AFTER(S_TX_BADSTATE)
312173306Ssam	{ 4,  "tx_notassoc",	"notassoc",	"tx failed 'cuz dest sta not associated" },
313173306Ssam#define	S_TX_CLASSIFY		AFTER(S_TX_NOTASSOC)
314173306Ssam	{ 4,  "tx_classify",	"classify",	"tx packet classification failed" },
315173306Ssam#define	S_DWDS_MCAST		AFTER(S_TX_CLASSIFY)
316173306Ssam	{ 8,  "dwds_mcast",	"dwds_mcast",	"mcast frame transmitted on dwds vap discarded" },
317173306Ssam#define	S_DWDS_QDROP		AFTER(S_DWDS_MCAST)
318173306Ssam	{ 8,  "dwds_qdrop",	"dwds_qdrop",	"4-address frame discarded because dwds pending queue is full" },
319173306Ssam#define	S_HT_ASSOC_NOHTCAP	AFTER(S_DWDS_QDROP)
320173306Ssam	{ 4,  "ht_nohtcap",	"ht_nohtcap",	"non-HT station rejected in HT-only BSS" },
321173306Ssam#define	S_HT_ASSOC_DOWNGRADE	AFTER(S_HT_ASSOC_NOHTCAP)
322173306Ssam	{ 4,  "ht_downgrade",	"ht_downgrade",	"HT station downgraded to legacy operation" },
323173306Ssam#define	S_HT_ASSOC_NORATE	AFTER(S_HT_ASSOC_DOWNGRADE)
324173306Ssam	{ 4,  "ht_norate",	"ht_norate",	"HT station rejected because of HT rate set" },
325195618Srpaulo#define	S_MESH_WRONGMESH	AFTER(S_HT_ASSOC_NORATE)
326195618Srpaulo	{ 4,  "mesh_wrong",	"mesh_wrong",	"frame discarded because sender not a mesh sta" },
327195618Srpaulo#define	S_MESH_NOLINK		AFTER(S_MESH_WRONGMESH)
328195618Srpaulo	{ 4,  "mesh_nolink",	"mesh_nolink",	"frame discarded because link not established" },
329195618Srpaulo#define	S_MESH_FWD_TTL		AFTER(S_MESH_NOLINK)
330195618Srpaulo	{ 4,  "mesh_fwd_ttl",	"mesh_fwd_ttl",	"frame not forwarded because TTL zero" },
331195618Srpaulo#define	S_MESH_FWD_NOBUF	AFTER(S_MESH_FWD_TTL)
332195618Srpaulo	{ 4,  "mesh_fwd_nobuf",	"mesh_fwd_nobuf",	"frame not forwarded because mbuf could not be allocated" },
333195618Srpaulo#define	S_MESH_FWD_TOOSHORT	AFTER(S_MESH_FWD_NOBUF)
334195618Srpaulo	{ 4,  "mesh_fwd_tooshort",	"mesh_fwd_tooshort",	"frame not forwarded because too short to have 802.11 header" },
335195618Srpaulo#define	S_MESH_FWD_DISABLED	AFTER(S_MESH_FWD_TOOSHORT)
336195618Srpaulo	{ 4,  "mesh_fwd_disabled",	"mesh_fwd_disabled",	"frame not forwarded because administratively disabled" },
337195618Srpaulo#define	S_MESH_FWD_NOPATH	AFTER(S_MESH_FWD_DISABLED)
338195618Srpaulo	{ 4,  "mesh_fwd_nopath",	"mesh_fwd_nopath",	"frame not forwarded because no path found to destination" },
339195618Srpaulo#define	S_HWMP_WRONGSEQ		AFTER(S_MESH_FWD_NOPATH)
340195618Srpaulo	{ 4,  "hwmp_wrongseq",	"hwmp_wrongseq",	"frame discarded because mesh sequence number is invalid" },
341195618Srpaulo#define	S_HWMP_ROOTREQS		AFTER(S_HWMP_WRONGSEQ)
342195618Srpaulo	{ 4,  "hwmp_rootreqs",	"hwmp_rootreqs",	"root PREQ frames sent" },
343195618Srpaulo#define	S_HWMP_ROOTANN		AFTER(S_HWMP_ROOTREQS)
344195618Srpaulo	{ 4,  "hwmp_rootann",	"hwmp_rootann",	"root RANN frames received" },
345195811Ssam#define	S_MESH_BADAE		AFTER(S_HWMP_ROOTANN)
346195811Ssam	{ 4,  "mesh_badae",	"mesh_badae",	"frame discarded for bad AddressExtension (AE)" },
347195811Ssam#define	S_MESH_RTADDFAILED	AFTER(S_MESH_BADAE)
348195811Ssam	{ 4,  "mesh_rtadd",	"mesh_rtadd",	"mesh route add failed" },
349195811Ssam#define	S_MESH_NOTPROXY		AFTER(S_MESH_RTADDFAILED)
350195811Ssam	{ 8,  "mesh_notproxy",	"mesh_notproxy","frame discarded because station not acting as a proxy" },
351195811Ssam#define	S_RX_BADALIGN		AFTER(S_MESH_NOTPROXY)
352195811Ssam	{ 4,  "rx_badalign",	"rx_badalign","frame discarded because payload re-alignment failed" },
353195811Ssam#define	S_INPUT			AFTER(S_RX_BADALIGN)
354173306Ssam	{ 8,	"input",	"input",	"total data frames received" },
355173306Ssam#define	S_RX_UCAST		AFTER(S_INPUT)
356161200Ssam	{ 8,	"rx_ucast",	"rx_ucast",	"unicast data frames received" },
357173306Ssam#define	S_RX_MCAST		AFTER(S_RX_UCAST)
358161200Ssam	{ 8,	"rx_mcast",	"rx_mcast",	"multicast data frames received" },
359173306Ssam#define	S_OUTPUT		AFTER(S_RX_MCAST)
360173306Ssam	{ 8,	"output",	"output",	"total data frames transmit" },
361173306Ssam#define	S_TX_UCAST		AFTER(S_OUTPUT)
362161200Ssam	{ 8,	"tx_ucast",	"tx_ucast",	"unicast data frames sent" },
363173306Ssam#define	S_TX_MCAST		AFTER(S_TX_UCAST)
364161200Ssam	{ 8,	"tx_mcast",	"tx_mcast",	"multicast data frames sent" },
365173306Ssam#define	S_RATE			AFTER(S_TX_MCAST)
366178699Ssam	{ 5,	"rate",		"rate",		"current transmit rate" },
367173306Ssam#define	S_RSSI			AFTER(S_RATE)
368178699Ssam	{ 5,	"rssi",		"rssi",		"current rssi" },
369173306Ssam#define	S_NOISE			AFTER(S_RSSI)
370178699Ssam	{ 5,	"noise",	"noise",	"current noise floor (dBm)" },
371173306Ssam#define	S_SIGNAL		AFTER(S_NOISE)
372178699Ssam	{ 5,	"signal",	"sig",		"current signal (dBm)" },
373232245Sadrian#define	S_BEACON_BAD		AFTER(S_SIGNAL)
374232245Sadrian	{ 9,	"beacon_bad",	"beaconbad",	"bad beacons received" },
375234019Sadrian#define	S_AMPDU_BARTX		AFTER(S_BEACON_BAD)
376234019Sadrian	{ 5,	"ampdu_bartx",	"bartx",	"BAR frames sent" },
377234019Sadrian#define	S_AMPDU_BARTX_FAIL	AFTER(S_AMPDU_BARTX)
378234019Sadrian	{ 9,	"ampdu_bartxfail",	"bartx_fail",	"BAR frames failed to send" },
379234019Sadrian#define	S_AMPDU_BARTX_RETRY	AFTER(S_AMPDU_BARTX_FAIL)
380234019Sadrian	{ 10,	"ampdu_bartxretry",	"bartx_retry",	"BAR frames retried" },
381161200Ssam};
382161200Ssam
383161200Ssamstruct wlanstatfoo_p {
384161200Ssam	struct wlanstatfoo base;
385161200Ssam	int s;
386161200Ssam	int opmode;
387161200Ssam	uint8_t mac[IEEE80211_ADDR_LEN];
388161200Ssam	struct ifreq ifr;
389161200Ssam	struct ieee80211_stats cur;
390161200Ssam	struct ieee80211_stats total;
391161200Ssam	struct ieee80211req ireq;
392161200Ssam	union {
393161200Ssam		struct ieee80211req_sta_req info;
394161200Ssam		char buf[1024];
395161200Ssam	} u_info;
396161200Ssam	struct ieee80211req_sta_stats ncur;
397161200Ssam	struct ieee80211req_sta_stats ntotal;
398161200Ssam};
399161200Ssam
400153317Ssamstatic void
401161200Ssamwlan_setifname(struct wlanstatfoo *wf0, const char *ifname)
402153317Ssam{
403161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0;
404161200Ssam
405161200Ssam	strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name));
406161200Ssam	strncpy(wf->ireq.i_name, ifname, sizeof (wf->ireq.i_name));
407153317Ssam}
408153317Ssam
409161200Ssamstatic const char *
410161200Ssamwlan_getifname(struct wlanstatfoo *wf0)
411153317Ssam{
412161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0;
413153317Ssam
414161200Ssam	return wf->ifr.ifr_name;
415161200Ssam}
416153317Ssam
417161200Ssamstatic int
418161200Ssamwlan_getopmode(struct wlanstatfoo *wf0)
419161200Ssam{
420161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0;
421153317Ssam
422161200Ssam	if (wf->opmode == -1) {
423161200Ssam		struct ifmediareq ifmr;
424153317Ssam
425161200Ssam		memset(&ifmr, 0, sizeof(ifmr));
426161200Ssam		strlcpy(ifmr.ifm_name, wf->ifr.ifr_name, sizeof(ifmr.ifm_name));
427161200Ssam		if (ioctl(wf->s, SIOCGIFMEDIA, &ifmr) < 0)
428161200Ssam			err(1, "%s (SIOCGIFMEDIA)", wf->ifr.ifr_name);
429188187Ssam		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
430188187Ssam			if (ifmr.ifm_current & IFM_FLAG0)
431188187Ssam				wf->opmode = IEEE80211_M_AHDEMO;
432188187Ssam			else
433188187Ssam				wf->opmode = IEEE80211_M_IBSS;
434188187Ssam		} else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
435161200Ssam			wf->opmode = IEEE80211_M_HOSTAP;
436161200Ssam		else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
437161200Ssam			wf->opmode = IEEE80211_M_MONITOR;
438161200Ssam		else
439161200Ssam			wf->opmode = IEEE80211_M_STA;
440161200Ssam	}
441161200Ssam	return wf->opmode;
442161200Ssam}
443153317Ssam
444161200Ssamstatic void
445161200Ssamgetlladdr(struct wlanstatfoo_p *wf)
446161200Ssam{
447161200Ssam	const struct sockaddr_dl *sdl;
448161200Ssam	struct ifaddrs *ifp, *p;
449153317Ssam
450161200Ssam	if (getifaddrs(&ifp) != 0)
451161200Ssam		err(1, "getifaddrs");
452161200Ssam	for (p = ifp; p != NULL; p = p->ifa_next)
453161200Ssam		if (strcmp(p->ifa_name, wf->ifr.ifr_name) == 0 &&
454161200Ssam		    p->ifa_addr->sa_family == AF_LINK)
455161200Ssam			break;
456161200Ssam	if (p == NULL)
457161200Ssam		errx(1, "did not find link layer address for interface %s",
458161200Ssam			wf->ifr.ifr_name);
459161200Ssam	sdl = (const struct sockaddr_dl *) p->ifa_addr;
460161200Ssam	IEEE80211_ADDR_COPY(wf->mac, LLADDR(sdl));
461161200Ssam	freeifaddrs(ifp);
462153317Ssam}
463153317Ssam
464188187Ssamstatic int
465188187Ssamgetbssid(struct wlanstatfoo_p *wf)
466188187Ssam{
467188187Ssam	wf->ireq.i_type = IEEE80211_IOC_BSSID;
468188187Ssam	wf->ireq.i_data = wf->mac;
469188187Ssam	wf->ireq.i_len = IEEE80211_ADDR_LEN;
470188187Ssam	return ioctl(wf->s, SIOCG80211, &wf->ireq);
471188187Ssam}
472188187Ssam
473161200Ssamstatic void
474161200Ssamwlan_setstamac(struct wlanstatfoo *wf0, const uint8_t *mac)
475153317Ssam{
476188210Ssam	static const uint8_t zeromac[IEEE80211_ADDR_LEN];
477161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) wf0;
478153317Ssam
479161200Ssam	if (mac == NULL) {
480161200Ssam		switch (wlan_getopmode(wf0)) {
481161200Ssam		case IEEE80211_M_HOSTAP:
482161200Ssam		case IEEE80211_M_MONITOR:
483188210Ssam			getlladdr(wf);
484188210Ssam			break;
485161200Ssam		case IEEE80211_M_IBSS:
486161200Ssam		case IEEE80211_M_AHDEMO:
487188210Ssam			/*
488188210Ssam			 * NB: this may not work in which case the
489188210Ssam			 * mac must be specified on the command line
490188210Ssam			 */
491188210Ssam			if (getbssid(wf) < 0 ||
492188210Ssam			    IEEE80211_ADDR_EQ(wf->mac, zeromac))
493188210Ssam				getlladdr(wf);
494153317Ssam			break;
495161200Ssam		case IEEE80211_M_STA:
496188187Ssam			if (getbssid(wf) < 0)
497188187Ssam				err(1, "%s (IEEE80211_IOC_BSSID)",
498188187Ssam				    wf->ireq.i_name);
499153317Ssam			break;
500153317Ssam		}
501161200Ssam	} else
502161200Ssam		IEEE80211_ADDR_COPY(wf->mac, mac);
503161200Ssam}
504153317Ssam
505161200Ssam/* XXX only fetch what's needed to do reports */
506161200Ssamstatic void
507161200Ssamwlan_collect(struct wlanstatfoo_p *wf,
508161200Ssam	struct ieee80211_stats *stats, struct ieee80211req_sta_stats *nstats)
509161200Ssam{
510153317Ssam
511161200Ssam	IEEE80211_ADDR_COPY(wf->u_info.info.is_u.macaddr, wf->mac);
512161200Ssam	wf->ireq.i_type = IEEE80211_IOC_STA_INFO;
513161200Ssam	wf->ireq.i_data = (caddr_t) &wf->u_info;
514161200Ssam	wf->ireq.i_len = sizeof(wf->u_info);
515188187Ssam	if (ioctl(wf->s, SIOCG80211, &wf->ireq) < 0) {
516188187Ssam		warn("%s:%s (IEEE80211_IOC_STA_INFO)", wf->ireq.i_name,
517188187Ssam		    ether_ntoa((const struct ether_addr*) wf->mac));
518188187Ssam	}
519161200Ssam
520161200Ssam	IEEE80211_ADDR_COPY(nstats->is_u.macaddr, wf->mac);
521161200Ssam	wf->ireq.i_type = IEEE80211_IOC_STA_STATS;
522161200Ssam	wf->ireq.i_data = (caddr_t) nstats;
523161200Ssam	wf->ireq.i_len = sizeof(*nstats);
524161200Ssam	if (ioctl(wf->s, SIOCG80211, &wf->ireq) < 0)
525188187Ssam		warn("%s:%s (IEEE80211_IOC_STA_STATS)", wf->ireq.i_name,
526188187Ssam		    ether_ntoa((const struct ether_addr*) wf->mac));
527161200Ssam
528161200Ssam	wf->ifr.ifr_data = (caddr_t) stats;
529161200Ssam	if (ioctl(wf->s, SIOCG80211STATS, &wf->ifr) < 0)
530170535Ssam		err(1, "%s (SIOCG80211STATS)", wf->ifr.ifr_name);
531161200Ssam}
532161200Ssam
533161200Ssamstatic void
534161200Ssamwlan_collect_cur(struct statfoo *sf)
535161200Ssam{
536161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf;
537161200Ssam
538161200Ssam	wlan_collect(wf, &wf->cur, &wf->ncur);
539161200Ssam}
540161200Ssam
541161200Ssamstatic void
542161200Ssamwlan_collect_tot(struct statfoo *sf)
543161200Ssam{
544161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf;
545161200Ssam
546161200Ssam	wlan_collect(wf, &wf->total, &wf->ntotal);
547161200Ssam}
548161200Ssam
549161200Ssamstatic void
550161200Ssamwlan_update_tot(struct statfoo *sf)
551161200Ssam{
552161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf;
553161200Ssam
554161200Ssam	wf->total = wf->cur;
555161200Ssam	wf->ntotal = wf->ncur;
556161200Ssam}
557161200Ssam
558178359Ssamvoid
559178359Ssamsetreason(char b[], size_t bs, int v)
560178359Ssam{
561178359Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
562178359Ssam    static const char *reasons[] = {
563178359Ssam	[IEEE80211_REASON_UNSPECIFIED]		= "unspecified",
564178359Ssam	[IEEE80211_REASON_AUTH_EXPIRE]		= "auth expire",
565178359Ssam	[IEEE80211_REASON_AUTH_LEAVE]		= "auth leave",
566178359Ssam	[IEEE80211_REASON_ASSOC_EXPIRE]		= "assoc expire",
567178359Ssam	[IEEE80211_REASON_ASSOC_TOOMANY]	= "assoc toomany",
568178359Ssam	[IEEE80211_REASON_NOT_AUTHED]		= "not authed",
569178359Ssam	[IEEE80211_REASON_NOT_ASSOCED]		= "not assoced",
570178359Ssam	[IEEE80211_REASON_ASSOC_LEAVE]		= "assoc leave",
571178359Ssam	[IEEE80211_REASON_ASSOC_NOT_AUTHED]	= "assoc not authed",
572178359Ssam	[IEEE80211_REASON_DISASSOC_PWRCAP_BAD]	= "disassoc pwrcap bad",
573178359Ssam	[IEEE80211_REASON_DISASSOC_SUPCHAN_BAD]	= "disassoc supchan bad",
574178359Ssam	[IEEE80211_REASON_IE_INVALID]		= "ie invalid",
575178359Ssam	[IEEE80211_REASON_MIC_FAILURE]		= "mic failure",
576178359Ssam	[IEEE80211_REASON_4WAY_HANDSHAKE_TIMEOUT]= "4-way handshake timeout",
577178359Ssam	[IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT] = "group key update timeout",
578178359Ssam	[IEEE80211_REASON_IE_IN_4WAY_DIFFERS]	= "ie in 4-way differs",
579178359Ssam	[IEEE80211_REASON_GROUP_CIPHER_INVALID]	= "group cipher invalid",
580178359Ssam	[IEEE80211_REASON_PAIRWISE_CIPHER_INVALID]= "pairwise cipher invalid",
581178359Ssam	[IEEE80211_REASON_AKMP_INVALID]		= "akmp invalid",
582178359Ssam	[IEEE80211_REASON_UNSUPP_RSN_IE_VERSION]= "unsupported rsn ie version",
583178359Ssam	[IEEE80211_REASON_INVALID_RSN_IE_CAP]	= "invalid rsn ie cap",
584178359Ssam	[IEEE80211_REASON_802_1X_AUTH_FAILED]	= "802.1x auth failed",
585178359Ssam	[IEEE80211_REASON_CIPHER_SUITE_REJECTED]= "cipher suite rejected",
586178359Ssam    };
587178359Ssam    if (v < N(reasons) && reasons[v] != NULL)
588178359Ssam	    snprintf(b, bs, "%s (%u)", reasons[v], v);
589178359Ssam    else
590178359Ssam	    snprintf(b, bs, "%u", v);
591178359Ssam#undef N
592178359Ssam}
593178359Ssam
594178359Ssamvoid
595178359Ssamsetstatus(char b[], size_t bs, int v)
596178359Ssam{
597178359Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
598178359Ssam    static const char *status[] = {
599178359Ssam	[IEEE80211_STATUS_SUCCESS]		= "success",
600178359Ssam	[IEEE80211_STATUS_UNSPECIFIED]		= "unspecified",
601178359Ssam	[IEEE80211_STATUS_CAPINFO]		= "capinfo",
602178359Ssam	[IEEE80211_STATUS_NOT_ASSOCED]		= "not assoced",
603178359Ssam	[IEEE80211_STATUS_OTHER]		= "other",
604178359Ssam	[IEEE80211_STATUS_ALG]			= "algorithm",
605178359Ssam	[IEEE80211_STATUS_SEQUENCE]		= "sequence",
606178359Ssam	[IEEE80211_STATUS_CHALLENGE]		= "challenge",
607178359Ssam	[IEEE80211_STATUS_TIMEOUT]		= "timeout",
608178359Ssam	[IEEE80211_STATUS_TOOMANY]		= "toomany",
609178359Ssam	[IEEE80211_STATUS_BASIC_RATE]		= "basic rate",
610178359Ssam	[IEEE80211_STATUS_SP_REQUIRED]		= "sp required",
611178359Ssam	[IEEE80211_STATUS_PBCC_REQUIRED]	= "pbcc required",
612178359Ssam	[IEEE80211_STATUS_CA_REQUIRED]		= "ca required",
613178359Ssam	[IEEE80211_STATUS_SPECMGMT_REQUIRED]	= "specmgmt required",
614178359Ssam	[IEEE80211_STATUS_PWRCAP_REQUIRED]	= "pwrcap required",
615178359Ssam	[IEEE80211_STATUS_SUPCHAN_REQUIRED]	= "supchan required",
616178359Ssam	[IEEE80211_STATUS_SHORTSLOT_REQUIRED]	= "shortslot required",
617178359Ssam	[IEEE80211_STATUS_DSSSOFDM_REQUIRED]	= "dsssofdm required",
618178359Ssam	[IEEE80211_STATUS_INVALID_IE]		= "invalid ie",
619178359Ssam	[IEEE80211_STATUS_GROUP_CIPHER_INVALID]	= "group cipher invalid",
620178359Ssam	[IEEE80211_STATUS_PAIRWISE_CIPHER_INVALID]= "pairwise cipher invalid",
621178359Ssam	[IEEE80211_STATUS_AKMP_INVALID]		= "akmp invalid",
622178359Ssam	[IEEE80211_STATUS_UNSUPP_RSN_IE_VERSION]= "unsupported rsn ie version",
623178359Ssam	[IEEE80211_STATUS_INVALID_RSN_IE_CAP]	= "invalid rsn ie cap",
624178359Ssam	[IEEE80211_STATUS_CIPHER_SUITE_REJECTED]= "cipher suite rejected",
625178359Ssam    };
626178359Ssam    if (v < N(status) && status[v] != NULL)
627178359Ssam	    snprintf(b, bs, "%s (%u)", status[v], v);
628178359Ssam    else
629178359Ssam	    snprintf(b, bs, "%u", v);
630178359Ssam#undef N
631178359Ssam}
632178359Ssam
633161200Ssamstatic int
634161200Ssamwlan_getinfo(struct wlanstatfoo_p *wf, int s, char b[], size_t bs)
635161200Ssam{
636161200Ssam	const struct ieee80211req_sta_info *si = &wf->u_info.info.info[0];
637161200Ssam
638161200Ssam	switch (s) {
639161200Ssam	case S_RATE:
640178359Ssam		snprintf(b, bs, "%uM", si->isi_txmbps/2);
641161200Ssam		return 1;
642161200Ssam	case S_RSSI:
643161200Ssam		snprintf(b, bs, "%d", si->isi_rssi);
644161200Ssam		return 1;
645161200Ssam	case S_NOISE:
646161200Ssam		snprintf(b, bs, "%d", si->isi_noise);
647161200Ssam		return 1;
648161200Ssam	case S_SIGNAL:
649161200Ssam		snprintf(b, bs, "%d", si->isi_rssi + si->isi_noise);
650161200Ssam		return 1;
651178359Ssam	case S_RX_AUTH_FAIL_CODE:
652178359Ssam		if (wf->cur.is_rx_authfail_code == 0)
653178359Ssam			break;
654178359Ssam		setstatus(b, bs, wf->cur.is_rx_authfail_code);
655178359Ssam		return 1;
656178359Ssam	case S_RX_DEAUTH_CODE:
657178359Ssam		if (wf->cur.is_rx_deauth_code == 0)
658178359Ssam			break;
659178359Ssam		setreason(b, bs, wf->cur.is_rx_deauth_code);
660178359Ssam		return 1;
661178359Ssam	case S_RX_DISASSOC_CODE:
662178359Ssam		if (wf->cur.is_rx_disassoc_code == 0)
663178359Ssam			break;
664178359Ssam		setreason(b, bs, wf->cur.is_rx_disassoc_code);
665178359Ssam		return 1;
666153317Ssam	}
667161200Ssam	b[0] = '\0';
668161200Ssam	return 0;
669161200Ssam}
670161200Ssam
671161200Ssamstatic int
672161200Ssamwlan_get_curstat(struct statfoo *sf, int s, char b[], size_t bs)
673161200Ssam{
674161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf;
675161200Ssam#define	STAT(x) \
676161200Ssam	snprintf(b, bs, "%u", wf->cur.is_##x - wf->total.is_##x); return 1
677161200Ssam#define	NSTAT(x) \
678161200Ssam	snprintf(b, bs, "%u", \
679161200Ssam	    wf->ncur.is_stats.ns_##x - wf->ntotal.is_stats.ns_##x); \
680161200Ssam	    return 1
681161200Ssam
682161200Ssam	switch (s) {
683161200Ssam	case S_RX_BADVERSION:	STAT(rx_badversion);
684161200Ssam	case S_RX_TOOSHORT:	STAT(rx_tooshort);
685161200Ssam	case S_RX_WRONGBSS:	STAT(rx_wrongbss);
686161200Ssam	case S_RX_DUP:		STAT(rx_dup);
687161200Ssam	case S_RX_WRONGDIR:	STAT(rx_wrongdir);
688161200Ssam	case S_RX_MCASTECHO:	STAT(rx_mcastecho);
689161200Ssam	case S_RX_NOTASSOC:	STAT(rx_notassoc);
690161200Ssam	case S_RX_NOPRIVACY:	STAT(rx_noprivacy);
691161200Ssam	case S_RX_UNENCRYPTED:	STAT(rx_unencrypted);
692161200Ssam	case S_RX_WEPFAIL:	STAT(rx_wepfail);
693161200Ssam	case S_RX_DECAP:	STAT(rx_decap);
694161200Ssam	case S_RX_MGTDISCARD:	STAT(rx_mgtdiscard);
695161200Ssam	case S_RX_CTL:		STAT(rx_ctl);
696161200Ssam	case S_RX_BEACON:	STAT(rx_beacon);
697161200Ssam	case S_RX_RSTOOBIG:	STAT(rx_rstoobig);
698161200Ssam	case S_RX_ELEM_MISSING:	STAT(rx_elem_missing);
699161200Ssam	case S_RX_ELEM_TOOBIG:	STAT(rx_elem_toobig);
700161200Ssam	case S_RX_ELEM_TOOSMALL:	STAT(rx_elem_toosmall);
701161200Ssam	case S_RX_ELEM_UNKNOWN:	STAT(rx_elem_unknown);
702161200Ssam	case S_RX_BADCHAN:	STAT(rx_badchan);
703161200Ssam	case S_RX_CHANMISMATCH:	STAT(rx_chanmismatch);
704161200Ssam	case S_RX_NODEALLOC:	STAT(rx_nodealloc);
705161200Ssam	case S_RX_SSIDMISMATCH:	STAT(rx_ssidmismatch);
706161200Ssam	case S_RX_AUTH_UNSUPPORTED:	STAT(rx_auth_unsupported);
707161200Ssam	case S_RX_AUTH_FAIL:	STAT(rx_auth_fail);
708161200Ssam	case S_RX_AUTH_COUNTERMEASURES:	STAT(rx_auth_countermeasures);
709161200Ssam	case S_RX_ASSOC_BSS:	STAT(rx_assoc_bss);
710161200Ssam	case S_RX_ASSOC_NOTAUTH:	STAT(rx_assoc_notauth);
711161200Ssam	case S_RX_ASSOC_CAPMISMATCH:	STAT(rx_assoc_capmismatch);
712161200Ssam	case S_RX_ASSOC_NORATE:	STAT(rx_assoc_norate);
713161200Ssam	case S_RX_ASSOC_BADWPAIE:	STAT(rx_assoc_badwpaie);
714161200Ssam	case S_RX_DEAUTH:	STAT(rx_deauth);
715161200Ssam	case S_RX_DISASSOC:	STAT(rx_disassoc);
716178359Ssam	case S_BMISS:		STAT(beacon_miss);
717161200Ssam	case S_RX_BADSUBTYPE:	STAT(rx_badsubtype);
718161200Ssam	case S_RX_NOBUF:	STAT(rx_nobuf);
719161200Ssam	case S_RX_DECRYPTCRC:	STAT(rx_decryptcrc);
720161200Ssam	case S_RX_AHDEMO_MGT:	STAT(rx_ahdemo_mgt);
721161200Ssam	case S_RX_BAD_AUTH:	STAT(rx_bad_auth);
722161200Ssam	case S_RX_UNAUTH:	STAT(rx_unauth);
723161200Ssam	case S_RX_BADKEYID:	STAT(rx_badkeyid);
724161200Ssam	case S_RX_CCMPREPLAY:	STAT(rx_ccmpreplay);
725161200Ssam	case S_RX_CCMPFORMAT:	STAT(rx_ccmpformat);
726161200Ssam	case S_RX_CCMPMIC:	STAT(rx_ccmpmic);
727161200Ssam	case S_RX_TKIPREPLAY:	STAT(rx_tkipreplay);
728161200Ssam	case S_RX_TKIPFORMAT:	STAT(rx_tkipformat);
729161200Ssam	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
730161200Ssam	case S_RX_TKIPICV:	STAT(rx_tkipicv);
731161200Ssam	case S_RX_BADCIPHER:	STAT(rx_badcipher);
732161200Ssam	case S_RX_NOCIPHERCTX:	STAT(rx_nocipherctx);
733161200Ssam	case S_RX_ACL:		STAT(rx_acl);
734161200Ssam	case S_TX_NOBUF:	STAT(tx_nobuf);
735161200Ssam	case S_TX_NONODE:	STAT(tx_nonode);
736161200Ssam	case S_TX_UNKNOWNMGT:	STAT(tx_unknownmgt);
737161200Ssam	case S_TX_BADCIPHER:	STAT(tx_badcipher);
738161200Ssam	case S_TX_NODEFKEY:	STAT(tx_nodefkey);
739161200Ssam	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
740161200Ssam	case S_TX_FRAGFRAMES:	STAT(tx_fragframes);
741161200Ssam	case S_TX_FRAGS:	STAT(tx_frags);
742161200Ssam	case S_SCAN_ACTIVE:	STAT(scan_active);
743161200Ssam	case S_SCAN_PASSIVE:	STAT(scan_passive);
744178359Ssam	case S_SCAN_BG:		STAT(scan_bg);
745161200Ssam	case S_NODE_TIMEOUT:	STAT(node_timeout);
746161200Ssam	case S_CRYPTO_NOMEM:	STAT(crypto_nomem);
747161200Ssam	case S_CRYPTO_TKIP:	STAT(crypto_tkip);
748161200Ssam	case S_CRYPTO_TKIPENMIC:	STAT(crypto_tkipenmic);
749161200Ssam	case S_CRYPTO_TKIPDEMIC:	STAT(crypto_tkipdemic);
750161200Ssam	case S_CRYPTO_TKIPCM:	STAT(crypto_tkipcm);
751161200Ssam	case S_CRYPTO_CCMP:	STAT(crypto_ccmp);
752161200Ssam	case S_CRYPTO_WEP:	STAT(crypto_wep);
753161200Ssam	case S_CRYPTO_SETKEY_CIPHER:	STAT(crypto_setkey_cipher);
754161200Ssam	case S_CRYPTO_SETKEY_NOKEY:	STAT(crypto_setkey_nokey);
755161200Ssam	case S_CRYPTO_DELKEY:	STAT(crypto_delkey);
756161200Ssam	case S_CRYPTO_BADCIPHER:	STAT(crypto_badcipher);
757161200Ssam	case S_CRYPTO_NOCIPHER:	STAT(crypto_nocipher);
758161200Ssam	case S_CRYPTO_ATTACHFAIL:	STAT(crypto_attachfail);
759161200Ssam	case S_CRYPTO_SWFALLBACK:	STAT(crypto_swfallback);
760161200Ssam	case S_CRYPTO_KEYFAIL:	STAT(crypto_keyfail);
761161200Ssam	case S_CRYPTO_ENMICFAIL:	STAT(crypto_enmicfail);
762161200Ssam	case S_IBSS_CAPMISMATCH:	STAT(ibss_capmismatch);
763161200Ssam	case S_IBSS_NORATE:	STAT(ibss_norate);
764161200Ssam	case S_PS_UNASSOC:	STAT(ps_unassoc);
765161200Ssam	case S_PS_BADAID:	STAT(ps_badaid);
766161200Ssam	case S_PS_QEMPTY:	STAT(ps_qempty);
767161200Ssam	case S_FF_BADHDR:	STAT(ff_badhdr);
768161200Ssam	case S_FF_TOOSHORT:	STAT(ff_tooshort);
769161200Ssam	case S_FF_SPLIT:	STAT(ff_split);
770161200Ssam	case S_FF_DECAP:	STAT(ff_decap);
771161200Ssam	case S_FF_ENCAP:	STAT(ff_encap);
772161200Ssam	case S_RX_BADBINTVAL:	STAT(rx_badbintval);
773161200Ssam	case S_RX_MGMT:		STAT(rx_mgmt);
774161200Ssam	case S_RX_DEMICFAIL:	STAT(rx_demicfail);
775161200Ssam	case S_RX_DEFRAG:	STAT(rx_defrag);
776170535Ssam	case S_RX_ACTION:	STAT(rx_action);
777170535Ssam	case S_AMSDU_TOOSHORT:	STAT(amsdu_tooshort);
778170535Ssam	case S_AMSDU_SPLIT:	STAT(amsdu_split);
779170535Ssam	case S_AMSDU_DECAP:	STAT(amsdu_decap);
780170535Ssam	case S_AMSDU_ENCAP:	STAT(amsdu_encap);
781173306Ssam	case S_AMPDU_REORDER:	STAT(ampdu_rx_reorder);
782170535Ssam	case S_AMPDU_FLUSH:	STAT(ampdu_rx_flush);
783170535Ssam	case S_AMPDU_BARBAD:	STAT(ampdu_bar_bad);
784170535Ssam	case S_AMPDU_BAROOW:	STAT(ampdu_bar_oow);
785173306Ssam	case S_AMPDU_BARMOVE:	STAT(ampdu_bar_move);
786170535Ssam	case S_AMPDU_BAR:	STAT(ampdu_bar_rx);
787173306Ssam	case S_AMPDU_MOVE:	STAT(ampdu_rx_move);
788170535Ssam	case S_AMPDU_OOR:	STAT(ampdu_rx_oor);
789170535Ssam	case S_AMPDU_COPY:	STAT(ampdu_rx_copy);
790173306Ssam	case S_AMPDU_DROP:	STAT(ampdu_rx_drop);
791173306Ssam	case S_AMPDU_AGE:	STAT(ampdu_rx_age);
792173306Ssam	case S_AMPDU_STOP:	STAT(ampdu_stop);
793173306Ssam	case S_AMPDU_STOP_FAILED:STAT(ampdu_stop_failed);
794173306Ssam	case S_ADDBA_REJECT:	STAT(addba_reject);
795173306Ssam	case S_ADDBA_NOREQUEST:	STAT(addba_norequest);
796173306Ssam	case S_ADDBA_BADTOKEN:	STAT(addba_badtoken);
797173306Ssam	case S_TX_BADSTATE:	STAT(tx_badstate);
798173306Ssam	case S_TX_NOTASSOC:	STAT(tx_notassoc);
799173306Ssam	case S_TX_CLASSIFY:	STAT(tx_classify);
800178359Ssam	case S_DWDS_MCAST:	STAT(dwds_mcast);
801178359Ssam	case S_DWDS_QDROP:	STAT(dwds_qdrop);
802173306Ssam	case S_HT_ASSOC_NOHTCAP:STAT(ht_assoc_nohtcap);
803173306Ssam	case S_HT_ASSOC_DOWNGRADE:STAT(ht_assoc_downgrade);
804173306Ssam	case S_HT_ASSOC_NORATE:	STAT(ht_assoc_norate);
805195618Srpaulo	case S_MESH_WRONGMESH:	STAT(mesh_wrongmesh);
806195618Srpaulo	case S_MESH_NOLINK:	STAT(mesh_nolink);
807195618Srpaulo	case S_MESH_FWD_TTL:	STAT(mesh_fwd_ttl);
808195618Srpaulo	case S_MESH_FWD_NOBUF:	STAT(mesh_fwd_nobuf);
809195618Srpaulo	case S_MESH_FWD_TOOSHORT: STAT(mesh_fwd_tooshort);
810195618Srpaulo	case S_MESH_FWD_DISABLED: STAT(mesh_fwd_disabled);
811195618Srpaulo	case S_MESH_FWD_NOPATH:	STAT(mesh_fwd_nopath);
812195618Srpaulo	case S_HWMP_WRONGSEQ:	STAT(hwmp_wrongseq);
813195618Srpaulo	case S_HWMP_ROOTREQS:	STAT(hwmp_rootreqs);
814195618Srpaulo	case S_HWMP_ROOTANN:	STAT(hwmp_rootrann);
815195811Ssam	case S_MESH_BADAE:	STAT(mesh_badae);
816195811Ssam	case S_MESH_RTADDFAILED:STAT(mesh_rtaddfailed);
817195811Ssam	case S_MESH_NOTPROXY:	STAT(mesh_notproxy);
818195811Ssam	case S_RX_BADALIGN:	STAT(rx_badalign);
819161200Ssam	case S_INPUT:		NSTAT(rx_data);
820161200Ssam	case S_OUTPUT:		NSTAT(tx_data);
821161200Ssam	case S_RX_UCAST:	NSTAT(rx_ucast);
822161200Ssam	case S_RX_MCAST:	NSTAT(rx_mcast);
823161200Ssam	case S_TX_UCAST:	NSTAT(tx_ucast);
824161200Ssam	case S_TX_MCAST:	NSTAT(tx_mcast);
825232245Sadrian	case S_BEACON_BAD:	STAT(beacon_bad);
826234019Sadrian	case S_AMPDU_BARTX:	STAT(ampdu_bar_tx);
827234019Sadrian	case S_AMPDU_BARTX_RETRY:	STAT(ampdu_bar_tx_retry);
828234019Sadrian	case S_AMPDU_BARTX_FAIL:	STAT(ampdu_bar_tx_fail);
829153317Ssam	}
830161200Ssam	return wlan_getinfo(wf, s, b, bs);
831161200Ssam#undef NSTAT
832161200Ssam#undef STAT
833153317Ssam}
834161200Ssam
835161200Ssamstatic int
836161200Ssamwlan_get_totstat(struct statfoo *sf, int s, char b[], size_t bs)
837161200Ssam{
838161200Ssam	struct wlanstatfoo_p *wf = (struct wlanstatfoo_p *) sf;
839161200Ssam#define	STAT(x) \
840161200Ssam	snprintf(b, bs, "%u", wf->total.is_##x); return 1
841161200Ssam#define	NSTAT(x) \
842161200Ssam	snprintf(b, bs, "%u", wf->ntotal.is_stats.ns_##x); return 1
843161200Ssam
844161200Ssam	switch (s) {
845161200Ssam	case S_RX_BADVERSION:	STAT(rx_badversion);
846161200Ssam	case S_RX_TOOSHORT:	STAT(rx_tooshort);
847161200Ssam	case S_RX_WRONGBSS:	STAT(rx_wrongbss);
848161200Ssam	case S_RX_DUP:	STAT(rx_dup);
849161200Ssam	case S_RX_WRONGDIR:	STAT(rx_wrongdir);
850161200Ssam	case S_RX_MCASTECHO:	STAT(rx_mcastecho);
851161200Ssam	case S_RX_NOTASSOC:	STAT(rx_notassoc);
852161200Ssam	case S_RX_NOPRIVACY:	STAT(rx_noprivacy);
853161200Ssam	case S_RX_UNENCRYPTED:	STAT(rx_unencrypted);
854161200Ssam	case S_RX_WEPFAIL:	STAT(rx_wepfail);
855161200Ssam	case S_RX_DECAP:	STAT(rx_decap);
856161200Ssam	case S_RX_MGTDISCARD:	STAT(rx_mgtdiscard);
857161200Ssam	case S_RX_CTL:		STAT(rx_ctl);
858161200Ssam	case S_RX_BEACON:	STAT(rx_beacon);
859161200Ssam	case S_RX_RSTOOBIG:	STAT(rx_rstoobig);
860161200Ssam	case S_RX_ELEM_MISSING:	STAT(rx_elem_missing);
861161200Ssam	case S_RX_ELEM_TOOBIG:	STAT(rx_elem_toobig);
862161200Ssam	case S_RX_ELEM_TOOSMALL:	STAT(rx_elem_toosmall);
863161200Ssam	case S_RX_ELEM_UNKNOWN:	STAT(rx_elem_unknown);
864161200Ssam	case S_RX_BADCHAN:	STAT(rx_badchan);
865161200Ssam	case S_RX_CHANMISMATCH:	STAT(rx_chanmismatch);
866161200Ssam	case S_RX_NODEALLOC:	STAT(rx_nodealloc);
867161200Ssam	case S_RX_SSIDMISMATCH:	STAT(rx_ssidmismatch);
868161200Ssam	case S_RX_AUTH_UNSUPPORTED:	STAT(rx_auth_unsupported);
869161200Ssam	case S_RX_AUTH_FAIL:	STAT(rx_auth_fail);
870161200Ssam	case S_RX_AUTH_COUNTERMEASURES:	STAT(rx_auth_countermeasures);
871161200Ssam	case S_RX_ASSOC_BSS:	STAT(rx_assoc_bss);
872161200Ssam	case S_RX_ASSOC_NOTAUTH:	STAT(rx_assoc_notauth);
873161200Ssam	case S_RX_ASSOC_CAPMISMATCH:	STAT(rx_assoc_capmismatch);
874161200Ssam	case S_RX_ASSOC_NORATE:	STAT(rx_assoc_norate);
875161200Ssam	case S_RX_ASSOC_BADWPAIE:	STAT(rx_assoc_badwpaie);
876161200Ssam	case S_RX_DEAUTH:	STAT(rx_deauth);
877161200Ssam	case S_RX_DISASSOC:	STAT(rx_disassoc);
878178359Ssam	case S_BMISS:		STAT(beacon_miss);
879161200Ssam	case S_RX_BADSUBTYPE:	STAT(rx_badsubtype);
880161200Ssam	case S_RX_NOBUF:	STAT(rx_nobuf);
881161200Ssam	case S_RX_DECRYPTCRC:	STAT(rx_decryptcrc);
882161200Ssam	case S_RX_AHDEMO_MGT:	STAT(rx_ahdemo_mgt);
883161200Ssam	case S_RX_BAD_AUTH:	STAT(rx_bad_auth);
884161200Ssam	case S_RX_UNAUTH:	STAT(rx_unauth);
885161200Ssam	case S_RX_BADKEYID:	STAT(rx_badkeyid);
886161200Ssam	case S_RX_CCMPREPLAY:	STAT(rx_ccmpreplay);
887161200Ssam	case S_RX_CCMPFORMAT:	STAT(rx_ccmpformat);
888161200Ssam	case S_RX_CCMPMIC:	STAT(rx_ccmpmic);
889161200Ssam	case S_RX_TKIPREPLAY:	STAT(rx_tkipreplay);
890161200Ssam	case S_RX_TKIPFORMAT:	STAT(rx_tkipformat);
891161200Ssam	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
892161200Ssam	case S_RX_TKIPICV:	STAT(rx_tkipicv);
893161200Ssam	case S_RX_BADCIPHER:	STAT(rx_badcipher);
894161200Ssam	case S_RX_NOCIPHERCTX:	STAT(rx_nocipherctx);
895161200Ssam	case S_RX_ACL:		STAT(rx_acl);
896161200Ssam	case S_TX_NOBUF:	STAT(tx_nobuf);
897161200Ssam	case S_TX_NONODE:	STAT(tx_nonode);
898161200Ssam	case S_TX_UNKNOWNMGT:	STAT(tx_unknownmgt);
899161200Ssam	case S_TX_BADCIPHER:	STAT(tx_badcipher);
900161200Ssam	case S_TX_NODEFKEY:	STAT(tx_nodefkey);
901161200Ssam	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
902161200Ssam	case S_TX_FRAGFRAMES:	STAT(tx_fragframes);
903161200Ssam	case S_TX_FRAGS:	STAT(tx_frags);
904161200Ssam	case S_SCAN_ACTIVE:	STAT(scan_active);
905161200Ssam	case S_SCAN_PASSIVE:	STAT(scan_passive);
906178359Ssam	case S_SCAN_BG:		STAT(scan_bg);
907161200Ssam	case S_NODE_TIMEOUT:	STAT(node_timeout);
908161200Ssam	case S_CRYPTO_NOMEM:	STAT(crypto_nomem);
909161200Ssam	case S_CRYPTO_TKIP:	STAT(crypto_tkip);
910161200Ssam	case S_CRYPTO_TKIPENMIC:	STAT(crypto_tkipenmic);
911161200Ssam	case S_CRYPTO_TKIPDEMIC:	STAT(crypto_tkipdemic);
912161200Ssam	case S_CRYPTO_TKIPCM:	STAT(crypto_tkipcm);
913161200Ssam	case S_CRYPTO_CCMP:	STAT(crypto_ccmp);
914161200Ssam	case S_CRYPTO_WEP:	STAT(crypto_wep);
915161200Ssam	case S_CRYPTO_SETKEY_CIPHER:	STAT(crypto_setkey_cipher);
916161200Ssam	case S_CRYPTO_SETKEY_NOKEY:	STAT(crypto_setkey_nokey);
917161200Ssam	case S_CRYPTO_DELKEY:	STAT(crypto_delkey);
918161200Ssam	case S_CRYPTO_BADCIPHER:	STAT(crypto_badcipher);
919161200Ssam	case S_CRYPTO_NOCIPHER:	STAT(crypto_nocipher);
920161200Ssam	case S_CRYPTO_ATTACHFAIL:	STAT(crypto_attachfail);
921161200Ssam	case S_CRYPTO_SWFALLBACK:	STAT(crypto_swfallback);
922161200Ssam	case S_CRYPTO_KEYFAIL:	STAT(crypto_keyfail);
923161200Ssam	case S_CRYPTO_ENMICFAIL:	STAT(crypto_enmicfail);
924161200Ssam	case S_IBSS_CAPMISMATCH:	STAT(ibss_capmismatch);
925161200Ssam	case S_IBSS_NORATE:	STAT(ibss_norate);
926161200Ssam	case S_PS_UNASSOC:	STAT(ps_unassoc);
927161200Ssam	case S_PS_BADAID:	STAT(ps_badaid);
928161200Ssam	case S_PS_QEMPTY:	STAT(ps_qempty);
929161200Ssam	case S_FF_BADHDR:	STAT(ff_badhdr);
930161200Ssam	case S_FF_TOOSHORT:	STAT(ff_tooshort);
931161200Ssam	case S_FF_SPLIT:	STAT(ff_split);
932161200Ssam	case S_FF_DECAP:	STAT(ff_decap);
933161200Ssam	case S_FF_ENCAP:	STAT(ff_encap);
934161200Ssam	case S_RX_BADBINTVAL:	STAT(rx_badbintval);
935161200Ssam	case S_RX_MGMT:		STAT(rx_mgmt);
936161200Ssam	case S_RX_DEMICFAIL:	STAT(rx_demicfail);
937161200Ssam	case S_RX_DEFRAG:	STAT(rx_defrag);
938170535Ssam	case S_RX_ACTION:	STAT(rx_action);
939170535Ssam	case S_AMSDU_TOOSHORT:	STAT(amsdu_tooshort);
940170535Ssam	case S_AMSDU_SPLIT:	STAT(amsdu_split);
941170535Ssam	case S_AMSDU_DECAP:	STAT(amsdu_decap);
942170535Ssam	case S_AMSDU_ENCAP:	STAT(amsdu_encap);
943173306Ssam	case S_AMPDU_REORDER:	STAT(ampdu_rx_reorder);
944170535Ssam	case S_AMPDU_FLUSH:	STAT(ampdu_rx_flush);
945170535Ssam	case S_AMPDU_BARBAD:	STAT(ampdu_bar_bad);
946170535Ssam	case S_AMPDU_BAROOW:	STAT(ampdu_bar_oow);
947173306Ssam	case S_AMPDU_BARMOVE:	STAT(ampdu_bar_move);
948170535Ssam	case S_AMPDU_BAR:	STAT(ampdu_bar_rx);
949173306Ssam	case S_AMPDU_MOVE:	STAT(ampdu_rx_move);
950170535Ssam	case S_AMPDU_OOR:	STAT(ampdu_rx_oor);
951170535Ssam	case S_AMPDU_COPY:	STAT(ampdu_rx_copy);
952173306Ssam	case S_AMPDU_DROP:	STAT(ampdu_rx_drop);
953173306Ssam	case S_AMPDU_AGE:	STAT(ampdu_rx_age);
954173306Ssam	case S_AMPDU_STOP:	STAT(ampdu_stop);
955173306Ssam	case S_AMPDU_STOP_FAILED:STAT(ampdu_stop_failed);
956173306Ssam	case S_ADDBA_REJECT:	STAT(addba_reject);
957173306Ssam	case S_ADDBA_NOREQUEST:	STAT(addba_norequest);
958173306Ssam	case S_ADDBA_BADTOKEN:	STAT(addba_badtoken);
959173306Ssam	case S_TX_BADSTATE:	STAT(tx_badstate);
960173306Ssam	case S_TX_NOTASSOC:	STAT(tx_notassoc);
961173306Ssam	case S_TX_CLASSIFY:	STAT(tx_classify);
962178359Ssam	case S_DWDS_MCAST:	STAT(dwds_mcast);
963178359Ssam	case S_DWDS_QDROP:	STAT(dwds_qdrop);
964173306Ssam	case S_HT_ASSOC_NOHTCAP:STAT(ht_assoc_nohtcap);
965173306Ssam	case S_HT_ASSOC_DOWNGRADE:STAT(ht_assoc_downgrade);
966173306Ssam	case S_HT_ASSOC_NORATE:	STAT(ht_assoc_norate);
967195618Srpaulo	case S_MESH_WRONGMESH:	STAT(mesh_wrongmesh);
968195618Srpaulo	case S_MESH_NOLINK:	STAT(mesh_nolink);
969195618Srpaulo	case S_MESH_FWD_TTL:	STAT(mesh_fwd_ttl);
970195618Srpaulo	case S_MESH_FWD_NOBUF:	STAT(mesh_fwd_nobuf);
971195618Srpaulo	case S_MESH_FWD_TOOSHORT: STAT(mesh_fwd_tooshort);
972195618Srpaulo	case S_MESH_FWD_DISABLED: STAT(mesh_fwd_disabled);
973195618Srpaulo	case S_MESH_FWD_NOPATH:	STAT(mesh_fwd_nopath);
974195618Srpaulo	case S_HWMP_WRONGSEQ:	STAT(hwmp_wrongseq);
975195618Srpaulo	case S_HWMP_ROOTREQS:	STAT(hwmp_rootreqs);
976195618Srpaulo	case S_HWMP_ROOTANN:	STAT(hwmp_rootrann);
977195811Ssam	case S_MESH_BADAE:	STAT(mesh_badae);
978195811Ssam	case S_MESH_RTADDFAILED:STAT(mesh_rtaddfailed);
979195811Ssam	case S_MESH_NOTPROXY:	STAT(mesh_notproxy);
980195811Ssam	case S_RX_BADALIGN:	STAT(rx_badalign);
981161200Ssam	case S_INPUT:		NSTAT(rx_data);
982161200Ssam	case S_OUTPUT:		NSTAT(tx_data);
983161200Ssam	case S_RX_UCAST:	NSTAT(rx_ucast);
984161200Ssam	case S_RX_MCAST:	NSTAT(rx_mcast);
985161200Ssam	case S_TX_UCAST:	NSTAT(tx_ucast);
986161200Ssam	case S_TX_MCAST:	NSTAT(tx_mcast);
987232245Sadrian	case S_BEACON_BAD:	STAT(beacon_bad);
988234019Sadrian	case S_AMPDU_BARTX:	STAT(ampdu_bar_tx);
989234019Sadrian	case S_AMPDU_BARTX_RETRY:	STAT(ampdu_bar_tx_retry);
990234019Sadrian	case S_AMPDU_BARTX_FAIL:	STAT(ampdu_bar_tx_fail);
991161200Ssam	}
992161200Ssam	return wlan_getinfo(wf, s, b, bs);
993161200Ssam#undef NSTAT
994161200Ssam#undef STAT
995161200Ssam}
996161200Ssam
997161200SsamSTATFOO_DEFINE_BOUNCE(wlanstatfoo)
998161200Ssam
999161200Ssamstruct wlanstatfoo *
1000161200Ssamwlanstats_new(const char *ifname, const char *fmtstring)
1001161200Ssam{
1002161200Ssam#define	N(a)	(sizeof(a) / sizeof(a[0]))
1003161200Ssam	struct wlanstatfoo_p *wf;
1004161200Ssam
1005161200Ssam	wf = calloc(1, sizeof(struct wlanstatfoo_p));
1006161200Ssam	if (wf != NULL) {
1007161200Ssam		statfoo_init(&wf->base.base, "wlanstats", wlanstats, N(wlanstats));
1008161200Ssam		/* override base methods */
1009161200Ssam		wf->base.base.collect_cur = wlan_collect_cur;
1010161200Ssam		wf->base.base.collect_tot = wlan_collect_tot;
1011161200Ssam		wf->base.base.get_curstat = wlan_get_curstat;
1012161200Ssam		wf->base.base.get_totstat = wlan_get_totstat;
1013161200Ssam		wf->base.base.update_tot = wlan_update_tot;
1014161200Ssam
1015161200Ssam		/* setup bounce functions for public methods */
1016161200Ssam		STATFOO_BOUNCE(wf, wlanstatfoo);
1017161200Ssam
1018161200Ssam		/* setup our public methods */
1019161200Ssam		wf->base.setifname = wlan_setifname;
1020161200Ssam		wf->base.getifname = wlan_getifname;
1021161200Ssam		wf->base.getopmode = wlan_getopmode;
1022161200Ssam		wf->base.setstamac = wlan_setstamac;
1023161200Ssam		wf->opmode = -1;
1024161200Ssam
1025161200Ssam		wf->s = socket(AF_INET, SOCK_DGRAM, 0);
1026161200Ssam		if (wf->s < 0)
1027161200Ssam			err(1, "socket");
1028161200Ssam
1029161200Ssam		wlan_setifname(&wf->base, ifname);
1030161200Ssam		wf->base.setfmt(&wf->base, fmtstring);
1031161200Ssam	}
1032161200Ssam	return &wf->base;
1033161200Ssam#undef N
1034161200Ssam}
1035