Re: [PATCH 8/8] Print frequency of radar events.

2016-11-17 Thread Benjamin Berg
On Thu, 2016-11-17 at 18:21 +0100, Henrik Eriksson wrote:
> On Mon, Nov 07, 2016 at 15:59:43 +0100, Benjamin Berg wrote:
> > > > +   if (!tb[NL80211_ATTR_RADAR_EVENT] || 
> > > > !tb[NL80211_ATTR_WIPHY_FREQ])
> > > > +   printf("BAD radar event");
> 
> Should not this end the parsing here or at least avoid getting the value of
> the NULL attributes below?  I do not know if libnl nla_get_u32() is
> intended to be NULL safe, but following
> https://www.infradead.org/~tgr/libnl/doc/api/attr_8c_source.html#l00624
> it seems like you will get whatever u32 value is at address
> (NULL+)NLA_HDRLEN, assuming it is readable.  The original behavior was to
> do nothing if tb[NL80211_ATTR_RADAR_EVENT] was not set.
> 
> > > > +   freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
> > > > +   event_type = 
> > > > nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);

Yes, my version of the patch was somewhat broken in that regard.
Johannes fixed it before merging and it will now correctly print "BAD
radar event\n" and stop processing in case one of the entries is
missing.

Benjamin

signature.asc
Description: This is a digitally signed message part


[PATCH 3/8] ibss: Use common freqchan helper for joining an ibss

2016-11-07 Thread Benjamin Berg
Simplify code by using the helper which has been introduced earlier.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 ibss.c | 72 ++
 1 file changed, 10 insertions(+), 62 deletions(-)

diff --git a/ibss.c b/ibss.c
index 2b0b495..84f1e95 100644
--- a/ibss.c
+++ b/ibss.c
@@ -13,45 +13,14 @@ static int join_ibss(struct nl80211_state *state,
 enum id_input id)
 {
char *end;
+   struct chandef chandef;
unsigned char abssid[6];
unsigned char rates[NL80211_MAX_SUPP_RATES];
int n_rates = 0;
char *value = NULL, *sptr = NULL;
float rate;
int bintval;
-   unsigned int i;
-   unsigned long freq;
-   const struct chanmode *chanmode_selected = NULL;
-   static const struct chanmode chanmode[] = {
-   { .name = "HT20",
- .width = NL80211_CHAN_WIDTH_20,
- .freq1_diff = 0,
- .chantype = NL80211_CHAN_HT20 },
-   { .name = "HT40+",
- .width = NL80211_CHAN_WIDTH_40,
- .freq1_diff = 10,
- .chantype = NL80211_CHAN_HT40PLUS },
-   { .name = "HT40-",
- .width = NL80211_CHAN_WIDTH_40,
- .freq1_diff = -10,
- .chantype = NL80211_CHAN_HT40MINUS },
-   { .name = "NOHT",
- .width = NL80211_CHAN_WIDTH_20_NOHT,
- .freq1_diff = 0,
- .chantype = NL80211_CHAN_NO_HT },
-   { .name = "5MHz",
- .width = NL80211_CHAN_WIDTH_5,
- .freq1_diff = 0,
- .chantype = -1 },
-   { .name = "10MHz",
- .width = NL80211_CHAN_WIDTH_10,
- .freq1_diff = 0,
- .chantype = -1 },
-   { .name = "80MHz",
- .width = NL80211_CHAN_WIDTH_80,
- .freq1_diff = 0,
- .chantype = -1 },
-   };
+   int parsed, err;
 
if (argc < 2)
return 1;
@@ -61,37 +30,16 @@ static int join_ibss(struct nl80211_state *state,
argv++;
argc--;
 
-   /* freq */
-   freq = strtoul(argv[0], , 10);
-   if (*end != '\0')
-   return 1;
-
-   NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-   argv++;
-   argc--;
+   err = parse_freqchan(, false, argc, argv, );
+   if (err)
+   return err;
 
-   if (argc) {
-   for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
-   if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
-   chanmode_selected = [i];
-   break;
-   }
-   }
-   if (chanmode_selected) {
-   NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-   chanmode_selected->width);
-   NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
-   get_cf1(chanmode_selected, freq));
-   if (chanmode_selected->chantype != -1)
-   NLA_PUT_U32(msg,
-   NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-   chanmode_selected->chantype);
+   argv += parsed;
+   argc -= parsed;
 
-   argv++;
-   argc--;
-   }
-
-   }
+   put_chandef(msg, );
+   if (err)
+   return err;
 
if (argc && strcmp(argv[0], "fixed-freq") == 0) {
NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED);
-- 
2.10.2



[PATCH 1/8] util: Add generic frequency/channel command line handler

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

The ability to parse channel definitions is required in a lot of places
inside iw. However, right now each of these duplicates a lot of code to
handle it.

So add a new helper which can be used everywhere.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 iw.h   |  10 +++
 util.c | 239 +
 2 files changed, 249 insertions(+)

diff --git a/iw.h b/iw.h
index 2837bd3..7d56391 100644
--- a/iw.h
+++ b/iw.h
@@ -70,6 +70,14 @@ struct chanmode {
int chantype; /* for older kernel */
 };
 
+struct chandef {
+   enum nl80211_chan_width width;
+
+   unsigned int control_freq;
+   unsigned int center_freq1;
+   unsigned int center_freq2;
+};
+
 #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
 #define DIV_ROUND_UP(x, y) (((x) + (y - 1)) / (y))
 
@@ -150,6 +158,8 @@ int parse_hex_mask(char *hexmask, unsigned char **result, 
size_t *result_len,
 unsigned char *parse_hex(char *hex, size_t *outlen);
 
 int parse_keys(struct nl_msg *msg, char **argv, int argc);
+int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv, 
int *parsed);
+int put_chandef(struct nl_msg *msg, struct chandef *chandef);
 
 void print_ht_mcs(const __u8 *mcs);
 void print_ampdu_length(__u8 exponent);
diff --git a/util.c b/util.c
index a338464..833b1ce 100644
--- a/util.c
+++ b/util.c
@@ -469,6 +469,245 @@ int parse_keys(struct nl_msg *msg, char **argv, int argc)
return 2;
 }
 
