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