Module Name: src
Committed By: bouyer
Date: Sun Feb 5 10:56:12 UTC 2017
Modified Files:
src/sys/netcan [bouyer-socketcan]: can.c can_pcb.c can_pcb.h
src/tests/net/can [bouyer-socketcan]: Makefile
Added Files:
src/tests/net/can [bouyer-socketcan]: t_canfilter.c
Log Message:
Implement CAN_RAW_FILTER socket option, and add tests for it.
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/sys/netcan/can.c \
src/sys/netcan/can_pcb.h
cvs rdiff -u -r1.1.2.1 -r1.1.2.2 src/sys/netcan/can_pcb.c
cvs rdiff -u -r1.1.2.2 -r1.1.2.3 src/tests/net/can/Makefile
cvs rdiff -u -r0 -r1.1.2.1 src/tests/net/can/t_canfilter.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netcan/can.c
diff -u src/sys/netcan/can.c:1.1.2.2 src/sys/netcan/can.c:1.1.2.3
--- src/sys/netcan/can.c:1.1.2.2 Mon Jan 16 18:03:38 2017
+++ src/sys/netcan/can.c Sun Feb 5 10:56:12 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
+/* $NetBSD: can.c,v 1.1.2.3 2017/02/05 10:56:12 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.3 2017/02/05 10:56:12 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -204,6 +204,9 @@ canintr(void)
if (m == NULL) /* no more queued packets */
break;
+#if 0
+ m_claim(m, &can_rx_mowner);
+#endif
sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
if (sotag) {
so = *(struct socket **)(sotag + 1);
@@ -219,9 +222,6 @@ canintr(void)
}
memset(&from, 0, sizeof(struct sockaddr_can));
rcv_ifindex = m->m_pkthdr.rcvif_index;
-#if 0
- m_claim(m, &can_rx_mowner);
-#endif
from.can_ifindex = rcv_ifindex;
from.can_len = sizeof(struct sockaddr_can);
from.can_family = AF_CAN;
@@ -239,6 +239,10 @@ canintr(void)
(canp->canp_flags & CANP_RECEIVE_OWN) == 0)
continue;
+ /* skip if the accept filter doen't match this pkt */
+ if (!can_pcbfilter(canp, m))
+ continue;
+
if (TAILQ_NEXT(canp, canp_queue) != NULL) {
/*
* we can't be sure we won't need
@@ -274,7 +278,6 @@ canintr(void)
static int
can_attach(struct socket *so, int proto)
{
- /*struct canpcb *canp;*/
int error;
KASSERT(sotocanpcb(so) == NULL);
@@ -298,7 +301,6 @@ can_attach(struct socket *so, int proto)
if (error) {
return error;
}
- /*canp = sotocanpcb(so);*/
KASSERT(solocked(so));
return error;
@@ -702,6 +704,10 @@ can_raw_getop(struct canpcb *canp, struc
optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
error = sockopt_set(sopt, &optval, sizeof(optval));
break;
+ case CAN_RAW_FILTER:
+ error = sockopt_set(sopt, canp->canp_filters,
+ sizeof(struct can_filter) * canp->canp_nfilters);
+ break;
default:
error = ENOPROTOOPT;
break;
@@ -736,6 +742,14 @@ can_raw_setop(struct canpcb *canp, struc
}
}
break;
+ case CAN_RAW_FILTER:
+ {
+ int nfilters = sopt->sopt_size / sizeof(struct can_filter);
+ if (sopt->sopt_size % sizeof(struct can_filter) != 0)
+ return EINVAL;
+ error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
+ break;
+ }
default:
error = ENOPROTOOPT;
break;
Index: src/sys/netcan/can_pcb.h
diff -u src/sys/netcan/can_pcb.h:1.1.2.2 src/sys/netcan/can_pcb.h:1.1.2.3
--- src/sys/netcan/can_pcb.h:1.1.2.2 Mon Jan 16 18:03:38 2017
+++ src/sys/netcan/can_pcb.h Sun Feb 5 10:56:12 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can_pcb.h,v 1.1.2.2 2017/01/16 18:03:38 bouyer Exp $ */
+/* $NetBSD: can_pcb.h,v 1.1.2.3 2017/02/05 10:56:12 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -52,13 +52,14 @@ struct canpcb {
int canp_flags;
struct socket *canp_socket; /* back pointer to socket */
struct ifnet *canp_ifp; /* interface this socket is bound to */
+
struct canpcbtable *canp_table;
+ struct can_filter *canp_filters; /* filter array */
+ int canp_nfilters; /* size of canp_filters */
};
LIST_HEAD(canpcbhead, canpcb);
-#define canp_faddr canp_dst.scan_addr
-
TAILQ_HEAD(canpcbqueue, canpcb);
struct canpcbtable {
@@ -97,6 +98,8 @@ void can_pcbpurgeif0(struct canpcbtable
void can_pcbpurgeif(struct canpcbtable *, struct ifnet *);
void can_pcbstate(struct canpcb *, int);
void can_setsockaddr(struct canpcb *, struct sockaddr_can *);
+int can_pcbsetfilter(struct canpcb *, struct can_filter *, int);
+bool can_pcbfilter(struct canpcb *, struct mbuf *);
#endif
#endif /* _NETCAN_CAN_PCB_H_ */
Index: src/sys/netcan/can_pcb.c
diff -u src/sys/netcan/can_pcb.c:1.1.2.1 src/sys/netcan/can_pcb.c:1.1.2.2
--- src/sys/netcan/can_pcb.c:1.1.2.1 Sun Jan 15 20:27:33 2017
+++ src/sys/netcan/can_pcb.c Sun Feb 5 10:56:12 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can_pcb.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $ */
+/* $NetBSD: can_pcb.c,v 1.1.2.2 2017/02/05 10:56:12 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,11 +30,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.1.2.2 2017/02/05 10:56:12 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
@@ -84,16 +85,27 @@ can_pcballoc(struct socket *so, void *v)
{
struct canpcbtable *table = v;
struct canpcb *canp;
+ struct can_filter *can_init_filter;
int s;
+ can_init_filter = kmem_alloc(sizeof(struct can_filter), KM_NOSLEEP);
+ if (can_init_filter == NULL)
+ return (ENOBUFS);
+ can_init_filter->can_id = 0;
+ can_init_filter->can_mask = 0; /* accept all by default */
+
s = splnet();
canp = pool_get(&canpcb_pool, PR_NOWAIT);
splx(s);
- if (canp == NULL)
+ if (canp == NULL) {
+ kmem_free(can_init_filter, sizeof(struct can_filter));
return (ENOBUFS);
+ }
memset(canp, 0, sizeof(*canp));
canp->canp_table = table;
canp->canp_socket = so;
+ canp->canp_filters = can_init_filter;
+ canp->canp_nfilters = 1;
so->so_pcb = canp;
s = splnet();
@@ -169,6 +181,7 @@ can_pcbdetach(void *v)
TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue);
splx(s);
sofree(so); /* sofree drops the lock */
+ can_pcbsetfilter(canp, NULL, 0);
pool_put(&canpcb_pool, canp);
mutex_enter(softnet_lock);
}
@@ -183,6 +196,32 @@ can_setsockaddr(struct canpcb *canp, str
scan->can_ifindex = canp->canp_ifp->if_index;
}
+int
+can_pcbsetfilter(struct canpcb *canp, struct can_filter *fp, int nfilters)
+{
+
+ struct can_filter *newf;
+
+ if (nfilters > 0) {
+ newf =
+ kmem_alloc(sizeof(struct can_filter) * nfilters, KM_SLEEP);
+ if (newf == NULL)
+ return ENOMEM;
+ memcpy(newf, fp, sizeof(struct can_filter) * nfilters);
+ } else {
+ newf = NULL;
+ }
+ if (canp->canp_filters != NULL) {
+ kmem_free(canp->canp_filters,
+ sizeof(struct can_filter) * canp->canp_nfilters);
+ }
+ canp->canp_filters = newf;
+ canp->canp_nfilters = nfilters;
+ return 0;
+}
+
+
+
#if 0
/*
* Pass some notification to all connections of a protocol
@@ -281,3 +320,24 @@ can_pcbstate(struct canpcb *canp, int st
canp->canp_state = state;
}
+
+/*
+ * check mbuf against socket accept filter.
+ * returns true if mbuf is accepted, false otherwise
+ */
+bool
+can_pcbfilter(struct canpcb *canp, struct mbuf *m)
+{
+ int i;
+ struct can_frame *fmp;
+ struct can_filter *fip;
+
+ fmp = mtod(m, struct can_frame *);
+ for (i = 0; i < canp->canp_nfilters; i++) {
+ fip = &canp->canp_filters[i];
+ if ((fmp->can_id & fip->can_mask) == fip->can_id)
+ return true;
+ }
+ /* no match */
+ return false;
+}
Index: src/tests/net/can/Makefile
diff -u src/tests/net/can/Makefile:1.1.2.2 src/tests/net/can/Makefile:1.1.2.3
--- src/tests/net/can/Makefile:1.1.2.2 Sat Feb 4 22:26:16 2017
+++ src/tests/net/can/Makefile Sun Feb 5 10:56:12 2017
@@ -1,12 +1,15 @@
-# $NetBSD: Makefile,v 1.1.2.2 2017/02/04 22:26:16 bouyer Exp $
+# $NetBSD: Makefile,v 1.1.2.3 2017/02/05 10:56:12 bouyer Exp $
#
.include <bsd.own.mk>
TESTSDIR= ${TESTSBASE}/net/can
-TESTS_C= t_can
-SRCS.t_can= t_can.c h_canutils.c
+TESTS_C= t_can t_canfilter
+
+SRCS.t_can= t_can.c h_canutils.c
+
+SRCS.t_canfilter= t_canfilter.c h_canutils.c
# XXX we don't use INET here, but we need rumpnet_netinet anyway:
# common code in if.c is compiled with -DINET and will dereference ip_pktq,
Added files:
Index: src/tests/net/can/t_canfilter.c
diff -u /dev/null src/tests/net/can/t_canfilter.c:1.1.2.1
--- /dev/null Sun Feb 5 10:56:12 2017
+++ src/tests/net/can/t_canfilter.c Sun Feb 5 10:56:12 2017
@@ -0,0 +1,537 @@
+/* $NetBSD: t_canfilter.c,v 1.1.2.1 2017/02/05 10:56:12 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Manuel Bouyer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: t_canfilter.c,v 1.1.2.1 2017/02/05 10:56:12 bouyer Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/sockio.h>
+#include <sys/param.h>
+
+#include <atf-c.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <netcan/can.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "h_macros.h"
+#include "h_canutils.h"
+
+ATF_TC(canfilter_basic);
+ATF_TC_HEAD(canfilter_basic, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check a simple CAN filter");
+ atf_tc_set_md_var(tc, "timeout", "5");
+}
+
+ATF_TC_BODY(canfilter_basic, tc)
+{
+ const char ifname[] = "canlo0";
+ int s, rv, v, vlen;
+ struct sockaddr_can sa;
+ struct ifreq ifr;
+ struct can_frame cf_send, cf_receive;
+ struct can_filter cfi;
+
+ rump_init();
+ cancfg_rump_createif(ifname);
+
+ s = -1;
+ if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+ atf_tc_fail_errno("CAN socket");
+ }
+
+ strcpy(ifr.ifr_name, ifname );
+ if (rump_sys_ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ atf_tc_fail_errno("SIOCGIFINDEX");
+ }
+ ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
+ ifname, ifr.ifr_ifindex);
+
+ sa.can_family = AF_CAN;
+ sa.can_ifindex = ifr.ifr_ifindex;
+
+ if (rump_sys_bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ atf_tc_fail_errno("bind");
+ }
+
+ v = 1;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
+ &v, sizeof(v)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_RECV_OWN_MSGS)");
+ }
+
+ /* set filter */
+#define MY_ID 1
+ cfi.can_id = MY_ID;
+ cfi.can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, sizeof(cfi)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
+ }
+
+ /*
+ * send a single byte message, but make sure remaining payload is
+ * not 0.
+ */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+
+ /* now send a packet with CAN_RTR_FLAG. Should pass too */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID | CAN_RTR_FLAG;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID | CAN_RTR_FLAG;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+
+ /* now send a packet for a different id. Should not pass */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 1;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ if (errno == EWOULDBLOCK)
+ return; /* expected timeout */
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 1;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+ atf_tc_fail("we got our own message");
+#undef MY_ID
+}
+
+ATF_TC(canfilter_null);
+ATF_TC_HEAD(canfilter_null, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check a NULL CAN filter");
+ atf_tc_set_md_var(tc, "timeout", "5");
+}
+
+ATF_TC_BODY(canfilter_null, tc)
+{
+ const char ifname[] = "canlo0";
+ int s, rv, v, vlen;
+ struct sockaddr_can sa;
+ struct ifreq ifr;
+ struct can_frame cf_send, cf_receive;
+ struct can_filter cfi[2];
+ int cfilen;
+
+ rump_init();
+ cancfg_rump_createif(ifname);
+
+ s = -1;
+ if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+ atf_tc_fail_errno("CAN socket");
+ }
+
+ strcpy(ifr.ifr_name, ifname );
+ if (rump_sys_ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ atf_tc_fail_errno("SIOCGIFINDEX");
+ }
+ ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
+ ifname, ifr.ifr_ifindex);
+
+ sa.can_family = AF_CAN;
+ sa.can_ifindex = ifr.ifr_ifindex;
+
+ if (rump_sys_bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ atf_tc_fail_errno("bind");
+ }
+
+ v = 1;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
+ &v, sizeof(v)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_RECV_OWN_MSGS)");
+ }
+
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ NULL, 0) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
+ }
+
+ /* get filter: should be NULL */
+ cfilen = sizeof(cfi);
+ if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, &cfilen) < 0) {
+ atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
+ }
+ ATF_CHECK_MSG(cfilen == 0,
+ "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
+ /*
+ * send a single byte message, but make sure remaining payload is
+ * not 0.
+ */
+#define MY_ID 1
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ if (errno == EWOULDBLOCK)
+ return; /* expected timeout */
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+ atf_tc_fail("we got our own message");
+#undef MY_ID
+}
+
+ATF_TC(canfilter_multiple);
+ATF_TC_HEAD(canfilter_multiple, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check multiple CAN filters");
+ atf_tc_set_md_var(tc, "timeout", "5");
+}
+
+ATF_TC_BODY(canfilter_multiple, tc)
+{
+ const char ifname[] = "canlo0";
+ int s, rv, v, vlen;
+ struct sockaddr_can sa;
+ struct ifreq ifr;
+ struct can_frame cf_send, cf_receive;
+ struct can_filter cfi[2];
+
+ rump_init();
+ cancfg_rump_createif(ifname);
+
+ s = -1;
+ if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+ atf_tc_fail_errno("CAN socket");
+ }
+
+ strcpy(ifr.ifr_name, ifname );
+ if (rump_sys_ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ atf_tc_fail_errno("SIOCGIFINDEX");
+ }
+ ATF_CHECK_MSG(ifr.ifr_ifindex > 0, "%s index is %d (not > 0)",
+ ifname, ifr.ifr_ifindex);
+
+ sa.can_family = AF_CAN;
+ sa.can_ifindex = ifr.ifr_ifindex;
+
+ if (rump_sys_bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ atf_tc_fail_errno("bind");
+ }
+
+ v = 1;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
+ &v, sizeof(v)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_RECV_OWN_MSGS)");
+ }
+
+ /* set filter: accept MY_ID and MY_ID+1 */
+#define MY_ID 1
+ cfi[0].can_id = MY_ID;
+ cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
+ cfi[1].can_id = MY_ID + 1;
+ cfi[1].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, sizeof(cfi)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
+ }
+
+ /*
+ * send a single byte message, but make sure remaining payload is
+ * not 0.
+ */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+
+ /* now send a packet with MY_ID+1. Should pass too */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 1;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 1;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+
+ /* now send a packet with MY_ID + 2. Should not pass */
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 2;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ cf_send.data[1] = 0xad;
+ cf_send.data[2] = 0xbe;
+ cf_send.data[3] = 0xef;
+
+ if (rump_sys_write(s, &cf_send, sizeof(cf_send) - 7) < 0) {
+ atf_tc_fail_errno("write");
+ }
+
+ if (can_read(s, &cf_receive, &rv) < 0) {
+ if (errno == EWOULDBLOCK)
+ return; /* expected timeout */
+ atf_tc_fail_errno("read");
+ }
+
+ ATF_CHECK_MSG(rv > 0, "short read on socket");
+
+ memset(&cf_send, 0, sizeof(cf_send));
+ cf_send.can_id = MY_ID + 2;
+ cf_send.can_dlc = 1;
+ cf_send.data[0] = 0xde;
+ /* other data[] are expected to be 0 */
+
+ ATF_CHECK_MSG(memcmp(&cf_send, &cf_receive, sizeof(cf_send)) == 0,
+ "received packet is not what we sent");
+ atf_tc_fail("we got our own message");
+#undef MY_ID
+}
+
+ATF_TC(canfilter_get);
+ATF_TC_HEAD(canfilter_get, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check reading CAN filters");
+ atf_tc_set_md_var(tc, "timeout", "5");
+}
+
+ATF_TC_BODY(canfilter_get, tc)
+{
+ const char ifname[] = "canlo0";
+ int s, rv, v, vlen;
+ struct sockaddr_can sa;
+ struct ifreq ifr;
+ struct can_frame cf_send, cf_receive;
+ struct can_filter cfi[2];
+ int cfilen;
+
+ rump_init();
+ cancfg_rump_createif(ifname);
+
+ s = -1;
+ if ((s = rump_sys_socket(AF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+ atf_tc_fail_errno("CAN socket");
+ }
+
+ cfilen = sizeof(cfi);
+ /* get filter: should be default filter */
+ if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, &cfilen) < 0) {
+ atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
+ }
+ ATF_CHECK_MSG(cfilen == sizeof(struct can_filter),
+ "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
+ ATF_CHECK_MSG(cfi[0].can_id == 0 && cfi[0].can_mask == 0,
+ "CAN_RAW_FILTER returns wrong filter (%d, %d)",
+ cfi[0].can_id, cfi[0].can_mask);
+
+ /* set filter: accept MY_ID and MY_ID+1 */
+#define MY_ID 1
+ cfi[0].can_id = MY_ID;
+ cfi[0].can_mask = CAN_SFF_MASK | CAN_EFF_FLAG;
+ cfi[1].can_id = MY_ID + 1;
+ cfi[1].can_mask = CAN_SFF_MASK;
+ if (rump_sys_setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, sizeof(cfi)) < 0) {
+ atf_tc_fail_errno("setsockopt(CAN_RAW_FILTER)");
+ }
+
+ /* and read back */
+ cfilen = sizeof(cfi);
+ memset(cfi, 0, cfilen);
+ if (rump_sys_getsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER,
+ &cfi, &cfilen) < 0) {
+ atf_tc_fail_errno("getsockopt(CAN_RAW_FILTER)");
+ }
+ ATF_CHECK_MSG(cfilen == sizeof(struct can_filter) * 2,
+ "CAN_RAW_FILTER returns wrong len (%d)", cfilen);
+ ATF_CHECK_MSG(cfi[0].can_id == MY_ID &&
+ cfi[0].can_mask == CAN_SFF_MASK | CAN_EFF_FLAG,
+ "CAN_RAW_FILTER returns wrong filter 0 (%d, %d)",
+ cfi[0].can_id, cfi[0].can_mask);
+ ATF_CHECK_MSG(cfi[1].can_id == MY_ID + 1 &&
+ cfi[1].can_mask == CAN_SFF_MASK,
+ "CAN_RAW_FILTER returns wrong filter 1 (%d, %d)",
+ cfi[1].can_id, cfi[1].can_mask);
+
+#undef MY_ID
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, canfilter_basic);
+ ATF_TP_ADD_TC(tp, canfilter_null);
+ ATF_TP_ADD_TC(tp, canfilter_multiple);
+ ATF_TP_ADD_TC(tp, canfilter_get);
+ return atf_no_error();
+}
+