xref: /linux/tools/testing/selftests/net/can/test_raw_filter.c (revision 509d3f45847627f4c5cdce004c3ec79262b5239c)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 /*
3  * Copyright (c) 2011 Volkswagen Group Electronic Research
4  * All rights reserved.
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/ioctl.h>
15 #include <sys/time.h>
16 #include <net/if.h>
17 #include <linux/if.h>
18 
19 #include <linux/can.h>
20 #include <linux/can/raw.h>
21 
22 #include "kselftest_harness.h"
23 
24 #define ID 0x123
25 
26 char CANIF[IFNAMSIZ];
27 
send_can_frames(int sock,int testcase)28 static int send_can_frames(int sock, int testcase)
29 {
30 	struct can_frame frame;
31 
32 	frame.can_dlc = 1;
33 	frame.data[0] = testcase;
34 
35 	frame.can_id = ID;
36 	if (write(sock, &frame, sizeof(frame)) < 0)
37 		goto write_err;
38 
39 	frame.can_id = (ID | CAN_RTR_FLAG);
40 	if (write(sock, &frame, sizeof(frame)) < 0)
41 		goto write_err;
42 
43 	frame.can_id = (ID | CAN_EFF_FLAG);
44 	if (write(sock, &frame, sizeof(frame)) < 0)
45 		goto write_err;
46 
47 	frame.can_id = (ID | CAN_EFF_FLAG | CAN_RTR_FLAG);
48 	if (write(sock, &frame, sizeof(frame)) < 0)
49 		goto write_err;
50 
51 	return 0;
52 
53 write_err:
54 	perror("write");
55 	return 1;
56 }
57 
FIXTURE(can_filters)58 FIXTURE(can_filters) {
59 	int sock;
60 };
61 
FIXTURE_SETUP(can_filters)62 FIXTURE_SETUP(can_filters)
63 {
64 	struct sockaddr_can addr;
65 	struct ifreq ifr;
66 	int recv_own_msgs = 1;
67 	int s, ret;
68 
69 	s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
70 	ASSERT_GE(s, 0)
71 		TH_LOG("failed to create CAN_RAW socket: %d", errno);
72 
73 	strncpy(ifr.ifr_name, CANIF, sizeof(ifr.ifr_name));
74 	ret = ioctl(s, SIOCGIFINDEX, &ifr);
75 	ASSERT_GE(ret, 0)
76 		TH_LOG("failed SIOCGIFINDEX: %d", errno);
77 
78 	addr.can_family = AF_CAN;
79 	addr.can_ifindex = ifr.ifr_ifindex;
80 
81 	setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
82 		   &recv_own_msgs, sizeof(recv_own_msgs));
83 
84 	ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
85 	ASSERT_EQ(ret, 0)
86 		TH_LOG("failed bind socket: %d", errno);
87 
88 	self->sock = s;
89 }
90 
FIXTURE_TEARDOWN(can_filters)91 FIXTURE_TEARDOWN(can_filters)
92 {
93 	close(self->sock);
94 }
95 
FIXTURE_VARIANT(can_filters)96 FIXTURE_VARIANT(can_filters) {
97 	int testcase;
98 	canid_t id;
99 	canid_t mask;
100 	int exp_num_rx;
101 	canid_t exp_flags[];
102 };
103 
104 /* Receive all frames when filtering for the ID in standard frame format */
FIXTURE_VARIANT_ADD(can_filters,base)105 FIXTURE_VARIANT_ADD(can_filters, base) {
106 	.testcase = 1,
107 	.id = ID,
108 	.mask = CAN_SFF_MASK,
109 	.exp_num_rx = 4,
110 	.exp_flags = {
111 		0,
112 		CAN_RTR_FLAG,
113 		CAN_EFF_FLAG,
114 		CAN_EFF_FLAG | CAN_RTR_FLAG,
115 	},
116 };
117 
118 /* Ignore EFF flag in filter ID if not covered by filter mask */
FIXTURE_VARIANT_ADD(can_filters,base_eff)119 FIXTURE_VARIANT_ADD(can_filters, base_eff) {
120 	.testcase = 2,
121 	.id = ID | CAN_EFF_FLAG,
122 	.mask = CAN_SFF_MASK,
123 	.exp_num_rx = 4,
124 	.exp_flags = {
125 		0,
126 		CAN_RTR_FLAG,
127 		CAN_EFF_FLAG,
128 		CAN_EFF_FLAG | CAN_RTR_FLAG,
129 	},
130 };
131 
132 /* Ignore RTR flag in filter ID if not covered by filter mask */
FIXTURE_VARIANT_ADD(can_filters,base_rtr)133 FIXTURE_VARIANT_ADD(can_filters, base_rtr) {
134 	.testcase = 3,
135 	.id = ID | CAN_RTR_FLAG,
136 	.mask = CAN_SFF_MASK,
137 	.exp_num_rx = 4,
138 	.exp_flags = {
139 		0,
140 		CAN_RTR_FLAG,
141 		CAN_EFF_FLAG,
142 		CAN_EFF_FLAG | CAN_RTR_FLAG,
143 	},
144 };
145 
146 /* Ignore EFF and RTR flags in filter ID if not covered by filter mask */
FIXTURE_VARIANT_ADD(can_filters,base_effrtr)147 FIXTURE_VARIANT_ADD(can_filters, base_effrtr) {
148 	.testcase = 4,
149 	.id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG,
150 	.mask = CAN_SFF_MASK,
151 	.exp_num_rx = 4,
152 	.exp_flags = {
153 		0,
154 		CAN_RTR_FLAG,
155 		CAN_EFF_FLAG,
156 		CAN_EFF_FLAG | CAN_RTR_FLAG,
157 	},
158 };
159 
160 /* Receive only SFF frames when expecting no EFF flag */
FIXTURE_VARIANT_ADD(can_filters,filter_eff)161 FIXTURE_VARIANT_ADD(can_filters, filter_eff) {
162 	.testcase = 5,
163 	.id = ID,
164 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG,
165 	.exp_num_rx = 2,
166 	.exp_flags = {
167 		0,
168 		CAN_RTR_FLAG,
169 	},
170 };
171 
172 /* Receive only EFF frames when filter id and filter mask include EFF flag */
FIXTURE_VARIANT_ADD(can_filters,filter_eff_eff)173 FIXTURE_VARIANT_ADD(can_filters, filter_eff_eff) {
174 	.testcase = 6,
175 	.id = ID | CAN_EFF_FLAG,
176 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG,
177 	.exp_num_rx = 2,
178 	.exp_flags = {
179 		CAN_EFF_FLAG,
180 		CAN_EFF_FLAG | CAN_RTR_FLAG,
181 	},
182 };
183 
184 /* Receive only SFF frames when expecting no EFF flag, ignoring RTR flag */
FIXTURE_VARIANT_ADD(can_filters,filter_eff_rtr)185 FIXTURE_VARIANT_ADD(can_filters, filter_eff_rtr) {
186 	.testcase = 7,
187 	.id = ID | CAN_RTR_FLAG,
188 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG,
189 	.exp_num_rx = 2,
190 	.exp_flags = {
191 		0,
192 		CAN_RTR_FLAG,
193 	},
194 };
195 
196 /* Receive only EFF frames when filter id and filter mask include EFF flag,
197  * ignoring RTR flag
198  */
FIXTURE_VARIANT_ADD(can_filters,filter_eff_effrtr)199 FIXTURE_VARIANT_ADD(can_filters, filter_eff_effrtr) {
200 	.testcase = 8,
201 	.id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG,
202 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG,
203 	.exp_num_rx = 2,
204 	.exp_flags = {
205 		CAN_EFF_FLAG,
206 		CAN_EFF_FLAG | CAN_RTR_FLAG,
207 	},
208 };
209 
210 /* Receive no remote frames when filtering for no RTR flag */
FIXTURE_VARIANT_ADD(can_filters,filter_rtr)211 FIXTURE_VARIANT_ADD(can_filters, filter_rtr) {
212 	.testcase = 9,
213 	.id = ID,
214 	.mask = CAN_SFF_MASK | CAN_RTR_FLAG,
215 	.exp_num_rx = 2,
216 	.exp_flags = {
217 		0,
218 		CAN_EFF_FLAG,
219 	},
220 };
221 
222 /* Receive no remote frames when filtering for no RTR flag, ignoring EFF flag */
FIXTURE_VARIANT_ADD(can_filters,filter_rtr_eff)223 FIXTURE_VARIANT_ADD(can_filters, filter_rtr_eff) {
224 	.testcase = 10,
225 	.id = ID | CAN_EFF_FLAG,
226 	.mask = CAN_SFF_MASK | CAN_RTR_FLAG,
227 	.exp_num_rx = 2,
228 	.exp_flags = {
229 		0,
230 		CAN_EFF_FLAG,
231 	},
232 };
233 
234 /* Receive only remote frames when filter includes RTR flag */
FIXTURE_VARIANT_ADD(can_filters,filter_rtr_rtr)235 FIXTURE_VARIANT_ADD(can_filters, filter_rtr_rtr) {
236 	.testcase = 11,
237 	.id = ID | CAN_RTR_FLAG,
238 	.mask = CAN_SFF_MASK | CAN_RTR_FLAG,
239 	.exp_num_rx = 2,
240 	.exp_flags = {
241 		CAN_RTR_FLAG,
242 		CAN_EFF_FLAG | CAN_RTR_FLAG,
243 	},
244 };
245 
246 /* Receive only remote frames when filter includes RTR flag, ignoring EFF
247  * flag
248  */
FIXTURE_VARIANT_ADD(can_filters,filter_rtr_effrtr)249 FIXTURE_VARIANT_ADD(can_filters, filter_rtr_effrtr) {
250 	.testcase = 12,
251 	.id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG,
252 	.mask = CAN_SFF_MASK | CAN_RTR_FLAG,
253 	.exp_num_rx = 2,
254 	.exp_flags = {
255 		CAN_RTR_FLAG,
256 		CAN_EFF_FLAG | CAN_RTR_FLAG,
257 	},
258 };
259 
260 /* Receive only SFF data frame when filtering for no flags */
FIXTURE_VARIANT_ADD(can_filters,filter_effrtr)261 FIXTURE_VARIANT_ADD(can_filters, filter_effrtr) {
262 	.testcase = 13,
263 	.id = ID,
264 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
265 	.exp_num_rx = 1,
266 	.exp_flags = {
267 		0,
268 	},
269 };
270 
271 /* Receive only EFF data frame when filtering for EFF but no RTR flag */
FIXTURE_VARIANT_ADD(can_filters,filter_effrtr_eff)272 FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_eff) {
273 	.testcase = 14,
274 	.id = ID | CAN_EFF_FLAG,
275 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
276 	.exp_num_rx = 1,
277 	.exp_flags = {
278 		CAN_EFF_FLAG,
279 	},
280 };
281 
282 /* Receive only SFF remote frame when filtering for RTR but no EFF flag */
FIXTURE_VARIANT_ADD(can_filters,filter_effrtr_rtr)283 FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_rtr) {
284 	.testcase = 15,
285 	.id = ID | CAN_RTR_FLAG,
286 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
287 	.exp_num_rx = 1,
288 	.exp_flags = {
289 		CAN_RTR_FLAG,
290 	},
291 };
292 
293 /* Receive only EFF remote frame when filtering for EFF and RTR flag */
FIXTURE_VARIANT_ADD(can_filters,filter_effrtr_effrtr)294 FIXTURE_VARIANT_ADD(can_filters, filter_effrtr_effrtr) {
295 	.testcase = 16,
296 	.id = ID | CAN_EFF_FLAG | CAN_RTR_FLAG,
297 	.mask = CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
298 	.exp_num_rx = 1,
299 	.exp_flags = {
300 		CAN_EFF_FLAG | CAN_RTR_FLAG,
301 	},
302 };
303 
304 /* Receive only SFF data frame when filtering for no EFF flag and no RTR flag
305  * but based on EFF mask
306  */
FIXTURE_VARIANT_ADD(can_filters,eff)307 FIXTURE_VARIANT_ADD(can_filters, eff) {
308 	.testcase = 17,
309 	.id = ID,
310 	.mask = CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
311 	.exp_num_rx = 1,
312 	.exp_flags = {
313 		0,
314 	},
315 };
316 
317 /* Receive only EFF data frame when filtering for EFF flag and no RTR flag but
318  * based on EFF mask
319  */
FIXTURE_VARIANT_ADD(can_filters,eff_eff)320 FIXTURE_VARIANT_ADD(can_filters, eff_eff) {
321 	.testcase = 18,
322 	.id = ID | CAN_EFF_FLAG,
323 	.mask = CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG,
324 	.exp_num_rx = 1,
325 	.exp_flags = {
326 		CAN_EFF_FLAG,
327 	},
328 };
329 
330 /* This test verifies that the raw CAN filters work, by checking if only frames
331  * with the expected set of flags are received. For each test case, the given
332  * filter (id and mask) is added and four CAN frames are sent with every
333  * combination of set/unset EFF/RTR flags.
334  */
TEST_F(can_filters,test_filter)335 TEST_F(can_filters, test_filter)
336 {
337 	struct can_filter rfilter;
338 	int ret;
339 
340 	rfilter.can_id = variant->id;
341 	rfilter.can_mask = variant->mask;
342 	setsockopt(self->sock, SOL_CAN_RAW, CAN_RAW_FILTER,
343 		   &rfilter, sizeof(rfilter));
344 
345 	TH_LOG("filters: can_id = 0x%08X can_mask = 0x%08X",
346 		rfilter.can_id, rfilter.can_mask);
347 
348 	ret = send_can_frames(self->sock, variant->testcase);
349 	ASSERT_EQ(ret, 0)
350 		TH_LOG("failed to send CAN frames");
351 
352 	for (int i = 0; i <= variant->exp_num_rx; i++) {
353 		struct can_frame frame;
354 		struct timeval tv = {
355 			.tv_sec = 0,
356 			.tv_usec = 50000, /* 50ms timeout */
357 		};
358 		fd_set rdfs;
359 
360 		FD_ZERO(&rdfs);
361 		FD_SET(self->sock, &rdfs);
362 
363 		ret = select(self->sock + 1, &rdfs, NULL, NULL, &tv);
364 		ASSERT_GE(ret, 0)
365 			TH_LOG("failed select for frame %d, err: %d)", i, errno);
366 
367 		ret = FD_ISSET(self->sock, &rdfs);
368 		if (i == variant->exp_num_rx) {
369 			ASSERT_EQ(ret, 0)
370 				TH_LOG("too many frames received");
371 		} else {
372 			ASSERT_NE(ret, 0)
373 				TH_LOG("too few frames received");
374 
375 			ret = read(self->sock, &frame, sizeof(frame));
376 			ASSERT_GE(ret, 0)
377 				TH_LOG("failed to read frame %d, err: %d", i, errno);
378 
379 			TH_LOG("rx: can_id = 0x%08X rx = %d", frame.can_id, i);
380 
381 			ASSERT_EQ(ID, frame.can_id & CAN_SFF_MASK)
382 				TH_LOG("received wrong can_id");
383 			ASSERT_EQ(variant->testcase, frame.data[0])
384 				TH_LOG("received wrong test case");
385 
386 			ASSERT_EQ(frame.can_id & ~CAN_ERR_MASK,
387 				  variant->exp_flags[i])
388 				TH_LOG("received unexpected flags");
389 		}
390 	}
391 }
392 
main(int argc,char ** argv)393 int main(int argc, char **argv)
394 {
395 	char *ifname = getenv("CANIF");
396 
397 	if (!ifname) {
398 		printf("CANIF environment variable must contain the test interface\n");
399 		return KSFT_FAIL;
400 	}
401 
402 	strncpy(CANIF, ifname, sizeof(CANIF) - 1);
403 
404 	return test_harness_run(argc, argv);
405 }
406