+static int parse_freqs(struct chandef *chandef, int argc, char **argv,
+  int *parsed)
+{
+   static const struct {
+   const char *name;
+   unsigned int val;
+   } bwmap[] = {
+   { .name = "5", .val = NL80211_CHAN_WIDTH_5, },
+   { .name = "10", .val = NL80211_CHAN_WIDTH_10, },
+   { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
+   { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
+   { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
+   { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
+   { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
+   };
+   uint32_t freq;
+   unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
+   char *end;
+
+   if (argc < 1)
+   return 0;
+
+   for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
+   if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
+   bwval = bwmap[i].val;
+   *parsed += 1;
+   break;
+   }
+   }
+   chandef->width = bwval;
+
+   /* First argument was not understood, give up gracefully. */
+   if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
+   return 0;
+
+   if (argc < 2)
+   return 0;
+
+   /* center freq 1 */
+   if (!*argv[1])
+   return 0;
+   freq = strtoul(argv[1], , 10);
+   if (*end)
+   return 0;
+   *parsed += 1;
+
+   chandef->center_freq1 = freq;
+
+   if (argc < 3)
+   return 0;
+
+   /* center freq 2 */
+   if (!*argv[2])
+   return 0;
+   freq = strtoul(argv[2], , 10);
+   if (*end)
+   return 0;
+   chandef->center_freq2 = freq;
+
+   *parsed += 1;
+
+   return 0;
+}
+
+
+/**
+ * parse_freqchan - Parse frequency or channel definition
+ *
+ * @chandef: chandef structure to be filled in
+ * @chan: Boolean whether to parse a channel or frequency based specifier
+ * @argc: Number of arguments
+ * @argv: Array of string arguments
+ * @parsed: Pointer to return the number of used arguments, or NULL to error
+ *  out if any argument is left unused.
+ *
+ * The given chandef structure will be filled in from the command line
+ * arguments. argc/argv will be updated so that further arguments from the
+ * command line can be parsed.
+ *
+ * Note that no integer argument may follow a frequency definition to allow the
+ * user to skip the center frequency definition(s).
+ *
+ * The working specifier if chan is set are:
+ *[NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
+ *
+ * And if frequency is set:
+ *[NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]
+ *[5|10|20|40|80|80+80|160] [ []]
+ *
+ * If the mode/channel width is not given the NOHT is assumed.
+ *
+ * Return: Number of used arguments, zero or negative error number otherwise
+ */
+int parse_freqchan(struct chandef *chandef, bool chan, int argc, char **argv,
+  int *parsed)
+{
+   char *end;
+   static const struct chanmode chanmode[] = {
+   { .name = "HT20",
+ .width = NL80211_CHAN_WIDTH_20,
+ .freq1_diff = 0,
+ .chantype = NL80211_CHAN_HT20 },
+   { .name = "HT4

[PATCH 5/8] Add cac command to allow clearing channels

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Allow the user to start a CAC for clearing DFS channels.

Signed-off-by: Simon Wunderlich <s...@simonwunderlich.de>
Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 phy.c | 145 ++
 1 file changed, 145 insertions(+)

diff --git a/phy.c b/phy.c
index 266de4d..be31820 100644
--- a/phy.c
+++ b/phy.c
@@ -226,6 +226,151 @@ COMMAND(set, channel, " 
[NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
 COMMAND(set, channel, " [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
 
+
+struct cac_event {
+   int ret;
+   uint32_t freq;
+};
+
+static int print_cac_event(struct nl_msg *msg, void *arg)
+{
+   struct nlattr *tb[NL80211_ATTR_MAX + 1];
+   struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+   enum nl80211_radar_event event_type;
+   struct cac_event *cac_event = arg;
+   uint32_t freq;
+
+   if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
+   return NL_SKIP;
+
+   nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+   if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
+   return NL_SKIP;
+
+   freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+   event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+   if (freq != cac_event->freq)
+   return NL_SKIP;
+
+   switch (event_type) {
+   case NL80211_RADAR_DETECTED:
+   printf("%d MHz: radar detected\n", freq);
+   break;
+   case NL80211_RADAR_CAC_FINISHED:
+   printf("%d MHz: CAC finished\n", freq);
+   break;
+   case NL80211_RADAR_CAC_ABORTED:
+   printf("%d MHz: CAC was aborted\n", freq);
+   break;
+   case NL80211_RADAR_NOP_FINISHED:
+   printf("%d MHz: NOP finished\n", freq);
+   break;
+   default:
+   printf("%d MHz: unknown radar event\n", freq);
+   }
+   cac_event->ret = 0;
+
+   return NL_SKIP;
+}
+
+static int handle_cac_trigger(struct nl80211_state *state,
+   struct nl_msg *msg,
+   int argc, char **argv,
+   enum id_input id)
+{
+   struct chandef chandef;
+   int res;
+
+   if (argc < 2)
+   return 1;
+
+   if (strcmp(argv[0], "channel") == 0) {
+   res = parse_freqchan(, true, argc - 1, argv + 1, NULL);
+   } else if (strcmp(argv[0], "freq") == 0) {
+   res = parse_freqchan(, false, argc - 1, argv + 1, NULL);
+   } else {
+   return 1;
+   }
+
+   if (res)
+   return res;
+
+   return put_chandef(msg, );
+}
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+   return NL_OK;
+}
+
+static int handle_cac(struct nl80211_state *state,
+ struct nl_msg *msg,
+ int argc, char **argv,
+ enum id_input id)
+{
+   int err;
+   struct nl_cb *radar_cb;
+   struct chandef chandef;
+   struct cac_event cac_event;
+   char **cac_trigger_argv = NULL;
+
+   radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
+   if (!radar_cb)
+   return 1;
+
+   if (argc < 3)
+   return 1;
+
+   if (strcmp(argv[2], "channel") == 0) {
+   err = parse_freqchan(, true, argc - 3, argv + 3, NULL);
+   } else if (strcmp(argv[2], "freq") == 0) {
+   err = parse_freqchan(, false, argc - 3, argv + 3, NULL);
+   } else {
+   return 1;
+   }
+
+   cac_trigger_argv = calloc(argc + 1, sizeof(char*));
+   if (!cac_trigger_argv)
+   return -ENOMEM;
+
+   cac_trigger_argv[0] = argv[0];
+   cac_trigger_argv[1] = "cac";
+   cac_trigger_argv[2] = "trigger";
+   memcpy(_trigger_argv[3], [2], (argc - 2) * sizeof(char*));
+
+   err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
+   free(cac_trigger_argv);
+   if (err)
+   return err;
+
+   cac_event.ret = 1;
+   cac_event.freq = chandef.control_freq;
+
+   __prepare_listen_events(state);
+   nl_socket_set_cb(state->nl_sock, radar_cb);
+
+   /* need to turn off sequence number checking */
+   nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+   nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, 
_event);
+   while (cac_event.ret > 0)
+   nl_recvmsgs(state->nl_sock, radar_cb);
+
+   return 0;
+}
+TOPLEVEL(cac, "channel  [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+ "freq

[PATCH 8/8] Print frequency of radar events.

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Signed-off-by: Simon Wunderlich <s...@simonwunderlich.de>
Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 event.c | 48 +---
 1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/event.c b/event.c
index 446debb..8014d73 100644
--- a/event.c
+++ b/event.c
@@ -584,30 +584,32 @@ static int print_event(struct nl_msg *msg, void *arg)
   nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
   nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
break;
-   case NL80211_CMD_RADAR_DETECT:
-   printf("radar event ");
-   if (tb[NL80211_ATTR_RADAR_EVENT]) {
-   switch (nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT])) {
-   case NL80211_RADAR_DETECTED:
-   printf("(radar detected)");
-   break;
-   case NL80211_RADAR_CAC_FINISHED:
-   printf("(cac finished)");
-   break;
-   case NL80211_RADAR_CAC_ABORTED:
-   printf("(cac aborted)");
-   break;
-   case NL80211_RADAR_NOP_FINISHED:
-   printf("(nop finished)");
-   break;
-   default:
-   printf("(unknown)");
-   break;
-   };
-   } else {
-   printf("(unknown)");
+   case NL80211_CMD_RADAR_DETECT: {
+   enum nl80211_radar_event event_type;
+   uint32_t freq;
+
+   if (!tb[NL80211_ATTR_RADAR_EVENT] || 
!tb[NL80211_ATTR_WIPHY_FREQ])
+   printf("BAD radar event");
+   freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+   event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+   switch (event_type) {
+   case NL80211_RADAR_DETECTED:
+   printf("%d MHz: radar detected\n", freq);
+   break;
+   case NL80211_RADAR_CAC_FINISHED:
+   printf("%d MHz: CAC finished\n", freq);
+   break;
+   case NL80211_RADAR_CAC_ABORTED:
+   printf("%d MHz: CAC was aborted\n", freq);
+   break;
+   case NL80211_RADAR_NOP_FINISHED:
+   printf("%d MHz: NOP finished\n", freq);
+   break;
+   default:
+   printf("%d MHz: unknown radar event\n", freq);
+   }
}
-   printf("\n");
break;
case NL80211_CMD_DEL_WIPHY:
printf("delete wiphy\n");
-- 
2.10.2



[PATCH 4/8] mesh: Use common freqchan helper for joining a mesh

2016-11-07 Thread Benjamin Berg
Simplify code by using the helper which has been introduced earlier.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 mesh.c | 67 +++---
 1 file changed, 11 insertions(+), 56 deletions(-)

diff --git a/mesh.c b/mesh.c
index a0047fe..97f236b 100644
--- a/mesh.c
+++ b/mesh.c
@@ -446,31 +446,6 @@ static int join_mesh(struct nl80211_state *state,
unsigned char rates[NL80211_MAX_SUPP_RATES];
int bintval, dtim_period, n_rates = 0;
char *end, *value = NULL, *sptr = NULL;
-   unsigned int i;
-   unsigned long freq = 0;
-   const struct chanmode *chanmode_selected = NULL;
-   static const struct chanmode chanmode[] = {
-   { .name = "HT20",
- .width = NL80211_CHAN_WIDTH_20,
- .freq1_diff = 0,
- .chantype = NL80211_CHAN_HT20 },
-   { .name = "HT40+",
- .width = NL80211_CHAN_WIDTH_40,
- .freq1_diff = 10,
- .chantype = NL80211_CHAN_HT40PLUS },
-   { .name = "HT40-",
- .width = NL80211_CHAN_WIDTH_40,
- .freq1_diff = -10,
- .chantype = NL80211_CHAN_HT40MINUS },
-   { .name = "NOHT",
- .width = NL80211_CHAN_WIDTH_20_NOHT,
- .freq1_diff = 0,
- .chantype = NL80211_CHAN_NO_HT },
-   { .name = "80MHz",
- .width = NL80211_CHAN_WIDTH_80,
- .freq1_diff = 0,
- .chantype = -1 },
-   };
 
if (argc < 1)
return 1;
@@ -481,40 +456,20 @@ static int join_mesh(struct nl80211_state *state,
 
/* freq */
if (argc > 1 && strcmp(argv[0], "freq") == 0) {
-   argv++;
-   argc--;
-
-   freq = strtoul(argv[0], , 10);
-   if (*end != '\0')
-   return 1;
-   NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-
-   argv++;
-   argc--;
-   }
+   struct chandef chandef;
+   int err, parsed;
 
-   /* channel type */
-   if (argc) {
-   for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
-   if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
-   chanmode_selected = [i];
-   break;
-   }
-   }
+   err = parse_freqchan(, false, argc - 1, argv + 1,
+);
+   if (err)
+   return err;
 
-   if (chanmode_selected) {
-   NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-   chanmode_selected->width);
-   NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
-   get_cf1(chanmode_selected, freq));
-   if (chanmode_selected->chantype != -1)
-   NLA_PUT_U32(msg,
-   NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-   chanmode_selected->chantype);
+   argv += parsed + 1;
+   argc -= parsed + 1;
 
-   argv++;
-   argc--;
-   }
+   put_chandef(msg, );
+   if (err)
+   return err;
}
 
/* basic rates */
-- 
2.10.2



[PATCH 0/8] iw: Add common chandef parser and new DFS related commands

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Hi,

This patchset adds commands for doing a CAC and sending CSA.

Another change is that parsing of command line frequency and channel
definitions is split out so that it can be shared between the different
users.

Benjamin

Benjamin Berg (7):
  util: Add generic frequency/channel command line handler
  phy: Use common freqchan helper for setting the operating channel
  ibss: Use common freqchan helper for joining an ibss
  mesh: Use common freqchan helper for joining a mesh
  Add cac command to allow clearing channels
  Add commands to send CSA
  Print frequency of radar events.

Simon Wunderlich (1):
  Add flag for DFS handling in IBSS

 event.c |  48 +--
 ibss.c  |  78 --
 interface.c |  72 
 iw.h|  11 +++
 mesh.c  |  67 +++
 phy.c   | 266 
 util.c  | 239 ++
 7 files changed, 533 insertions(+), 248 deletions(-)

-- 
2.10.2



[PATCH 2/8] phy: Use common freqchan helper for setting the operating channel

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Simplify code by using the helper which has been introduced earlier.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 phy.c | 143 --
 1 file changed, 25 insertions(+), 118 deletions(-)

diff --git a/phy.c b/phy.c
index c57a71f..266de4d 100644
--- a/phy.c
+++ b/phy.c
@@ -183,140 +183,47 @@ static int handle_name(struct nl80211_state *state,
 COMMAND(set, name, "", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, 
handle_name,
"Rename this wireless device.");
 
-static int handle_freqs(struct nl_msg *msg, int argc, char **argv)
-{
-   static const struct {
-   const char *name;
-   unsigned int val;
-   } bwmap[] = {
-   { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
-   { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
-   { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
-   { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
-   { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
-   };
-   uint32_t freq;
-   unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
-   char *end;
-
-   if (argc < 1)
-   return 1;
-
-   for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
-   if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
-   bwval = bwmap[i].val;
-   break;
-   }
-   }
-
-   if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
-   return 1;
-
-   NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval);
-
-   if (argc == 1)
-   return 0;
-
-   /* center freq 1 */
-   if (!*argv[1])
-   return 1;
-   freq = strtoul(argv[1], , 10);
-   if (*end)
-   return 1;
-   NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq);
-
-   if (argc == 2)
-   return 0;
-
-   /* center freq 2 */
-   if (!*argv[2])
-   return 1;
-   freq = strtoul(argv[2], , 10);
-   if (*end)
-   return 1;
-   NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq);
-
-   return 0;
- nla_put_failure:
-   return -ENOBUFS;
-}
-
-static int handle_freqchan(struct nl_msg *msg, bool chan,
-  int argc, char **argv)
-{
-   char *end;
-   static const struct {
-   const char *name;
-   unsigned int val;
-   } htmap[] = {
-   { .name = "HT20", .val = NL80211_CHAN_HT20, },
-   { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
-   { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
-   };
-   unsigned int htval = NL80211_CHAN_NO_HT;
-   unsigned int freq;
-   unsigned int i;
-
-   if (!argc || argc > 4)
-   return 1;
-
-   if (!*argv[0])
-   return 1;
-   freq = strtoul(argv[0], , 10);
-   if (*end)
-   return 1;
-
-   if (chan) {
-   enum nl80211_band band;
-   band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
-   freq = ieee80211_channel_to_frequency(freq, band);
-   }
-
-   NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-
-   if (argc > 2) {
-   return handle_freqs(msg, argc - 1, argv + 1);
-   } else if (argc == 2) {
-   for (i = 0; i < ARRAY_SIZE(htmap); i++) {
-   if (strcasecmp(htmap[i].name, argv[1]) == 0) {
-   htval = htmap[i].val;
-   break;
-   }
-   }
-   if (htval == NL80211_CHAN_NO_HT)
-   return handle_freqs(msg, argc - 1, argv + 1);
-   }
-
-   NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
-
-   return 0;
- nla_put_failure:
-   return -ENOBUFS;
-}
-
 static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
   int argc, char **argv,
   enum id_input id)
 {
-   return handle_freqchan(msg, false, argc, argv);
+   struct chandef chandef;
+   int res;
+
+   res = parse_freqchan(, false, argc, argv, NULL);
+   if (res)
+   return res;
+
+   return put_chandef(msg, );
 }
-COMMAND(set, freq, " [HT20|HT40+|HT40-]",
+
+COMMAND(set, freq,
+   " [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
+   " [5|10|20|40|80|80+80|160] [ 
[]]",
NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
"Set frequency/channel the hardware is using, including HT\n"
"configuration.");
-COMMAND(set, freq, " [HT20|HT40+|HT40-]\n"
-  " [20|40|80|80+80|160] [] 
[]",
+COMMAND(set, freq,
+   " [NO

[PATCH 7/8] Add flag for DFS handling in IBSS

2016-11-07 Thread Benjamin Berg
From: Simon Wunderlich <s...@simonwunderlich.de>

When Userspace is capable of handling DFS, it can inform the kernel
about that by sending the NL80211_ATTR_HANDLE_DFS attribute when joining
an IBSS. DFS channels will then be unlocked.

Note that this flag is only added for debugging purposes and therefore
hidden from the user by prefixing with __ and not documenting it.

Signed-off-by: Simon Wunderlich <s...@simonwunderlich.de>
Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 ibss.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/ibss.c b/ibss.c
index 84f1e95..7087cc9 100644
--- a/ibss.c
+++ b/ibss.c
@@ -47,6 +47,12 @@ static int join_ibss(struct nl80211_state *state,
argc--;
}
 
+   if (argc && strcmp(argv[0], "__dfs-enable") == 0) {
+   NLA_PUT_FLAG(msg, NL80211_ATTR_HANDLE_DFS);
+   argv++;
+   argc--;
+   }
+
if (argc) {
if (mac_addr_a2n(abssid, argv[0]) == 0) {
NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid);
-- 
2.10.2



[PATCH 6/8] Add commands to send CSA

2016-11-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Add a new set of commands to send a CSA. Both the number of beacons and the
flag to block TX can be given optionally.

Signed-off-by: Simon Wunderlich <s...@simonwunderlich.de>
Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 interface.c | 72 +
 iw.h|  1 +
 2 files changed, 73 insertions(+)

diff --git a/interface.c b/interface.c
index 57dd3c3..1c9ebfb 100644
--- a/interface.c
+++ b/interface.c
@@ -644,3 +644,75 @@ nla_put_failure:
 COMMAND(set, mcast_rate, "",
NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate,
"Set the multicast bitrate.");
+
+
+static int handle_chanfreq(struct nl80211_state *state, struct nl_msg *msg,
+  bool chan, int argc, char **argv,
+  enum id_input id)
+{
+   struct chandef chandef;
+   int res;
+   int parsed;
+   char *end;
+
+   res = parse_freqchan(, chan, argc, argv, );
+   if (res)
+   return res;
+
+   argc -= parsed;
+   argv += parsed;
+
+   while (argc) {
+   unsigned int beacons = 10;
+
+   if (strcmp(argv[0], "beacons") == 0) {
+   if (argc < 2)
+   return 1;
+
+   beacons = strtol(argv[1], , 10);
+   if (*end)
+   return 1;
+
+   argc -= 2;
+   argv += 2;
+
+   NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, beacons);
+   } else if (strcmp(argv[0], "block-tx") == 0) {
+   argc -= 1;
+   argv += 1;
+
+   NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
+   } else {
+   return 1;
+   }
+   }
+
+   return put_chandef(msg, );
+
+ nla_put_failure:
+   return -ENOBUFS;
+}
+
+static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
+  int argc, char **argv,
+  enum id_input id)
+{
+   return handle_chanfreq(state, msg, false, argc, argv, id);
+}
+
+static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
+  int argc, char **argv,
+  enum id_input id)
+{
+   return handle_chanfreq(state, msg, true, argc, argv, id);
+}
+
+SECTION(switch);
+COMMAND(switch, freq,
+   " [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] [beacons ] 
[block-tx]\n"
+   " [5|10|20|40|80|80+80|160] [ 
[]] [beacons ] [block-tx]",
+   NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_freq,
+   "Switch the operating channel by sending a channel switch announcement 
(CSA).");
+COMMAND(switch, channel, " [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz] 
[beacons ] [block-tx]",
+   NL80211_CMD_CHANNEL_SWITCH, 0, CIB_NETDEV, handle_chan, NULL);
+
diff --git a/iw.h b/iw.h
index 7d56391..0857baf 100644
--- a/iw.h
+++ b/iw.h
@@ -202,6 +202,7 @@ int get_cf1(const struct chanmode *chanmode, unsigned long 
freq);
"[randomise[=/]]"
 int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv);
 
+DECLARE_SECTION(switch);
 DECLARE_SECTION(set);
 DECLARE_SECTION(get);
 
-- 
2.10.2



[PATCH] ath10k: Fix spinlock use in coverage class hack

2016-09-14 Thread Benjamin Berg
ath10k_hw_qca988x_set_coverage_class needs to hold both conf_mutex and
the data_lock spin lock for parts of the function. However, data_lock
is only needed while storing the coverage_class to store the value that
the card is configured to.

Fix the locking issue by only holding data_lock for the required duration.

Signed-off-by: Benjamin Berg <benja...@sipsolutions.net>
---

And yes, I fully agree with your points of it being rather fragile. But as
you said, it should be entirely safe if not used. Obviously a firmware
implementation would be preferential.

This locking issue was pretty unnecessary. Lets see if any more issues show
up in a closer review.

 drivers/net/wireless/ath/ath10k/core.h | 2 +-
 drivers/net/wireless/ath/ath10k/hw.c   | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 89b07be..5f8c31f 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -915,7 +915,7 @@ struct ath10k {
struct work_struct set_coverage_class_work;
/* protected by conf_mutex */
struct {
-   /* protected by data_lock */
+   /* writing also protected by data_lock */
s16 coverage_class;
 
u32 reg_phyclk;
diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index e182f09..bd5ca6a 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -243,7 +243,6 @@ static void ath10k_hw_qca988x_set_coverage_class(struct 
ath10k *ar,
u32 fw_dbglog_level;
 
mutex_lock(>conf_mutex);
-   spin_lock_bh(>data_lock);
 
/* Only modify registers if the core is started. */
if ((ar->state != ATH10K_STATE_ON) &&
@@ -356,12 +355,14 @@ static void ath10k_hw_qca988x_set_coverage_class(struct 
ath10k *ar,
 
 store_regs:
/* After an error we will not retry setting the coverage class. */
+   spin_lock_bh(>data_lock);
ar->fw_coverage.coverage_class = value;
+   spin_unlock_bh(>data_lock);
+
ar->fw_coverage.reg_slottime_conf = slottime_reg;
ar->fw_coverage.reg_ack_cts_timeout_conf = timeout_reg;
 
 unlock:
-   spin_unlock_bh(>data_lock);
mutex_unlock(>conf_mutex);
 }
 
-- 
2.9.3



[PATCH] ath10k: Add missing CONFIG_ATH10K_DEBUGFS check

2016-09-12 Thread Benjamin Berg
The patch "ath10k: allow setting coverage class" was missing a check for
CONFIG_ATH10K_DEBUGFS so it would try to use non-existing struct elements
in some configurations. Fix this by adding the appropriate ifdef.

Signed-off-by: Benjamin Berg <benja...@sipsolutions.net>
---

Sorry, so turns out the kbuild test robot is correct and I forgot the ifdef
to check for CONFIG_ATH10K_DEBUGFS, so here a fixup commit for it.

Other than that everything looks good to me in the pending branch.

Benjamin


 drivers/net/wireless/ath/ath10k/hw.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index c52b5f4..e182f09 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -338,8 +338,13 @@ static void ath10k_hw_qca988x_set_coverage_class(struct 
ath10k *ar,
 * set the registers again if the firmware does an internal reset and
 * this way we will be notified of the event.
 */
+#ifdef CONFIG_ATH10K_DEBUGFS
fw_dbglog_mask = ar->debug.fw_dbglog_mask;
fw_dbglog_level = ar->debug.fw_dbglog_level;
+#else
+   fw_dbglog_mask = 0;
+   fw_dbglog_level = 0;
+#endif
 
if (value > 0) {
if (fw_dbglog_level > ATH10K_DBGLOG_LEVEL_WARN)
-- 
2.9.3



Re: ath9k: Fix beacon configuration assertion failure

2016-08-22 Thread Benjamin Berg
On Fr, 2016-08-19 at 13:03 +0300, Kalle Valo wrote:
> Actually, I see two patches which might be related but not identical:
> 
> ath9k: fix client mode beacon configuration
> https://patchwork.kernel.org/patch/9247699/
> 
> ath9k: Fix beacon configuration assertion failure
> https://patchwork.kernel.org/patch/9281191/
> 
> Felix (CCed) & Benjamin: please take a look and advice which one I
> should take.

Yes, both patches are designed to fix the same issue in my patch.

Felix solution looks entirely correct to me, the second solution seems
slightly wrong because it prevents the call to ath9k_beacon_config from
happening instead of ensuring the correct parameter value.
ath9k_beacon_config needs to be called even if iter_data.beacons is
false as it disables the interrupts.

Benjamin


Re: [PATCH] ath10k: Allow setting coverage class

2016-07-29 Thread Benjamin Berg
On Mi, 2016-07-27 at 10:26 -0700, Ben Greear wrote:
> On 07/27/2016 01:33 AM, Benjamin Berg wrote:
> > 
> > Unfortunately ath10k does not generally allow modifying the coverage class
> > with the stock firmware and Qualcomm has so far refused to implement this
> > feature so that it can be properly supported in ath10k. If we however know
> > the registers that need to be modified for proper operation with a higher
> > coverage class, then we can do these modifications from the driver.
> > 
> > This patch implements this hack for first generation cards which are based
> > on a core that is similar to ath9k. The registers are modified in place and
> > need to be re-written every time the firmware sets them. To achieve this
> > the register status is verified after any event from the firmware.
> > 
> > The coverage class may not be modified temporarily right after the card
> > re-initializes the registers. This is for example the case during scanning.
> > 
> > A warning will be generated if the hack is not supported on the card or
> > unexpected values are hit. There is no error reporting for userspace
> > applications though (this is a limitation in the mac80211 driver
> > interface).
> > 
> > > > Thanks to Sebastian Gottschall <s.gottsch...@dd-wrt.com> for initially
> > working on a userspace support for this. This patch wouldn't have been
> > possible without this documentation.
> 
> I would be concerned about the various resets firmware does to work around
> hardware hangs as well.  I don't think any events are generated for these, 
> unless
> you count the dbglog messages?

Yeah, I am aware of the fact that the firmware may do internal resets
from time to time. The interesting question (and one for which I do not
know the answer) is whether we get a wmi or other event under all
conditions where the register may be rewritten due to a reset.

The current code will re-set the register value after any wmi event
including debug messages. If this is not enough, then the only solution
might be to periodically poll the register values instead of relying on
a received event.

Benjamin

signature.asc
Description: This is a digitally signed message part


[PATCH] ath10k: Allow setting coverage class

2016-07-27 Thread Benjamin Berg
Unfortunately ath10k does not generally allow modifying the coverage class
with the stock firmware and Qualcomm has so far refused to implement this
feature so that it can be properly supported in ath10k. If we however know
the registers that need to be modified for proper operation with a higher
coverage class, then we can do these modifications from the driver.

This patch implements this hack for first generation cards which are based
on a core that is similar to ath9k. The registers are modified in place and
need to be re-written every time the firmware sets them. To achieve this
the register status is verified after any event from the firmware.

The coverage class may not be modified temporarily right after the card
re-initializes the registers. This is for example the case during scanning.

A warning will be generated if the hack is not supported on the card or
unexpected values are hit. There is no error reporting for userspace
applications though (this is a limitation in the mac80211 driver
interface).

Thanks to Sebastian Gottschall <s.gottsch...@dd-wrt.com> for initially
working on a userspace support for this. This patch wouldn't have been
possible without this documentation.

Signed-off-by: Benjamin Berg <benja...@sipsolutions.net>
Signed-off-by: Simon Wunderlich <s...@simonwunderlich.de>
Signed-off-by: Mathias Kretschmer <mathias.kretsch...@fit.fraunhofer.de>
---
 drivers/net/wireless/ath/ath10k/core.h|  10 ++
 drivers/net/wireless/ath/ath10k/hw.c  |   9 ++
 drivers/net/wireless/ath/ath10k/hw.h  |  28 +-
 drivers/net/wireless/ath/ath10k/mac.c |  10 ++
 drivers/net/wireless/ath/ath10k/wmi-ops.h |  17 
 drivers/net/wireless/ath/ath10k/wmi.c | 151 ++
 6 files changed, 224 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 9374bcd..781219b 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -935,6 +935,16 @@ struct ath10k {
struct ath10k_thermal thermal;
struct ath10k_wow wow;
 
+   /* protected by data_lock */
+   struct {
+   s16 coverage_class;
+
+   u32 reg_slottime_conf;
+   u32 reg_slottime_orig;
+   u32 reg_ack_cts_timeout_conf;
+   u32 reg_ack_cts_timeout_orig;
+   } fw_coverage;
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index f903d46..82249be 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -22,6 +22,7 @@ const struct ath10k_hw_regs qca988x_regs = {
.rtc_soc_base_address   = 0x4000,
.rtc_wmac_base_address  = 0x5000,
.soc_core_base_address  = 0x9000,
+   .wlan_mac_base_address  = 0x0002,
.ce_wrapper_base_address= 0x00057000,
.ce0_base_address   = 0x00057400,
.ce1_base_address   = 0x00057800,
@@ -48,6 +49,7 @@ const struct ath10k_hw_regs qca6174_regs = {
.rtc_soc_base_address   = 0x0800,
.rtc_wmac_base_address  = 0x1000,
.soc_core_base_address  = 0x0003a000,
+   .wlan_mac_base_address  = 0x0002,
.ce_wrapper_base_address= 0x00034000,
.ce0_base_address   = 0x00034400,
.ce1_base_address   = 0x00034800,
@@ -74,6 +76,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
.rtc_soc_base_address   = 0x0008,
.rtc_wmac_base_address  = 0x,
.soc_core_base_address  = 0x00082000,
+   .wlan_mac_base_address  = 0x0003,
.ce_wrapper_base_address= 0x0004d000,
.ce0_base_address   = 0x0004a000,
.ce1_base_address   = 0x0004a400,
@@ -109,6 +112,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
 const struct ath10k_hw_regs qca4019_regs = {
.rtc_soc_base_address   = 0x0008,
.soc_core_base_address  = 0x00082000,
+   .wlan_mac_base_address  = 0x0003,
.ce_wrapper_base_address= 0x0004d000,
.ce0_base_address   = 0x0004a000,
.ce1_base_address   = 0x0004a400,
@@ -139,6 +143,7 @@ const struct ath10k_hw_regs qca4019_regs = {
 };
 
 const struct ath10k_hw_values qca988x_values = {
+   .mac_core_rev   = ATH10K_HW_MAC_CORE_ATH9K,
.rtc_state_val_on   = 3,
.ce_count   = 8,
.msi_assign_ce_max  = 7,
@@ -148,6 +153,7 @@ const

[PATCH v2 6/6] ath9k: Fix beacon configuration for addition/removal of interfaces

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

This patch fixes some issues with interface reconfiguration. It could
for example happen that an AP interface in beacon slot 0 was removed
leaving an IBSS station in one of the other slots. When this happens
the driver never sends out the beacon as it only tries to send a beacon
from slot 0.

Appart from that the tracking of required changes to the beacon config is
relatively complicated and prone to errors.

The approach taken here is to solve reconfiguration issues is to
reconfigure the beacons when any interface changes. This means that
the complexity of deciding whether an interface change may modify the
beacon configuration is gone. It also means that the beacon config will
be reliably updated when an interface is removed.

The issue that a single non-AP interface might not be in beacon
slot 0 and wouldn't be send out is solved by moving it into the
first slot. The TSF value in hardware is adjusted accordingly so
that the timestamp of the beacons stay consistent.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h  |   7 +-
 drivers/net/wireless/ath/ath9k/beacon.c | 240 ++--
 drivers/net/wireless/ath/ath9k/common.h |   1 +
 drivers/net/wireless/ath/ath9k/main.c   |  43 +++---
 4 files changed, 165 insertions(+), 126 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h 
b/drivers/net/wireless/ath/ath9k/ath9k.h
index 93b3793..26fc8ec 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -637,6 +637,8 @@ struct ath9k_vif_iter_data {
int nwds;  /* number of WDS vifs */
int nadhocs;   /* number of adhoc vifs */
int nocbs; /* number of OCB vifs */
+   int nbcnvifs;  /* number of beaconing vifs */
+   struct ieee80211_vif *primary_beacon_vif;
struct ieee80211_vif *primary_sta;
 };
 
@@ -685,10 +687,11 @@ struct ath_beacon {
 };
 
 void ath9k_beacon_tasklet(unsigned long data);
-void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
-u32 changed);
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
+bool beacons);
 void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
+void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc);
 void ath9k_set_beacon(struct ath_softc *sc);
 bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_csa_update(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c 
b/drivers/net/wireless/ath/ath9k/beacon.c
index d8b4971..e36f947 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct 
ieee80211_vif *vif)
}
 
sc->beacon.bslot[avp->av_bslot] = vif;
-   sc->nbcnvifs++;
 
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
avp->av_bslot);
@@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, 
struct ieee80211_vif *vif)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_buf *bf = avp->av_bcbuf;
-   struct ath_beacon_config *cur_conf = >cur_chan->beacon;
 
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
avp->av_bslot);
 
tasklet_disable(>bcon_tasklet);
 
-   cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
-
if (bf && bf->bf_mpdu) {
struct sk_buff *skb = bf->bf_mpdu;
dma_unmap_single(sc->dev, bf->bf_buf_addr,
@@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, 
struct ieee80211_vif *vif)
 
avp->av_bcbuf = NULL;
sc->beacon.bslot[avp->av_bslot] = NULL;
-   sc->nbcnvifs--;
list_add_tail(>list, >beacon.bbuf);
 
tasklet_enable(>bcon_tasklet);
 }
 
+void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
+{
+   struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+   struct ieee80211_vif *vif;
+   struct ath_vif *avp;
+   s64 tsfadjust;
+   u32 offset;
+   int first_slot = ATH_BCBUF;
+   int slot;
+
+   tasklet_disable(>bcon_tasklet);
+
+   /* Find first taken slot. */
+   for (slot = 0; slot < ATH_BCBUF; slot++) {
+   if (sc->beacon.bslot[slot]) {
+   first_slot = slot;
+   break;
+   }
+   }
+   if (first_slot == 0)
+   goto out;
+
+   /* Re-enumarate all slots, moving them forward. */
+   for (slot = 0; slot

[PATCH v2 5/6] ath9k: Remove some #defined constants to decrease verbosity

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

The removed ATH9K_SLOT_TIME_X constants simply map the value in microseconds
to the same integer. These constants were not used consistently, so fix the
inconsistency issue by replacing all occurances with the integer equivalent.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/beacon.c | 2 +-
 drivers/net/wireless/ath/ath9k/dynack.c | 4 ++--
 drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c   | 2 +-
 drivers/net/wireless/ath/ath9k/hw.c | 2 +-
 drivers/net/wireless/ath/ath9k/init.c   | 2 +-
 drivers/net/wireless/ath/ath9k/mac.h| 4 
 drivers/net/wireless/ath/ath9k/main.c   | 7 ---
 8 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/beacon.c 
b/drivers/net/wireless/ath/ath9k/beacon.c
index 800c96b..d8b4971 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
txq = sc->tx.txq_map[IEEE80211_AC_BE];
ath9k_hw_get_txq_props(ah, txq->axq_qnum, _be);
qi.tqi_aifs = qi_be.tqi_aifs;
-   if (ah->slottime == ATH9K_SLOT_TIME_20)
+   if (ah->slottime == 20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
diff --git a/drivers/net/wireless/ath/ath9k/dynack.c 
b/drivers/net/wireless/ath/ath9k/dynack.c
index d2ff0fc..7334c9b0 100644
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
 void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
 {
/* ackto = slottime + sifs + air delay */
-   u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+   u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = >dynack;
 
an->ackto = ackto;
@@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
 void ath_dynack_reset(struct ath_hw *ah)
 {
/* ackto = slottime + sifs + air delay */
-   u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
+   u32 ackto = 9 + 16 + 64;
struct ath_dynack *da = >dynack;
 
da->lto = jiffies;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c 
b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index e6bcb4c..2c0e4d2 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
 * Long slot time  : 2x cwmin
 * Short slot time : 4x cwmin
 */
-   if (ah->slottime == ATH9K_SLOT_TIME_20)
+   if (ah->slottime == 20)
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
else
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c 
b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index c148c6c..b65c1b6 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
 
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
priv->beacon.bslot[i] = NULL;
-   priv->beacon.slottime = ATH9K_SLOT_TIME_9;
+   priv->beacon.slottime = 9;
 
ath9k_cmn_init_channels_rates(common);
ath9k_cmn_init_crypto(ah);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c 
b/drivers/net/wireless/ath/ath9k/hw.c
index 1c27e2d..f091599 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -454,7 +454,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
if (AR_SREV_9100(ah))
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
 
-   ah->slottime = ATH9K_SLOT_TIME_9;
+   ah->slottime = 9;
ah->globaltxtimeout = (u32) -1;
ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true;
diff --git a/drivers/net/wireless/ath/ath9k/init.c 
b/drivers/net/wireless/ath/ath9k/init.c
index 2ee8624..89654d5 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -372,7 +372,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
 
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
-   sc->beacon.slottime = ATH9K_SLOT_TIME_9;
+   sc->beacon.slottime = 9;
 
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
sc->beacon.bslot[i] = NULL;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h 
b/drivers/net/wireless/ath/ath9k/mac.h
index 7fbf

[PATCH v2 3/6] ath9k: Use tsf offset helper in ath9k_hw_reset

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

These changes make ath9k_hw_reset more consistent with other places that
handle the TSF value by using the same helper routine.

A slight improvement is to not assume that a fixed time of 1.5ms has
passed for the initval writes when compared to the first write attempt.
Instead the TSF value is re-calculated which will yield a higher accuracy
of the restored TSF timer.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/hw.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c 
b/drivers/net/wireless/ath/ath9k/hw.c
index 8b2895f..1c27e2d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1832,8 +1832,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
u32 saveLedState;
u32 saveDefAntenna;
u32 macStaId1;
+   struct timespec tsf_ts;
+   u32 tsf_offset;
u64 tsf = 0;
-   s64 usec = 0;
int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@@ -1877,8 +1878,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
/* Save TSF before chip reset, a cold reset clears it */
+   getrawmonotonic(_ts);
tsf = ath9k_hw_gettsf64(ah);
-   usec = ktime_to_us(ktime_get_raw());
 
saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1911,8 +1912,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
}
 
/* Restore TSF */
-   usec = ktime_to_us(ktime_get_raw()) - usec;
-   ath9k_hw_settsf64(ah, tsf + usec);
+   tsf_offset = ath9k_hw_get_tsf_offset(_ts, NULL);
+   ath9k_hw_settsf64(ah, tsf + tsf_offset);
 
if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
@@ -1932,12 +1933,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
/*
 * Some AR91xx SoC devices frequently fail to accept TSF writes
 * right after the chip reset. When that happens, write a new
-* value after the initvals have been applied, with an offset
-* based on measured time difference
+* value after the initvals have been applied.
 */
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
-   tsf += 1500;
-   ath9k_hw_settsf64(ah, tsf);
+   tsf_offset = ath9k_hw_get_tsf_offset(_ts, NULL);
+   ath9k_hw_settsf64(ah, tsf + tsf_offset);
}
 
ath9k_hw_init_mfp(ah);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/6] ath9k: Correct TSF adjustment to align the beacon time correctly

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Beacons were not send out at (timestamp % beacon_time == 0) for interfaces
other than the primary one. To send out beacons with the correct timestamp
according to 10.1.3.2 of the 802.11 standard the tsf_adjustment has to be
set to the negative time difference instead of positive. This way the
later beacons get corrected to have a lower (and similar) timestamp with
regard to the beacon from slot 0.

I am not aware about any issues that have been caused by this.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/beacon.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/beacon.c 
b/drivers/net/wireless/ath/ath9k/beacon.c
index 5cf0cd7..800c96b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -279,17 +279,21 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, 
struct ieee80211_vif *vif)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_beacon_config *cur_conf = >chanctx->beacon;
-   u32 tsfadjust;
+   s64 tsfadjust;
 
if (avp->av_bslot == 0)
return;
 
+   /* tsf_adjust is added to the TSF value. We send out the beacon late,
+* so need to adjust the TSF starting point to be later in time (i.e.
+* the theoretical first beacon has a TSF of 0 after correction).
+*/
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
-   tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
+   tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
avp->tsf_adjust = cpu_to_le64(tsfadjust);
 
-   ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
-   (unsigned long long)tsfadjust, avp->av_bslot);
+   ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
+   (signed long long)tsfadjust, avp->av_bslot);
 }
 
 bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/6] ath9k: Handle channel context in get_/set_/reset_tsf

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

The ath9k TSF handling routines need to be aware of the channel context that
is being modified. With this change the TSF related values that are stored
in each channel context will be correctly tracked and the harware will only
be updated if the modified context is currently the active one.

Without this change the TSF modifications done using these routines would
for example be lost during a hardware reset as done by ath_complete_reset.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 21 ++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index 8b63988..375c2ac 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1823,11 +1823,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw 
*hw,
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
u64 tsf;
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
-   tsf = ath9k_hw_gettsf64(sc->sc_ah);
+   /* Get current TSF either from HW or kernel time. */
+   if (sc->cur_chan == avp->chanctx) {
+   tsf = ath9k_hw_gettsf64(sc->sc_ah);
+   } else {
+   tsf = sc->cur_chan->tsf_val +
+ ath9k_hw_get_tsf_offset(>cur_chan->tsf_ts, NULL);
+   }
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 
@@ -1839,10 +1846,14 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
  u64 tsf)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
-   ath9k_hw_settsf64(sc->sc_ah, tsf);
+   getrawmonotonic(>chanctx->tsf_ts);
+   if (sc->cur_chan == avp->chanctx)
+   ath9k_hw_settsf64(sc->sc_ah, tsf);
+   avp->chanctx->tsf_val = tsf;
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 }
@@ -1850,11 +1861,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
 static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
 
mutex_lock(>mutex);
 
ath9k_ps_wakeup(sc);
-   ath9k_hw_reset_tsf(sc->sc_ah);
+   getrawmonotonic(>chanctx->tsf_ts);
+   if (sc->cur_chan == avp->chanctx)
+   ath9k_hw_reset_tsf(sc->sc_ah);
+   avp->chanctx->tsf_val = 0;
ath9k_ps_restore(sc);
 
mutex_unlock(>mutex);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 4/6] ath9k: Expose tsf_adjustment in mac80211 tsf getters and setters.

2016-07-04 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

The ath9k driver modifies the TSF for VIFs for the purpose of sending
beacons in a staggered fashion. This patch exposes this VIF specific
adjustment of the TSF value to mac80211. Without the change the TSF
routines handle the hardware TSF value instead of the actual TSF value as
seen on the air.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index 375c2ac..f2ebc85 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1835,6 +1835,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct 
ieee80211_vif *vif)
tsf = sc->cur_chan->tsf_val +
  ath9k_hw_get_tsf_offset(>cur_chan->tsf_ts, NULL);
}
+   tsf += le64_to_cpu(avp->tsf_adjust);
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 
@@ -1850,6 +1851,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
+   tsf -= le64_to_cpu(avp->tsf_adjust);
getrawmonotonic(>chanctx->tsf_ts);
if (sc->cur_chan == avp->chanctx)
ath9k_hw_settsf64(sc->sc_ah, tsf);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/6] ath9k: Expose tsf_adjustment in mac80211 tsf getters and setters.

2016-06-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index 375c2ac..f2ebc85 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1835,6 +1835,7 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct 
ieee80211_vif *vif)
tsf = sc->cur_chan->tsf_val +
  ath9k_hw_get_tsf_offset(>cur_chan->tsf_ts, NULL);
}
+   tsf += le64_to_cpu(avp->tsf_adjust);
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 
@@ -1850,6 +1851,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
+   tsf -= le64_to_cpu(avp->tsf_adjust);
getrawmonotonic(>chanctx->tsf_ts);
if (sc->cur_chan == avp->chanctx)
ath9k_hw_settsf64(sc->sc_ah, tsf);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/6] ath9k: Handle channel context in get_/set_/reset_tsf

