xref: /freebsd/tools/tools/mwl/mwlstats/mwlstats.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
1 /*-
2  * Copyright (c) 2007 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * mwl statistics class.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/file.h>
38 #include <sys/ioctl.h>
39 #include <sys/sockio.h>
40 #include <sys/socket.h>
41 
42 #include <net/if.h>
43 #include <net/if_media.h>
44 
45 #include <err.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 
52 #include "../../../../sys/net80211/ieee80211_ioctl.h"
53 #include "../../../../sys/net80211/ieee80211_radiotap.h"
54 
55 /*
56  * Get Hardware Statistics.
57  */
58 struct mwl_hal_hwstats {
59 	uint32_t	TxRetrySuccesses;
60 	uint32_t	TxMultipleRetrySuccesses;
61 	uint32_t	TxFailures;
62 	uint32_t	RTSSuccesses;
63 	uint32_t	RTSFailures;
64 	uint32_t	AckFailures;
65 	uint32_t	RxDuplicateFrames;
66 	uint32_t	FCSErrorCount;
67 	uint32_t	TxWatchDogTimeouts;
68 	uint32_t	RxOverflows;
69 	uint32_t	RxFragErrors;
70 	uint32_t	RxMemErrors;
71 	uint32_t	PointerErrors;
72 	uint32_t	TxUnderflows;
73 	uint32_t	TxDone;
74 	uint32_t	TxDoneBufTryPut;
75 	uint32_t	TxDoneBufPut;
76 	uint32_t	Wait4TxBuf;
77 	uint32_t	TxAttempts;
78 	uint32_t	TxSuccesses;
79 	uint32_t	TxFragments;
80 	uint32_t	TxMulticasts;
81 	uint32_t	RxNonCtlPkts;
82 	uint32_t	RxMulticasts;
83 	uint32_t	RxUndecryptableFrames;
84 	uint32_t 	RxICVErrors;
85 	uint32_t	RxExcludedFrames;
86 };
87 #include "../../../../sys/dev/mwl/if_mwlioctl.h"
88 
89 #include "mwlstats.h"
90 
91 #define	AFTER(prev)	((prev)+1)
92 
93 static const struct fmt mwlstats[] = {
94 #define	S_INPUT		0
95 	{ 8,	"input",	"input",	"total frames received" },
96 #define	S_RX_MCAST	AFTER(S_INPUT)
97 	{ 7,	"rxmcast",	"rxmcast",	"rx multicast frames" },
98 #define	S_RX_NONCTL	AFTER(S_RX_MCAST)
99 	{ 8,	"rxnonctl",	"rxnonctl"	"rx non control frames" },
100 #define	S_RX_MGT	AFTER(S_RX_NONCTL)
101 	{ 5,	"rxmgt",	"rxmgt",	"rx management frames" },
102 #define	S_RX_CTL	AFTER(S_RX_MGT)
103 	{ 5,	"rxctl",	"rxctl",	"rx control frames" },
104 #define	S_OUTPUT	AFTER(S_RX_CTL)
105 	{ 8,	"output",	"output",	"total frames transmit" },
106 #define	S_TX_MCAST	AFTER(S_OUTPUT)
107 	{ 7,	"txmcast",	"txmcast",	"tx multicast frames" },
108 #define	S_TX_MGMT	AFTER(S_TX_MCAST)
109 	{ 5,	"txmgt",	"txmgt",	"tx management frames" },
110 #define	S_TX_RETRY	AFTER(S_TX_MGMT)
111 	{ 7,	"txretry",	"txretry",	"tx success with 1 retry" },
112 #define	S_TX_MRETRY	AFTER(S_TX_RETRY)
113 	{ 8,	"txmretry",	"txmretry",	"tx success with >1 retry" },
114 #define	S_TX_RTSGOOD	AFTER(S_TX_MRETRY)
115 	{ 7,	"rtsgood",	"rtsgood",	"RTS tx success" },
116 #define	S_TX_RTSBAD	AFTER(S_TX_RTSGOOD)
117 	{ 6,	"rtsbad",	"rtsbad",	"RTS tx failed" },
118 #define	S_TX_NOACK	AFTER(S_TX_RTSBAD)
119 	{ 5,	"noack",	"noack",	"tx failed because no ACK was received" },
120 #define	S_RX_DUPLICATE	AFTER(S_TX_NOACK)
121 	{ 5,	"rxdup",	"rxdup",	"rx discarded by f/w as dup" },
122 #define	S_RX_FCS	AFTER(S_RX_DUPLICATE)
123 	{ 5,	"rxfcs",	"rxfcs",	"rx discarded by f/w for bad FCS" },
124 #define	S_TX_WATCHDOG	AFTER(S_RX_FCS)
125 	{ 7,	"txwatch",	"txwatch",	"MAC tx hang (f/w recovery)" },
126 #define	S_RX_OVERFLOW	AFTER(S_TX_WATCHDOG)
127 	{ 6,	"rxover",	"rxover",	"no f/w buffer for rx" },
128 #define	S_RX_FRAGERROR	AFTER(S_RX_OVERFLOW)
129 	{ 6,	"rxfrag",	"rxfrag",	"rx failed in f/w due to defrag" },
130 #define	S_RX_MEMERROR	AFTER(S_RX_FRAGERROR)
131 	{ 5,	"rxmem",	"rxmem",	"rx failed in f/w 'cuz out of of memory" },
132 #define	S_PTRERROR	AFTER(S_RX_MEMERROR)
133 	{ 6,	"badptr",	"badptr",	"MAC internal pointer problem" },
134 #define	S_TX_UNDERFLOW	AFTER(S_PTRERROR)
135 	{ 7,	"txunder",	"txunder",	"tx failed in f/w 'cuz of underflow" },
136 #define	S_TX_DONE	AFTER(S_TX_UNDERFLOW)
137 	{ 6,	"txdone",	"txdone",	"MAC tx ops completed" },
138 #define	S_TX_DONEBUFPUT	AFTER(S_TX_DONE)
139 	{ 9,	"txdoneput",	"txdoneput",	"tx buffers returned by f/w to host" },
140 #define	S_TX_WAIT4BUF	AFTER(S_TX_DONEBUFPUT)
141 	{ 6,	"txwait",	"txwait",	"no f/w buffers available when supplied a tx descriptor" },
142 #define	S_TX_ATTEMPTS	AFTER(S_TX_WAIT4BUF)
143 	{ 5,	"txtry",	"txtry",	"tx descriptors processed by f/w" },
144 #define	S_TX_SUCCESS	AFTER(S_TX_ATTEMPTS)
145 	{ 4,	"txok",		"txok",		"tx attempts successful" },
146 #define	S_TX_FRAGS	AFTER(S_TX_SUCCESS)
147 	{ 6,	"txfrag",	"txfrag",	"tx attempts with fragmentation" },
148 #define	S_RX_UNDECRYPT	AFTER(S_TX_FRAGS)
149 	{ 7,	"rxcrypt",	"rxcrypt",	"rx failed in f/w 'cuz decrypt failed" },
150 #define	S_RX_ICVERROR	AFTER(S_RX_UNDECRYPT)
151 	{ 5,	"rxicv",	"rxicv",	"rx failed in f/w 'cuz ICV check" },
152 #define	S_RX_EXCLUDE	AFTER(S_RX_ICVERROR)
153 	{ 8,	"rxfilter",	"rxfilter",	"rx frames filtered in f/w" },
154 #define	S_TX_LINEAR	AFTER(S_RX_EXCLUDE)
155 	{ 5,	"txlinear",	"txlinear",	"tx linearized to cluster" },
156 #define	S_TX_DISCARD	AFTER(S_TX_LINEAR)
157 	{ 5,	"txdisc",	"txdisc",	"tx frames discarded prior to association" },
158 #define	S_TX_QSTOP	AFTER(S_TX_DISCARD)
159 	{ 5,	"qstop",	"qstop",	"tx stopped 'cuz no xmit buffer" },
160 #define	S_TX_ENCAP	AFTER(S_TX_QSTOP)
161 	{ 5,	"txencode",	"txencode",	"tx encapsulation failed" },
162 #define	S_TX_NOMBUF	AFTER(S_TX_ENCAP)
163 	{ 5,	"txnombuf",	"txnombuf",	"tx failed 'cuz mbuf allocation failed" },
164 #define	S_TX_SHORTPRE	AFTER(S_TX_NOMBUF)
165 	{ 5,	"shpre",	"shpre",	"tx frames with short preamble" },
166 #define	S_TX_NOHEADROOM	AFTER(S_TX_SHORTPRE)
167 	{ 5,	"nohead",	"nohead",	"tx frames discarded for lack of headroom" },
168 #define	S_TX_BADFRAMETYPE	AFTER(S_TX_NOHEADROOM)
169 	{ 5,	"badtxtype",	"badtxtype",	"tx frames discarded for invalid/unknown 802.11 frame type" },
170 #define	S_RX_CRYPTO_ERR	AFTER(S_TX_BADFRAMETYPE)
171 	{ 5,	"crypt",	"crypt",	"rx failed 'cuz decryption" },
172 #define	S_RX_NOMBUF	AFTER(S_RX_CRYPTO_ERR)
173 	{ 5,	"rxnombuf",	"rxnombuf",	"rx setup failed 'cuz no mbuf" },
174 #define	S_RX_TKIPMIC	AFTER(S_RX_NOMBUF)
175 	{ 5,	"rxtkipmic",	"rxtkipmic",	"rx failed 'cuz TKIP MIC error" },
176 #define	S_RX_NODMABUF	AFTER(S_RX_TKIPMIC)
177 	{ 5,	"rxnodmabuf",	"rxnodmabuf",	"rx failed 'cuz no DMA buffer available" },
178 #define	S_RX_DMABUFMISSING	AFTER(S_RX_NODMABUF)
179 	{ 5,	"rxdmabufmissing",	"rxdmabufmissing",	"rx descriptor with no DMA buffer attached" },
180 #define	S_TX_NODATA	AFTER(S_RX_DMABUFMISSING)
181 	{ 5,	"txnodata",	"txnodata",	"tx discarded empty frame" },
182 #define	S_TX_BUSDMA	AFTER(S_TX_NODATA)
183 	{ 5,	"txbusdma",	"txbusdma",	"tx failed for dma resources" },
184 #define	S_RX_BUSDMA	AFTER(S_TX_BUSDMA)
185 	{ 5,	"rxbusdma",	"rxbusdma",	"rx setup failed for dma resources" },
186 #define	S_AMPDU_NOSTREAM	AFTER(S_RX_BUSDMA)
187 	{ 5,	"ampdu_nostream","ampdu_nostream","ADDBA request failed 'cuz all BA streams in use" },
188 #define	S_AMPDU_REJECT	AFTER(S_AMPDU_NOSTREAM)
189 	{ 5,	"ampdu_reject","ampdu_reject","ADDBA request failed 'cuz station already has one BA stream" },
190 #define	S_ADDBA_NOSTREAM	AFTER(S_AMPDU_REJECT)
191 	{ 5,	"addba_nostream","addba_nostream","ADDBA response processed but no BA stream present" },
192 #define	S_TX_TSO	AFTER(S_ADDBA_NOSTREAM)
193 	{ 8,	"txtso",	"tso",		"tx frames using TSO" },
194 #define	S_TSO_BADETH	AFTER(S_TX_TSO)
195 	{ 5,	"tsoeth",	"tsoeth",	"TSO failed 'cuz ether header type not IPv4" },
196 #define	S_TSO_NOHDR	AFTER(S_TSO_BADETH)
197 	{ 5,	"tsonohdr",	"tsonohdr",	"TSO failed 'cuz header not in first mbuf" },
198 #define	S_TSO_BADSPLIT	AFTER(S_TSO_NOHDR)
199 	{ 5,	"tsobadsplit",	"tsobadsplit",	"TSO failed 'cuz payload split failed" },
200 #define	S_BAWATCHDOG	AFTER(S_TSO_BADSPLIT)
201 	{ 5,	"bawatchdog",	"bawatchdog",	"BA watchdog interrupts" },
202 #define	S_BAWATCHDOG_NOTFOUND	AFTER(S_BAWATCHDOG)
203 	{ 5,	"bawatchdog_notfound",	"bawatchdog_notfound",
204 	  "BA watchdog for unknown stream" },
205 #define	S_BAWATCHDOG_EMPTY	AFTER(S_BAWATCHDOG_NOTFOUND)
206 	{ 5,	"bawatchdog_empty",	"bawatchdog_empty",
207 	  "BA watchdog on all streams but none found" },
208 #define	S_BAWATCHDOG_FAILED	AFTER(S_BAWATCHDOG_EMPTY)
209 	{ 5,	"bawatchdog_failed",	"bawatchdog_failed",
210 	  "BA watchdog processing failed to get bitmap from f/w" },
211 #define	S_RADARDETECT	AFTER(S_BAWATCHDOG_FAILED)
212 	{ 5,	"radardetect",	"radardetect",	"radar detect interrupts" },
213 #define	S_RATE		AFTER(S_RADARDETECT)
214 	{ 4,	"rate",		"rate",		"rate of last transmit" },
215 #define	S_TX_RSSI	AFTER(S_RATE)
216 	{ 4,	"arssi",	"arssi",	"rssi of last ack" },
217 #define	S_RX_RSSI	AFTER(S_TX_RSSI)
218 	{ 4,	"rssi",		"rssi",		"avg recv rssi" },
219 #define	S_RX_NOISE	AFTER(S_RX_RSSI)
220 	{ 5,	"noise",	"noise",	"rx noise floor" },
221 #define	S_TX_SIGNAL	AFTER(S_RX_NOISE)
222 	{ 4,	"asignal",	"asig",		"signal of last ack (dBm)" },
223 #define	S_RX_SIGNAL	AFTER(S_TX_SIGNAL)
224 	{ 4,	"signal",	"sig",		"avg recv signal (dBm)" },
225 #define	S_ANT_TX0	AFTER(S_RX_SIGNAL)
226 	{ 8,	"tx0",		"ant0(tx)",	"frames tx on antenna 0" },
227 #define	S_ANT_TX1	(S_RX_SIGNAL+2)
228 	{ 8,	"tx1",		"ant1(tx)",	"frames tx on antenna 1"  },
229 #define	S_ANT_TX2	(S_RX_SIGNAL+3)
230 	{ 8,	"tx2",		"ant2(tx)",	"frames tx on antenna 2"  },
231 #define	S_ANT_TX3	(S_RX_SIGNAL+4)
232 	{ 8,	"tx3",		"ant3(tx)",	"frames tx on antenna 3"  },
233 #define	S_ANT_RX0	AFTER(S_ANT_TX3)
234 	{ 8,	"rx0",		"ant0(rx)",	"frames rx on antenna 0"  },
235 #define	S_ANT_RX1	(S_ANT_TX3+2)
236 	{ 8,	"rx1",		"ant1(rx)",	"frames rx on antenna 1"   },
237 #define	S_ANT_RX2	(S_ANT_TX3+3)
238 	{ 8,	"rx2",		"ant2(rx)",	"frames rx on antenna 2"   },
239 #define	S_ANT_RX3	(S_ANT_TX3+4)
240 	{ 8,	"rx3",		"ant3(rx)",	"frames rx on antenna 3"   },
241 };
242 /* NB: this intentionally avoids per-antenna stats */
243 #define	S_LAST	(S_RX_SIGNAL+1)
244 
245 struct mwlstatfoo_p {
246 	struct mwlstatfoo base;
247 	int s;
248 	struct ifreq ifr;
249 	struct mwl_stats cur;
250 	struct mwl_stats total;
251 };
252 
253 static void
254 mwl_setifname(struct mwlstatfoo *wf0, const char *ifname)
255 {
256 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) wf0;
257 
258 	strncpy(wf->ifr.ifr_name, ifname, sizeof (wf->ifr.ifr_name));
259 }
260 
261 static void
262 mwl_collect(struct mwlstatfoo_p *wf, struct mwl_stats *stats)
263 {
264 	wf->ifr.ifr_data = (caddr_t) stats;
265 	if (ioctl(wf->s, SIOCGMVSTATS, &wf->ifr) < 0)
266 		err(1, "%s: ioctl: %s", __func__, wf->ifr.ifr_name);
267 }
268 
269 static void
270 mwl_collect_cur(struct bsdstat *sf)
271 {
272 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
273 
274 	mwl_collect(wf, &wf->cur);
275 }
276 
277 static void
278 mwl_collect_tot(struct bsdstat *sf)
279 {
280 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
281 
282 	mwl_collect(wf, &wf->total);
283 }
284 
285 static void
286 mwl_update_tot(struct bsdstat *sf)
287 {
288 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
289 
290 	wf->total = wf->cur;
291 }
292 
293 static void
294 setrate(char b[], size_t bs, uint8_t rate)
295 {
296 	if (rate & IEEE80211_RATE_MCS)
297 		snprintf(b, bs, "MCS%u", rate & IEEE80211_RATE_VAL);
298 	else if (rate & 1)
299 		snprintf(b, bs, "%u.5M", rate / 2);
300 	else
301 		snprintf(b, bs, "%uM", rate / 2);
302 }
303 
304 static int
305 mwl_get_curstat(struct bsdstat *sf, int s, char b[], size_t bs)
306 {
307 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
308 #define	STAT(x) \
309 	snprintf(b, bs, "%u", wf->cur.mst_##x - wf->total.mst_##x); return 1
310 #define	HWSTAT(x) \
311 	snprintf(b, bs, "%u", wf->cur.hw_stats.x - wf->total.hw_stats.x); return 1
312 #define	RXANT(x) \
313 	snprintf(b, bs, "%u", wf->cur.mst_ant_rx[x] - wf->total.mst_ant_rx[x]); return 1
314 #define	TXANT(x) \
315 	snprintf(b, bs, "%u", wf->cur.mst_ant_tx[x] - wf->total.mst_ant_tx[x]); return 1
316 
317 	switch (s) {
318 	case S_INPUT:
319 		snprintf(b, bs, "%lu", (u_long)(
320 		    (wf->cur.mst_rx_packets - wf->total.mst_rx_packets)));
321 		return 1;
322 	case S_OUTPUT:
323 		snprintf(b, bs, "%lu", (u_long)(
324 		    wf->cur.mst_tx_packets - wf->total.mst_tx_packets));
325 		return 1;
326 	case S_RATE:
327 		setrate(b, bs, wf->cur.mst_tx_rate);
328 		return 1;
329 	case S_TX_RETRY:	HWSTAT(TxRetrySuccesses);
330 	case S_TX_MRETRY:	HWSTAT(TxMultipleRetrySuccesses);
331 	case S_TX_RTSGOOD:	HWSTAT(RTSSuccesses);
332 	case S_TX_RTSBAD:	HWSTAT(RTSFailures);
333 	case S_TX_NOACK:	HWSTAT(AckFailures);
334 	case S_RX_DUPLICATE:	HWSTAT(RxDuplicateFrames);
335 	case S_RX_FCS:		HWSTAT(FCSErrorCount);
336 	case S_TX_WATCHDOG:	HWSTAT(TxWatchDogTimeouts);
337 	case S_RX_OVERFLOW:	HWSTAT(RxOverflows);
338 	case S_RX_FRAGERROR:	HWSTAT(RxFragErrors);
339 	case S_RX_MEMERROR:	HWSTAT(RxMemErrors);
340 	case S_PTRERROR:	HWSTAT(PointerErrors);
341 	case S_TX_UNDERFLOW:	HWSTAT(TxUnderflows);
342 	case S_TX_DONE:		HWSTAT(TxDone);
343 	case S_TX_DONEBUFPUT:	HWSTAT(TxDoneBufPut);
344 	case S_TX_WAIT4BUF:	HWSTAT(Wait4TxBuf);
345 	case S_TX_ATTEMPTS:	HWSTAT(TxAttempts);
346 	case S_TX_SUCCESS:	HWSTAT(TxSuccesses);
347 	case S_TX_FRAGS:	HWSTAT(TxFragments);
348 	case S_TX_MCAST:	HWSTAT(TxMulticasts);
349 	case S_RX_NONCTL:	HWSTAT(RxNonCtlPkts);
350 	case S_RX_MCAST:	HWSTAT(RxMulticasts);
351 	case S_RX_UNDECRYPT:	HWSTAT(RxUndecryptableFrames);
352 	case S_RX_ICVERROR:	HWSTAT(RxICVErrors);
353 	case S_RX_EXCLUDE:	HWSTAT(RxExcludedFrames);
354 	case S_TX_MGMT:		STAT(tx_mgmt);
355 	case S_TX_DISCARD:	STAT(tx_discard);
356 	case S_TX_QSTOP:	STAT(tx_qstop);
357 	case S_TX_ENCAP:	STAT(tx_encap);
358 	case S_TX_NOMBUF:	STAT(tx_nombuf);
359 	case S_TX_LINEAR:	STAT(tx_linear);
360 	case S_TX_NODATA:	STAT(tx_nodata);
361 	case S_TX_BUSDMA:	STAT(tx_busdma);
362 	case S_TX_SHORTPRE:	STAT(tx_shortpre);
363 	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
364 	case S_TX_BADFRAMETYPE:	STAT(tx_badframetype);
365 	case S_RX_CRYPTO_ERR:	STAT(rx_crypto);
366 	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
367 	case S_RX_NODMABUF:	STAT(rx_nodmabuf);
368 	case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing);
369 	case S_RX_NOMBUF:	STAT(rx_nombuf);
370 	case S_RX_BUSDMA:	STAT(rx_busdma);
371 	case S_AMPDU_NOSTREAM:	STAT(ampdu_nostream);
372 	case S_AMPDU_REJECT:	STAT(ampdu_reject);
373 	case S_ADDBA_NOSTREAM:	STAT(addba_nostream);
374 	case S_TX_TSO:		STAT(tx_tso);
375 	case S_TSO_BADETH:	STAT(tso_badeth);
376 	case S_TSO_NOHDR:	STAT(tso_nohdr);
377 	case S_TSO_BADSPLIT:	STAT(tso_badsplit);
378 	case S_BAWATCHDOG:	STAT(bawatchdog);
379 	case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound);
380 	case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty);
381 	case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed);
382 	case S_RADARDETECT:	STAT(radardetect);
383 	case S_RX_RSSI:
384 		snprintf(b, bs, "%d", wf->cur.mst_rx_rssi);
385 		return 1;
386 	case S_ANT_TX0:		TXANT(0);
387 	case S_ANT_TX1:		TXANT(1);
388 	case S_ANT_TX2:		TXANT(2);
389 	case S_ANT_TX3:		TXANT(3);
390 	case S_ANT_RX0:		RXANT(0);
391 	case S_ANT_RX1:		RXANT(1);
392 	case S_ANT_RX2:		RXANT(2);
393 	case S_ANT_RX3:		RXANT(3);
394 	case S_RX_NOISE:
395 		snprintf(b, bs, "%d", wf->cur.mst_rx_noise);
396 		return 1;
397 	case S_RX_SIGNAL:
398 		snprintf(b, bs, "%d",
399 			wf->cur.mst_rx_rssi + wf->cur.mst_rx_noise);
400 		return 1;
401 	}
402 	b[0] = '\0';
403 	return 0;
404 #undef RXANT
405 #undef TXANT
406 #undef HWSTAT
407 #undef STAT
408 }
409 
410 static int
411 mwl_get_totstat(struct bsdstat *sf, int s, char b[], size_t bs)
412 {
413 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
414 #define	STAT(x) \
415 	snprintf(b, bs, "%u", wf->total.mst_##x); return 1
416 #define	HWSTAT(x) \
417 	snprintf(b, bs, "%u", wf->total.hw_stats.x); return 1
418 #define	TXANT(x) \
419 	snprintf(b, bs, "%u", wf->total.mst_ant_tx[x]); return 1
420 #define	RXANT(x) \
421 	snprintf(b, bs, "%u", wf->total.mst_ant_rx[x]); return 1
422 
423 	switch (s) {
424 	case S_INPUT:
425 		snprintf(b, bs, "%lu", (u_long)wf->total.mst_rx_packets);
426 		return 1;
427 	case S_OUTPUT:
428 		snprintf(b, bs, "%lu", (u_long) wf->total.mst_tx_packets);
429 		return 1;
430 	case S_RATE:
431 		setrate(b, bs, wf->total.mst_tx_rate);
432 		return 1;
433 	case S_TX_RETRY:	HWSTAT(TxRetrySuccesses);
434 	case S_TX_MRETRY:	HWSTAT(TxMultipleRetrySuccesses);
435 	case S_TX_RTSGOOD:	HWSTAT(RTSSuccesses);
436 	case S_TX_RTSBAD:	HWSTAT(RTSFailures);
437 	case S_TX_NOACK:	HWSTAT(AckFailures);
438 	case S_RX_DUPLICATE:	HWSTAT(RxDuplicateFrames);
439 	case S_RX_FCS:		HWSTAT(FCSErrorCount);
440 	case S_TX_WATCHDOG:	HWSTAT(TxWatchDogTimeouts);
441 	case S_RX_OVERFLOW:	HWSTAT(RxOverflows);
442 	case S_RX_FRAGERROR:	HWSTAT(RxFragErrors);
443 	case S_RX_MEMERROR:	HWSTAT(RxMemErrors);
444 	case S_PTRERROR:	HWSTAT(PointerErrors);
445 	case S_TX_UNDERFLOW:	HWSTAT(TxUnderflows);
446 	case S_TX_DONE:		HWSTAT(TxDone);
447 	case S_TX_DONEBUFPUT:	HWSTAT(TxDoneBufPut);
448 	case S_TX_WAIT4BUF:	HWSTAT(Wait4TxBuf);
449 	case S_TX_ATTEMPTS:	HWSTAT(TxAttempts);
450 	case S_TX_SUCCESS:	HWSTAT(TxSuccesses);
451 	case S_TX_FRAGS:	HWSTAT(TxFragments);
452 	case S_TX_MCAST:	HWSTAT(TxMulticasts);
453 	case S_RX_NONCTL:	HWSTAT(RxNonCtlPkts);
454 	case S_RX_MCAST:	HWSTAT(RxMulticasts);
455 	case S_RX_UNDECRYPT:	HWSTAT(RxUndecryptableFrames);
456 	case S_RX_ICVERROR:	HWSTAT(RxICVErrors);
457 	case S_RX_EXCLUDE:	HWSTAT(RxExcludedFrames);
458 	case S_TX_MGMT:		STAT(tx_mgmt);
459 	case S_TX_DISCARD:	STAT(tx_discard);
460 	case S_TX_QSTOP:	STAT(tx_qstop);
461 	case S_TX_ENCAP:	STAT(tx_encap);
462 	case S_TX_NOMBUF:	STAT(tx_nombuf);
463 	case S_TX_LINEAR:	STAT(tx_linear);
464 	case S_TX_NODATA:	STAT(tx_nodata);
465 	case S_TX_BUSDMA:	STAT(tx_busdma);
466 	case S_TX_SHORTPRE:	STAT(tx_shortpre);
467 	case S_TX_NOHEADROOM:	STAT(tx_noheadroom);
468 	case S_TX_BADFRAMETYPE:	STAT(tx_badframetype);
469 	case S_RX_CRYPTO_ERR:	STAT(rx_crypto);
470 	case S_RX_TKIPMIC:	STAT(rx_tkipmic);
471 	case S_RX_NODMABUF:	STAT(rx_nodmabuf);
472 	case S_RX_DMABUFMISSING:STAT(rx_dmabufmissing);
473 	case S_RX_NOMBUF:	STAT(rx_nombuf);
474 	case S_RX_BUSDMA:	STAT(rx_busdma);
475 	case S_AMPDU_NOSTREAM:	STAT(ampdu_nostream);
476 	case S_AMPDU_REJECT:	STAT(ampdu_reject);
477 	case S_ADDBA_NOSTREAM:	STAT(addba_nostream);
478 	case S_TX_TSO:		STAT(tx_tso);
479 	case S_TSO_BADETH:	STAT(tso_badeth);
480 	case S_TSO_NOHDR:	STAT(tso_nohdr);
481 	case S_TSO_BADSPLIT:	STAT(tso_badsplit);
482 	case S_BAWATCHDOG:	STAT(bawatchdog);
483 	case S_BAWATCHDOG_NOTFOUND:STAT(bawatchdog_notfound);
484 	case S_BAWATCHDOG_EMPTY: STAT(bawatchdog_empty);
485 	case S_BAWATCHDOG_FAILED:STAT(bawatchdog_failed);
486 	case S_RADARDETECT:	STAT(radardetect);
487 	case S_RX_RSSI:
488 		snprintf(b, bs, "%d", wf->total.mst_rx_rssi);
489 		return 1;
490 	case S_ANT_TX0:		TXANT(0);
491 	case S_ANT_TX1:		TXANT(1);
492 	case S_ANT_TX2:		TXANT(2);
493 	case S_ANT_TX3:		TXANT(3);
494 	case S_ANT_RX0:		RXANT(0);
495 	case S_ANT_RX1:		RXANT(1);
496 	case S_ANT_RX2:		RXANT(2);
497 	case S_ANT_RX3:		RXANT(3);
498 	case S_RX_NOISE:
499 		snprintf(b, bs, "%d", wf->total.mst_rx_noise);
500 		return 1;
501 	case S_RX_SIGNAL:
502 		snprintf(b, bs, "%d",
503 			wf->total.mst_rx_rssi + wf->total.mst_rx_noise);
504 		return 1;
505 	}
506 	b[0] = '\0';
507 	return 0;
508 #undef RXANT
509 #undef TXANT
510 #undef HWSTAT
511 #undef STAT
512 }
513 
514 static void
515 mwl_print_verbose(struct bsdstat *sf, FILE *fd)
516 {
517 	struct mwlstatfoo_p *wf = (struct mwlstatfoo_p *) sf;
518 	const struct fmt *f;
519 	char s[32];
520 	const char *indent;
521 	int i, width;
522 
523 	width = 0;
524 	for (i = 0; i < S_LAST; i++) {
525 		f = &sf->stats[i];
526 		if (f->width > width)
527 			width = f->width;
528 	}
529 	for (i = 0; i < S_LAST; i++) {
530 		f = &sf->stats[i];
531 		if (mwl_get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0")) {
532 			indent = "";
533 			fprintf(fd, "%s%-*s %s\n", indent, width, s, f->desc);
534 		}
535 	}
536 	fprintf(fd, "Antenna profile:\n");
537 	for (i = 0; i < 4; i++)
538 		if (wf->total.mst_ant_rx[i] || wf->total.mst_ant_tx[i])
539 			fprintf(fd, "[%u] tx %8u rx %8u\n", i,
540 				wf->total.mst_ant_tx[i],
541 				wf->total.mst_ant_rx[i]);
542 }
543 
544 BSDSTAT_DEFINE_BOUNCE(mwlstatfoo)
545 
546 struct mwlstatfoo *
547 mwlstats_new(const char *ifname, const char *fmtstring)
548 {
549 	struct mwlstatfoo_p *wf;
550 
551 	wf = calloc(1, sizeof(struct mwlstatfoo_p));
552 	if (wf != NULL) {
553 		bsdstat_init(&wf->base.base, "mwlstats", mwlstats,
554 		    nitems(mwlstats));
555 		/* override base methods */
556 		wf->base.base.collect_cur = mwl_collect_cur;
557 		wf->base.base.collect_tot = mwl_collect_tot;
558 		wf->base.base.get_curstat = mwl_get_curstat;
559 		wf->base.base.get_totstat = mwl_get_totstat;
560 		wf->base.base.update_tot = mwl_update_tot;
561 		wf->base.base.print_verbose = mwl_print_verbose;
562 
563 		/* setup bounce functions for public methods */
564 		BSDSTAT_BOUNCE(wf, mwlstatfoo);
565 
566 		/* setup our public methods */
567 		wf->base.setifname = mwl_setifname;
568 #if 0
569 		wf->base.setstamac = wlan_setstamac;
570 #endif
571 		wf->s = socket(AF_INET, SOCK_DGRAM, 0);
572 		if (wf->s < 0)
573 			err(1, "socket");
574 
575 		mwl_setifname(&wf->base, ifname);
576 		wf->base.setfmt(&wf->base, fmtstring);
577 	}
578 	return &wf->base;
579 }
580