xref: /aosp_15_r20/external/iw/coalesce.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
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