Module Name:    src
Committed By:   bouyer
Date:           Sun Jan 15 20:27:34 UTC 2017

Modified Files:
        src/sys [bouyer-socketcan]: Makefile
        src/sys/conf [bouyer-socketcan]: files
        src/sys/net [bouyer-socketcan]: netisr.h netisr_dispatch.h
        src/sys/rump/include/opt [bouyer-socketcan]: opt_rumpkernel.h
        src/sys/rump/include/rump [bouyer-socketcan]: rumpdefs.h
        src/sys/rump/net [bouyer-socketcan]: Makefile.rumpnetcomp
        src/sys/sys [bouyer-socketcan]: socket.h
Added Files:
        src/sys/netcan [bouyer-socketcan]: Makefile can.c can.h can_pcb.c
            can_pcb.h can_proto.c can_var.h files.netcan if_canloop.c
        src/sys/rump/net/lib/libnetcan [bouyer-socketcan]: Makefile
            NETCAN.ioconf netcan_component.c

Log Message:
Initial commit of a CAN socket layer, compatible with linux SoccketCAN
(but incomplete). Based on work from Robert Swindells.


To generate a diff of this commit:
cvs rdiff -u -r1.79 -r1.79.22.1 src/sys/Makefile
cvs rdiff -u -r1.1168 -r1.1168.2.1 src/sys/conf/files
cvs rdiff -u -r1.44 -r1.44.4.1 src/sys/net/netisr.h
cvs rdiff -u -r1.18 -r1.18.12.1 src/sys/net/netisr_dispatch.h
cvs rdiff -u -r0 -r1.1.2.1 src/sys/netcan/Makefile src/sys/netcan/can.c \
    src/sys/netcan/can.h src/sys/netcan/can_pcb.c src/sys/netcan/can_pcb.h \
    src/sys/netcan/can_proto.c src/sys/netcan/can_var.h \
    src/sys/netcan/files.netcan src/sys/netcan/if_canloop.c
cvs rdiff -u -r1.5 -r1.5.4.1 src/sys/rump/include/opt/opt_rumpkernel.h
cvs rdiff -u -r1.36 -r1.36.4.1 src/sys/rump/include/rump/rumpdefs.h
cvs rdiff -u -r1.16 -r1.16.2.1 src/sys/rump/net/Makefile.rumpnetcomp
cvs rdiff -u -r0 -r1.1.2.1 src/sys/rump/net/lib/libnetcan/Makefile \
    src/sys/rump/net/lib/libnetcan/NETCAN.ioconf \
    src/sys/rump/net/lib/libnetcan/netcan_component.c
cvs rdiff -u -r1.120 -r1.120.2.1 src/sys/sys/socket.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/Makefile
diff -u src/sys/Makefile:1.79 src/sys/Makefile:1.79.22.1
--- src/sys/Makefile:1.79	Fri Mar  1 18:25:27 2013
+++ src/sys/Makefile	Sun Jan 15 20:27:33 2017
@@ -1,9 +1,9 @@
-#	$NetBSD: Makefile,v 1.79 2013/03/01 18:25:27 joerg Exp $
+#	$NetBSD: Makefile,v 1.79.22.1 2017/01/15 20:27:33 bouyer Exp $
 
 .include <bsd.own.mk>
 
 SUBDIR=	altq arch compat dev fs miscfs \
-	net net80211 netatalk netbt netipsec netinet netinet6 \
+	net net80211 netatalk netbt netcan netipsec netinet netinet6 \
         netisdn netkey netmpls netnatm netsmb \
 	nfs opencrypto sys ufs uvm
 

Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1168 src/sys/conf/files:1.1168.2.1
--- src/sys/conf/files:1.1168	Mon Dec 26 23:12:33 2016
+++ src/sys/conf/files	Sun Jan 15 20:27:33 2017
@@ -1,4 +1,4 @@
-#	$NetBSD: files,v 1.1168 2016/12/26 23:12:33 pgoyette Exp $
+#	$NetBSD: files,v 1.1168.2.1 2017/01/15 20:27:33 bouyer Exp $
 #	@(#)files.newconf	7.5 (Berkeley) 5/10/93
 
 version 	20150846
@@ -229,6 +229,7 @@ file	net/bpfjit.c	sljit & bpfjit
 include "net80211/files.net80211"
 include "netatalk/files.netatalk"
 include "netbt/files.netbt"
+include "netcan/files.netcan"
 include "netinet/files.netinet"
 include "netinet6/files.netinet6"
 include "netipsec/files.netipsec"
@@ -1435,6 +1436,7 @@ defpseudo stf:		ifnet
 defpseudodev tap:	ifnet, ether, arp
 defpseudo carp:		ifnet, ether, arp
 defpseudodev etherip:	ifnet, ether, arp
+defpseudo canloop:	ifnet
 
 defpseudo sequencer
 defpseudo clockctl

Index: src/sys/net/netisr.h
diff -u src/sys/net/netisr.h:1.44 src/sys/net/netisr.h:1.44.4.1
--- src/sys/net/netisr.h:1.44	Mon May 25 08:29:01 2015
+++ src/sys/net/netisr.h	Sun Jan 15 20:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: netisr.h,v 1.44 2015/05/25 08:29:01 ozaki-r Exp $ */
+/* $NetBSD: netisr.h,v 1.44.4.1 2017/01/15 20:27:33 bouyer Exp $ */
 
 /*
  * Copyright (c) 1980, 1986, 1989, 1993
@@ -53,6 +53,7 @@
 #include "opt_atalk.h"
 #include "opt_mpls.h"
 #include "opt_natm.h"
+#include "opt_can.h"
 #include "arp.h"
 #endif /* defined(_KERNEL_OPT) */
 
@@ -90,6 +91,10 @@
 #ifdef NETATALK
 #include <netatalk/at_extern.h>
 #endif
+#ifdef CAN
+#include <netcan/can.h>
+#include <netcan/can_var.h>
+#endif
 
 #endif /* !defined(_LOCORE) */
 #endif /* defined(_KERNEL) */
@@ -109,6 +114,7 @@
 #define	NETISR_NATM	27		/* same as AF_NATM */
 #define	NETISR_ARP	28		/* same as AF_ARP */
 #define	NETISR_MPLS	33		/* same as AF_MPLS */
+#define	NETISR_CAN	35		/* same as AF_CAN */
 #define	NETISR_MAX	AF_MAX
 
 #if !defined(_LOCORE) && defined(_KERNEL)

Index: src/sys/net/netisr_dispatch.h
diff -u src/sys/net/netisr_dispatch.h:1.18 src/sys/net/netisr_dispatch.h:1.18.12.1
--- src/sys/net/netisr_dispatch.h:1.18	Thu Jun  5 23:48:16 2014
+++ src/sys/net/netisr_dispatch.h	Sun Jan 15 20:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: netisr_dispatch.h,v 1.18 2014/06/05 23:48:16 rmind Exp $ */
+/* $NetBSD: netisr_dispatch.h,v 1.18.12.1 2017/01/15 20:27:33 bouyer Exp $ */
 
 #ifndef _NET_NETISR_DISPATCH_H_
 #define _NET_NETISR_DISPATCH_H_
