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