2016-06-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 21 ++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index 8b63988..375c2ac 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1823,11 +1823,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw 
*hw,
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
u64 tsf;
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
-   tsf = ath9k_hw_gettsf64(sc->sc_ah);
+   /* Get current TSF either from HW or kernel time. */
+   if (sc->cur_chan == avp->chanctx) {
+   tsf = ath9k_hw_gettsf64(sc->sc_ah);
+   } else {
+   tsf = sc->cur_chan->tsf_val +
+ ath9k_hw_get_tsf_offset(>cur_chan->tsf_ts, NULL);
+   }
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 
@@ -1839,10 +1846,14 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
  u64 tsf)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
 
mutex_lock(>mutex);
ath9k_ps_wakeup(sc);
-   ath9k_hw_settsf64(sc->sc_ah, tsf);
+   getrawmonotonic(>chanctx->tsf_ts);
+   if (sc->cur_chan == avp->chanctx)
+   ath9k_hw_settsf64(sc->sc_ah, tsf);
+   avp->chanctx->tsf_val = tsf;
ath9k_ps_restore(sc);
mutex_unlock(>mutex);
 }
@@ -1850,11 +1861,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw,
 static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
struct ath_softc *sc = hw->priv;
+   struct ath_vif *avp = (void *)vif->drv_priv;
 
