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