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