mutex_lock(>mutex);
 
ath9k_ps_wakeup(sc);
-   ath9k_hw_reset_tsf(sc->sc_ah);
+   getrawmonotonic(>chanctx->tsf_ts);
+   if (sc->cur_chan == avp->chanctx)
+   ath9k_hw_reset_tsf(sc->sc_ah);
+   avp->chanctx->tsf_val = 0;
ath9k_ps_restore(sc);
 
mutex_unlock(>mutex);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/6] ath9k: Use defined constants consistently.

2016-06-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index f2ebc85..6a81298 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1785,9 +1785,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw 
*hw,
if ((avp->chanctx == sc->cur_chan) &&
(changed & BSS_CHANGED_ERP_SLOT)) {
if (bss_conf->use_short_slot)
-   slottime = 9;
+   slottime = ATH9K_SLOT_TIME_9;
else
-   slottime = 20;
+   slottime = ATH9K_SLOT_TIME_20;
+
if (vif->type == NL80211_IFTYPE_AP) {
/*
 * Defer update, so that connected stations can adjust
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/6] ath9k: Use tsf offset helper in ath9k_hw_reset

2016-06-07 Thread Benjamin Berg
From: Benjamin Berg <benjamin.b...@open-mesh.com>

Not much of a change. Only small fix is that we don't assume that
exactly 1.5ms have passed for the second AR91xx SoC TSF setting.

Signed-off-by: Benjamin Berg <benjamin.b...@open-mesh.com>
---
 drivers/net/wireless/ath/ath9k/hw.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c 
b/drivers/net/wireless/ath/ath9k/hw.c
index 8b2895f..1c27e2d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1832,8 +1832,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
u32 saveLedState;
u32 saveDefAntenna;
u32 macStaId1;
+   struct timespec tsf_ts;
+   u32 tsf_offset;
u64 tsf = 0;
-   s64 usec = 0;
int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@@ -1877,8 +1878,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
 
/* Save TSF before chip reset, a cold reset clears it */
+   getrawmonotonic(_ts);
tsf = ath9k_hw_gettsf64(ah);
-   usec = ktime_to_us(ktime_get_raw());
 
saveLedState = REG_READ(ah, AR_CFG_LED) &
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1911,8 +1912,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
}
 
/* Restore TSF */
-   usec = ktime_to_us(ktime_get_raw()) - usec;
-   ath9k_hw_settsf64(ah, tsf + usec);
+   tsf_offset = ath9k_hw_get_tsf_offset(_ts, NULL);
+   ath9k_hw_settsf64(ah, tsf + tsf_offset);
 
if (AR_SREV_9280_20_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
@@ -1932,12 +1933,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct 
ath9k_channel *chan,
/*
 * Some AR91xx SoC devices frequently fail to accept TSF writes
 * right after the chip reset. When that happens, write a new
-* value after the initvals have been applied, with an offset
-* based on measured time difference
+* value after the initvals have been applied.
 */
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
-   tsf += 1500;
-   ath9k_hw_settsf64(ah, tsf);
+   tsf_offset = ath9k_hw_get_tsf_offset(_ts, NULL);
+   ath9k_hw_settsf64(ah, tsf + tsf_offset);
}
 
ath9k_hw_init_mfp(ah);
-- 
2.8.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] ath9k: Prevent radard detection and spectral scan to be used concurrently

