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