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