@@ -41,5 +41,8 @@
 #ifdef NATM
 	DONETISR(NETISR_NATM,natmintr);
 #endif
+#ifdef CAN
+	DONETISR(NETISR_CAN,canintr);
+#endif
 
 #endif /* !_NET_NETISR_DISPATCH_H_ */

Index: src/sys/rump/include/opt/opt_rumpkernel.h
diff -u src/sys/rump/include/opt/opt_rumpkernel.h:1.5 src/sys/rump/include/opt/opt_rumpkernel.h:1.5.4.1
--- src/sys/rump/include/opt/opt_rumpkernel.h:1.5	Fri Apr 15 01:35:26 2016
+++ src/sys/rump/include/opt/opt_rumpkernel.h	Sun Jan 15 20:27:33 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: opt_rumpkernel.h,v 1.5 2016/04/15 01:35:26 ozaki-r Exp $	*/
+/*	$NetBSD: opt_rumpkernel.h,v 1.5.4.1 2017/01/15 20:27:33 bouyer Exp $	*/
 
 #ifndef __NetBSD__
 #define __NetBSD__
@@ -22,6 +22,8 @@
 
 #define MPLS	1
 
+#define CAN	1
+
 #define SOSEND_NO_LOAN
 
 #undef PIPE_SOCKETPAIR /* would need uipc_usrreq.c */

Index: src/sys/rump/include/rump/rumpdefs.h
diff -u src/sys/rump/include/rump/rumpdefs.h:1.36 src/sys/rump/include/rump/rumpdefs.h:1.36.4.1
--- src/sys/rump/include/rump/rumpdefs.h:1.36	Tue Feb  2 01:15:58 2016
+++ src/sys/rump/include/rump/rumpdefs.h	Sun Jan 15 20:27:33 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rumpdefs.h,v 1.36 2016/02/02 01:15:58 pooka Exp $	*/
+/*	$NetBSD: rumpdefs.h,v 1.36.4.1 2017/01/15 20:27:33 bouyer Exp $	*/
 
 /*
  *	AUTOMATICALLY GENERATED.  DO NOT EDIT.
@@ -240,7 +240,8 @@ enum rump_vtype	{ RUMP_VNON, RUMP_VREG, 
 #define	RUMP_AF_IEEE80211	32		
 #define	RUMP_AF_MPLS		33		
 #define	RUMP_AF_ROUTE	34		
-#define	RUMP_AF_MAX		35
+#define	RUMP_AF_CAN		35
+#define	RUMP_AF_MAX		36
 #define	RUMP_PF_UNSPEC	RUMP_AF_UNSPEC
 #define	RUMP_PF_LOCAL	RUMP_AF_LOCAL
 #define	RUMP_PF_UNIX		RUMP_PF_LOCAL	
@@ -277,6 +278,7 @@ enum rump_vtype	{ RUMP_VNON, RUMP_VREG, 
 #define RUMP_PF_BLUETOOTH	RUMP_AF_BLUETOOTH
 #define	RUMP_PF_MPLS		RUMP_AF_MPLS
 #define	RUMP_PF_ROUTE	RUMP_AF_ROUTE
+#define	RUMP_PF_CAN		RUMP_AF_CAN
 #define	RUMP_PF_MAX		RUMP_AF_MAX
 #define	RUMP_SO_DEBUG	0x0001		
 #define	RUMP_SO_ACCEPTCONN	0x0002		

Index: src/sys/rump/net/Makefile.rumpnetcomp
diff -u src/sys/rump/net/Makefile.rumpnetcomp:1.16 src/sys/rump/net/Makefile.rumpnetcomp:1.16.2.1
--- src/sys/rump/net/Makefile.rumpnetcomp:1.16	Sat Nov 26 03:17:58 2016
+++ src/sys/rump/net/Makefile.rumpnetcomp	Sun Jan 15 20:27:34 2017
@@ -1,9 +1,9 @@
-#	$NetBSD: Makefile.rumpnetcomp,v 1.16 2016/11/26 03:17:58 ozaki-r Exp $
+#	$NetBSD: Makefile.rumpnetcomp,v 1.16.2.1 2017/01/15 20:27:34 bouyer Exp $
 #
 
 .include <bsd.own.mk>
 
-RUMPNETCOMP=	agr bridge net net80211 netbt netinet netinet6
+RUMPNETCOMP=	agr bridge net net80211 netbt netcan netinet netinet6
 RUMPNETCOMP+=	gif netmpls npf local pppoe shmif tap tun vlan
 
 .if ${MKSLJIT} != "no" || make(rumpdescribe)

Index: src/sys/sys/socket.h
diff -u src/sys/sys/socket.h:1.120 src/sys/sys/socket.h:1.120.2.1
--- src/sys/sys/socket.h:1.120	Wed Sep 21 10:50:23 2016
+++ src/sys/sys/socket.h	Sun Jan 15 20:27:34 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: socket.h,v 1.120 2016/09/21 10:50:23 roy Exp $	*/
+/*	$NetBSD: socket.h,v 1.120.2.1 2017/01/15 20:27:34 bouyer Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -221,7 +221,8 @@ struct	accept_filter_arg {
 #define	AF_IEEE80211	32		/* IEEE80211 */
 #define	AF_MPLS		33		/* MultiProtocol Label Switching */
 #define	AF_ROUTE	34		/* Internal Routing Protocol */
