xref: /netbsd/tests/net/can/t_canfilter.c (revision 3e7aaa91)
1 /*	$NetBSD: t_canfilter.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $	*/
2 
3 /*-
4  * Copyright (c) 2017 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Manuel Bouyer
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
20  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: t_canfilter.c,v 1.2 2017/05/27 21:02:56 bouyer Exp $");
36 #endif /* not lint */
37 
38 #include <sys/types.h>
39 #include <sys/resource.h>
40 #include <sys/wait.h>
41 #include <sys/sockio.h>
42 #include <sys/param.h>
43 
44 #include <atf-c.h>
45 #include <assert.h>
46 #include <fcntl.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 
52 #include <net/if.h>
53 #include <netcan/can.h>
54 
55 #include <rump/rump.h>
56 #include <rump/rump_syscalls.h>
57 
58 #include "h_macros.h"
59 #include "h_canutils.h"
60 
61 ATF_TC(canfilter_basic);
ATF_TC_HEAD(canfilter_basic,tc)62 ATF_TC_HEAD(canfilter_basic, tc)
63 {
64 
65 	atf_tc_set_md_var(tc, "descr", "check a simple CAN filter");
66 	atf_tc_set_md_var(tc, "timeout", "5");
67 }
68 
ATF_TC_BODY(canfilter_basic,tc)69 ATF_TC_BODY(canfilter_basic, tc)
70 {
71 	const char ifname[] = "canlo0";
72 	int s, rv;
73 	struct can_frame cf_send, cf_receive;
74 	struct can_filter cfi;
75 
76 	rump_init();
77 	cancfg_rump_createif(ifname);
78 
79 	s = can_socket_with_own();
80 
81 	can_bind(s, ifname);
82 
83 	/* set filter */
84 #define MY_ID	1
85 	cfi.can_id = MY_ID;
86 	cfi.can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
87 	if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
88 	    &cfi, sizeof(cfi)) < 0) {
89 		atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
90 	}
91 
92 	/*
93 	 * send a single byte message, but make sure remaining payload is
94 	 * not 0.
95 	 */
96 
97 	memset(&cf_send, 0, sizeof(cf_send));
98 	cf_send.can_id = MY_ID;
99 	cf_send.can_dlc = 1;
100 	cf_send.data[0] = 0xde;
101 	cf_send.data[1] = 0xad;
102 	cf_send.data[2] = 0xbe;
103 	cf_send.data[3] = 0xef;
104 
105 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
106 		atf_tc_fail_errno("write");
107 	}
108 
109 	if (can_read(s, &cf_receive, &rv) < 0) {
110 		atf_tc_fail_errno("read");
111 	}
112 
113 	ATF_CHECK_MSG(rv > 0, "short read on socket");
114 
115 	memset(&cf_send, 0, sizeof(cf_send));
116 	cf_send.can_id = MY_ID;
117 	cf_send.can_dlc = 1;
118 	cf_send.data[0] = 0xde;
119 	/* other data[] are expected to be 0 */
120 
121 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
122 	    "received packet is not what we sent");
123 
124 	/* now send a packet with CAN_RTR_FLAG. Should pass too */
125 
126 	memset(&cf_send, 0, sizeof(cf_send));
127 	cf_send.can_id = MY_ID | CAN_RTR_FLAG;
128 	cf_send.can_dlc = 1;
129 	cf_send.data[0] = 0xde;
130 	cf_send.data[1] = 0xad;
131 	cf_send.data[2] = 0xbe;
132 	cf_send.data[3] = 0xef;
133 
134 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
135 		atf_tc_fail_errno("write");
136 	}
137 
138 	if (can_read(s, &cf_receive, &rv) < 0) {
139 		atf_tc_fail_errno("read");
140 	}
141 
142 	ATF_CHECK_MSG(rv > 0, "short read on socket");
143 
144 	memset(&cf_send, 0, sizeof(cf_send));
145 	cf_send.can_id = MY_ID | CAN_RTR_FLAG;
146 	cf_send.can_dlc = 1;
147 	cf_send.data[0] = 0xde;
148 	/* other data[] are expected to be 0 */
149 
150 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
151 	    "received packet is not what we sent");
152 
153 	/* now send a packet for a different id. Should not pass */
154 
155 	memset(&cf_send, 0, sizeof(cf_send));
156 	cf_send.can_id = MY_ID + 1;
157 	cf_send.can_dlc = 1;
158 	cf_send.data[0] = 0xde;
159 	cf_send.data[1] = 0xad;
160 	cf_send.data[2] = 0xbe;
161 	cf_send.data[3] = 0xef;
162 
163 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
164 		atf_tc_fail_errno("write");
165 	}
166 
167 	if (can_read(s, &cf_receive, &rv) < 0) {
168 		if (errno == EWOULDBLOCK)
169 			return; /* expected timeout */
170 		atf_tc_fail_errno("read");
171 	}
172 
173 	ATF_CHECK_MSG(rv > 0, "short read on socket");
174 
175 	memset(&cf_send, 0, sizeof(cf_send));
176 	cf_send.can_id = MY_ID + 1;
177 	cf_send.can_dlc = 1;
178 	cf_send.data[0] = 0xde;
179 	/* other data[] are expected to be 0 */
180 
181 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
182 	    "received packet is not what we sent");
183 	atf_tc_fail("we got our own message");
184 #undef MY_ID
185 }
186 
187 ATF_TC(canfilter_null);
ATF_TC_HEAD(canfilter_null,tc)188 ATF_TC_HEAD(canfilter_null, tc)
189 {
190 
191 	atf_tc_set_md_var(tc, "descr", "check a NULL CAN filter");
192 	atf_tc_set_md_var(tc, "timeout", "5");
193 }
194 
ATF_TC_BODY(canfilter_null,tc)195 ATF_TC_BODY(canfilter_null, tc)
196 {
197 	const char ifname[] = "canlo0";
198 	int s, rv;
199 	struct can_frame cf_send, cf_receive;
200 	struct can_filter cfi[2];
201 	socklen_t cfilen;
202 
203 	rump_init();
204 	cancfg_rump_createif(ifname);
205 
206 	s = can_socket_with_own();
207 	can_bind(s, ifname);
208 
209 	if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
210 	    NULL,  0) < 0) {
211 		atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
212 	}
213 
214 	/* get filter: should be NULL */
215 	cfilen = sizeof(cfi);
216 	if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
217 	    &cfi, &cfilen) < 0) {
218 		atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
219 	}
220 	ATF_CHECK_MSG(cfilen == 0,
221 	    "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
222 	/*
223 	 * send a single byte message, but make sure remaining payload is
224 	 * not 0.
225 	 */
226 #define MY_ID	1
227 
228 	memset(&cf_send, 0, sizeof(cf_send));
229 	cf_send.can_id = MY_ID;
230 	cf_send.can_dlc = 1;
231 	cf_send.data[0] = 0xde;
232 	cf_send.data[1] = 0xad;
233 	cf_send.data[2] = 0xbe;
234 	cf_send.data[3] = 0xef;
235 
236 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
237 		atf_tc_fail_errno("write");
238 	}
239 
240 	if (can_read(s, &cf_receive, &rv) < 0) {
241 		if (errno == EWOULDBLOCK)
242 			return; /* expected timeout */
243 		atf_tc_fail_errno("read");
244 	}
245 
246 	ATF_CHECK_MSG(rv > 0, "short read on socket");
247 
248 	memset(&cf_send, 0, sizeof(cf_send));
249 	cf_send.can_id = MY_ID;
250 	cf_send.can_dlc = 1;
251 	cf_send.data[0] = 0xde;
252 	/* other data[] are expected to be 0 */
253 
254 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
255 	    "received packet is not what we sent");
256 	atf_tc_fail("we got our own message");
257 #undef MY_ID
258 }
259 
260 ATF_TC(canfilter_multiple);
ATF_TC_HEAD(canfilter_multiple,tc)261 ATF_TC_HEAD(canfilter_multiple, tc)
262 {
263 
264 	atf_tc_set_md_var(tc, "descr", "check multiple CAN filters");
265 	atf_tc_set_md_var(tc, "timeout", "5");
266 }
267 
ATF_TC_BODY(canfilter_multiple,tc)268 ATF_TC_BODY(canfilter_multiple, tc)
269 {
270 	const char ifname[] = "canlo0";
271 	int s, rv;
272 	struct can_frame cf_send, cf_receive;
273 	struct can_filter cfi[2];
274 
275 	rump_init();
276 	cancfg_rump_createif(ifname);
277 
278 	s = can_socket_with_own();
279 
280 	can_bind(s, ifname);
281 
282 	/* set filter: accept MY_ID and MY_ID+1 */
283 #define MY_ID	1
284 	cfi[0].can_id = MY_ID;
285 	cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
286 	cfi[1].can_id = MY_ID + 1;
287 	cfi[1].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
288 	if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
289 	    &cfi, sizeof(cfi)) < 0) {
290 		atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
291 	}
292 
293 	/*
294 	 * send a single byte message, but make sure remaining payload is
295 	 * not 0.
296 	 */
297 
298 	memset(&cf_send, 0, sizeof(cf_send));
299 	cf_send.can_id = MY_ID;
300 	cf_send.can_dlc = 1;
301 	cf_send.data[0] = 0xde;
302 	cf_send.data[1] = 0xad;
303 	cf_send.data[2] = 0xbe;
304 	cf_send.data[3] = 0xef;
305 
306 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
307 		atf_tc_fail_errno("write");
308 	}
309 
310 	if (can_read(s, &cf_receive, &rv) < 0) {
311 		atf_tc_fail_errno("read");
312 	}
313 
314 	ATF_CHECK_MSG(rv > 0, "short read on socket");
315 
316 	memset(&cf_send, 0, sizeof(cf_send));
317 	cf_send.can_id = MY_ID;
318 	cf_send.can_dlc = 1;
319 	cf_send.data[0] = 0xde;
320 	/* other data[] are expected to be 0 */
321 
322 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
323 	    "received packet is not what we sent");
324 
325 	/* now send a packet with MY_ID+1. Should pass too */
326 
327 	memset(&cf_send, 0, sizeof(cf_send));
328 	cf_send.can_id = MY_ID + 1;
329 	cf_send.can_dlc = 1;
330 	cf_send.data[0] = 0xde;
331 	cf_send.data[1] = 0xad;
332 	cf_send.data[2] = 0xbe;
333 	cf_send.data[3] = 0xef;
334 
335 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
336 		atf_tc_fail_errno("write");
337 	}
338 
339 	if (can_read(s, &cf_receive, &rv) < 0) {
340 		atf_tc_fail_errno("read");
341 	}
342 
343 	ATF_CHECK_MSG(rv > 0, "short read on socket");
344 
345 	memset(&cf_send, 0, sizeof(cf_send));
346 	cf_send.can_id = MY_ID  + 1;
347 	cf_send.can_dlc = 1;
348 	cf_send.data[0] = 0xde;
349 	/* other data[] are expected to be 0 */
350 
351 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
352 	    "received packet is not what we sent");
353 
354 	/* now send a packet with MY_ID + 2. Should not pass */
355 
356 	memset(&cf_send, 0, sizeof(cf_send));
357 	cf_send.can_id = MY_ID + 2;
358 	cf_send.can_dlc = 1;
359 	cf_send.data[0] = 0xde;
360 	cf_send.data[1] = 0xad;
361 	cf_send.data[2] = 0xbe;
362 	cf_send.data[3] = 0xef;
363 
364 	if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
365 		atf_tc_fail_errno("write");
366 	}
367 
368 	if (can_read(s, &cf_receive, &rv) < 0) {
369 		if (errno == EWOULDBLOCK)
370 			return; /* expected timeout */
371 		atf_tc_fail_errno("read");
372 	}
373 
374 	ATF_CHECK_MSG(rv > 0, "short read on socket");
375 
376 	memset(&cf_send, 0, sizeof(cf_send));
377 	cf_send.can_id = MY_ID + 2;
378 	cf_send.can_dlc = 1;
379 	cf_send.data[0] = 0xde;
380 	/* other data[] are expected to be 0 */
381 
382 	ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
383 	    "received packet is not what we sent");
384 	atf_tc_fail("we got our own message");
385 #undef MY_ID
386 }
387 
388 ATF_TC(canfilter_get);
ATF_TC_HEAD(canfilter_get,tc)389 ATF_TC_HEAD(canfilter_get, tc)
390 {
391 
392 	atf_tc_set_md_var(tc, "descr", "check reading CAN filters");
393 	atf_tc_set_md_var(tc, "timeout", "5");
394 }
395 
ATF_TC_BODY(canfilter_get,tc)396 ATF_TC_BODY(canfilter_get, tc)
397 {
398 	const char ifname[] = "canlo0";
399 	int s;
400 	struct can_filter cfi[2];
401 	socklen_t cfilen;
402 
403 	rump_init();
404 	cancfg_rump_createif(ifname);
405 
406 	s = -1;
407 	if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
408 		atf_tc_fail_errno("CAN socket");
409 	}
410 
411 	cfilen = sizeof(cfi);
412 	/* get filter: should be default filter */
413 	if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
414 	    &cfi, &cfilen) < 0) {
415 		atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
416 	}
417 	ATF_CHECK_MSG(cfilen == sizeof(struct can_filter),
418 	    "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
419 	ATF_CHECK_MSG(cfi[0].can_id == 0 && cfi[0].can_mask == 0,
420 	    "CAN_RAW_FILTER returns wrong filter (%d, %d)",
421 	    cfi[0].can_id, cfi[0].can_mask);
422 
423 	/* set filter: accept MY_ID and MY_ID+1 */
424 #define MY_ID	1
425 	cfi[0].can_id = MY_ID;
426 	cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
427 	cfi[1].can_id = MY_ID + 1;
428 	cfi[1].can_mask = CAN_SFF_MASK;
429 	if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
430 	    &cfi, sizeof(cfi)) < 0) {
431 		atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
432 	}
433 
434 	/* and read back */
435 	cfilen = sizeof(cfi);
436 	memset(cfi, 0, cfilen);
437 	if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
438 	    &cfi, &cfilen) < 0) {
439 		atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
440 	}
441 	ATF_CHECK_MSG(cfilen == sizeof(struct can_filter) * 2,
442 	    "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
443 	ATF_CHECK_MSG(cfi[0].can_id == MY_ID &&
444 	    cfi[0].can_mask == (CAN_SFF_MASK | CAN_EFF_FLAG),
445 	    "CAN_RAW_FILTER returns wrong filter 0 (%d, %d)",
446 	    cfi[0].can_id, cfi[0].can_mask);
447 	ATF_CHECK_MSG(cfi[1].can_id == MY_ID + 1 &&
448 	    cfi[1].can_mask == CAN_SFF_MASK,
449 	    "CAN_RAW_FILTER returns wrong filter 1 (%d, %d)",
450 	    cfi[1].can_id, cfi[1].can_mask);
451 
452 #undef MY_ID
453 }
454 
ATF_TP_ADD_TCS(tp)455 ATF_TP_ADD_TCS(tp)
456 {
457 
458         ATF_TP_ADD_TC(tp, canfilter_basic);
459         ATF_TP_ADD_TC(tp, canfilter_null);
460         ATF_TP_ADD_TC(tp, canfilter_multiple);
461         ATF_TP_ADD_TC(tp, canfilter_get);
462 	return atf_no_error();
463 }
464 
465