xref: /freebsd/tools/tools/ath/athani/main.c (revision 2f513db7)
1 /*-
2  * Copyright (c) 2019 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 #include "diag.h"
32 
33 #include "ah.h"
34 #include "ah_internal.h"
35 
36 #include <getopt.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <err.h>
41 
42 #include "../common/ctrl.h"
43 
44 /*
45  * This is a simple wrapper program around the ANI diagnostic interface.
46  * It is for fetching and setting the live ANI configuration when trying
47  * to diagnose a noisy environment.
48  */
49 
50 /*
51  * HAL_DIAG_ANI_CMD is used to set the ANI configuration.
52  * HAL_DIAG_ANI_CURRENT is used to fetch the current ANI configuration.
53  */
54 
55 struct ani_var {
56   const char *name;
57   int id;
58 };
59 
60 static struct ani_var ani_labels[] = {
61   { "ofdm_noise_immunity_level", 1, },
62   { "noise_immunity_level", 1, },
63   { "ofdm_weak_signal_detect", 2, },
64   { "cck_weak_signal_threshold", 3, },
65   { "firstep_level", 4, },
66   { "spur_immunity_level", 5, },
67   { "mrc_cck", 8, },
68   { "cck_noise_immunity_level", 9, },
69   { NULL, -1, },
70 };
71 
72 static void
73 usage(void)
74 {
75 	fprintf(stderr, "usage: athani [-i interface] [-l]\n");
76 	fprintf(stderr, "    -i: interface\n");
77 	fprintf(stderr, "    -l: list ANI labels\n");
78 	fprintf(stderr, "  If no args are given after flags, the ANI state will be listed.\n");
79 	fprintf(stderr, "  To set, use '<label> <value>' to set the state\n");
80 	exit(-1);
81 }
82 
83 static void
84 list_labels(void)
85 {
86 	int i;
87 
88 	for (i = 0; ani_labels[i].name != NULL; i++) {
89 		printf("%s (%d)\n", ani_labels[i].name, ani_labels[i].id);
90 	}
91 }
92 
93 static int
94 ani_write_state(struct ath_driver_req *req, const char *ifname,
95   const char *label, const char *value)
96 {
97 	struct ath_diag atd;
98 	uint32_t args[2];
99 	uint32_t cmd, val;
100 	size_t sl;
101 	int i;
102 
103 	/* Find the label */
104 	sl = strlen(label);
105 	for (i = 0; ani_labels[i].name != NULL; i++) {
106 		if ((strlen(ani_labels[i].name) == sl) &&
107 		    (strcmp(label, ani_labels[i].name) == 0)) {
108 			cmd = ani_labels[i].id;
109 			break;
110 		}
111 	}
112 	if (ani_labels[i].name == NULL) {
113 		fprintf(stderr, "%s: couldn't find ANI label (%s)\n",
114 		    __func__, label);
115 		return (-1);
116 	}
117 
118 	val = strtoul(value, NULL, 0);
119 
120 	/*
121 	 * Whilst we're doing the ath_diag pieces, we have to set this
122 	 * ourselves.
123 	 */
124 	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
125 
126 	/*
127 	 * Populate HAL_DIAG_ANI_CMD fields.
128 	 */
129 	args[0] = cmd;
130 	args[1] = val;
131 
132 	atd.ad_id = HAL_DIAG_ANI_CMD | ATH_DIAG_IN;
133 	atd.ad_out_data = NULL;
134 	atd.ad_out_size = 0;
135 	atd.ad_in_data = (void *) &args;
136 	atd.ad_in_size = sizeof(args);
137 
138 	if (ath_driver_req_fetch_diag(req, SIOCGATHDIAG, &atd) < 0) {
139 		warn("SIOCGATHDIAG HAL_DIAG_ANI_CMD (%s)", atd.ad_name);
140 		return (-1);
141 	}
142 
143 	return (0);
144 }
145 
146 static void
147 ani_read_state(struct ath_driver_req *req, const char *ifname)
148 {
149 	struct ath_diag atd;
150 	HAL_ANI_STATE state;
151 
152 	/*
153 	 * Whilst we're doing the ath_diag pieces, we have to set this
154 	 * ourselves.
155 	 */
156 	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
157 
158 	atd.ad_id = HAL_DIAG_ANI_CURRENT; /* XXX | DIAG_DYN? */
159 	atd.ad_out_data = (caddr_t) &state;
160 	atd.ad_out_size = sizeof(state);
161 
162 	if (ath_driver_req_fetch_diag(req, SIOCGATHDIAG, &atd) < 0)
163 		err(1, "%s", atd.ad_name);
164 
165 
166 	printf("  ofdm_noise_immunity_level=%d\n", state.noiseImmunityLevel);
167 	printf("  cck_noise_immunity_level=%d\n", state.cckNoiseImmunityLevel);
168 	printf("  spur_immunity_level=%d\n", state.spurImmunityLevel);
169 	printf("  firstep_level=%d\n", state.firstepLevel);
170 	printf("  ofdm_weak_signal_detect=%d\n", state.ofdmWeakSigDetectOff);
171 	printf("  cck_weak_signal_threshold=%d\n", state.cckWeakSigThreshold);
172 	printf("  mrc_cck=%d\n", state.mrcCck);
173 	/* XXX TODO: cycle counts? */
174 }
175 
176 int
177 main(int argc, char *argv[])
178 {
179 	struct ath_diag atd;
180 	const char *ifname;
181 	struct ath_driver_req req;
182 	int what, c;
183 
184 	ath_driver_req_init(&req);
185 
186 	ifname = getenv("ATH");
187 	if (!ifname)
188 		ifname = ATH_DEFAULT;
189 
190 	what = 0;
191 	while ((c = getopt(argc, argv, "i:l")) != -1)
192 		switch (c) {
193 		case 'i':
194 			ifname = optarg;
195 			break;
196 		case 'l':
197 			list_labels();
198 			exit(0);
199 		default:
200 			usage();
201 			/*NOTREACHED*/
202 		}
203 
204 	/* Initialise the driver interface */
205 	if (ath_driver_req_open(&req, ifname) < 0) {
206 		exit(127);
207 	}
208 
209 	argc -= optind;
210 	argv += optind;
211 
212 	if (argc == 0) {
213 		ani_read_state(&req, ifname);
214 		exit(0);
215 	}
216 
217 	if (argc < 2) {
218 		usage();
219 		/*NOTREACHED*/
220 	}
221 
222 	if (ani_write_state(&req, ifname, argv[0], argv[1]) != 0)
223 		exit(1);
224 
225 	exit(0);
226 }
227