1 /*-
2 * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.org>
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 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <err.h>
38 #include <net/if.h>
39 #include <sys/endian.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/sysctl.h>
43
44 #include "net80211/ieee80211_ioctl.h"
45 #include "net80211/ieee80211_radiotap.h"
46
47 #include "if_iwn_ioctl.h"
48 #include "if_iwnreg.h"
49 #include "iwnstats.h"
50 #include "iwn_ioctl.h"
51
52 #define IWN_DEFAULT_IF "iwn0"
53
54 static struct iwnstats *
iwnstats_new(const char * ifname)55 iwnstats_new(const char *ifname)
56 {
57 struct iwnstats *is;
58 char buf[128];
59
60 is = calloc(1, sizeof(struct iwnstats));
61 if (is == NULL)
62 return (NULL);
63
64 snprintf(buf, sizeof(buf), "/dev/%s", ifname);
65 is->s = open(buf, O_RDWR);
66 if (is->s < 0)
67 err(1, "open");
68
69 return (is);
70 }
71
72 static void
iwn_stats_phy_print(struct iwn_rx_phy_stats * rxphy,const char * prefix)73 iwn_stats_phy_print(struct iwn_rx_phy_stats *rxphy, const char *prefix)
74 {
75
76 printf("%s: %s: ina=%d, fina=%d, bad_plcp=%d, bad_crc32=%d, overrun=%d, eoverrun=%d\n",
77 __func__,
78 prefix,
79 le32toh(rxphy->ina),
80 le32toh(rxphy->fina),
81 le32toh(rxphy->bad_plcp),
82 le32toh(rxphy->bad_crc32),
83 le32toh(rxphy->overrun),
84 le32toh(rxphy->eoverrun));
85
86 printf("%s: %s: fa=%d, bad_fina_sync=%d, sfd_timeout=%d, fina_timeout=%d, no_rts_ack=%d\n",
87 __func__,
88 prefix,
89 le32toh(rxphy->fa),
90 le32toh(rxphy->bad_fina_sync),
91 le32toh(rxphy->sfd_timeout),
92 le32toh(rxphy->fina_timeout),
93 le32toh(rxphy->no_rts_ack));
94
95 printf("%s: %s: rxe_limit=%d, ack=%d, cts=%d, ba_resp=%d, dsp_kill=%d, bad_mh=%d, rssi_sum=%d\n",
96 __func__,
97 prefix,
98 le32toh(rxphy->rxe_limit),
99 le32toh(rxphy->ack),
100 le32toh(rxphy->cts),
101 le32toh(rxphy->ba_resp),
102 le32toh(rxphy->dsp_kill),
103 le32toh(rxphy->bad_mh),
104 le32toh(rxphy->rssi_sum));
105 }
106
107 static void
iwn_stats_rx_general_print(struct iwn_rx_general_stats * g)108 iwn_stats_rx_general_print(struct iwn_rx_general_stats *g)
109 {
110
111 printf("%s: bad_cts=%d, bad_ack=%d, not_bss=%d, filtered=%d, bad_chan=%d, beacons=%d\n",
112 __func__,
113 le32toh(g->bad_cts),
114 le32toh(g->bad_ack),
115 le32toh(g->not_bss),
116 le32toh(g->filtered),
117 le32toh(g->bad_chan),
118 le32toh(g->beacons));
119
120 /* XXX it'd be nice to have adc/ina saturated as a % of time */
121 printf("%s: missed_beacons=%d, adc_saturated=%d, ina_searched=%d\n",
122 __func__,
123 le32toh(g->missed_beacons),
124 le32toh(g->adc_saturated),
125 le32toh(g->ina_searched));
126
127 printf("%s: noise=[%d, %d, %d] flags=0x%08x, load=%d, fa=%d\n",
128 __func__,
129 le32toh(g->noise[0]),
130 le32toh(g->noise[1]),
131 le32toh(g->noise[2]),
132 le32toh(g->flags),
133 le32toh(g->load),
134 le32toh(g->fa));
135
136 printf("%s: rssi=[%d, %d, %d] energy=[%d %d %d]\n",
137 __func__,
138 le32toh(g->rssi[0]),
139 le32toh(g->rssi[1]),
140 le32toh(g->rssi[2]),
141 le32toh(g->energy[0]),
142 le32toh(g->energy[1]),
143 le32toh(g->energy[2]));
144 }
145
146 static void
iwn_stats_tx_print(struct iwn_tx_stats * tx)147 iwn_stats_tx_print(struct iwn_tx_stats *tx)
148 {
149
150 printf("%s: preamble=%d, rx_detected=%d, bt_defer=%d, bt_kill=%d, short_len=%d\n",
151 __func__,
152 le32toh(tx->preamble),
153 le32toh(tx->rx_detected),
154 le32toh(tx->bt_defer),
155 le32toh(tx->bt_kill),
156 le32toh(tx->short_len));
157
158 printf("%s: cts_timeout=%d, ack_timeout=%d, exp_ack=%d, ack=%d, msdu=%d\n",
159 __func__,
160 le32toh(tx->cts_timeout),
161 le32toh(tx->ack_timeout),
162 le32toh(tx->exp_ack),
163 le32toh(tx->ack),
164 le32toh(tx->msdu));
165
166 printf("%s: burst_err1=%d, burst_err2=%d, cts_collision=%d, ack_collision=%d\n",
167 __func__,
168 le32toh(tx->burst_err1),
169 le32toh(tx->burst_err2),
170 le32toh(tx->cts_collision),
171 le32toh(tx->ack_collision));
172
173 printf("%s: ba_timeout=%d, ba_resched=%d, query_ampdu=%d, query=%d, query_ampdu_frag=%d\n",
174 __func__,
175 le32toh(tx->ba_timeout),
176 le32toh(tx->ba_resched),
177 le32toh(tx->query_ampdu),
178 le32toh(tx->query),
179 le32toh(tx->query_ampdu_frag));
180
181 printf("%s: query_mismatch=%d, not_ready=%d, underrun=%d, bt_ht_kill=%d, rx_ba_resp=%d\n",
182 __func__,
183 le32toh(tx->query_mismatch),
184 le32toh(tx->not_ready),
185 le32toh(tx->underrun),
186 le32toh(tx->bt_ht_kill),
187 le32toh(tx->rx_ba_resp));
188 }
189
190 static void
iwn_stats_ht_phy_print(struct iwn_rx_ht_phy_stats * ht)191 iwn_stats_ht_phy_print(struct iwn_rx_ht_phy_stats *ht)
192 {
193
194 printf("%s: bad_plcp=%d, overrun=%d, eoverrun=%d, good_crc32=%d, bad_crc32=%d\n",
195 __func__,
196 le32toh(ht->bad_plcp),
197 le32toh(ht->overrun),
198 le32toh(ht->eoverrun),
199 le32toh(ht->good_crc32),
200 le32toh(ht->bad_crc32));
201
202 printf("%s: bad_mh=%d, good_ampdu_crc32=%d, ampdu=%d, fragment=%d\n",
203 __func__,
204 le32toh(ht->bad_plcp),
205 le32toh(ht->good_ampdu_crc32),
206 le32toh(ht->ampdu),
207 le32toh(ht->fragment));
208 }
209
210
211 static void
iwn_stats_general_print(struct iwn_stats * stats)212 iwn_stats_general_print(struct iwn_stats *stats)
213 {
214
215 /* General */
216 printf("%s: temp=%d, temp_m=%d, burst_check=%d, burst=%d, sleep=%d, slot_out=%d, slot_idle=%d\n",
217 __func__,
218 le32toh(stats->general.temp),
219 le32toh(stats->general.temp_m),
220 le32toh(stats->general.burst_check),
221 le32toh(stats->general.burst),
222 le32toh(stats->general.sleep),
223 le32toh(stats->general.slot_out),
224 le32toh(stats->general.slot_idle));
225 printf("%s: slot_out=%d, ttl_tstamp=0x%08x, tx_ant_a=%d, tx_ant_b=%d, exec=%d, probe=%d\n",
226 __func__,
227 le32toh(stats->general.slot_out),
228 le32toh(stats->general.ttl_tstamp),
229 le32toh(stats->general.tx_ant_a),
230 le32toh(stats->general.tx_ant_b),
231 le32toh(stats->general.exec),
232 le32toh(stats->general.probe));
233 printf("%s: rx_enabled=%d\n",
234 __func__,
235 le32toh(stats->general.rx_enabled));
236 }
237
238 static void
iwn_print(struct iwnstats * is)239 iwn_print(struct iwnstats *is)
240 {
241 struct iwn_stats *s;
242 struct timeval tv;
243
244 s = &is->st;
245
246 gettimeofday(&tv, NULL);
247 printf("time=%ld.%.6ld\n", (long)tv.tv_sec, (long)tv.tv_usec);
248
249 iwn_stats_general_print(s);
250
251 /* RX */
252 iwn_stats_phy_print(&s->rx.ofdm, "ofdm");
253 iwn_stats_phy_print(&s->rx.cck, "cck");
254 iwn_stats_ht_phy_print(&s->rx.ht);
255 iwn_stats_rx_general_print(&s->rx.general);
256
257 /* TX */
258 iwn_stats_tx_print(&s->tx);
259 printf("--\n");
260 }
261
262 static void
usage(void)263 usage(void)
264 {
265 printf("Usage: iwnstats [-h] [-i ifname]\n");
266 printf(" -h: Help\n");
267 printf(" -i <ifname>: Use ifname (default %s)\n",
268 IWN_DEFAULT_IF);
269 }
270
271 int
main(int argc,char * argv[])272 main(int argc, char *argv[])
273 {
274 struct iwnstats *is;
275 int ch;
276 char *ifname;
277 bool first;
278
279 ifname = strdup(IWN_DEFAULT_IF);
280
281 /* Parse command line arguments */
282 while ((ch = getopt(argc, argv,
283 "hi:")) != -1) {
284 switch (ch) {
285 case 'i':
286 if (ifname)
287 free(ifname);
288 ifname = strdup(optarg);
289 break;
290 default:
291 case '?':
292 case 'h':
293 usage();
294 exit(1);
295 }
296 }
297
298 is = iwnstats_new(ifname);
299
300 if (is == NULL) {
301 fprintf(stderr, "%s: couldn't allocate new stats structure\n",
302 argv[0]);
303 exit(127);
304 }
305
306 /* begin fetching data */
307 first = true;
308 while (1) {
309 if (iwn_collect(is) != 0) {
310 fprintf(stderr, "%s: fetch failed\n", argv[0]);
311 if (first)
312 return 1;
313 goto next;
314 }
315
316 iwn_print(is);
317
318 next:
319 usleep(100 * 1000);
320 first = false;
321 }
322
323 exit(0);
324 }
325