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