2015-06-01 Thread Benjamin Berg
In the case that a spectral scan is enabled the PHY errors sent by the
hardware as part of the scanning might trigger the radar detection and
channels might be marked as 'unusable' incorrectly. This patch fixes
the issue by preventing the spectral scan to be enabled if DFS is used
and only analysing the PHY errors for DFS if radar detection is enabled.

Reported-by: Mathias Kretschmer mathias.kretsch...@fokus.fraunhofer.de
Signed-off-by: Benjamin Berg benja...@sipsolutions.net
Signed-off-by: Simon Wunderlich s...@simonwunderlich.de

[v3.19+]
---

The patch does apply to 3.19+ with a bit of fuzz.


 drivers/net/wireless/ath/ath9k/common-spectral.c | 4 
 drivers/net/wireless/ath/ath9k/main.c| 6 ++
 drivers/net/wireless/ath/ath9k/recv.c| 7 +--
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c 
b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5cee231..59b5ad8 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -312,6 +312,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
size_t count, loff_t *ppos)
 {
struct ath_spec_scan_priv *spec_priv = file-private_data;
+   struct ath_hw *ah = spec_priv-ah;
struct ath_common *common = ath9k_hw_common(spec_priv-ah);
char buf[32];
ssize_t len;
@@ -319,6 +320,9 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
if (config_enabled(CONFIG_ATH9K_TX99))
return -EOPNOTSUPP;
 
+   if (ah-hw-conf.radar_enabled)
+   return -EINVAL;
+
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index b0badef..2d63062 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1433,6 +1433,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 
changed)
if (!ath9k_is_chanctx_enabled()  (changed  
IEEE80211_CONF_CHANGE_CHANNEL)) {
ctx-offchannel = !!(conf-flags  IEEE80211_CONF_OFFCHANNEL);
ath_chanctx_set_channel(sc, ctx, hw-conf.chandef);
+
+   /* We need to ensure that spectral scan is disabled. */
+   if (conf-radar_enabled 
+   sc-spec_priv.spectral_mode != SPECTRAL_DISABLED)
+   ath9k_cmn_spectral_scan_config(common, sc-spec_priv,
+  SPECTRAL_DISABLED);
}
 
mutex_unlock(sc-mutex);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c 
b/drivers/net/wireless/ath/ath9k/recv.c
index 6fb40ef..167628f 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -870,8 +870,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 * can be dropped.
 */
if (rx_stats-rs_status  ATH9K_RXERR_PHY) {
-   ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status-mactime);
-   if (ath_cmn_process_fft(sc-spec_priv, hdr, rx_stats, 
rx_status-mactime))
+   if (hw-conf.radar_enabled)
+   ath9k_dfs_process_phyerr(sc, hdr,
+rx_stats, rx_status-mactime);
+   else if (ath_cmn_process_fft(sc-spec_priv, hdr
+rx_stats, rx_status-mactime))
RX_STAT_INC(rx_spectral);
 
return -EINVAL;
-- 
2.1.4

--
To unsubscribe from this list: send the line unsubscribe linux-wireless in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html