]> git.ipfire.org Git - thirdparty/iw.git/commitdiff
iw: add coalesce support
authorAmitkumar Karwar <akarwar@marvell.com>
Fri, 28 Jun 2013 19:53:45 +0000 (12:53 -0700)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 8 Jul 2013 11:19:36 +0000 (13:19 +0200)
User can configure multiple coalesce rules using 'iw coalesce
enable <config-file>' command. The setting can be cleared using
'iw coalesce disable' command. 'iw coalesce show' displays current
configuration.

Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Makefile
coalesce.c [new file with mode: 0644]
info.c

index c485b5e96553ba478b983341248ec220b01dda7c..f042e307c189deac3af726ca220563ed9779ed1c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ OBJS = iw.o genl.o event.o info.o phy.o \
        interface.o ibss.o station.o survey.o util.o \
        mesh.o mpath.o scan.o reg.o version.o \
        reason.o status.o connect.o link.o offch.o ps.o cqm.o \
-       bitrate.o wowlan.o roc.o p2p.o
+       bitrate.o wowlan.o coalesce.o roc.o p2p.o
 OBJS += sections.o
 
 OBJS-$(HWSIM) += hwsim.o
diff --git a/coalesce.c b/coalesce.c
new file mode 100644 (file)
index 0000000..22d1534
--- /dev/null
@@ -0,0 +1,285 @@
+#include <net/if.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include <arpa/inet.h>
+
+#include "nl80211.h"
+#include "iw.h"
+
+SECTION(coalesce);
+
+static int handle_coalesce_enable(struct nl80211_state *state, struct nl_cb *cb,
+                                 struct nl_msg *msg, int argc, char **argv,
+                                 enum id_input id)
+{
+       struct nlattr *nl_rules, *nl_rule = NULL, *nl_pats, *nl_pat;
+       unsigned char *pat, *mask;
+       size_t patlen;
+       int patnum = 0, pkt_offset, err = 1;
+       char *eptr, *value1, *value2, *sptr = NULL, *end, buf[16768];
+       enum nl80211_coalesce_condition condition;
+       FILE *f = fopen(argv[0], "r");
+       enum {
+               PS_DELAY,
+               PS_CONDITION,
+               PS_PATTERNS
+       } parse_state = PS_DELAY;
+       int rule_num = 0;
+
+       if (!f)
+               return 1;
+
+       nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
+       if (!nl_rules)
+               return -ENOBUFS;
+
+       while (!feof(f)) {
+               char *eol;
+
+               if (!fgets(buf, sizeof(buf), f))
+                       break;
+
+               eol = strchr(buf + 5, '\r');
+               if (eol)
+                       *eol = 0;
+               eol = strchr(buf + 5, '\n');
+               if (eol)
+                       *eol = 0;
+
+               switch (parse_state) {
+               case PS_DELAY:
+                       if (strncmp(buf, "delay=", 6) == 0) {
+                               char *delay = buf + 6;
+
+                               rule_num++;
+                               nl_rule = nla_nest_start(msg, rule_num);
+                               if (!nl_rule)
+                                       goto close;
+
+                               NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
+                                           strtoul(delay, &end, 10));
+                               if (*end != '\0')
+                                       goto close;
+                               parse_state = PS_CONDITION;
+                       } else {
+                               goto close;
+                       }
+                       break;
+               case PS_CONDITION:
+                       if (strncmp(buf, "condition=", 10) == 0) {
+                               char *cond = buf + 10;
+
+                               condition = strtoul(cond, &end, 10);
+                               if (*end != '\0')
+                                       goto close;
+                               NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
+                                           condition);
+                               parse_state = PS_PATTERNS;
+                       } else {
+                               goto close;
+                       }
+                       break;
+               case PS_PATTERNS:
+                       if (strncmp(buf, "patterns=", 9) == 0) {
+                               char *cur_pat = buf + 9;
+                               char *next_pat = strchr(buf + 9, ',');
+
+                               if (next_pat) {
+                                       *next_pat = 0;
+                                       next_pat++;
+                               }
+
+                               nl_pats = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
+                               while (1) {
+                                       value1 = strtok_r(cur_pat, "+", &sptr);
+                                       value2 = strtok_r(NULL, "+", &sptr);
+
+                                       if (!value2) {
+                                               pkt_offset = 0;
+                                               if (!value1)
+                                                       goto close;
+                                               value2 = value1;
+                                       } else {
+                                               pkt_offset = strtoul(value1, &eptr, 10);
+                                               if (eptr != value1 + strlen(value1))
+                                                       goto close;
+                                       }
+
+                                       if (parse_hex_mask(value2, &pat, &patlen, &mask))
+                                               goto close;
+
+                                       nl_pat = nla_nest_start(msg, ++patnum);
+                                       NLA_PUT(msg, NL80211_PKTPAT_MASK,
+                                               DIV_ROUND_UP(patlen, 8), mask);
+                                       NLA_PUT(msg, NL80211_PKTPAT_PATTERN, patlen, pat);
+                                       NLA_PUT_U32(msg, NL80211_PKTPAT_OFFSET,
+                                                   pkt_offset);
+                                       nla_nest_end(msg, nl_pat);
+                                       free(mask);
+                                       free(pat);
+
+                                       if (!next_pat)
+                                               break;
+                                       cur_pat = next_pat;
+                                       next_pat = strchr(cur_pat, ',');
+                                       if (next_pat) {
+                                               *next_pat = 0;
+                                               next_pat++;
+                                       }
+                               }
+                               nla_nest_end(msg, nl_pats);
+                               nla_nest_end(msg, nl_rule);
+                               parse_state = PS_DELAY;
+
+                       } else {
+                               goto close;
+                       }
+                       break;
+               default:
+                       if (buf[0] == '#')
+                               continue;
+                       goto close;
+               }
+       }
+
+       if (parse_state == PS_DELAY)
+               err = 0;
+       else
+               err = 1;
+       goto close;
+nla_put_failure:
+       err = -ENOBUFS;
+close:
+       fclose(f);
+       nla_nest_end(msg, nl_rules);
+       return err;
+}
+
+COMMAND(coalesce, enable, "<config-file>",
+       NL80211_CMD_SET_COALESCE, 0, CIB_PHY, handle_coalesce_enable,
+       "Enable coalesce with given configuration.\n"
+       "The configuration file contains coalesce rules:\n"
+       "  delay=<delay>\n"
+       "  condition=<condition>\n"
+       "  patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n"
+       "  delay=<delay>\n"
+       "  condition=<condition>\n"
+       "  patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n"
+       "  ...\n"
+       "delay: maximum coalescing delay in msec.\n"
+       "condition: 0/1 i.e. 'not match'/'match' the patterns\n"
+       "patterns: each pattern is given as a bytestring with '-' in\n"
+       "places where any byte may be present, e.g. 00:11:22:-:44 will\n"
+       "match 00:11:22:33:44 and 00:11:22:33:ff:44 etc. Offset and\n"
+       "pattern should be separated by '+', e.g. 18+43:34:00:12 will\n"
+       "match '43:34:00:12' after 18 bytes of offset in Rx packet.\n");
+
+static int
+handle_coalesce_disable(struct nl80211_state *state, struct nl_cb *cb,
+                       struct nl_msg *msg, int argc, char **argv,
+                       enum id_input id)
+{
+       /* just a set w/o coalesce attribute */
+       return 0;
+}
+COMMAND(coalesce, disable, "", NL80211_CMD_SET_COALESCE, 0, CIB_PHY,
+       handle_coalesce_disable, "Disable coalesce.");
+
+static int print_coalesce_handler(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *attrs[NL80211_ATTR_MAX + 1];
+       struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *pattern, *rule;
+       int rem_pattern, rem_rule;
+       enum nl80211_coalesce_condition condition;
+       int delay;
+
+       nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+                 genlmsg_attrlen(gnlh, 0), NULL);
+
+       if (!attrs[NL80211_ATTR_COALESCE_RULE]) {
+               printf("Coalesce is disabled.\n");
+               return NL_SKIP;
+       }
+
+       printf("Coalesce is enabled:\n");
+
+       nla_for_each_nested(rule, attrs[NL80211_ATTR_COALESCE_RULE], rem_rule) {
+               struct nlattr *ruleattr[NUM_NL80211_ATTR_COALESCE_RULE];
+
+               nla_parse(ruleattr, NL80211_ATTR_COALESCE_RULE_MAX,
+                         nla_data(rule), nla_len(rule), NULL);
+
+               delay = nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_DELAY]);
+               condition =
+                    nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_CONDITION]);
+
+               printf("Rule - max coalescing delay: %dmsec condition:", delay);
+               if (condition)
+                       printf("match\n");
+               else
+                       printf("not match\n");
+
+               if (ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN]) {
+                       nla_for_each_nested(pattern,
+                                           ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
+                                           rem_pattern) {
+                               struct nlattr *patattr[NUM_NL80211_PKTPAT];
+                               int i, patlen, masklen, pkt_offset;
+                               uint8_t *mask, *pat;
+
+                               nla_parse(patattr, MAX_NL80211_PKTPAT,
+                                         nla_data(pattern), nla_len(pattern),
+                                         NULL);
+                               if (!patattr[NL80211_PKTPAT_MASK] ||
+                                   !patattr[NL80211_PKTPAT_PATTERN] ||
+                                   !patattr[NL80211_PKTPAT_OFFSET]) {
+                                       printf(" * (invalid pattern specification)\n");
+                                       continue;
+                               }
+                               masklen = nla_len(patattr[NL80211_PKTPAT_MASK]);
+                               patlen = nla_len(patattr[NL80211_PKTPAT_PATTERN]);
+                               pkt_offset = nla_get_u32(patattr[NL80211_PKTPAT_OFFSET]);
+                               if (DIV_ROUND_UP(patlen, 8) != masklen) {
+                                       printf(" * (invalid pattern specification)\n");
+                                       continue;
+                               }
+                               printf(" * packet offset: %d", pkt_offset);
+                               printf(" pattern: ");
+                               pat = nla_data(patattr[NL80211_PKTPAT_PATTERN]);
+                               mask = nla_data(patattr[NL80211_PKTPAT_MASK]);
+                               for (i = 0; i < patlen; i++) {
+                                       if (mask[i / 8] & (1 << (i % 8)))
+                                               printf("%.2x", pat[i]);
+                                       else
+                                               printf("--");
+                                       if (i != patlen - 1)
+                                               printf(":");
+                               }
+                               printf("\n");
+                       }
+               }
+       }
+
+       return NL_SKIP;
+}
+
+static int handle_coalesce_show(struct nl80211_state *state, struct nl_cb *cb,
+                             struct nl_msg *msg, int argc, char **argv,
+                             enum id_input id)
+{
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+                 print_coalesce_handler, NULL);
+
+       return 0;
+}
+COMMAND(coalesce, show, "", NL80211_CMD_GET_COALESCE, 0, CIB_PHY, handle_coalesce_show,
+       "Show coalesce status.");
diff --git a/info.c b/info.c
index d893ffc4e2ab27c147f70f3e098419688ad67d6d..7e61e883058e5148608e1a321591a6cdf7e8097d 100644 (file)
--- a/info.c
+++ b/info.c
@@ -528,6 +528,21 @@ broken_combination:
                        printf("\tDevice supports AP scan.\n");
        }
 
+       if (tb_msg[NL80211_ATTR_COALESCE_RULE]) {
+               struct nl80211_coalesce_rule_support *rule;
+               struct nl80211_pattern_support *pat;
+
+               printf("\tCoalesce support:\n");
+               rule = nla_data(tb_msg[NL80211_ATTR_COALESCE_RULE]);
+               pat = &rule->pat;
+               printf("\t\t * Maximum %u coalesce rules supported\n"
+                      "\t\t * Each rule contains upto %u patterns of %u-%u bytes,\n"
+                      "\t\t   maximum packet offset %u bytes\n"
+                      "\t\t * Maximum supported coalescing delay %u msecs\n",
+                       rule->max_rules, pat->max_patterns, pat->min_pattern_len,
+                       pat->max_pattern_len, pat->max_pkt_offset, rule->max_delay);
+       }
+
        return NL_SKIP;
 }