]>
Commit | Line | Data |
---|---|---|
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 | ||
14 | SECTION(coalesce); | |
15 | ||
34b23014 | 16 | static 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; | |
157 | nla_put_failure: | |
158 | err = -ENOBUFS; | |
159 | close: | |
160 | fclose(f); | |
161 | nla_nest_end(msg, nl_rules); | |
162 | return err; | |
163 | } | |
164 | ||
165 | COMMAND(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 | ||
184 | static int | |
34b23014 | 185 | handle_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 | } | |
192 | COMMAND(coalesce, disable, "", NL80211_CMD_SET_COALESCE, 0, CIB_PHY, | |
193 | handle_coalesce_disable, "Disable coalesce."); | |
194 | ||
195 | static 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 | 274 | static 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 | } | |
282 | COMMAND(coalesce, show, "", NL80211_CMD_GET_COALESCE, 0, CIB_PHY, handle_coalesce_show, | |
283 | "Show coalesce status."); |