[athani] Add a simple tool to list and control ANI parameters.
This is a WIP tool I'm using to figure out why ANI is weirdly busted in my home FreeBSD AP/STA setup. Although athstats (mostly) gets the ANI statistics correct, ANI is making the radio deaf it doesn't recover without being disabled. It's very WIP. Tested: * Carambola 2, (AR9331), AP/STA mode.
This commit is contained in:
parent
7fbcfe69e7
commit
28adfbfe13
@ -3,6 +3,6 @@
|
||||
SUBDIR= arcode athdebug athdecode athkey athpoke athprom athrd athregs athalq
|
||||
SUBDIR+= athstats ath_prom_read athradar athaggrstats
|
||||
SUBDIR+= ath_ee_v14_print ath_ee_v4k_print ath_ee_9287_print ath_ee_9300_print
|
||||
SUBDIR+= athsurvey athratestats athspectral
|
||||
SUBDIR+= athsurvey athratestats athspectral athani
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
23
tools/tools/ath/athani/Makefile
Normal file
23
tools/tools/ath/athani/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= athani
|
||||
MAN=
|
||||
|
||||
CFLAGS+= -I../../../../sys/contrib
|
||||
|
||||
SRCS= main.c
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/../common/
|
||||
.PATH.c: ${.CURDIR}/../common/
|
||||
SRCS+= ctrl.c
|
||||
|
||||
CLEANFILES+= opt_ah.h
|
||||
|
||||
opt_ah.h:
|
||||
echo "#define AH_DEBUG 1" > opt_ah.h
|
||||
echo "#define AH_DEBUG_COUNTRY 1" >> opt_ah.h
|
||||
echo "#define AH_SUPPORT_AR5416 1" >> opt_ah.h
|
||||
|
||||
.include <bsd.prog.mk>
|
226
tools/tools/ath/athani/main.c
Normal file
226
tools/tools/ath/athani/main.c
Normal file
@ -0,0 +1,226 @@
|
||||
/*-
|
||||
* Copyright (c) 2019 Adrian Chadd <adrian@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include "diag.h"
|
||||
|
||||
#include "ah.h"
|
||||
#include "ah_internal.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "../common/ctrl.h"
|
||||
|
||||
/*
|
||||
* This is a simple wrapper program around the ANI diagnostic interface.
|
||||
* It is for fetching and setting the live ANI configuration when trying
|
||||
* to diagnose a noisy environment.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HAL_DIAG_ANI_CMD is used to set the ANI configuration.
|
||||
* HAL_DIAG_ANI_CURRENT is used to fetch the current ANI configuration.
|
||||
*/
|
||||
|
||||
struct ani_var {
|
||||
const char *name;
|
||||
int id;
|
||||
};
|
||||
|
||||
static struct ani_var ani_labels[] = {
|
||||
{ "ofdm_noise_immunity_level", 1, },
|
||||
{ "noise_immunity_level", 1, },
|
||||
{ "ofdm_weak_signal_detect", 2, },
|
||||
{ "cck_weak_signal_threshold", 3, },
|
||||
{ "firstep_level", 4, },
|
||||
{ "spur_immunity_level", 5, },
|
||||
{ "mrc_cck", 8, },
|
||||
{ "cck_noise_immunity_level", 9, },
|
||||
{ NULL, -1, },
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: athani [-i interface] [-l]\n");
|
||||
fprintf(stderr, " -i: interface\n");
|
||||
fprintf(stderr, " -l: list ANI labels\n");
|
||||
fprintf(stderr, " If no args are given after flags, the ANI state will be listed.\n");
|
||||
fprintf(stderr, " To set, use '<label> <value>' to set the state\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void
|
||||
list_labels(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ani_labels[i].name != NULL; i++) {
|
||||
printf("%s (%d)\n", ani_labels[i].name, ani_labels[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ani_write_state(struct ath_driver_req *req, const char *ifname,
|
||||
const char *label, const char *value)
|
||||
{
|
||||
struct ath_diag atd;
|
||||
uint32_t args[2];
|
||||
uint32_t cmd, val;
|
||||
size_t sl;
|
||||
int i;
|
||||
|
||||
/* Find the label */
|
||||
sl = strlen(label);
|
||||
for (i = 0; ani_labels[i].name != NULL; i++) {
|
||||
if ((strlen(ani_labels[i].name) == sl) &&
|
||||
(strcmp(label, ani_labels[i].name) == 0)) {
|
||||
cmd = ani_labels[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ani_labels[i].name == NULL) {
|
||||
fprintf(stderr, "%s: couldn't find ANI label (%s)\n",
|
||||
__func__, label);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
val = strtoul(value, NULL, 0);
|
||||
|
||||
/*
|
||||
* Whilst we're doing the ath_diag pieces, we have to set this
|
||||
* ourselves.
|
||||
*/
|
||||
strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
|
||||
|
||||
/*
|
||||
* Populate HAL_DIAG_ANI_CMD fields.
|
||||
*/
|
||||
args[0] = cmd;
|
||||
args[1] = val;
|
||||
|
||||
atd.ad_id = HAL_DIAG_ANI_CMD | ATH_DIAG_IN;
|
||||
atd.ad_out_data = NULL;
|
||||
atd.ad_out_size = 0;
|
||||
atd.ad_in_data = (void *) &args;
|
||||
atd.ad_in_size = sizeof(args);
|
||||
|
||||
if (ath_driver_req_fetch_diag(req, SIOCGATHDIAG, &atd) < 0) {
|
||||
warn("SIOCGATHDIAG HAL_DIAG_ANI_CMD (%s)", atd.ad_name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ani_read_state(struct ath_driver_req *req, const char *ifname)
|
||||
{
|
||||
struct ath_diag atd;
|
||||
HAL_ANI_STATE state;
|
||||
|
||||
/*
|
||||
* Whilst we're doing the ath_diag pieces, we have to set this
|
||||
* ourselves.
|
||||
*/
|
||||
strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
|
||||
|
||||
atd.ad_id = HAL_DIAG_ANI_CURRENT; /* XXX | DIAG_DYN? */
|
||||
atd.ad_out_data = (caddr_t) &state;
|
||||
atd.ad_out_size = sizeof(state);
|
||||
|
||||
if (ath_driver_req_fetch_diag(req, SIOCGATHDIAG, &atd) < 0)
|
||||
err(1, "%s", atd.ad_name);
|
||||
|
||||
|
||||
printf(" ofdm_noise_immunity_level=%d\n", state.noiseImmunityLevel);
|
||||
printf(" cck_noise_immunity_level=%d\n", state.cckNoiseImmunityLevel);
|
||||
printf(" spur_immunity_level=%d\n", state.spurImmunityLevel);
|
||||
printf(" firstep_level=%d\n", state.firstepLevel);
|
||||
printf(" ofdm_weak_signal_detect=%d\n", state.ofdmWeakSigDetectOff);
|
||||
printf(" cck_weak_signal_threshold=%d\n", state.cckWeakSigThreshold);
|
||||
printf(" mrc_cck=%d\n", state.mrcCckOff);
|
||||
/* XXX TODO: cycle counts? */
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ath_diag atd;
|
||||
const char *ifname;
|
||||
struct ath_driver_req req;
|
||||
int what, c;
|
||||
|
||||
ath_driver_req_init(&req);
|
||||
|
||||
ifname = getenv("ATH");
|
||||
if (!ifname)
|
||||
ifname = ATH_DEFAULT;
|
||||
|
||||
what = 0;
|
||||
while ((c = getopt(argc, argv, "i:l")) != -1)
|
||||
switch (c) {
|
||||
case 'i':
|
||||
ifname = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
list_labels();
|
||||
exit(0);
|
||||
default:
|
||||
usage();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Initialise the driver interface */
|
||||
if (ath_driver_req_open(&req, ifname) < 0) {
|
||||
exit(127);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0) {
|
||||
ani_read_state(&req, ifname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
if (ani_write_state(&req, ifname, argv[0], argv[1]) != 0)
|
||||
exit(1);
|
||||
|
||||
exit(0);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user