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