1193242Ssam/*-
2193242Ssam * Copyright (c) 2007 Sam Leffler, Errno Consulting
3193242Ssam * All rights reserved.
4193242Ssam *
5193242Ssam * Redistribution and use in source and binary forms, with or without
6193242Ssam * modification, are permitted provided that the following conditions
7193242Ssam * are met:
8193242Ssam * 1. Redistributions of source code must retain the above copyright
9193242Ssam *    notice, this list of conditions and the following disclaimer,
10193242Ssam *    without modification.
11193242Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12193242Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13193242Ssam *    redistribution must be conditioned upon including a substantially
14193242Ssam *    similar Disclaimer requirement for further binary redistribution.
15193242Ssam *
16193242Ssam * NO WARRANTY
17193242Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18193242Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19193242Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20193242Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21193242Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22193242Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23193242Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24193242Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25193242Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26193242Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27193242Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28193242Ssam *
29193242Ssam * $FreeBSD$
30193242Ssam */
31193242Ssam
32193242Ssam/*
33193242Ssam * mwl statistics class.
34193242Ssam */
35193242Ssam#include <sys/types.h>
36193242Ssam#include <sys/file.h>
37193242Ssam#include <sys/sockio.h>
38193242Ssam#include <sys/socket.h>
39193242Ssam#include <sys/ioctl.h>
40193242Ssam#include <net/if.h>
41193242Ssam#include <net/if_media.h>
42193242Ssam
43193242Ssam#include <stdlib.h>
44193242Ssam#include <stdio.h>
45193242Ssam#include <signal.h>
46193242Ssam#include <string.h>
47193242Ssam#include <unistd.h>
48193242Ssam#include <err.h>
49193242Ssam
50197454Srpaulo#include "../../../../sys/net80211/ieee80211_ioctl.h"
51197454Srpaulo#include "../../../../sys/net80211/ieee80211_radiotap.h"
52193242Ssam
53193242Ssam/*
54193242Ssam * Get Hardware Statistics.
55193242Ssam */
56193242Ssamstruct mwl_hal_hwstats {
57193242Ssam	uint32_t	TxRetrySuccesses;
58193242Ssam	uint32_t	TxMultipleRetrySuccesses;
59193242Ssam	uint32_t	TxFailures;
60193242Ssam	uint32_t	RTSSuccesses;
61193242Ssam	uint32_t	RTSFailures;
62193242Ssam	uint32_t	AckFailures;
63193242Ssam	uint32_t	RxDuplicateFrames;
64193242Ssam	uint32_t	FCSErrorCount;
65193242Ssam	uint32_t	TxWatchDogTimeouts;
66193242Ssam	uint32_t	RxOverflows;
67193242Ssam	uint32_t	RxFragErrors;
68193242Ssam	uint32_t	RxMemErrors;
69193242Ssam	uint32_t	PointerErrors;
70193242Ssam	uint32_t	TxUnderflows;
71193242Ssam	uint32_t	TxDone;
72193242Ssam	uint32_t	TxDoneBufTryPut;
73193242Ssam	uint32_t	TxDoneBufPut;
74193242Ssam	uint32_t	Wait4TxBuf;
75193242Ssam	uint32_t	TxAttempts;
76193242Ssam	uint32_t	TxSuccesses;
77193242Ssam	uint32_t	TxFragments;
78193242Ssam	uint32_t	TxMulticasts;
79193242Ssam	uint32_t	RxNonCtlPkts;
80193242Ssam	uint32_t	RxMulticasts;
81193242Ssam	uint32_t	RxUndecryptableFrames;
82193242Ssam	uint32_t 	RxICVErrors;
83193242Ssam	uint32_t	RxExcludedFrames;
84193242Ssam};
85193242Ssam#include "../../../../sys/dev/mwl/if_mwlioctl.h"
86193242Ssam
87193242Ssam#include "mwlstats.h"
88193242Ssam
89193242Ssam#define	AFTER(prev)	((prev)+1)
90193242Ssam
91193242Ssamstatic const struct fmt mwlstats[] = {
92193242Ssam#define	S_INPUT		0
93193242Ssam	{ 8,	"input",	"input",	"total frames received" },
94193242Ssam#define	S_RX_MCAST	AFTER(S_INPUT)
95193242Ssam	{ 7,	"rxmcast",	"rxmcast",	"rx multicast frames" },
96193242Ssam#define	S_RX_NONCTL	AFTER(S_RX_MCAST)
97193242Ssam	{ 8,	"rxnonctl",	"rxnonctl"	"rx non control frames" },
98193242Ssam#define	S_RX_MGT	AFTER(S_RX_NONCTL)
99193242Ssam	{ 5,	"rxmgt",	"rxmgt",	"rx management frames" },
100193242Ssam#define	S_RX_CTL	AFTER(S_RX_MGT)
101193242Ssam	{ 5,	"rxctl",	"rxctl",	"rx control frames" },
102193242Ssam#define	S_OUTPUT	AFTER(S_RX_CTL)
103193242Ssam	{ 8,	"output",	"output",	"total frames transmit" },
104193242Ssam#define	S_TX_MCAST	AFTER(S_OUTPUT)
105193242Ssam	{ 7,	"txmcast",	"txmcast",	"tx multicast frames" },
106193242Ssam#define	S_TX_MGMT	AFTER(S_TX_MCAST)
107193242Ssam	{ 5,	"txmgt",	"txmgt",	"tx management frames" },
108193242Ssam#define	S_TX_RETRY	AFTER(S_TX_MGMT)
109193242Ssam	{ 7,	"txretry",	"txretry",	"tx success with 1 retry" },
110193242Ssam#define	S_TX_MRETRY	AFTER(S_TX_RETRY)
111193242Ssam	{ 8,	"txmretry",	"txmretry",	"tx success with >1 retry" },
112193242Ssam#define	S_TX_RTSGOOD	AFTER(S_TX_MRETRY)
113193242Ssam	{ 7,	"rtsgood",	"rtsgood",	"RTS tx success" },
114193242Ssam#define	S_TX_RTSBAD	AFTER(S_TX_RTSGOOD)
115193242Ssam	{ 6,	"rtsbad",	"rtsbad",	"RTS tx failed" },
116193242Ssam#define	S_TX_NOACK	AFTER(S_TX_RTSBAD)
117193242Ssam	{ 5,	"noack",	"noack",	"tx failed because no ACK was received" },
118193242Ssam#define	S_RX_DUPLICATE	AFTER(S_TX_NOACK)
119193242Ssam	{ 5,	"rxdup",	"rxdup",	"rx discarded by f/w as dup" },
120193242Ssam#define	S_RX_FCS	AFTER(S_RX_DUPLICATE)
121193242Ssam	{ 5,	"rxfcs",	"rxfcs",	"rx discarded by f/w for bad FCS" },
122193242Ssam#define	S_TX_WATCHDOG	AFTER(S_RX_FCS)
123193242Ssam	{ 7,	"txwatch",	"txwatch",	"MAC tx hang (f/w recovery)" },
124193242Ssam#define	S_RX_OVERFLOW	AFTER(S_TX_WATCHDOG)
125193242Ssam	{ 6,	"rxover",	"rxover",	"no f/w buffer for rx" },
126193242Ssam#define	S_RX_FRAGERROR	AFTER(S_RX_OVERFLOW)
127193242Ssam	{ 6,	"rxfrag",	"rxfrag",	"rx failed in f/w due to defrag" },
128193242Ssam#define	S_RX_MEMERROR	AFTER(S_RX_FRAGERROR)
129193242Ssam	{ 5,	"rxmem",	"rxmem",	"rx failed in f/w 'cuz out of of memory" },
130193242Ssam#define	S_PTRERROR	AFTER(S_RX_MEMERROR)
131193242Ssam	{ 6,	"badptr",	"badptr",	"MAC internal pointer problem" },
132193242Ssam#define	S_TX_UNDERFLOW	AFTER(S_PTRERROR)
133193242Ssam	{ 7,	"txunder",	"txunder",	"tx failed in f/w 'cuz of underflow" },
134193242Ssam#define	S_TX_DONE	AFTER(S_TX_UNDERFLOW)
135193242Ssam	{ 6,	"txdone",	"txdone",	"MAC tx ops completed" },
136193242Ssam#define	S_TX_DONEBUFPUT	AFTER(S_TX_DONE)
137193242Ssam	{ 9,	"txdoneput",	"txdoneput",	"tx buffers returned by f/w to host" },
138193242Ssam#define	S_TX_WAIT4BUF	AFTER(S_TX_DONEBUFPUT)
139193242Ssam	{ 6,	"txwait",	"txwait",	"no f/w buffers available when supplied a tx descriptor" },
140193242Ssam#define	S_TX_ATTEMPTS	AFTER(S_TX_WAIT4BUF)
141193242Ssam	{ 5,	"txtry",	"txtry",	"tx descriptors processed by f/w" },
142193242Ssam#define	S_TX_SUCCESS	AFTER(S_TX_ATTEMPTS)
143193242Ssam	{ 4,	"txok",		"txok",		"tx attempts successful" },
144193242Ssam#define	S_TX_FRAGS	AFTER(S_TX_SUCCESS)
145193242Ssam	{ 6,	"txfrag",	"txfrag",	"tx attempts with fragmentation" },
146193242Ssam#define	S_RX_UNDECRYPT	AFTER(S_TX_FRAGS)
147193242Ssam	{ 7,	"rxcrypt",	"rxcrypt",	"rx failed in f/w 'cuz decrypt failed" },
148193242Ssam#define	S_RX_ICVERROR	AFTER(S_RX_UNDECRYPT)
149193242Ssam	{ 5,	"rxicv",	"rxicv",	"rx failed in f/w 'cuz ICV check" },
150193242Ssam#define	S_RX_EXCLUDE	AFTER(S_RX_ICVERROR)
151193242Ssam	{ 8,	"rxfilter",	"rxfilter",	"rx frames filtered in f/w" },
152193242Ssam#define	S_TX_LINEAR	AFTER(S_RX_EXCLUDE)
153193242Ssam	{ 5,	"txlinear",	"txlinear",	"tx linearized to cluster" },
154193242Ssam#define	S_TX_DISCARD	AFTER(S_TX_LINEAR)
155193242Ssam	{ 5,	"txdisc",	"txdisc",	"tx frames discarded prior to association" },
156193242Ssam#define	S_TX_QSTOP	AFTER(S_TX_DISCARD)
157193242Ssam	{ 5,	"qstop",	"qstop",	"tx stopped 'cuz no xmit buffer" },
158193242Ssam#define	S_TX_ENCAP	AFTER(S_TX_QSTOP)
159193242Ssam	{ 5,	"txencode",	"txencode",	"tx encapsulation failed" },
160193242Ssam#define	S_TX_NOMBUF	AFTER(S_TX_ENCAP)
161193242Ssam	{ 5,	"txnombuf",	"txnombuf",	"tx failed 'cuz mbuf allocation failed" },
162193242Ssam#define	S_TX_SHORTPRE	AFTER(S_TX_NOMBUF)
163193242Ssam	{ 5,	"shpre",	"shpre",	"tx frames with short preamble" },
164193242Ssam#define	S_TX_NOHEADROOM	AFTER(S_TX_SHORTPRE)
165193242Ssam	{ 5,	"nohead",	"nohead",	"tx frames discarded for lack of headroom" },
166193242Ssam#define	S_TX_BADFRAMETYPE	AFTER(S_TX_NOHEADROOM)
167193242Ssam	{ 5,	"badtxtype",	"badtxtype",	"tx frames discarded for invalid/unknown 802.11 frame type" },
168193242Ssam#define	S_RX_CRYPTO_ERR	AFTER(S_TX_BADFRAMETYPE)
169193242Ssam	{ 5,	"crypt",	"crypt",	"rx failed 'cuz decryption" },
170193242Ssam#define	S_RX_NOMBUF	AFTER(S_RX_CRYPTO_ERR)
171193242Ssam	{ 5,	"rxnombuf",	"rxnombuf",	"rx setup failed 'cuz no mbuf" },
172193242Ssam#define	S_RX_TKIPMIC	AFTER(S_RX_NOMBUF)
173193242Ssam	{ 5,	"rxtkipmic",	"rxtkipmic",	"rx failed 'cuz TKIP MIC error" },
174193242Ssam#define	S_RX_NODMABUF	AFTER(S_RX_TKIPMIC)
175193242Ssam	{ 5,	"rxnodmabuf",	"rxnodmabuf",	"rx failed 'cuz no DMA buffer available" },
176193242Ssam#define	S_RX_DMABUFMISSING	AFTER(S_RX_NODMABUF)
177193242Ssam	{ 5,	"rxdmabufmissing",	"rxdmabufmissing",	"rx descriptor with no DMA buffer attached" },
178193242Ssam#define	S_TX_NODATA	AFTER(S_RX_DMABUFMISSING)
179193242Ssam	{ 5,	"txnodata",	"txnodata",	"tx discarded empty frame" },
180193242Ssam#define	S_TX_BUSDMA	AFTER(S_TX_NODATA)
181193242Ssam	{ 5,	"txbusdma",	"txbusdma",	"tx failed for dma resources" },
182193242Ssam#define	S_RX_BUSDMA	AFTER(S_TX_BUSDMA)
183193242Ssam	{ 5,	"rxbusdma",	"rxbusdma",	"rx setup failed for dma resources" },
184193242Ssam#define	S_AMPDU_NOSTREAM	AFTER(S_RX_BUSDMA)
185193242Ssam	{ 5,	"ampdu_nostream","ampdu_nostream","ADDBA request failed 'cuz all BA streams in use" },
186193242Ssam#define	S_AMPDU_REJECT	AFTER(S_AMPDU_NOSTREAM)
187193242Ssam	{ 5,	"ampdu_reject","ampdu_reject","ADDBA request failed 'cuz station already has one BA stream" },
188193242Ssam#define	S_ADDBA_NOSTREAM	AFTER(S_AMPDU_REJECT)
189193242Ssam	{ 5,	"addba_nostream","addba_nostream","ADDBA response processed but no BA stream present" },
190193242Ssam#define	S_TX_TSO	AFTER(S_ADDBA_NOSTREAM)
191193242Ssam	{ 8,	"txtso",	"tso",		"tx frames using TSO" },
192193242Ssam#define	S_TSO_BADETH	AFTER(S_TX_TSO)
193193242Ssam	{ 5,	"tsoeth",	"tsoeth",	"TSO failed 'cuz ether header type not IPv4" },
194193242Ssam#define	S_TSO_NOHDR	AFTER(S_TSO_BADETH)
195193242Ssam	{ 5,	"tsonohdr",	"tsonohdr",	"TSO failed 'cuz header not in first mbuf" },
196193242Ssam#define	S_TSO_BADSPLIT	AFTER(S_TSO_NOHDR)
197193242Ssam	{ 5,	"tsobadsplit",	"tsobadsplit",	"TSO failed 'cuz payload split failed" },
198193242Ssam#define	S_BAWATCHDOG	AFTER(S_TSO_BADSPLIT)
199193242Ssam	{ 5,	"bawatchdog",	"bawatchdog",	"BA watchdog interrupts" },
200193242Ssam#define	S_BAWATCHDOG_NOTFOUND	AFTER(S_BAWATCHDOG)
201193242Ssam	{ 5,	"bawatchdog_notfound",	"bawatchdog_notfound",
202193242Ssam	  "BA watchdog for unknown stream" },
203193242Ssam#define	S_BAWATCHDOG_EMPTY	AFTER(S_BAWATCHDOG_NOTFOUND)
204193242Ssam	{ 5,	"bawatchdog_empty",	"bawatchdog_empty",
205193242Ssam	  "BA watchdog on all streams but none found" },
206193242Ssam#define	S_BAWATCHDOG_FAILED	AFTER(S_BAWATCHDOG_EMPTY)
207193242Ssam	{ 5,	"bawatchdog_failed",	"bawatchdog_failed",
208193242Ssam	  "BA watchdog processing failed to get bitmap from f/w" },
209193242Ssam#define	S_RADARDETECT	AFTER(S_BAWATCHDOG_FAILED)
210193242Ssam	{ 5,	"radardetect",	"radardetect",	"radar detect interrupts" },
211193242Ssam#define	S_RATE		AFTER(S_RADARDETECT)
212193242Ssam	{ 4,	"rate",		"rate",		"rate of last transmit" },
213193242Ssam#define	S_TX_RSSI	AFTER(S_RATE)
214193242Ssam	{ 4,	"arssi",	"arssi",	"rssi of last ack" },
215193242Ssam#define	S_RX_RSSI	AFTER(S_TX_RSSI)
216193242Ssam	{ 4,	"rssi",		"rssi",		"avg recv rssi" },
217193242Ssam#define	S_RX_NOISE	AFTER(S_RX_RSSI)
218193242Ssam	{ 5,	"noise",	"noise",	"rx noise floor" },
219193242Ssam#define	S_TX_SIGNAL	AFTER(S_RX_NOISE)
220193242Ssam	{ 4,	"asignal",	"asig",		"signal of last ack (dBm)" },
221193242Ssam#define	S_RX_SIGNAL	AFTER(S_TX_SIGNAL)
222193242Ssam	{ 4,	"signal",	"sig",		"avg recv signal (dBm)" },
223193242Ssam#define	S_ANT_TX0	AFTER(S_RX_SIGNAL)
224193242Ssam	{ 8,	"tx0",		"ant0(tx)",	"frames tx on antenna 0" },
225193242Ssam#define	S_ANT_TX1	(S_RX_SIGNAL+2)
226193242Ssam	{ 8,	"tx1",		"ant1(tx)",	"frames tx on antenna 1"  },
227193242Ssam#define	S_ANT_TX2	(S_RX_SIGNAL+3)
228193242Ssam	{ 8,	"tx2",		"ant2(tx)",	"frames tx on antenna 2"  },
229193242Ssam#define	S_ANT_TX3	(S_RX_SIGNAL+4)
230193242Ssam	{ 8,	"tx3",		"ant3(tx)",	"frames tx on antenna 3"  },
231193242Ssam#define	S_ANT_RX0	AFTER(S_ANT_TX3)
232193242Ssam	{ 8,	"rx0",		"ant0(rx)",	"frames rx on antenna 0"  },
233193242Ssam#define	S_ANT_RX1	(S_ANT_TX3+2)
234193242Ssam	{ 8,	"rx1",		"ant1(rx)",	"frames rx on antenna 1"   },
235193242Ssam#define	S_ANT_RX2	(S_ANT_TX3+3)
236193242Ssam	{ 8,	"rx2",		"ant2(rx)",	"frames rx on antenna 2"   },
237193242Ssam#define	S_ANT_RX3	(S_ANT_TX3+4)
238193242Ssam	{ 8,	"rx3",		"ant3(rx)",	"frames rx on antenna 3"   },
239193242Ssam};
240193242Ssam/* NB: this intentionally avoids per-antenna stats */
241193242Ssam#define	S_LAST	(S_RX_SIGNAL+1)
242193242Ssam
243193242Ssamstruct mwlstatfoo_p {
244193242Ssam	struct mwlstatfoo base;
245193242Ssam	int s;
246193242Ssam	struct ifreq ifr;
247193242Ssam	struct mwl_stats cur;
248193242Ssam	struct mwl_stats total;
249193242Ssam};
250193242Ssam
251193242Ssamstatic void
252193242Ssammwl_setifname(struct mwlstatfoo *wf0, const char *ifname)
253193242Ssam{
254193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) wf0;
255193242Ssam
256193242Ssam	strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name));
257193242Ssam}
258193242Ssam
259193242Ssamstatic void
260193242Ssammwl_collect(struct mwlstatfoo_p *wf, struct mwl_stats *stats)
261193242Ssam{
262193242Ssam	wf->ifr.ifr_data = (caddr_t) stats;
263193242Ssam	if (ioctl(wf->s, SIOCGMVSTATS, &wf->ifr) < 0)
264193242Ssam		err(1, wf->ifr.ifr_name);
265193242Ssam}
266193242Ssam
267193242Ssamstatic void
268193242Ssammwl_collect_cur(struct statfoo *sf)
269193242Ssam{
270193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
271193242Ssam
272193242Ssam	mwl_collect(wf, &wf->cur);
273193242Ssam}
274193242Ssam
275193242Ssamstatic void
276193242Ssammwl_collect_tot(struct statfoo *sf)
277193242Ssam{
278193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
279193242Ssam
280193242Ssam	mwl_collect(wf, &wf->total);
281193242Ssam}
282193242Ssam
283193242Ssamstatic void
284193242Ssammwl_update_tot(struct statfoo *sf)
285193242Ssam{
286193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
287193242Ssam
288193242Ssam	wf->total = wf->cur;
289193242Ssam}
290193242Ssam
291193242Ssamstatic void
292193242Ssamsetrate(char b[], size_t bs, uint8_t rate)
293193242Ssam{
294193242Ssam	if (rate & IEEE80211_RATE_MCS)
295193242Ssam		snprintf(b, bs, "MCS%u", rate & IEEE80211_RATE_VAL);
296193242Ssam	else if (rate & 1)
297193242Ssam		snprintf(b, bs, "%u.5M", rate / 2);
298193242Ssam	else
299193242Ssam		snprintf(b, bs, "%uM", rate / 2);
300193242Ssam}
301193242Ssam
302193242Ssamstatic int
303193242Ssammwl_get_curstat(struct statfoo *sf, int s, char b[], size_t bs)
304193242Ssam{
305193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
306193242Ssam#define	STAT(x) \
307193242Ssam	snprintf(b, bs, "%u", wf->cur.mst_##x - wf->total.mst_##x); return 1
308193242Ssam#define	HWSTAT(x) \
309193242Ssam	snprintf(b, bs, "%u", wf->cur.hw_stats.x - wf->total.hw_stats.x); return 1
310193242Ssam#define	RXANT(x) \
311193242Ssam	snprintf(b, bs, "%u", wf->cur.mst_ant_rx[x] - wf->total.mst_ant_rx[x]); return 1
312193242Ssam#define	TXANT(x) \
313193242Ssam	snprintf(b, bs, "%u", wf->cur.mst_ant_tx[x] - wf->total.mst_ant_tx[x]); return 1
314193242Ssam
315193242Ssam	switch (s) {
316193242Ssam	case S_INPUT:
317193242Ssam		snprintf(b, bs, "%lu", (u_long)(
318193242Ssam		    (wf->cur.mst_rx_packets - wf->total.mst_rx_packets)));
319193242Ssam		return 1;
320193242Ssam	case S_OUTPUT:
321193242Ssam		snprintf(b, bs, "%lu", (u_long)(
322193242Ssam		    wf->cur.mst_tx_packets - wf->total.mst_tx_packets));
323193242Ssam		return 1;
324193242Ssam	case S_RATE:
325193242Ssam		setrate(b, bs, wf->cur.mst_tx_rate);
326193242Ssam		return 1;
327193242Ssam	case S_TX_RETRY:	HWSTAT(TxRetrySuccesses);
328193242Ssam	case S_TX_MRETRY:	HWSTAT(TxMultipleRetrySuccesses);
329193242Ssam	case S_TX_RTSGOOD:	HWSTAT(RTSSuccesses);
330193242Ssam	case S_TX_RTSBAD:	HWSTAT(RTSFailures);
331193242Ssam	case S_TX_NOACK:	HWSTAT(AckFailures);
332193242Ssam	case S_RX_DUPLICATE:	HWSTAT(RxDuplicateFrames);
333193242Ssam	case S_RX_FCS:		HWSTAT(FCSErrorCount);
334193242Ssam	case S_TX_WATCHDOG:	HWSTAT(TxWatchDogTimeouts);
335193242Ssam	case S_RX_OVERFLOW:	HWSTAT(RxOverflows);
336193242Ssam	case S_RX_FRAGERROR:	HWSTAT(RxFragErrors);
337193242Ssam	case S_RX_MEMERROR:	HWSTAT(RxMemErrors);
338193242Ssam	case S_PTRERROR:	HWSTAT(PointerErrors);
339193242Ssam	case S_TX_UNDERFLOW:	HWSTAT(TxUnderflows);
340193242Ssam	case S_TX_DONE:		HWSTAT(TxDone);
341193242Ssam	case S_TX_DONEBUFPUT:	HWSTAT(TxDoneBufPut);
342193242Ssam	case S_TX_WAIT4BUF:	HWSTAT(Wait4TxBuf);
343193242Ssam	case S_TX_ATTEMPTS:	HWSTAT(TxAttempts);
344193242Ssam	case S_TX_SUCCESS:	HWSTAT(TxSuccesses);
345193242Ssam	case S_TX_FRAGS:	HWSTAT(TxFragments);
346193242Ssam	case S_TX_MCAST:	HWSTAT(TxMulticasts);
347193242Ssam	case S_RX_NONCTL:	HWSTAT(RxNonCtlPkts);
348193242Ssam	case S_RX_MCAST:	HWSTAT(RxMulticasts);
349193242Ssam	case S_RX_UNDECRYPT:	HWSTAT(RxUndecryptableFrames);
350193242Ssam	case S_RX_ICVERROR:	HWSTAT(RxICVErrors);
351193242Ssam	case S_RX_EXCLUDE:	HWSTAT(RxExcludedFrames);
352193242Ssam	case S_TX_MGMT:		STAT(tx_mgmt);
353193242Ssam	case S_TX_DISCARD:	STAT(tx_discard);
354193242Ssam	case S_TX_QSTOP:	STAT(tx_qstop);
355193242Ssam	case S_TX_ENCAP:	STAT(tx_encap);
356193242Ssam	case S_TX_NOMBUF:	STAT(tx_nombuf);
357193242Ssam	case S_TX_LINEAR:	STAT(tx_linear);
358193242Ssam	case S_TX_NODATA:	STAT(tx_nodata);
359193242Ssam	case S_TX_BUSDMA:	STAT(tx_busdma);
360193242Ssam	case S_TX_SHORTPRE:	STAT(tx_shortpre);
361193242Ssam	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
362193242Ssam	case S_TX_BADFRAMETYPE:	STAT(tx_badframetype);
363193242Ssam	case S_RX_CRYPTO_ERR:	STAT(rx_crypto);
364193242Ssam	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
365193242Ssam	case S_RX_NODMABUF:	STAT(rx_nodmabuf);
366193242Ssam	case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing);
367193242Ssam	case S_RX_NOMBUF:	STAT(rx_nombuf);
368193242Ssam	case S_RX_BUSDMA:	STAT(rx_busdma);
369193242Ssam	case S_AMPDU_NOSTREAM:	STAT(ampdu_nostream);
370193242Ssam	case S_AMPDU_REJECT:	STAT(ampdu_reject);
371193242Ssam	case S_ADDBA_NOSTREAM:	STAT(addba_nostream);
372193242Ssam	case S_TX_TSO:		STAT(tx_tso);
373193242Ssam	case S_TSO_BADETH:	STAT(tso_badeth);
374193242Ssam	case S_TSO_NOHDR:	STAT(tso_nohdr);
375193242Ssam	case S_TSO_BADSPLIT:	STAT(tso_badsplit);
376193242Ssam	case S_BAWATCHDOG:	STAT(bawatchdog);
377193242Ssam	case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound);
378193242Ssam	case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty);
379193242Ssam	case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed);
380193242Ssam	case S_RADARDETECT:	STAT(radardetect);
381193242Ssam	case S_RX_RSSI:
382193242Ssam		snprintf(b, bs, "%d", wf->cur.mst_rx_rssi);
383193242Ssam		return 1;
384193242Ssam	case S_ANT_TX0:		TXANT(0);
385193242Ssam	case S_ANT_TX1:		TXANT(1);
386193242Ssam	case S_ANT_TX2:		TXANT(2);
387193242Ssam	case S_ANT_TX3:		TXANT(3);
388193242Ssam	case S_ANT_RX0:		RXANT(0);
389193242Ssam	case S_ANT_RX1:		RXANT(1);
390193242Ssam	case S_ANT_RX2:		RXANT(2);
391193242Ssam	case S_ANT_RX3:		RXANT(3);
392193242Ssam	case S_RX_NOISE:
393193242Ssam		snprintf(b, bs, "%d", wf->cur.mst_rx_noise);
394193242Ssam		return 1;
395193242Ssam	case S_RX_SIGNAL:
396193242Ssam		snprintf(b, bs, "%d",
397193242Ssam			wf->cur.mst_rx_rssi + wf->cur.mst_rx_noise);
398193242Ssam		return 1;
399193242Ssam	}
400193242Ssam	b[0] = '\0';
401193242Ssam	return 0;
402193242Ssam#undef RXANT
403193242Ssam#undef TXANT
404193242Ssam#undef HWSTAT
405193242Ssam#undef STAT
406193242Ssam}
407193242Ssam
408193242Ssamstatic int
409193242Ssammwl_get_totstat(struct statfoo *sf, int s, char b[], size_t bs)
410193242Ssam{
411193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
412193242Ssam#define	STAT(x) \
413193242Ssam	snprintf(b, bs, "%u", wf->total.mst_##x); return 1
414193242Ssam#define	HWSTAT(x) \
415193242Ssam	snprintf(b, bs, "%u", wf->total.hw_stats.x); return 1
416193242Ssam#define	TXANT(x) \
417193242Ssam	snprintf(b, bs, "%u", wf->total.mst_ant_tx[x]); return 1
418193242Ssam#define	RXANT(x) \
419193242Ssam	snprintf(b, bs, "%u", wf->total.mst_ant_rx[x]); return 1
420193242Ssam
421193242Ssam	switch (s) {
422193242Ssam	case S_INPUT:
423193242Ssam		snprintf(b, bs, "%lu", (u_long)wf->total.mst_rx_packets);
424193242Ssam		return 1;
425193242Ssam	case S_OUTPUT:
426193242Ssam		snprintf(b, bs, "%lu", (u_long) wf->total.mst_tx_packets);
427193242Ssam		return 1;
428193242Ssam	case S_RATE:
429193242Ssam		setrate(b, bs, wf->total.mst_tx_rate);
430193242Ssam		return 1;
431193242Ssam	case S_TX_RETRY:	HWSTAT(TxRetrySuccesses);
432193242Ssam	case S_TX_MRETRY:	HWSTAT(TxMultipleRetrySuccesses);
433193242Ssam	case S_TX_RTSGOOD:	HWSTAT(RTSSuccesses);
434193242Ssam	case S_TX_RTSBAD:	HWSTAT(RTSFailures);
435193242Ssam	case S_TX_NOACK:	HWSTAT(AckFailures);
436193242Ssam	case S_RX_DUPLICATE:	HWSTAT(RxDuplicateFrames);
437193242Ssam	case S_RX_FCS:		HWSTAT(FCSErrorCount);
438193242Ssam	case S_TX_WATCHDOG:	HWSTAT(TxWatchDogTimeouts);
439193242Ssam	case S_RX_OVERFLOW:	HWSTAT(RxOverflows);
440193242Ssam	case S_RX_FRAGERROR:	HWSTAT(RxFragErrors);
441193242Ssam	case S_RX_MEMERROR:	HWSTAT(RxMemErrors);
442193242Ssam	case S_PTRERROR:	HWSTAT(PointerErrors);
443193242Ssam	case S_TX_UNDERFLOW:	HWSTAT(TxUnderflows);
444193242Ssam	case S_TX_DONE:		HWSTAT(TxDone);
445193242Ssam	case S_TX_DONEBUFPUT:	HWSTAT(TxDoneBufPut);
446193242Ssam	case S_TX_WAIT4BUF:	HWSTAT(Wait4TxBuf);
447193242Ssam	case S_TX_ATTEMPTS:	HWSTAT(TxAttempts);
448193242Ssam	case S_TX_SUCCESS:	HWSTAT(TxSuccesses);
449193242Ssam	case S_TX_FRAGS:	HWSTAT(TxFragments);
450193242Ssam	case S_TX_MCAST:	HWSTAT(TxMulticasts);
451193242Ssam	case S_RX_NONCTL:	HWSTAT(RxNonCtlPkts);
452193242Ssam	case S_RX_MCAST:	HWSTAT(RxMulticasts);
453193242Ssam	case S_RX_UNDECRYPT:	HWSTAT(RxUndecryptableFrames);
454193242Ssam	case S_RX_ICVERROR:	HWSTAT(RxICVErrors);
455193242Ssam	case S_RX_EXCLUDE:	HWSTAT(RxExcludedFrames);
456193242Ssam	case S_TX_MGMT:		STAT(tx_mgmt);
457193242Ssam	case S_TX_DISCARD:	STAT(tx_discard);
458193242Ssam	case S_TX_QSTOP:	STAT(tx_qstop);
459193242Ssam	case S_TX_ENCAP:	STAT(tx_encap);
460193242Ssam	case S_TX_NOMBUF:	STAT(tx_nombuf);
461193242Ssam	case S_TX_LINEAR:	STAT(tx_linear);
462193242Ssam	case S_TX_NODATA:	STAT(tx_nodata);
463193242Ssam	case S_TX_BUSDMA:	STAT(tx_busdma);
464193242Ssam	case S_TX_SHORTPRE:	STAT(tx_shortpre);
465193242Ssam	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
466193242Ssam	case S_TX_BADFRAMETYPE:	STAT(tx_badframetype);
467193242Ssam	case S_RX_CRYPTO_ERR:	STAT(rx_crypto);
468193242Ssam	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
469193242Ssam	case S_RX_NODMABUF:	STAT(rx_nodmabuf);
470193242Ssam	case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing);
471193242Ssam	case S_RX_NOMBUF:	STAT(rx_nombuf);
472193242Ssam	case S_RX_BUSDMA:	STAT(rx_busdma);
473193242Ssam	case S_AMPDU_NOSTREAM:	STAT(ampdu_nostream);
474193242Ssam	case S_AMPDU_REJECT:	STAT(ampdu_reject);
475193242Ssam	case S_ADDBA_NOSTREAM:	STAT(addba_nostream);
476193242Ssam	case S_TX_TSO:		STAT(tx_tso);
477193242Ssam	case S_TSO_BADETH:	STAT(tso_badeth);
478193242Ssam	case S_TSO_NOHDR:	STAT(tso_nohdr);
479193242Ssam	case S_TSO_BADSPLIT:	STAT(tso_badsplit);
480193242Ssam	case S_BAWATCHDOG:	STAT(bawatchdog);
481193242Ssam	case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound);
482193242Ssam	case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty);
483193242Ssam	case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed);
484193242Ssam	case S_RADARDETECT:	STAT(radardetect);
485193242Ssam	case S_RX_RSSI:
486193242Ssam		snprintf(b, bs, "%d", wf->total.mst_rx_rssi);
487193242Ssam		return 1;
488193242Ssam	case S_ANT_TX0:		TXANT(0);
489193242Ssam	case S_ANT_TX1:		TXANT(1);
490193242Ssam	case S_ANT_TX2:		TXANT(2);
491193242Ssam	case S_ANT_TX3:		TXANT(3);
492193242Ssam	case S_ANT_RX0:		RXANT(0);
493193242Ssam	case S_ANT_RX1:		RXANT(1);
494193242Ssam	case S_ANT_RX2:		RXANT(2);
495193242Ssam	case S_ANT_RX3:		RXANT(3);
496193242Ssam	case S_RX_NOISE:
497193242Ssam		snprintf(b, bs, "%d", wf->total.mst_rx_noise);
498193242Ssam		return 1;
499193242Ssam	case S_RX_SIGNAL:
500193242Ssam		snprintf(b, bs, "%d",
501193242Ssam			wf->total.mst_rx_rssi + wf->total.mst_rx_noise);
502193242Ssam		return 1;
503193242Ssam	}
504193242Ssam	b[0] = '\0';
505193242Ssam	return 0;
506193242Ssam#undef RXANT
507193242Ssam#undef TXANT
508193242Ssam#undef HWSTAT
509193242Ssam#undef STAT
510193242Ssam}
511193242Ssam
512193242Ssamstatic void
513193242Ssammwl_print_verbose(struct statfoo *sf, FILE *fd)
514193242Ssam{
515193242Ssam	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
516193242Ssam	const struct fmt *f;
517193242Ssam	char s[32];
518193242Ssam	const char *indent;
519193242Ssam	int i, width;
520193242Ssam
521193242Ssam	width = 0;
522193242Ssam	for (i = 0; i < S_LAST; i++) {
523193242Ssam		f = &sf->stats[i];
524193242Ssam		if (f->width > width)
525193242Ssam			width = f->width;
526193242Ssam	}
527193242Ssam	for (i = 0; i < S_LAST; i++) {
528193242Ssam		f = &sf->stats[i];
529193242Ssam		if (mwl_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) {
530193242Ssam			indent = "";
531193242Ssam			fprintf(fd, "%s%-*s %s\n", indent, width, s, f->desc);
532193242Ssam		}
533193242Ssam	}
534193242Ssam	fprintf(fd, "Antenna profile:\n");
535193242Ssam	for (i = 0; i < 4; i++)
536193242Ssam		if (wf->total.mst_ant_rx[i] || wf->total.mst_ant_tx[i])
537193242Ssam			fprintf(fd, "[%u] tx %8u rx %8u\n", i,
538193242Ssam				wf->total.mst_ant_tx[i],
539193242Ssam				wf->total.mst_ant_rx[i]);
540193242Ssam}
541193242Ssam
542193242SsamSTATFOO_DEFINE_BOUNCE(mwlstatfoo)
543193242Ssam
544193242Ssamstruct mwlstatfoo *
545193242Ssammwlstats_new(const char *ifname, const char *fmtstring)
546193242Ssam{
547193242Ssam#define	N(a)	(sizeof(a) / sizeof(a[0]))
548193242Ssam	struct mwlstatfoo_p *wf;
549193242Ssam
550193242Ssam	wf = calloc(1, sizeof(struct mwlstatfoo_p));
551193242Ssam	if (wf != NULL) {
552193242Ssam		statfoo_init(&wf->base.base, "mwlstats", mwlstats, N(mwlstats));
553193242Ssam		/* override base methods */
554193242Ssam		wf->base.base.collect_cur = mwl_collect_cur;
555193242Ssam		wf->base.base.collect_tot = mwl_collect_tot;
556193242Ssam		wf->base.base.get_curstat = mwl_get_curstat;
557193242Ssam		wf->base.base.get_totstat = mwl_get_totstat;
558193242Ssam		wf->base.base.update_tot = mwl_update_tot;
559193242Ssam		wf->base.base.print_verbose = mwl_print_verbose;
560193242Ssam
561193242Ssam		/* setup bounce functions for public methods */
562193242Ssam		STATFOO_BOUNCE(wf, mwlstatfoo);
563193242Ssam
564193242Ssam		/* setup our public methods */
565193242Ssam		wf->base.setifname = mwl_setifname;
566193242Ssam#if 0
567193242Ssam		wf->base.setstamac = wlan_setstamac;
568193242Ssam#endif
569193242Ssam		wf->s = socket(AF_INET, SOCK_DGRAM, 0);
570193242Ssam		if (wf->s < 0)
571193242Ssam			err(1, "socket");
572193242Ssam
573193242Ssam		mwl_setifname(&wf->base, ifname);
574193242Ssam		wf->base.setfmt(&wf->base, fmtstring);
575193242Ssam	}
576193242Ssam	return &wf->base;
577193242Ssam#undef N
578193242Ssam}
579