-#define	AF_MAX		35
+#define	AF_CAN		35
+#define	AF_MAX		36
 
 /*
  * Structure used by kernel to store most
@@ -330,6 +331,7 @@ struct sockaddr_storage {
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define	PF_MPLS		AF_MPLS
 #define	PF_ROUTE	AF_ROUTE
+#define	PF_CAN		AF_CAN
 
 #define	PF_MAX		AF_MAX
 

Added files:

Index: src/sys/netcan/Makefile
diff -u /dev/null src/sys/netcan/Makefile:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/Makefile	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,8 @@
+#	$NetBSD: Makefile,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $
+
+KDIR=	/sys/netcan
+INCSDIR= /usr/include/netcan
+
+INCS=	can.h
+
+.include <bsd.kinc.mk>
Index: src/sys/netcan/can.c
diff -u /dev/null src/sys/netcan/can.c:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can.c	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,697 @@
+/*	$NetBSD: can.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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>
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/proc.h>
+#include <sys/kauth.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netcan/can.h>
+#include <netcan/can_pcb.h>
+#include <netcan/can_var.h>
+
+struct canpcb canpcb;
+#if 0
+struct canpcb canrawpcb;
+#endif
+
+struct	canpcbtable cbtable;
+
+struct ifqueue	canintrq;
+int	canqmaxlen = IFQ_MAXLEN;
+
+int can_copy_output = 0;
+int can_output_cnt = 0;
+struct mbuf *can_lastout;
+
+int	can_sendspace = 4096;		/* really max datagram size */
+int	can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
+					/* 40 1K datagrams */
+#ifndef CANHASHSIZE
+#define	CANHASHSIZE	128
+#endif
+int	canhashsize = CANHASHSIZE;
+
+static int can_output(struct mbuf *, struct canpcb *);
+
+static int can_control(struct socket *, u_long, void *, struct ifnet *);
+
+void
+can_init(void)
+{
+	canintrq.ifq_maxlen = canqmaxlen;
+	IFQ_LOCK_INIT(&canintrq);
+	can_pcbinit(&cbtable, canhashsize, canhashsize);
+}
+
+/*
+ * Generic control operations (ioctl's).
+ */
+/* ARGSUSED */
+static int
+can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
+{
+#if 0
+	struct can_ifreq *cfr = (struct can_ifreq *)data;
+	int error = 0;
+#endif
+
+
+	switch (cmd) {
+
+	default:
+		if (ifp == 0 || ifp->if_ioctl == 0)
+			return (EOPNOTSUPP);
+		return ((*ifp->if_ioctl)(ifp, cmd, data));
+	}
+	return (0);
+}
+
+static int
+can_purgeif(struct socket *so, struct ifnet *ifp)
+{
+	return 0;
+}
+
+static int
+can_output(struct mbuf *m, struct canpcb *canp)
+{
+	struct ifnet *ifp;
+	int error = 0;
+
+	if (canp == 0) {
+		printf("can_output: no pcb\n");
+		error = EINVAL;
+		goto done;
+	}
+	ifp = canp->canp_ifp;
+	if (ifp == 0) {
+		error = EDESTADDRREQ;
+		goto done;
+	}
+	if (m->m_len <= ifp->if_mtu) {
+		can_output_cnt++;
+		error = (*ifp->if_output)(ifp, m, NULL, 0);
+		goto done;
+	} else error = EMSGSIZE;
+
+	m_freem(m);
+done:
+	return (error);
+}
+
+/*
+ * Process a received CAN frame
+ * the packet is in the mbuf chain m with
+ * the CAN header.
+ */
+void
+can_input(struct ifnet *ifp, struct mbuf *m)
+{
+	struct ifqueue *inq;
+
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		m_freem(m);
+		return;
+	}
+
+	inq = &canintrq;
+	
+	IFQ_LOCK(inq);
+	if (IF_QFULL(inq)) {
+		IF_DROP(inq);
+		IFQ_UNLOCK(inq);
+		m_freem(m);
+	} else {
+		IF_ENQUEUE(inq, m);
+		IFQ_UNLOCK(inq);
+		schednetisr(NETISR_CAN);
+		ifp->if_ipackets++;
+		ifp->if_ibytes += m->m_pkthdr.len;
+	}
+}
+
+void
+canintr(void)
+{
+	int		rcv_ifindex;
+	struct mbuf    *m;
+
+	struct sockaddr_can from;
+	struct canpcb   *canp;
+
+	mutex_enter(softnet_lock);
+	for (;;) {
+		IFQ_LOCK(&canintrq);
+		IF_DEQUEUE(&canintrq, m);
+		IFQ_UNLOCK(&canintrq);
+
+		if (m == 0)	/* no more queued packets */
+			break;
+
+		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;
+
+		TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
+			struct mbuf *mc;
+			if (canp->canp_ifp != NULL &&
+			    canp->canp_ifp->if_index != rcv_ifindex) {
+				continue;
+			}
+			if (TAILQ_NEXT(canp, canp_queue) != NULL) {
+				/*
+				 * we can't be sure we won't need 
+				 * the original mbuf later so copy 
+				 */
+				mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+				if (mc == NULL) {
+					/* deliver this mbuf and abort */
+					mc = m;
+					m = NULL;
+				}
+			} else {
+				mc = m;
+				m = NULL;
+			}
+			if (sbappendaddr(&canp->canp_socket->so_rcv,
+					 (struct sockaddr *) &from, mc,
+					 (struct mbuf *) 0) == 0) {
+				m_freem(mc);
+			} else
+				sorwakeup(canp->canp_socket);
+			if (m == NULL)
+				break;
+		}
+		/* If it didn't go anywhere just delete it */
+		if (m) {
+			m_freem(m);
+		}
+	}
+	mutex_exit(softnet_lock);
+}
+
+static int
+can_attach(struct socket *so, int proto)
+{
+	/*struct canpcb *canp;*/
+	int error;
+
+	KASSERT(sotocanpcb(so) == NULL);
+
+	/* Assign the lock (must happen even if we will error out). */
+	sosetlock(so);
+
+#ifdef MBUFTRACE
+	so->so_mowner = &can_mowner;
+	so->so_rcv.sb_mowner = &can_rx_mowner;
+	so->so_snd.sb_mowner = &can_tx_mowner;
+#endif
+	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+		error = soreserve(so, can_sendspace, can_recvspace);
+		if (error) {
+			return error;
+		}
+	}
+
+	error = can_pcballoc(so, &cbtable);
+	if (error) {
+		return error;
+	}
+	/*canp = sotocanpcb(so);*/
+	KASSERT(solocked(so));
+
+	return error;
+}
+
+static void
+can_detach(struct socket *so)
+{
+	struct canpcb *canp;
+
+	KASSERT(solocked(so));
+	canp = sotocanpcb(so);
+	can_pcbdetach(canp);
+}
+
+static int
+can_accept(struct socket *so, struct sockaddr *nam)
+{
+	KASSERT(solocked(so));
+
+	panic("can_accept");
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
+{
+	struct canpcb *canp = sotocanpcb(so);
+	struct sockaddr_can *scan = (struct sockaddr_can *)nam;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	return can_pcbbind(canp, scan, l);
+}
+
+static int
+can_listen(struct socket *so, struct lwp *l)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
+{
+	struct canpcb *canp = sotocanpcb(so);
+	int error = 0;
+
+	KASSERT(solocked(so));
+	KASSERT(canp != NULL);
+	KASSERT(nam != NULL);
+
+	error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
+	if (! error)
+		soisconnected(so);
+	return error;
+}
+
+static int
+can_connect2(struct socket *so, struct socket *so2)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_disconnect(struct socket *so)
+{
+	struct canpcb *canp = sotocanpcb(so);
+
+	KASSERT(solocked(so));
+	KASSERT(canp != NULL);
+
+	/*soisdisconnected(so);*/
+	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
+	can_pcbdisconnect(canp);
+	can_pcbstate(canp, CANP_BOUND);		/* XXX */
+	return 0;
+}
+
+static int
+can_shutdown(struct socket *so)
+{
+	KASSERT(solocked(so));
+
+	socantsendmore(so);
+	return 0;
+}
+
+static int
+can_abort(struct socket *so)
+{
+	KASSERT(solocked(so));
+
+	panic("can_abort");
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
+{
+	return can_control(so, cmd, nam, ifp);
+}
+
+static int
+can_stat(struct socket *so, struct stat *ub)
+{
+	KASSERT(solocked(so));
+
+	/* stat: don't bother with a blocksize. */
+	return 0;
+}
+
+static int
+can_peeraddr(struct socket *so, struct sockaddr *nam)
+{
+	KASSERT(solocked(so));
+	KASSERT(sotocanpcb(so) != NULL);
+	KASSERT(nam != NULL);
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_sockaddr(struct socket *so, struct sockaddr *nam)
+{
+	KASSERT(solocked(so));
+	KASSERT(sotocanpcb(so) != NULL);
+	KASSERT(nam != NULL);
+
+	can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
+
+	return 0;
+}
+
+static int
+can_rcvd(struct socket *so, int flags, struct lwp *l)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_recvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
+    struct mbuf *control, struct lwp *l)
+{
+	struct canpcb *canp = sotocanpcb(so);
+	int error = 0;
+	int s;
+
+	if (control && control->m_len) {
+		return EINVAL;
+	}
+
+	if (nam) {
+		if ((so->so_state & SS_ISCONNECTED) != 0) {
+			return EISCONN;
+		}
+		s = splnet();
+		error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
+		if (error) {
+			splx(s);
+			return error;
+		}
+	} else {
+		if ((so->so_state & SS_ISCONNECTED) == 0) {
+			return EDESTADDRREQ;
+		}
+	}
+	error = can_output(m, canp);
+	if (nam) {
+		struct sockaddr_can lscan;
+		memset(&lscan, 0, sizeof(lscan));
+		lscan.can_family = AF_CAN;
+		lscan.can_len = sizeof(lscan);
+		can_pcbbind(canp, &lscan, l);
+	}
+	return error;
+}
+
+static int
+can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
+{
+	KASSERT(solocked(so));
+
+	m_freem(m);
+	m_freem(control);
+
+	return EOPNOTSUPP;
+}
+
+#if 0
+int
+can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
+	   struct mbuf *control, struct lwp *l)
+{
+	struct canpcb *canp;
+	int s;
+	int error = 0;
+
+	if (req == PRU_CONTROL)
+		 return (can_control(so, (long)m, nam,
+		     (struct ifnet *)control));
+
+	if (req == PRU_PURGEIF) {
+#if 0
+		can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
+		can_purgeif((struct ifnet *)control);
+		can_pcbpurgeif(&udbtable, (struct ifnet *)control);
+#endif
+		return (0);
+	}
+
+	s = splsoftnet();
+	canp = sotocanpcb(so);
+#ifdef DIAGNOSTIC
+	if (req != PRU_SEND && req != PRU_SENDOOB && control)
+		panic("can_usrreq: unexpected control mbuf");
+#endif
+	if (canp == 0 && req != PRU_ATTACH) {
+		printf("can_usrreq: no pcb %p %d\n", canp, req);
+		error = EINVAL;
+		goto release;
+	}
+
+	/*
+	 * Note: need to block can_input while changing
+	 * the can pcb queue and/or pcb addresses.
+	 */
+	switch (req) {
+
+	  case PRU_ATTACH:
+	      if (canp != 0) {
+			 error = EISCONN;
+			 break;
+		 }
+#ifdef MBUFTRACE
+		so->so_mowner = &can_mowner;
+		so->so_rcv.sb_mowner = &can_rx_mowner;
+		so->so_snd.sb_mowner = &can_tx_mowner;
+#endif
+		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+			error = soreserve(so, can_sendspace, can_recvspace);
+			if (error)
+				break;
+		}
+		error = can_pcballoc(so, &cbtable);
+		if (error)
+			break;
+		canp = sotocanpcb(so);
+#if 0
+		inp->inp_ip.ip_ttl = ip_defttl;
+#endif
+		break;
+
+	case PRU_DETACH:
+		can_pcbdetach(canp);
+		break;
+
+	case PRU_BIND:
+		error = can_pcbbind(canp, nam, l);
+		break;
+
+	case PRU_LISTEN:
+		error = EOPNOTSUPP;
+		break;
+
+	case PRU_CONNECT:
+		error = can_pcbconnect(canp, nam);
+		if (error)
+			break;
+		soisconnected(so);
+		break;
+
+	case PRU_CONNECT2:
+		error = EOPNOTSUPP;
+		break;
+
+	case PRU_DISCONNECT:
+		/*soisdisconnected(so);*/
+		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
+		can_pcbdisconnect(canp);
+		can_pcbstate(canp, CANP_BOUND);		/* XXX */
+		break;
+
+	case PRU_SHUTDOWN:
+		socantsendmore(so);
+		break;
+
+	case PRU_RCVD:
+		error = EOPNOTSUPP;
+		break;
+
+	case PRU_SEND:
+		break;
+
+	case PRU_SENSE:
+		/*
+		 * stat: don't bother with a blocksize.
+		 */
+		splx(s);
+		return (0);
+
+	case PRU_RCVOOB:
+		error =  EOPNOTSUPP;
+		break;
+
+	case PRU_SENDOOB:
+		m_freem(control);
+		m_freem(m);
+		error =  EOPNOTSUPP;
+		break;
+
+	case PRU_SOCKADDR:
+
+		break;
+
+	case PRU_PEERADDR:
+		error =  EOPNOTSUPP;
+		break;
+
+	default:
+		panic("can_usrreq");
+	}
+
+release:
+	splx(s);
+	return (error);
+}
+#endif
+
+#if 0
+static void
+can_notify(struct canpcb *canp, int errno)
+{
+
+	canp->canp_socket->so_error = errno;
+	sorwakeup(canp->canp_socket);
+	sowwakeup(canp->canp_socket);
+}
+
+void *
+can_ctlinput(int cmd, struct sockaddr *sa, void *v)
+{
+	struct ip *ip = v;
+	struct canhdr *uh;
+	void (*notify) __P((struct inpcb *, int)) = can_notify;
+	int errno;
+
+	if (sa->sa_family != AF_CAN
+	 || sa->sa_len != sizeof(struct sockaddr_can))
+		return NULL;
+	if ((unsigned)cmd >= PRC_NCMDS)
+		return NULL;
+	errno = inetctlerrmap[cmd];
+	if (PRC_IS_REDIRECT(cmd))
+		notify = in_rtchange, ip = 0;
+	else if (cmd == PRC_HOSTDEAD)
+		ip = 0;
+	else if (errno == 0)
+		return NULL;
+	if (ip) {
+		uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
+		in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
+		    ip->ip_src, uh->uh_sport, errno, notify);
+
+		/* XXX mapped address case */
+	} else
+		can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
+		    notify);
+	return NULL;
+}
+#endif
+
+PR_WRAP_USRREQS(can)
+#define	can_attach	can_attach_wrapper
+#define	can_detach	can_detach_wrapper
+#define	can_accept	can_accept_wrapper
+#define	can_bind	can_bind_wrapper
+#define	can_listen	can_listen_wrapper
+#define	can_connect	can_connect_wrapper
+#define	can_connect2	can_connect2_wrapper
+#define	can_disconnect	can_disconnect_wrapper
+#define	can_shutdown	can_shutdown_wrapper
+#define	can_abort	can_abort_wrapper
+#define	can_ioctl	can_ioctl_wrapper
+#define	can_stat	can_stat_wrapper
+#define	can_peeraddr	can_peeraddr_wrapper
+#define	can_sockaddr	can_sockaddr_wrapper
+#define	can_rcvd	can_rcvd_wrapper
+#define	can_recvoob	can_recvoob_wrapper
+#define	can_send	can_send_wrapper
+#define	can_sendoob	can_sendoob_wrapper
+#define	can_purgeif	can_purgeif_wrapper
+
+const struct pr_usrreqs can_usrreqs = {
+	.pr_attach	= can_attach,
+	.pr_detach	= can_detach,
+	.pr_accept	= can_accept,
+	.pr_bind	= can_bind,
+	.pr_listen	= can_listen,
+	.pr_connect	= can_connect,
+	.pr_connect2	= can_connect2,
+	.pr_disconnect	= can_disconnect,
+	.pr_shutdown	= can_shutdown,
+	.pr_abort	= can_abort,
+	.pr_ioctl	= can_ioctl,
+	.pr_stat	= can_stat,
+	.pr_peeraddr	= can_peeraddr,
+	.pr_sockaddr	= can_sockaddr,
+	.pr_rcvd	= can_rcvd,
+	.pr_recvoob	= can_recvoob,
+	.pr_send	= can_send,
+	.pr_sendoob	= can_sendoob,
+	.pr_purgeif	= can_purgeif,
+};
Index: src/sys/netcan/can.h
diff -u /dev/null src/sys/netcan/can.h:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can.h	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,133 @@
+/*	$NetBSD: can.h,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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.
+ */
+
+#ifndef _NETCAN_CAN_H
+#define _NETCAN_CAN_H
+
+#include <sys/featuretest.h>
+#include <machine/int_types.h>
+
+
+/* Definitions compatible (as much as possible) with socketCAN */
+
+/*
+ * CAN id structure
+ * bits 0-28	: CAN identifier (11/29 bits, see bit 31)
+ * bit2 29-31	: see below
+ */
+
+typedef uint32_t canid_t;
+typedef uint32_t can_err_mask_t;
+
+/* canid_t bits 29-31 descriptions */
+#define CAN_EFF_FLAG 0x80000000U	/* extended frame format */
+#define CAN_RTR_FLAG 0x40000000U	/* remote transmission request */
+#define CAN_ERR_FLAG 0x20000000U	/* error message frame */
+
+/* valid bits in CAN ID for frame formats */
+#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
+#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
+#define CAN_ERR_MASK 0x1FFFFFFFU /* error frame format */
+
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN frame */
+struct can_frame {
+	canid_t	can_id; /* ID + EFF/RTR/ERR flags */
+	uint8_t	can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
+	uint8_t	__pad;
+	uint8_t	__res0;
+	uint8_t __res1;
+	uint8_t	data[CAN_MAX_DLEN];
+};
+
+#define CAN_MTU         (sizeof(struct can_frame))
+
+/* protocols */
+#define CAN_RAW         1 /* RAW sockets */
+#define CAN_NPROTO	2
+
+#define SOL_CAN_BASE 100
+
+/*
+ * Socket address, CAN style
+ */
+struct sockaddr_can {
+	u_int8_t	can_len;
+	sa_family_t	can_family;
+	int 		can_ifindex;
+	union {
+		/* transport protocol class address information (e.g. ISOTP) */
+		struct { canid_t rx_id, tx_id; } tp;
+		/* reserved for future CAN protocols address information */
+	} can_addr;
+};
+
+/*
+ * Options for use with [gs]etsockopt
+ * First word of comment is data type; bool is stored in int.
+ */
+
+#define CAN_RAW_FILTER	1 /* struct can_filter: set filter */
+
+/*
+ * CAN ID based filter
+ * checks received can_id & can_filter.can_mask against
+ *   can_filter.can_id & can_filter.can_mask
+ * valid flags for can_id:
+ *     CAN_INV_FILTER: invert filter
+ * valid flags for can_mask:
+ *     CAN_ERR_FLAG: filter for error message frames
+ */
+struct can_filter {
+	canid_t can_id;
+	canid_t can_mask;
+};
+
+#define CAN_INV_FILTER 0x20000000U
+
+#ifdef _NETBSD_SOURCE
+
+/* CAN sockets ioctl */
+
+#define SIOCSCANBAUD	_IOW('i', 134, int) /* set interface speed */
+#define SIOCGCANBAUD	_IOR('i', 135, int) /* get interface speed */
+
+#ifdef _KERNEL
+
+#define	satoscan(sa)	((struct sockaddr_can *)(sa))
+#define	scantosa(scan)	((struct sockaddr *)(scan))
+
+#endif /* _KERNEL */
+#endif /* _NETBSD_SOURCE */
+#endif /* _NETCAN_CAN_H */
Index: src/sys/netcan/can_pcb.c
diff -u /dev/null src/sys/netcan/can_pcb.c:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can_pcb.c	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,283 @@
+/*	$NetBSD: can_pcb.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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>
+__KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/pool.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netcan/can.h>
+#include <netcan/can_var.h>
+#include <netcan/can_pcb.h>
+
+#define	CANPCBHASH_BIND(table, ifindex) \
+	&(table)->canpt_bindhashtbl[ \
+	    (ifindex) & (table)->canpt_bindhash]
+#define	CANPCBHASH_CONNECT(table, ifindex) \
+	&(table)->canpt_connecthashtbl[ \
+	    (ifindex) & (table)->canpt_bindhash]
+
+struct pool canpcb_pool;
+
+void
+can_pcbinit(struct canpcbtable *table, int bindhashsize, int connecthashsize)
+{
+	static int canpcb_pool_initialized;
+
+	if (canpcb_pool_initialized == 0) {
+		pool_init(&canpcb_pool, sizeof(struct canpcb), 0, 0, 0,
+		    "canpcbpl", NULL, IPL_SOFTNET);
+		canpcb_pool_initialized = 1;
+	}
+
+	TAILQ_INIT(&table->canpt_queue);
+	table->canpt_bindhashtbl = hashinit(bindhashsize, HASH_LIST, true,
+	    &table->canpt_bindhash);
+	table->canpt_connecthashtbl = hashinit(connecthashsize, HASH_LIST,
+	    true, &table->canpt_connecthash);
+}
+
+int
+can_pcballoc(struct socket *so, void *v)
+{
+	struct canpcbtable *table = v;
+	struct canpcb *canp;
+	int s;
+
+	s = splnet();
+	canp = pool_get(&canpcb_pool, PR_NOWAIT);
+	splx(s);
+	if (canp == NULL)
+		return (ENOBUFS);
+	memset(canp, 0, sizeof(*canp));
+	canp->canp_table = table;
+	canp->canp_socket = so;
+
+	so->so_pcb = canp;
+	s = splnet();
+	TAILQ_INSERT_HEAD(&table->canpt_queue, canp, canp_queue);
+	can_pcbstate(canp, CANP_ATTACHED);
+	splx(s);
+	return (0);
+}
+
+int
+can_pcbbind(void *v, struct sockaddr_can *scan, struct lwp *l)
+{
+	struct canpcb *canp = v;
+
+	if (scan->can_family != AF_CAN)
+		return (EAFNOSUPPORT);
+	if (scan->can_ifindex != 0) {
+		canp->canp_ifp = if_byindex(scan->can_ifindex);
+		if (canp->canp_ifp == NULL)
+			return (EADDRNOTAVAIL);
+		soisconnected(canp->canp_socket);
+	} else {
+		canp->canp_ifp = NULL;
+		canp->canp_socket->so_state &= ~SS_ISCONNECTED;	/* XXX */
+	}
+	can_pcbstate(canp, CANP_BOUND);
+	return 0;
+}
+
+/*
+ * Connect from a socket to a specified address.
+ */
+int
+can_pcbconnect(void *v, struct sockaddr_can *scan)
+{
+#if 0
+	struct canpcb *canp = v;
+	struct sockaddr_can *ifaddr = NULL;
+	int error;
+#endif
+
+	if (scan->can_family != AF_CAN)
+		return (EAFNOSUPPORT);
+#if 0
+	memcpy(&canp->canp_dst, scan, sizeof(struct sockaddr_can));
+	can_pcbstate(canp, CANP_CONNECTED);
+	return 0;
+#endif
+	return EOPNOTSUPP;
+}
+
+void
+can_pcbdisconnect(void *v)
+{
+	struct canpcb *canp = v;
+
+	can_pcbstate(canp, CANP_BOUND);
+	if (canp->canp_socket->so_state & SS_NOFDREF)
+		can_pcbdetach(canp);
+}
+
+void
+can_pcbdetach(void *v)
+{
+	struct canpcb *canp = v;
+	struct socket *so = canp->canp_socket;
+	int s;
+
+	KASSERT(mutex_owned(softnet_lock));
+	so->so_pcb = NULL;
+	s =  splnet();
+	can_pcbstate(canp, CANP_ATTACHED);
+	TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue);
+	splx(s);
+	sofree(so); /* sofree drops the lock */
+	pool_put(&canpcb_pool, canp);
+	mutex_enter(softnet_lock);
+}
+
+void
+can_setsockaddr(struct canpcb *canp, struct sockaddr_can *scan)
+{
+
+	memset(scan, 0, sizeof (*scan));
+	scan->can_family = AF_CAN;
+	scan->can_len = sizeof(*scan);
+	scan->can_ifindex = canp->canp_ifp->if_index;
+}
+
+#if 0
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst.  The local address and/or port numbers
+ * may be specified to limit the search.  The "usual action" will be
+ * taken, depending on the ctlinput cmd.  The caller must filter any
+ * cmds that are uninteresting (e.g., no error in the map).
+ * Call the protocol specific routine (if any) to report
+ * any errors for each matching socket.
+ *
+ * Must be called at splsoftnet.
+ */
+int
+can_pcbnotify(struct canpcbtable *table, u_int32_t faddr, u_int32_t laddr,
+    int errno, void (*notify)(struct canpcb *, int))
+{
+	struct canpcbhead *head;
+	struct canpcb *canp, *ncanp;
+	int nmatch;
+
+	if (faddr == 0 || notify == 0)
+		return (0);
+
+	nmatch = 0;
+	head = CANPCBHASH_CONNECT(table, faddr, laddr);
+	for (canp = LIST_FIRST(head); canp != NULL; canp = ncanp) {
+		ncanp = LIST_NEXT(canp, canp_hash);
+		if (canp->canp_faddr == faddr &&
+		    canp->canp_laddr == laddr) {
+			(*notify)(canp, errno);
+			nmatch++;
+		}
+	}
+	return (nmatch);
+}
+
+void
+can_pcbnotifyall(struct canpcbtable *table, u_int32_t faddr, int errno,
+    void (*notify)(struct canpcb *, int))
+{
+	struct canpcb *canp, *ncanp;
+
+	if (faddr == 0 || notify == 0)
+		return;
+
+	TAILQ_FOREACH_SAFE(canp, &table->canpt_queue, canp_queue, ncanp) {
+		if (canp->canp_faddr == faddr)
+			(*notify)(canp, errno);
+	}
+}
+#endif
+
+#if 0
+void
+can_pcbpurgeif0(struct canpcbtable *table, struct ifnet *ifp)
+{
+	struct canpcb *canp, *ncanp;
+	struct ip_moptions *imo;
+	int i, gap;
+
+}
+
+void
+can_pcbpurgeif(struct canpcbtable *table, struct ifnet *ifp)
+{
+	struct canpcb *canp, *ncanp;
+
+	for (canp = CIRCLEQ_FIRST(&table->canpt_queue);
+	    canp != (void *)&table->canpt_queue;
+	    canp = ncanp) {
+		ncanp = CIRCLEQ_NEXT(canp, canp_queue);
+	}
+}
+#endif
+
+
+
+void
+can_pcbstate(struct canpcb *canp, int state)
+{
+	int ifindex = canp->canp_ifp ? canp->canp_ifp->if_index : 0;
+
+	if (canp->canp_state > CANP_ATTACHED)
+		LIST_REMOVE(canp, canp_hash);
+
+	switch (state) {
+	case CANP_BOUND:
+		LIST_INSERT_HEAD(CANPCBHASH_BIND(canp->canp_table,
+		    ifindex), canp, canp_hash);
+		break;
+	case CANP_CONNECTED:
+		LIST_INSERT_HEAD(CANPCBHASH_CONNECT(canp->canp_table,
+		    ifindex), canp, canp_hash);
+		break;
+	}
+
+	canp->canp_state = state;
+}
Index: src/sys/netcan/can_pcb.h
diff -u /dev/null src/sys/netcan/can_pcb.h:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can_pcb.h	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,98 @@
+/*	$NetBSD: can_pcb.h,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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.
+ */
+
+#ifndef _NETCAN_CAN_PCB_H_
+#define _NETCAN_CAN_PCB_H_
+
+#include <sys/queue.h>
+
+/*
+ * Common structure pcb for can protocol implementation.
+ * Here are stored pointers to local and foreign host table
+ * entries, local and foreign socket numbers, and pointers
+ * up (to a socket structure) and down (to a protocol-specific)
+ * control block.
+ */
+struct canpcbpolicy;
+
+
+struct canpcb {
+	LIST_ENTRY(canpcb) canp_hash;
+	LIST_ENTRY(canpcb) canp_lhash;
+	TAILQ_ENTRY(canpcb) canp_queue;
+	int		canp_state;
+	struct		socket *canp_socket;	/* back pointer to socket */
+	struct		ifnet *canp_ifp;
+	struct		canpcbtable *canp_table;
+};
+
+LIST_HEAD(canpcbhead, canpcb);
+
+#define canp_faddr	canp_dst.scan_addr
+
+TAILQ_HEAD(canpcbqueue, canpcb);
+
+struct canpcbtable {
+	struct	canpcbqueue canpt_queue;
+	struct	canpcbhead *canpt_bindhashtbl;
+	struct	canpcbhead *canpt_connecthashtbl;
+	u_long	canpt_bindhash;
+	u_long	canpt_connecthash;
+};
+
+/* states in inp_state: */
+#define	CANP_ATTACHED		0
+#define	CANP_BOUND		1
+#define	CANP_CONNECTED		2
+
+/* flags in inp_flags: */
+
+#define	sotocanpcb(so)		((struct canpcb *)(so)->so_pcb)
+
+#ifdef _KERNEL
+void	can_losing(struct canpcb *);
+int	can_pcballoc (struct socket *, void *);
+int	can_pcbbind(void *, struct sockaddr_can *, struct lwp *);
+int	can_pcbconnect(void *, struct sockaddr_can *);
+void	can_pcbdetach(void *);
+void	can_pcbdisconnect(void *);
+void	can_pcbinit(struct canpcbtable *, int, int);
+int	can_pcbnotify(struct canpcbtable *, u_int32_t,
+	    u_int32_t, int, void (*)(struct canpcb *, int));
+void	can_pcbnotifyall(struct canpcbtable *, u_int32_t, int,
+	    void (*)(struct canpcb *, int));
+void	can_pcbpurgeif0(struct canpcbtable *, struct ifnet *);
+void	can_pcbpurgeif(struct canpcbtable *, struct ifnet *);
+void	can_pcbstate(struct canpcb *, int);
+void	can_setsockaddr(struct canpcb *, struct sockaddr_can *);
+#endif
+
+#endif /* _NETCAN_CAN_PCB_H_ */
Index: src/sys/netcan/can_proto.c
diff -u /dev/null src/sys/netcan/can_proto.c:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can_proto.c	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,75 @@
+/*	$NetBSD: can_proto.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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>
+__KERNEL_RCSID(0, "$NetBSD: can_proto.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+/*
+ * CAN protocol family
+ */
+#include <netcan/can.h>
+#include <netcan/can_var.h>
+
+DOMAIN_DEFINE(candomain);	/* forward declare and add to link set */
+
+const struct protosw cansw[] = {
+{
+	.pr_type = SOCK_RAW,
+	.pr_domain = &candomain,
+	.pr_init = can_init,
+	.pr_flags = PR_ATOMIC|PR_ADDR,
+	.pr_usrreqs = &can_usrreqs,
+}
+};
+
+struct domain candomain = {
+	.dom_family = PF_CAN,
+	.dom_name = "can",
+	.dom_init = can_init,
+	.dom_externalize = NULL, .dom_dispose = NULL,
+	.dom_protosw = cansw,
+	.dom_protoswNPROTOSW = &cansw[__arraycount(cansw)],
+	.dom_ifqueues = { &canintrq, NULL },
+	.dom_link = { NULL },
+	.dom_mowner = MOWNER_INIT("",""),
+	.dom_sa_cmpofs = offsetof(struct sockaddr_can, can_ifindex),
+	.dom_sa_cmplen = sizeof(int)
+};
Index: src/sys/netcan/can_var.h
diff -u /dev/null src/sys/netcan/can_var.h:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/can_var.h	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,56 @@
+/*	$NetBSD: can_var.h,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $	*/
+
+/*-
+ * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Robert Swindells and 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.
+ */
+
+#ifndef _NETCAN_CAN_VAR_H_
+#define _NETCAN_CAN_VAR_H_
+
+#include <sys/queue.h>
+
+struct can_ifreq {
+	char            cfr_name[IFNAMSIZ];	/* if name, e.g. "sja0" */
+};
+
+#ifdef _KERNEL
+
+extern struct ifqueue canintrq;
+extern struct domain candomain;
+
+extern const struct pr_usrreqs can_usrreqs;
+
+void can_input(struct ifnet *, struct mbuf *);
+void *can_ctlinput(int, struct sockaddr *, void *);
+int can_ctloutput(int, struct socket *, int, int, struct mbuf **);
+void can_init(void);
+void canintr(void);
+
+#endif
+
+#endif
Index: src/sys/netcan/files.netcan
diff -u /dev/null src/sys/netcan/files.netcan:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/files.netcan	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,8 @@
+#	$NetBSD: files.netcan,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $
+
+defflag opt_can.h		CAN 	# ISO-15765 CAN network stack
+
+file	netcan/can.c		can
+file	netcan/can_proto.c	can
+file	netcan/can_pcb.c	can
+file	net/if_canloop.c	canloop
Index: src/sys/netcan/if_canloop.c
diff -u /dev/null src/sys/netcan/if_canloop.c:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/netcan/if_canloop.c	Sun Jan 15 20:27:33 2017
@@ -0,0 +1,232 @@
+/*	$NetBSD: if_canloop.c,v 1.1.2.1 2017/01/15 20:27:33 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.
+ */
+
+
+/*
+ * Loopback interface driver for the CAN protocol
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_canloop.c,v 1.1.2.1 2017/01/15 20:27:33 bouyer Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_can.h"
+#include "opt_net_mpsafe.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <sys/module.h>
+
+#include <sys/cpu.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+
+#ifdef	CAN
+#include <netcan/can.h>
+#endif
+#include <net/bpf.h>
+
+void canloopattach(int);
+void canloopinit(void);
+static int	canloop_clone_create(struct if_clone *, int);
+static int	canloop_clone_destroy(struct ifnet *);
+static int	canloop_ioctl(struct ifnet *, u_long, void *);
+static int	canloop_output(struct ifnet *,
+	struct mbuf *, const struct sockaddr *, const struct rtentry *);
+
+static int	canloop_count;
+
+static struct if_clone canloop_cloner =
+    IF_CLONE_INITIALIZER("canlo", canloop_clone_create, canloop_clone_destroy);
+
+void
+canloopattach(int n)
+{
+
+	/*
+	 * Nothing to do here, initialization is handled by the
+	 * module initialization code in canloopnit() below).
+	 */
+}
+
+void
+canloopinit(void)
+{
+
+	canloop_count = 0;
+	if_clone_attach(&canloop_cloner);
+}
+
+static int
+canloopdetach(void)
+{
+	if (canloop_count > 0)
+		return EBUSY;
+	if_clone_detach(&canloop_cloner);
+	return 0;
+}
+
+static int
+canloop_clone_create(struct if_clone *ifc, int unit)
+{
+	struct ifnet *ifp;
+
+	ifp = if_alloc(IFT_OTHER);
+
+	if_initname(ifp, ifc->ifc_name, unit);
+
+	ifp->if_mtu = sizeof(struct can_frame);
+	ifp->if_flags = IFF_LOOPBACK | IFF_RUNNING;
+	ifp->if_extflags = IFEF_OUTPUT_MPSAFE;
+	ifp->if_ioctl = canloop_ioctl;
+	ifp->if_output = canloop_output;
+	ifp->if_type = IFT_OTHER;
+	ifp->if_hdrlen = 0;
+	ifp->if_addrlen = 0;
+	ifp->if_dlt = DLT_CAN_SOCKETCAN;
+	IFQ_SET_READY(&ifp->if_snd);
+	if_attach(ifp);
+	if_alloc_sadl(ifp);
+	bpf_attach(ifp, DLT_CAN_SOCKETCAN, sizeof(u_int));
+#ifdef MBUFTRACE
+	ifp->if_mowner = malloc(sizeof(struct mowner), M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
+	    sizeof(ifp->if_mowner->mo_name));
+	MOWNER_ATTACH(ifp->if_mowner);
+#endif
+	canloop_count++;
+
+	return (0);
+}
+
+static int
+canloop_clone_destroy(struct ifnet *ifp)
+{
+
+#ifdef MBUFTRACE
+	MOWNER_DETACH(ifp->if_mowner);
+	free(ifp->if_mowner, M_DEVBUF);
+#endif
+
+	bpf_detach(ifp);
+	if_detach(ifp);
+
+	if_free(ifp);
+	canloop_count--;
+	KASSERT(canloop_count >= 0);
+	return (0);
+}
+
+static int
+canloop_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
+    const struct rtentry *rt)
+{
+	int error = 0;
+	size_t pktlen;
+
+	MCLAIM(m, ifp->if_mowner);
+
+	KERNEL_LOCK(1, NULL);
+
+	if ((m->m_flags & M_PKTHDR) == 0)
+		panic("canloop_output: no header mbuf");
+	if (ifp->if_flags & IFF_LOOPBACK)
+		bpf_mtap_af(ifp, AF_CAN, m);
+	m_set_rcvif(m, ifp);
+
+	pktlen = m->m_pkthdr.len;
+	ifp->if_opackets++;
+	ifp->if_obytes += pktlen;
+
+	m_tag_delete_nonpersistent(m);
+
+#ifdef CAN
+	can_input(ifp, m);
+#else
+	printf("%s: can't handle CAN packet\n", ifp->if_xname);
+	m_freem(m);
+	error = EAFNOSUPPORT;
+#endif
+
+	KERNEL_UNLOCK_ONE(NULL);
+	return error;
+}
+
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+static int
+canloop_ioctl(struct ifnet *ifp, u_long cmd, void *data)
+{
+	struct ifreq *ifr = data;
+	int error = 0;
+
+	switch (cmd) {
+
+	case SIOCINITIFADDR:
+		error = EAFNOSUPPORT;
+		break;
+
+	case SIOCSIFMTU:
+		if ((unsigned)ifr->ifr_mtu != sizeof(struct can_frame))
+			error = EINVAL;
+		break;
+
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		error = EAFNOSUPPORT;
+		break;
+
+	default:
+		error = ifioctl_common(ifp, cmd, data);
+	}
+	return (error);
+}
+
+/*
+ * Module infrastructure
+ */
+#include "../net/if_module.h"
+
+IF_MODULE(MODULE_CLASS_DRIVER, canloop, "")

