]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/ath/athani/main.c
MFS r365608:
[FreeBSD/FreeBSD.git] / tools / tools / ath / athani / main.c
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.mrcCckOff);
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 }