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