]> git.ipfire.org Git - thirdparty/iw.git/blame - coalesce.c
iw: bump version to 4.7
[thirdparty/iw.git] / coalesce.c
CommitLineData
aa0f5dbe
AK
1#include <errno.h>
2#include <string.h>
3#include <stdio.h>
4
5#include <netlink/genl/genl.h>
6#include <netlink/genl/family.h>
7#include <netlink/genl/ctrl.h>
8#include <netlink/msg.h>
9#include <netlink/attr.h>
10
aa0f5dbe
AK
11#include "nl80211.h"
12#include "iw.h"
13
14SECTION(coalesce);
15
34b23014 16static int handle_coalesce_enable(struct nl80211_state *state,
aa0f5dbe
AK
17 struct nl_msg *msg, int argc, char **argv,
18 enum id_input id)
19{
20 struct nlattr *nl_rules, *nl_rule = NULL, *nl_pats, *nl_pat;
21 unsigned char *pat, *mask;
22 size_t patlen;
23 int patnum = 0, pkt_offset, err = 1;
24 char *eptr, *value1, *value2, *sptr = NULL, *end, buf[16768];
25 enum nl80211_coalesce_condition condition;
26 FILE *f = fopen(argv[0], "r");
27 enum {
28 PS_DELAY,
29 PS_CONDITION,
30 PS_PATTERNS
31 } parse_state = PS_DELAY;
32 int rule_num = 0;
33
34 if (!f)
35 return 1;
36
37 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE);
bfb64ed0
YY
38 if (!nl_rules) {
39 fclose(f);
aa0f5dbe 40 return -ENOBUFS;
bfb64ed0 41 }
aa0f5dbe
AK
42
43 while (!feof(f)) {
44 char *eol;
45
46 if (!fgets(buf, sizeof(buf), f))
47 break;
48
49 eol = strchr(buf + 5, '\r');
50 if (eol)
51 *eol = 0;
52 eol = strchr(buf + 5, '\n');
53 if (eol)
54 *eol = 0;
55
56 switch (parse_state) {
57 case PS_DELAY:
58 if (strncmp(buf, "delay=", 6) == 0) {
59 char *delay = buf + 6;
60
61 rule_num++;
62 nl_rule = nla_nest_start(msg, rule_num);
63 if (!nl_rule)
64 goto close;
65
66 NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_DELAY,
67 strtoul(delay, &end, 10));
68 if (*end != '\0')
69 goto close;
70 parse_state = PS_CONDITION;
71 } else {
72 goto close;
73 }
74 break;
75 case PS_CONDITION:
76 if (strncmp(buf, "condition=", 10) == 0) {
77 char *cond = buf + 10;
78
79 condition = strtoul(cond, &end, 10);
80 if (*end != '\0')
81 goto close;
82 NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION,
83 condition);
84 parse_state = PS_PATTERNS;
85 } else {
86 goto close;
87 }
88 break;
89 case PS_PATTERNS:
90 if (strncmp(buf, "patterns=", 9) == 0) {
91 char *cur_pat = buf + 9;
92 char *next_pat = strchr(buf + 9, ',');
93
94 if (next_pat) {
95 *next_pat = 0;
96 next_pat++;
97 }
98
99 nl_pats = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE_PKT_PATTERN);
100 while (1) {
101 value1 = strtok_r(cur_pat, "+", &sptr);
102 value2 = strtok_r(NULL, "+", &sptr);
103
104 if (!value2) {
105 pkt_offset = 0;
106 if (!value1)
107 goto close;
108 value2 = value1;
109 } else {
110 pkt_offset = strtoul(value1, &eptr, 10);
111 if (eptr != value1 + strlen(value1))
112 goto close;
113 }
114
115 if (parse_hex_mask(value2, &pat, &patlen, &mask))
116 goto close;
117
118 nl_pat = nla_nest_start(msg, ++patnum);
119 NLA_PUT(msg, NL80211_PKTPAT_MASK,
120 DIV_ROUND_UP(patlen, 8), mask);
121 NLA_PUT(msg, NL80211_PKTPAT_PATTERN, patlen, pat);
122 NLA_PUT_U32(msg, NL80211_PKTPAT_OFFSET,
123 pkt_offset);
124 nla_nest_end(msg, nl_pat);
125 free(mask);
126 free(pat);
127
128 if (!next_pat)
129 break;
130 cur_pat = next_pat;
131 next_pat = strchr(cur_pat, ',');
132 if (next_pat) {
133 *next_pat = 0;
134 next_pat++;
135 }
136 }
137 nla_nest_end(msg, nl_pats);
138 nla_nest_end(msg, nl_rule);
139 parse_state = PS_DELAY;
140
141 } else {
142 goto close;
143 }
144 break;
145 default:
146 if (buf[0] == '#')
147 continue;
148 goto close;
149 }
150 }
151
152 if (parse_state == PS_DELAY)
153 err = 0;
154 else
155 err = 1;
156 goto close;
157nla_put_failure:
158 err = -ENOBUFS;
159close:
160 fclose(f);
161 nla_nest_end(msg, nl_rules);
162 return err;
163}
164
165COMMAND(coalesce, enable, "<config-file>",
166 NL80211_CMD_SET_COALESCE, 0, CIB_PHY, handle_coalesce_enable,
167 "Enable coalesce with given configuration.\n"
168 "The configuration file contains coalesce rules:\n"
169 " delay=<delay>\n"
170 " condition=<condition>\n"
171 " patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n"
172 " delay=<delay>\n"
173 " condition=<condition>\n"
174 " patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n"
175 " ...\n"
176 "delay: maximum coalescing delay in msec.\n"
4f7bb083 177 "condition: 1/0 i.e. 'not match'/'match' the patterns\n"
aa0f5dbe
AK
178 "patterns: each pattern is given as a bytestring with '-' in\n"
179 "places where any byte may be present, e.g. 00:11:22:-:44 will\n"
180 "match 00:11:22:33:44 and 00:11:22:33:ff:44 etc. Offset and\n"
181 "pattern should be separated by '+', e.g. 18+43:34:00:12 will\n"
182 "match '43:34:00:12' after 18 bytes of offset in Rx packet.\n");
183
184static int
34b23014 185handle_coalesce_disable(struct nl80211_state *state,
aa0f5dbe
AK
186 struct nl_msg *msg, int argc, char **argv,
187 enum id_input id)
188{
189 /* just a set w/o coalesce attribute */
190 return 0;
191}
192COMMAND(coalesce, disable, "", NL80211_CMD_SET_COALESCE, 0, CIB_PHY,
193 handle_coalesce_disable, "Disable coalesce.");
194
195static int print_coalesce_handler(struct nl_msg *msg, void *arg)
196{
197 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
198 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
199 struct nlattr *pattern, *rule;
200 int rem_pattern, rem_rule;
201 enum nl80211_coalesce_condition condition;
202 int delay;
203
204 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
205 genlmsg_attrlen(gnlh, 0), NULL);
206
207 if (!attrs[NL80211_ATTR_COALESCE_RULE]) {
208 printf("Coalesce is disabled.\n");
209 return NL_SKIP;
210 }
211
212 printf("Coalesce is enabled:\n");
213
214 nla_for_each_nested(rule, attrs[NL80211_ATTR_COALESCE_RULE], rem_rule) {
215 struct nlattr *ruleattr[NUM_NL80211_ATTR_COALESCE_RULE];
216
217 nla_parse(ruleattr, NL80211_ATTR_COALESCE_RULE_MAX,
218 nla_data(rule), nla_len(rule), NULL);
219
220 delay = nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_DELAY]);
221 condition =
222 nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_CONDITION]);
223
224 printf("Rule - max coalescing delay: %dmsec condition:", delay);
225 if (condition)
aa0f5dbe 226 printf("not match\n");
4f7bb083
AK
227 else
228 printf("match\n");
aa0f5dbe
AK
229
230 if (ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN]) {
231 nla_for_each_nested(pattern,
232 ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN],
233 rem_pattern) {
234 struct nlattr *patattr[NUM_NL80211_PKTPAT];
235 int i, patlen, masklen, pkt_offset;
236 uint8_t *mask, *pat;
237
238 nla_parse(patattr, MAX_NL80211_PKTPAT,
239 nla_data(pattern), nla_len(pattern),
240 NULL);
241 if (!patattr[NL80211_PKTPAT_MASK] ||
242 !patattr[NL80211_PKTPAT_PATTERN] ||
243 !patattr[NL80211_PKTPAT_OFFSET]) {
244 printf(" * (invalid pattern specification)\n");
245 continue;
246 }
247 masklen = nla_len(patattr[NL80211_PKTPAT_MASK]);
248 patlen = nla_len(patattr[NL80211_PKTPAT_PATTERN]);
249 pkt_offset = nla_get_u32(patattr[NL80211_PKTPAT_OFFSET]);
250 if (DIV_ROUND_UP(patlen, 8) != masklen) {
251 printf(" * (invalid pattern specification)\n");
252 continue;
253 }
254 printf(" * packet offset: %d", pkt_offset);
255 printf(" pattern: ");
256 pat = nla_data(patattr[NL80211_PKTPAT_PATTERN]);
257 mask = nla_data(patattr[NL80211_PKTPAT_MASK]);
258 for (i = 0; i < patlen; i++) {
259 if (mask[i / 8] & (1 << (i % 8)))
260 printf("%.2x", pat[i]);
261 else
262 printf("--");
263 if (i != patlen - 1)
264 printf(":");
265 }
266 printf("\n");
267 }
268 }
269 }
270
271 return NL_SKIP;
272}
273
34b23014 274static int handle_coalesce_show(struct nl80211_state *state,
aa0f5dbe
AK
275 struct nl_msg *msg, int argc, char **argv,
276 enum id_input id)
277{
34b23014 278 register_handler(print_coalesce_handler, NULL);
aa0f5dbe
AK
279
280 return 0;
281}
282COMMAND(coalesce, show, "", NL80211_CMD_GET_COALESCE, 0, CIB_PHY, handle_coalesce_show,
283 "Show coalesce status.");