xref: /aosp_15_r20/external/iproute2/tc/em_canid.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker  * em_canid.c  Ematch rule to match CAN frames according to their CAN identifiers
3*de1e4e89SAndroid Build Coastguard Worker  *
4*de1e4e89SAndroid Build Coastguard Worker  *             This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker  *             modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker  *             as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker  *             2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker  *
9*de1e4e89SAndroid Build Coastguard Worker  * Idea:       Oliver Hartkopp <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker  * Copyright:  (c) 2011 Czech Technical University in Prague
11*de1e4e89SAndroid Build Coastguard Worker  *             (c) 2011 Volkswagen Group Research
12*de1e4e89SAndroid Build Coastguard Worker  * Authors:    Michal Sojka <[email protected]>
13*de1e4e89SAndroid Build Coastguard Worker  *             Pavel Pisa <[email protected]>
14*de1e4e89SAndroid Build Coastguard Worker  *             Rostislav Lisovy <[email protected]>
15*de1e4e89SAndroid Build Coastguard Worker  * Funded by:  Volkswagen Group Research
16*de1e4e89SAndroid Build Coastguard Worker  *
17*de1e4e89SAndroid Build Coastguard Worker  * Documentation: http://rtime.felk.cvut.cz/can/socketcan-qdisc-final.pdf
18*de1e4e89SAndroid Build Coastguard Worker  */
19*de1e4e89SAndroid Build Coastguard Worker 
20*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
26*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
27*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
28*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
29*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
30*de1e4e89SAndroid Build Coastguard Worker #include <linux/can.h>
31*de1e4e89SAndroid Build Coastguard Worker #include <inttypes.h>
32*de1e4e89SAndroid Build Coastguard Worker #include "m_ematch.h"
33*de1e4e89SAndroid Build Coastguard Worker 
34*de1e4e89SAndroid Build Coastguard Worker #define EM_CANID_RULES_MAX 400 /* Main reason for this number is Nelink
35*de1e4e89SAndroid Build Coastguard Worker 	message size limit equal to Single memory page size. When dump()
36*de1e4e89SAndroid Build Coastguard Worker 	is invoked, there are even some ematch related headers sent from
37*de1e4e89SAndroid Build Coastguard Worker 	kernel to userspace together with em_canid configuration --
38*de1e4e89SAndroid Build Coastguard Worker 	400*sizeof(struct can_filter) should fit without any problems */
39*de1e4e89SAndroid Build Coastguard Worker 
40*de1e4e89SAndroid Build Coastguard Worker extern struct ematch_util canid_ematch_util;
41*de1e4e89SAndroid Build Coastguard Worker struct rules {
42*de1e4e89SAndroid Build Coastguard Worker 	struct can_filter *rules_raw;
43*de1e4e89SAndroid Build Coastguard Worker 	int rules_capacity;	/* Size of array allocated for rules_raw */
44*de1e4e89SAndroid Build Coastguard Worker 	int rules_cnt;		/* Actual number of rules stored in rules_raw */
45*de1e4e89SAndroid Build Coastguard Worker };
46*de1e4e89SAndroid Build Coastguard Worker 
canid_print_usage(FILE * fd)47*de1e4e89SAndroid Build Coastguard Worker static void canid_print_usage(FILE *fd)
48*de1e4e89SAndroid Build Coastguard Worker {
49*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fd,
50*de1e4e89SAndroid Build Coastguard Worker 		"Usage: canid(IDLIST)\n" \
51*de1e4e89SAndroid Build Coastguard Worker 		"where: IDLIST := IDSPEC [ IDLIST ]\n" \
52*de1e4e89SAndroid Build Coastguard Worker 		"       IDSPEC := { ’sff’ CANID | ’eff’ CANID }\n" \
53*de1e4e89SAndroid Build Coastguard Worker 		"       CANID := ID[:MASK]\n" \
54*de1e4e89SAndroid Build Coastguard Worker 		"       ID, MASK := hexadecimal number (i.e. 0x123)\n" \
55*de1e4e89SAndroid Build Coastguard Worker 		"Example: canid(sff 0x123 sff 0x124 sff 0x125:0xf)\n");
56*de1e4e89SAndroid Build Coastguard Worker }
57*de1e4e89SAndroid Build Coastguard Worker 
canid_parse_rule(struct rules * rules,struct bstr * a,int iseff)58*de1e4e89SAndroid Build Coastguard Worker static int canid_parse_rule(struct rules *rules, struct bstr *a, int iseff)
59*de1e4e89SAndroid Build Coastguard Worker {
60*de1e4e89SAndroid Build Coastguard Worker 	unsigned int can_id = 0;
61*de1e4e89SAndroid Build Coastguard Worker 	unsigned int can_mask = 0;
62*de1e4e89SAndroid Build Coastguard Worker 
63*de1e4e89SAndroid Build Coastguard Worker 	if (sscanf(a->data, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
64*de1e4e89SAndroid Build Coastguard Worker 		if (sscanf(a->data, "%"SCNx32, &can_id) != 1) {
65*de1e4e89SAndroid Build Coastguard Worker 			return -1;
66*de1e4e89SAndroid Build Coastguard Worker 		} else {
67*de1e4e89SAndroid Build Coastguard Worker 			can_mask = (iseff) ? CAN_EFF_MASK : CAN_SFF_MASK;
68*de1e4e89SAndroid Build Coastguard Worker 		}
69*de1e4e89SAndroid Build Coastguard Worker 	}
70*de1e4e89SAndroid Build Coastguard Worker 
71*de1e4e89SAndroid Build Coastguard Worker 	/* Stretch rules array up to EM_CANID_RULES_MAX if necessary */
72*de1e4e89SAndroid Build Coastguard Worker 	if (rules->rules_cnt == rules->rules_capacity) {
73*de1e4e89SAndroid Build Coastguard Worker 		if (rules->rules_capacity <= EM_CANID_RULES_MAX/2) {
74*de1e4e89SAndroid Build Coastguard Worker 			rules->rules_capacity *= 2;
75*de1e4e89SAndroid Build Coastguard Worker 			rules->rules_raw = realloc(rules->rules_raw,
76*de1e4e89SAndroid Build Coastguard Worker 				sizeof(struct can_filter) * rules->rules_capacity);
77*de1e4e89SAndroid Build Coastguard Worker 		} else {
78*de1e4e89SAndroid Build Coastguard Worker 			return -2;
79*de1e4e89SAndroid Build Coastguard Worker 		}
80*de1e4e89SAndroid Build Coastguard Worker 	}
81*de1e4e89SAndroid Build Coastguard Worker 
82*de1e4e89SAndroid Build Coastguard Worker 	rules->rules_raw[rules->rules_cnt].can_id =
83*de1e4e89SAndroid Build Coastguard Worker 		can_id | ((iseff) ? CAN_EFF_FLAG : 0);
84*de1e4e89SAndroid Build Coastguard Worker 	rules->rules_raw[rules->rules_cnt].can_mask =
85*de1e4e89SAndroid Build Coastguard Worker 		can_mask | CAN_EFF_FLAG;
86*de1e4e89SAndroid Build Coastguard Worker 
87*de1e4e89SAndroid Build Coastguard Worker 	rules->rules_cnt++;
88*de1e4e89SAndroid Build Coastguard Worker 
89*de1e4e89SAndroid Build Coastguard Worker 	return 0;
90*de1e4e89SAndroid Build Coastguard Worker }
91*de1e4e89SAndroid Build Coastguard Worker 
canid_parse_eopt(struct nlmsghdr * n,struct tcf_ematch_hdr * hdr,struct bstr * args)92*de1e4e89SAndroid Build Coastguard Worker static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
93*de1e4e89SAndroid Build Coastguard Worker 			  struct bstr *args)
94*de1e4e89SAndroid Build Coastguard Worker {
95*de1e4e89SAndroid Build Coastguard Worker 	int iseff = 0;
96*de1e4e89SAndroid Build Coastguard Worker 	int ret = 0;
97*de1e4e89SAndroid Build Coastguard Worker 	struct rules rules = {
98*de1e4e89SAndroid Build Coastguard Worker 		.rules_capacity = 25, /* Denominator of EM_CANID_RULES_MAX
99*de1e4e89SAndroid Build Coastguard Worker 			Will be multiplied by 2 to calculate the size for realloc() */
100*de1e4e89SAndroid Build Coastguard Worker 		.rules_cnt = 0
101*de1e4e89SAndroid Build Coastguard Worker 	};
102*de1e4e89SAndroid Build Coastguard Worker 
103*de1e4e89SAndroid Build Coastguard Worker #define PARSE_ERR(CARG, FMT, ARGS...) \
104*de1e4e89SAndroid Build Coastguard Worker 	em_parse_error(EINVAL, args, CARG, &canid_ematch_util, FMT, ##ARGS)
105*de1e4e89SAndroid Build Coastguard Worker 
106*de1e4e89SAndroid Build Coastguard Worker 	if (args == NULL)
107*de1e4e89SAndroid Build Coastguard Worker 		return PARSE_ERR(args, "canid: missing arguments");
108*de1e4e89SAndroid Build Coastguard Worker 
109*de1e4e89SAndroid Build Coastguard Worker 	rules.rules_raw = calloc(rules.rules_capacity,
110*de1e4e89SAndroid Build Coastguard Worker 				 sizeof(struct can_filter));
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker 	do {
113*de1e4e89SAndroid Build Coastguard Worker 		if (!bstrcmp(args, "sff")) {
114*de1e4e89SAndroid Build Coastguard Worker 			iseff = 0;
115*de1e4e89SAndroid Build Coastguard Worker 		} else if (!bstrcmp(args, "eff")) {
116*de1e4e89SAndroid Build Coastguard Worker 			iseff = 1;
117*de1e4e89SAndroid Build Coastguard Worker 		} else {
118*de1e4e89SAndroid Build Coastguard Worker 			ret = PARSE_ERR(args, "canid: invalid key");
119*de1e4e89SAndroid Build Coastguard Worker 			goto exit;
120*de1e4e89SAndroid Build Coastguard Worker 		}
121*de1e4e89SAndroid Build Coastguard Worker 
122*de1e4e89SAndroid Build Coastguard Worker 		args = bstr_next(args);
123*de1e4e89SAndroid Build Coastguard Worker 		if (args == NULL) {
124*de1e4e89SAndroid Build Coastguard Worker 			ret = PARSE_ERR(args, "canid: missing argument");
125*de1e4e89SAndroid Build Coastguard Worker 			goto exit;
126*de1e4e89SAndroid Build Coastguard Worker 		}
127*de1e4e89SAndroid Build Coastguard Worker 
128*de1e4e89SAndroid Build Coastguard Worker 		ret = canid_parse_rule(&rules, args, iseff);
129*de1e4e89SAndroid Build Coastguard Worker 		if (ret == -1) {
130*de1e4e89SAndroid Build Coastguard Worker 			ret = PARSE_ERR(args, "canid: Improperly formed CAN ID & mask\n");
131*de1e4e89SAndroid Build Coastguard Worker 			goto exit;
132*de1e4e89SAndroid Build Coastguard Worker 		} else if (ret == -2) {
133*de1e4e89SAndroid Build Coastguard Worker 			ret = PARSE_ERR(args, "canid: Too many arguments on input\n");
134*de1e4e89SAndroid Build Coastguard Worker 			goto exit;
135*de1e4e89SAndroid Build Coastguard Worker 		}
136*de1e4e89SAndroid Build Coastguard Worker 	} while ((args = bstr_next(args)) != NULL);
137*de1e4e89SAndroid Build Coastguard Worker 
138*de1e4e89SAndroid Build Coastguard Worker 	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
139*de1e4e89SAndroid Build Coastguard Worker 	addraw_l(n, MAX_MSG, rules.rules_raw,
140*de1e4e89SAndroid Build Coastguard Worker 		sizeof(struct can_filter) * rules.rules_cnt);
141*de1e4e89SAndroid Build Coastguard Worker 
142*de1e4e89SAndroid Build Coastguard Worker #undef PARSE_ERR
143*de1e4e89SAndroid Build Coastguard Worker exit:
144*de1e4e89SAndroid Build Coastguard Worker 	free(rules.rules_raw);
145*de1e4e89SAndroid Build Coastguard Worker 	return ret;
146*de1e4e89SAndroid Build Coastguard Worker }
147*de1e4e89SAndroid Build Coastguard Worker 
canid_print_eopt(FILE * fd,struct tcf_ematch_hdr * hdr,void * data,int data_len)148*de1e4e89SAndroid Build Coastguard Worker static int canid_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
149*de1e4e89SAndroid Build Coastguard Worker 			  int data_len)
150*de1e4e89SAndroid Build Coastguard Worker {
151*de1e4e89SAndroid Build Coastguard Worker 	struct can_filter *conf = data; /* Array with rules */
152*de1e4e89SAndroid Build Coastguard Worker 	int rules_count;
153*de1e4e89SAndroid Build Coastguard Worker 	int i;
154*de1e4e89SAndroid Build Coastguard Worker 
155*de1e4e89SAndroid Build Coastguard Worker 	rules_count = data_len / sizeof(struct can_filter);
156*de1e4e89SAndroid Build Coastguard Worker 
157*de1e4e89SAndroid Build Coastguard Worker 	for (i = 0; i < rules_count; i++) {
158*de1e4e89SAndroid Build Coastguard Worker 		struct can_filter *pcfltr = &conf[i];
159*de1e4e89SAndroid Build Coastguard Worker 
160*de1e4e89SAndroid Build Coastguard Worker 		if (pcfltr->can_id & CAN_EFF_FLAG) {
161*de1e4e89SAndroid Build Coastguard Worker 			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_EFF_MASK))
162*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fd, "eff 0x%"PRIX32,
163*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_id & CAN_EFF_MASK);
164*de1e4e89SAndroid Build Coastguard Worker 			else
165*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fd, "eff 0x%"PRIX32":0x%"PRIX32,
166*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_id & CAN_EFF_MASK,
167*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_mask & CAN_EFF_MASK);
168*de1e4e89SAndroid Build Coastguard Worker 		} else {
169*de1e4e89SAndroid Build Coastguard Worker 			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_SFF_MASK))
170*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fd, "sff 0x%"PRIX32,
171*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_id & CAN_SFF_MASK);
172*de1e4e89SAndroid Build Coastguard Worker 			else
173*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fd, "sff 0x%"PRIX32":0x%"PRIX32,
174*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_id & CAN_SFF_MASK,
175*de1e4e89SAndroid Build Coastguard Worker 						pcfltr->can_mask & CAN_SFF_MASK);
176*de1e4e89SAndroid Build Coastguard Worker 		}
177*de1e4e89SAndroid Build Coastguard Worker 
178*de1e4e89SAndroid Build Coastguard Worker 		if ((i + 1) < rules_count)
179*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fd, " ");
180*de1e4e89SAndroid Build Coastguard Worker 	}
181*de1e4e89SAndroid Build Coastguard Worker 
182*de1e4e89SAndroid Build Coastguard Worker 	return 0;
183*de1e4e89SAndroid Build Coastguard Worker }
184*de1e4e89SAndroid Build Coastguard Worker 
185*de1e4e89SAndroid Build Coastguard Worker struct ematch_util canid_ematch_util = {
186*de1e4e89SAndroid Build Coastguard Worker 	.kind = "canid",
187*de1e4e89SAndroid Build Coastguard Worker 	.kind_num = TCF_EM_CANID,
188*de1e4e89SAndroid Build Coastguard Worker 	.parse_eopt = canid_parse_eopt,
189*de1e4e89SAndroid Build Coastguard Worker 	.print_eopt = canid_print_eopt,
190*de1e4e89SAndroid Build Coastguard Worker 	.print_usage = canid_print_usage
191*de1e4e89SAndroid Build Coastguard Worker };
192