Index: src/sys/rump/net/lib/libnetcan/Makefile
diff -u /dev/null src/sys/rump/net/lib/libnetcan/Makefile:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/rump/net/lib/libnetcan/Makefile	Sun Jan 15 20:27:34 2017
@@ -0,0 +1,20 @@
+#	$NetBSD: Makefile,v 1.1.2.1 2017/01/15 20:27:34 bouyer Exp $
+#
+
+NOLINT=	#defined
+
+.include <bsd.own.mk>
+
+.PATH:	${.CURDIR}/../../../../netcan
+
+LIB=	rumpnet_netcan
+COMMENT=CAN (PF_CAN)
+
+IOCONF=	NETCAN.ioconf
+
+SRCS=	can.c can_pcb.c can_proto.c if_canloop.c
+
+SRCS+=	netcan_component.c
+
+.include <bsd.lib.mk>
+.include <bsd.klinks.mk>
Index: src/sys/rump/net/lib/libnetcan/NETCAN.ioconf
diff -u /dev/null src/sys/rump/net/lib/libnetcan/NETCAN.ioconf:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/rump/net/lib/libnetcan/NETCAN.ioconf	Sun Jan 15 20:27:34 2017
@@ -0,0 +1,7 @@
+#	$NetBSD: NETCAN.ioconf,v 1.1.2.1 2017/01/15 20:27:34 bouyer Exp $
+
+ioconf		netcan
+
+include		"conf/files"
+
+pseudo-device   canloop
Index: src/sys/rump/net/lib/libnetcan/netcan_component.c
diff -u /dev/null src/sys/rump/net/lib/libnetcan/netcan_component.c:1.1.2.1
--- /dev/null	Sun Jan 15 20:27:34 2017
+++ src/sys/rump/net/lib/libnetcan/netcan_component.c	Sun Jan 15 20:27:34 2017
@@ -0,0 +1,52 @@
+/*	$NetBSD: netcan_component.c,v 1.1.2.1 2017/01/15 20:27:34 bouyer Exp $	*/
+
+/*
+ * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
+ *
+ * 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 AUTHOR ``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 AUTHOR 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>
+__KERNEL_RCSID(0, "$NetBSD: netcan_component.c,v 1.1.2.1 2017/01/15 20:27:34 bouyer Exp $");
+
+#include <sys/param.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+
+#include <rump-sys/kern.h>
+#include <rump-sys/net.h>
+#include <net/netisr.h>
+#include <netcan/can_var.h>
+
+RUMP_COMPONENT(RUMP_COMPONENT_NET)
+{
+	extern struct domain candomain;
+
+	domain_attach(&candomain);
+	rump_netisr_register(NETISR_CAN, canintr);
+}
+
+void  canloopinit(void);
+RUMP_COMPONENT(RUMP_COMPONENT_NET_IF)
+{
+	canloopinit();
+}

Reply via email to