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();
+}
+

Reply via email to