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