aboutsummaryrefslogtreecommitdiff
path: root/tools/tools/ath
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2019-03-06 07:58:19 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2019-03-06 07:58:19 +0000
commit28adfbfe13ddc91eda8c1a0c451e192ec2b1650b (patch)
tree6be201818b6a44b5baf69e29062241fb0985261e /tools/tools/ath
parent7fbcfe69e763a89d0d7d58813afea8d2cd857669 (diff)
downloadsrc-28adfbfe13ddc91eda8c1a0c451e192ec2b1650b.tar.gz
src-28adfbfe13ddc91eda8c1a0c451e192ec2b1650b.zip
[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.
Notes
Notes: svn path=/head/; revision=344842
Diffstat (limited to 'tools/tools/ath')
-rw-r--r--tools/tools/ath/Makefile2
-rw-r--r--tools/tools/ath/athani/Makefile23
-rw-r--r--tools/tools/ath/athani/main.c226
3 files changed, 250 insertions, 1 deletions
diff --git a/tools/tools/ath/Makefile b/tools/tools/ath/Makefile
index b17f4c4b2dcc..1b5543909b63 100644
--- a/tools/tools/ath/Makefile
+++ b/tools/tools/ath/Makefile
@@ -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>
diff --git a/tools/tools/ath/athani/Makefile b/tools/tools/ath/athani/Makefile
new file mode 100644
index 000000000000..b475a6b0ed63
--- /dev/null
+++ b/tools/tools/ath/athani/Makefile
@@ -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>
diff --git a/tools/tools/ath/athani/main.c b/tools/tools/ath/athani/main.c
new file mode 100644
index 000000000000..e2147091780d
--- /dev/null
+++ b/tools/tools/ath/athani/main.c
@@ -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);
+}