xref: /netbsd-src/sys/netcan/can.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: can.c,v 1.14 2024/07/05 04:31:54 rin Exp $	*/
26e4cb2b9Sbouyer 
36e4cb2b9Sbouyer /*-
46e4cb2b9Sbouyer  * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
56e4cb2b9Sbouyer  * All rights reserved.
66e4cb2b9Sbouyer  *
76e4cb2b9Sbouyer  * This code is derived from software contributed to The NetBSD Foundation
86e4cb2b9Sbouyer  * by Robert Swindells and Manuel Bouyer
96e4cb2b9Sbouyer  *
106e4cb2b9Sbouyer  * Redistribution and use in source and binary forms, with or without
116e4cb2b9Sbouyer  * modification, are permitted provided that the following conditions
126e4cb2b9Sbouyer  * are met:
136e4cb2b9Sbouyer  * 1. Redistributions of source code must retain the above copyright
146e4cb2b9Sbouyer  *    notice, this list of conditions and the following disclaimer.
156e4cb2b9Sbouyer  * 2. Redistributions in binary form must reproduce the above copyright
166e4cb2b9Sbouyer  *    notice, this list of conditions and the following disclaimer in the
176e4cb2b9Sbouyer  *    documentation and/or other materials provided with the distribution.
186e4cb2b9Sbouyer  *
196e4cb2b9Sbouyer  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206e4cb2b9Sbouyer  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216e4cb2b9Sbouyer  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226e4cb2b9Sbouyer  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236e4cb2b9Sbouyer  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246e4cb2b9Sbouyer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256e4cb2b9Sbouyer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266e4cb2b9Sbouyer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276e4cb2b9Sbouyer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286e4cb2b9Sbouyer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296e4cb2b9Sbouyer  * POSSIBILITY OF SUCH DAMAGE.
306e4cb2b9Sbouyer  */
316e4cb2b9Sbouyer 
326e4cb2b9Sbouyer #include <sys/cdefs.h>
33*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: can.c,v 1.14 2024/07/05 04:31:54 rin Exp $");
346e4cb2b9Sbouyer 
356e4cb2b9Sbouyer #include <sys/param.h>
366e4cb2b9Sbouyer #include <sys/systm.h>
376e4cb2b9Sbouyer #include <sys/mbuf.h>
386e4cb2b9Sbouyer #include <sys/ioctl.h>
396e4cb2b9Sbouyer #include <sys/domain.h>
406e4cb2b9Sbouyer #include <sys/protosw.h>
416e4cb2b9Sbouyer #include <sys/errno.h>
426e4cb2b9Sbouyer #include <sys/socket.h>
436e4cb2b9Sbouyer #include <sys/socketvar.h>
446e4cb2b9Sbouyer #include <sys/proc.h>
456e4cb2b9Sbouyer #include <sys/kauth.h>
466e4cb2b9Sbouyer 
476e4cb2b9Sbouyer #include <net/if.h>
486e4cb2b9Sbouyer #include <net/if_types.h>
49ca257ba4Sthorpej #include <net/pktqueue.h>
506e4cb2b9Sbouyer #include <net/route.h>
516e4cb2b9Sbouyer #include <net/bpf.h>
526e4cb2b9Sbouyer 
536e4cb2b9Sbouyer #include <netcan/can.h>
546e4cb2b9Sbouyer #include <netcan/can_pcb.h>
556e4cb2b9Sbouyer #include <netcan/can_var.h>
566e4cb2b9Sbouyer 
576e4cb2b9Sbouyer struct canpcb canpcb;
586e4cb2b9Sbouyer #if 0
596e4cb2b9Sbouyer struct canpcb canrawpcb;
606e4cb2b9Sbouyer #endif
616e4cb2b9Sbouyer 
626e4cb2b9Sbouyer struct	canpcbtable cbtable;
636e4cb2b9Sbouyer 
64ca257ba4Sthorpej pktqueue_t *		can_pktq		__read_mostly;
656e4cb2b9Sbouyer int	canqmaxlen = IFQ_MAXLEN;
666e4cb2b9Sbouyer 
676e4cb2b9Sbouyer int can_copy_output = 0;
686e4cb2b9Sbouyer int can_output_cnt = 0;
696e4cb2b9Sbouyer struct mbuf *can_lastout;
706e4cb2b9Sbouyer 
716e4cb2b9Sbouyer int	can_sendspace = 4096;		/* really max datagram size */
726e4cb2b9Sbouyer int	can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
736e4cb2b9Sbouyer 					/* 40 1K datagrams */
746e4cb2b9Sbouyer #ifndef CANHASHSIZE
756e4cb2b9Sbouyer #define	CANHASHSIZE	128
766e4cb2b9Sbouyer #endif
776e4cb2b9Sbouyer int	canhashsize = CANHASHSIZE;
786e4cb2b9Sbouyer 
7908e0fb1cSozaki-r #ifdef MBUFTRACE
8008e0fb1cSozaki-r static struct mowner can_mowner = MOWNER_INIT("can", "");
8108e0fb1cSozaki-r static struct mowner can_rx_mowner = MOWNER_INIT("can", "rx");
8208e0fb1cSozaki-r static struct mowner can_tx_mowner = MOWNER_INIT("can", "tx");
8308e0fb1cSozaki-r #endif
8408e0fb1cSozaki-r 
856e4cb2b9Sbouyer static int can_output(struct mbuf *, struct canpcb *);
866e4cb2b9Sbouyer 
876e4cb2b9Sbouyer static int can_control(struct socket *, u_long, void *, struct ifnet *);
886e4cb2b9Sbouyer 
89ca257ba4Sthorpej static void canintr(void *);
90ca257ba4Sthorpej 
916e4cb2b9Sbouyer void
can_init(void)926e4cb2b9Sbouyer can_init(void)
936e4cb2b9Sbouyer {
94ca257ba4Sthorpej 	can_pktq = pktq_create(canqmaxlen, canintr, NULL);
95ca257ba4Sthorpej 	KASSERT(can_pktq != NULL);
96ca257ba4Sthorpej 
976e4cb2b9Sbouyer 	can_pcbinit(&cbtable, canhashsize, canhashsize);
986e4cb2b9Sbouyer }
996e4cb2b9Sbouyer 
1006e4cb2b9Sbouyer /*
1016e4cb2b9Sbouyer  * Generic control operations (ioctl's).
1026e4cb2b9Sbouyer  */
1036e4cb2b9Sbouyer static int
can_get_netlink(struct ifnet * ifp,struct ifdrv * ifd)1046e4cb2b9Sbouyer can_get_netlink(struct ifnet *ifp, struct ifdrv *ifd)
1056e4cb2b9Sbouyer {
1066e4cb2b9Sbouyer 	struct canif_softc *csc = ifp->if_softc;
1076e4cb2b9Sbouyer 
1086e4cb2b9Sbouyer 	if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL)
1096e4cb2b9Sbouyer 		return EOPNOTSUPP;
1106e4cb2b9Sbouyer 
1116e4cb2b9Sbouyer 	switch(ifd->ifd_cmd) {
1126e4cb2b9Sbouyer 	case CANGLINKTIMECAP:
1136e4cb2b9Sbouyer 		if (ifd->ifd_len != sizeof(struct can_link_timecaps))
1146e4cb2b9Sbouyer 			return EINVAL;
1156e4cb2b9Sbouyer 		return copyout(&csc->csc_timecaps, ifd->ifd_data, ifd->ifd_len);
1166e4cb2b9Sbouyer 	case CANGLINKTIMINGS:
1176e4cb2b9Sbouyer 		if (ifd->ifd_len != sizeof(struct can_link_timings))
1186e4cb2b9Sbouyer 			return EINVAL;
1196e4cb2b9Sbouyer 		return copyout(&csc->csc_timings, ifd->ifd_data, ifd->ifd_len);
1206e4cb2b9Sbouyer 	case CANGLINKMODE:
1216e4cb2b9Sbouyer 		if (ifd->ifd_len != sizeof(uint32_t))
1226e4cb2b9Sbouyer 			return EINVAL;
1236e4cb2b9Sbouyer 		return copyout(&csc->csc_linkmodes, ifd->ifd_data, ifd->ifd_len);
1246e4cb2b9Sbouyer 	}
1256e4cb2b9Sbouyer 	return EOPNOTSUPP;
1266e4cb2b9Sbouyer }
1276e4cb2b9Sbouyer 
1286e4cb2b9Sbouyer static int
can_set_netlink(struct ifnet * ifp,struct ifdrv * ifd)1296e4cb2b9Sbouyer can_set_netlink(struct ifnet *ifp, struct ifdrv *ifd)
1306e4cb2b9Sbouyer {
1316e4cb2b9Sbouyer 	struct canif_softc *csc = ifp->if_softc;
1326e4cb2b9Sbouyer 	uint32_t mode;
1336e4cb2b9Sbouyer 	int error;
1346e4cb2b9Sbouyer 
1356e4cb2b9Sbouyer 	if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL)
1366e4cb2b9Sbouyer 		return EOPNOTSUPP;
1376e4cb2b9Sbouyer 
13835c89f29Schristos 	error = kauth_authorize_network(kauth_cred_get(),
1396e4cb2b9Sbouyer 	    KAUTH_NETWORK_INTERFACE,
1406e4cb2b9Sbouyer 	    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
1416e4cb2b9Sbouyer 	    (void *)SIOCSDRVSPEC, NULL);
1426e4cb2b9Sbouyer 	if (error != 0)
1436e4cb2b9Sbouyer 		return error;
1446e4cb2b9Sbouyer 
1456e4cb2b9Sbouyer 	if ((ifp->if_flags & IFF_UP) != 0) {
1466e4cb2b9Sbouyer 		return EBUSY;
1476e4cb2b9Sbouyer 	}
1486e4cb2b9Sbouyer 
1496e4cb2b9Sbouyer 	switch(ifd->ifd_cmd) {
1506e4cb2b9Sbouyer 	case CANSLINKTIMINGS:
1516e4cb2b9Sbouyer 		if (ifd->ifd_len != sizeof(struct can_link_timings))
1526e4cb2b9Sbouyer 			return EINVAL;
1536e4cb2b9Sbouyer 		return copyin(ifd->ifd_data, &csc->csc_timings, ifd->ifd_len);
1546e4cb2b9Sbouyer 
1556e4cb2b9Sbouyer 	case CANSLINKMODE:
1566e4cb2b9Sbouyer 	case CANCLINKMODE:
1576e4cb2b9Sbouyer 		if (ifd->ifd_len != sizeof(uint32_t))
1586e4cb2b9Sbouyer 			return EINVAL;
1596e4cb2b9Sbouyer 		error = copyin(ifd->ifd_data, &mode, ifd->ifd_len);
1606e4cb2b9Sbouyer 		if (error)
1616e4cb2b9Sbouyer 			return error;
1626e4cb2b9Sbouyer 		if ((mode & csc->csc_timecaps.cltc_linkmode_caps) != mode)
1636e4cb2b9Sbouyer 			return EINVAL;
1646e4cb2b9Sbouyer 		/* XXX locking */
1656e4cb2b9Sbouyer 		if (ifd->ifd_cmd == CANSLINKMODE)
1666e4cb2b9Sbouyer 			csc->csc_linkmodes |= mode;
1676e4cb2b9Sbouyer 		else
1686e4cb2b9Sbouyer 			csc->csc_linkmodes &= ~mode;
1696e4cb2b9Sbouyer 		return 0;
1706e4cb2b9Sbouyer 	}
1716e4cb2b9Sbouyer 	return EOPNOTSUPP;
1726e4cb2b9Sbouyer }
1736e4cb2b9Sbouyer 
1746e4cb2b9Sbouyer /* ARGSUSED */
1756e4cb2b9Sbouyer static int
can_control(struct socket * so,u_long cmd,void * data,struct ifnet * ifp)1766e4cb2b9Sbouyer can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
1776e4cb2b9Sbouyer {
1786e4cb2b9Sbouyer #if 0
1796e4cb2b9Sbouyer 	struct can_ifreq *cfr = (struct can_ifreq *)data;
1806e4cb2b9Sbouyer 	int error = 0;
1816e4cb2b9Sbouyer #endif
1826e4cb2b9Sbouyer 	if (ifp == NULL)
1836e4cb2b9Sbouyer 		return (EOPNOTSUPP);
1846e4cb2b9Sbouyer 
1856e4cb2b9Sbouyer 	switch (cmd) {
1866e4cb2b9Sbouyer 	case SIOCGDRVSPEC:
1876e4cb2b9Sbouyer 		return can_get_netlink(ifp, (struct ifdrv *) data);
1886e4cb2b9Sbouyer 	case SIOCSDRVSPEC:
1896e4cb2b9Sbouyer 		return can_set_netlink(ifp, (struct ifdrv *) data);
1906e4cb2b9Sbouyer 	default:
1916e4cb2b9Sbouyer 		if (ifp->if_ioctl == 0)
1926e4cb2b9Sbouyer 			return (EOPNOTSUPP);
193daeb11daSriastradh 		return (if_ioctl(ifp, cmd, data));
1946e4cb2b9Sbouyer 	}
1956e4cb2b9Sbouyer 	return (0);
1966e4cb2b9Sbouyer }
1976e4cb2b9Sbouyer 
1986e4cb2b9Sbouyer static int
can_purgeif(struct socket * so,struct ifnet * ifp)1996e4cb2b9Sbouyer can_purgeif(struct socket *so, struct ifnet *ifp)
2006e4cb2b9Sbouyer {
2016e4cb2b9Sbouyer 	return 0;
2026e4cb2b9Sbouyer }
2036e4cb2b9Sbouyer 
2046e4cb2b9Sbouyer void
can_ifattach(struct ifnet * ifp)2056e4cb2b9Sbouyer can_ifattach(struct ifnet *ifp)
2066e4cb2b9Sbouyer {
2076e4cb2b9Sbouyer 	if_attach(ifp);
2086e4cb2b9Sbouyer 	ifp->if_mtu = sizeof(struct can_frame);
2096e4cb2b9Sbouyer 	ifp->if_type = IFT_OTHER;
2106e4cb2b9Sbouyer 	ifp->if_hdrlen = 0;
2116e4cb2b9Sbouyer 	ifp->if_addrlen = 0;
2126e4cb2b9Sbouyer 	ifp->if_dlt = DLT_CAN_SOCKETCAN;
2136e4cb2b9Sbouyer 	ifp->if_output = NULL; /* unused */
2146e4cb2b9Sbouyer 	IFQ_SET_READY(&ifp->if_snd);
2156e4cb2b9Sbouyer 	if_alloc_sadl(ifp);
2166e4cb2b9Sbouyer 	bpf_attach(ifp, DLT_CAN_SOCKETCAN, 0);
2176e4cb2b9Sbouyer }
2186e4cb2b9Sbouyer 
2196e4cb2b9Sbouyer void
can_ifdetach(struct ifnet * ifp)2206e4cb2b9Sbouyer can_ifdetach(struct ifnet *ifp)
2216e4cb2b9Sbouyer {
2226e4cb2b9Sbouyer 	bpf_detach(ifp);
2236e4cb2b9Sbouyer 	if_detach(ifp);
2246e4cb2b9Sbouyer }
2256e4cb2b9Sbouyer 
2266e4cb2b9Sbouyer void
can_ifinit_timings(struct canif_softc * csc)2276e4cb2b9Sbouyer can_ifinit_timings(struct canif_softc *csc)
2286e4cb2b9Sbouyer {
2296e4cb2b9Sbouyer 	/* uninitialized parameters is all-one */
2306e4cb2b9Sbouyer 	memset(&csc->csc_timings, 0xff, sizeof(struct can_link_timings));
2316e4cb2b9Sbouyer }
2326e4cb2b9Sbouyer 
2336e4cb2b9Sbouyer static int
can_output(struct mbuf * m,struct canpcb * canp)2346e4cb2b9Sbouyer can_output(struct mbuf *m, struct canpcb *canp)
2356e4cb2b9Sbouyer {
2366e4cb2b9Sbouyer 	struct ifnet *ifp;
2376e4cb2b9Sbouyer 	struct m_tag *sotag;
2386e4cb2b9Sbouyer 	struct canif_softc *csc;
2396e4cb2b9Sbouyer 
2406e4cb2b9Sbouyer 	if (canp == NULL) {
2416e4cb2b9Sbouyer 		printf("can_output: no pcb\n");
2426e4cb2b9Sbouyer 		return EINVAL;
2436e4cb2b9Sbouyer 	}
2446e4cb2b9Sbouyer 	ifp = canp->canp_ifp;
2456e4cb2b9Sbouyer 	if (ifp == 0) {
2466e4cb2b9Sbouyer 		return EDESTADDRREQ;
2476e4cb2b9Sbouyer 	}
2486e4cb2b9Sbouyer 	csc = ifp->if_softc;
2496e4cb2b9Sbouyer 	if (csc && (csc->csc_linkmodes & CAN_LINKMODE_LISTENONLY)) {
2506e4cb2b9Sbouyer 		return ENETUNREACH;
2516e4cb2b9Sbouyer 	}
2526e4cb2b9Sbouyer 
2536e4cb2b9Sbouyer 	sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
2546e4cb2b9Sbouyer 	if (sotag == NULL) {
2551a2cab17Sthorpej 		if_statinc(ifp, if_oerrors);
2566e4cb2b9Sbouyer 		return ENOMEM;
2576e4cb2b9Sbouyer 	}
2586e4cb2b9Sbouyer 	mutex_enter(&canp->canp_mtx);
2596e4cb2b9Sbouyer 	canp_ref(canp);
2606e4cb2b9Sbouyer 	mutex_exit(&canp->canp_mtx);
2616e4cb2b9Sbouyer 	*(struct canpcb **)(sotag + 1) = canp;
2626e4cb2b9Sbouyer 	m_tag_prepend(m, sotag);
2636e4cb2b9Sbouyer 
2646e4cb2b9Sbouyer 	if (m->m_len <= ifp->if_mtu) {
2656e4cb2b9Sbouyer 		can_output_cnt++;
2666e4cb2b9Sbouyer 		return ifq_enqueue(ifp, m);
2676e4cb2b9Sbouyer 	} else
2686e4cb2b9Sbouyer 		return EMSGSIZE;
2696e4cb2b9Sbouyer }
2706e4cb2b9Sbouyer 
2716e4cb2b9Sbouyer /*
2726e4cb2b9Sbouyer  * cleanup mbuf tag, keeping the PACKET_TAG_SO tag
2736e4cb2b9Sbouyer  */
2746e4cb2b9Sbouyer void
can_mbuf_tag_clean(struct mbuf * m)2756e4cb2b9Sbouyer can_mbuf_tag_clean(struct mbuf *m)
2766e4cb2b9Sbouyer {
2776e4cb2b9Sbouyer 	struct m_tag *sotag;
2786e4cb2b9Sbouyer 
2795c987100Smaxv 	sotag = m_tag_find(m, PACKET_TAG_SO);
2806e4cb2b9Sbouyer 	if (sotag)
2816e4cb2b9Sbouyer 		m_tag_unlink(m, sotag);
2826e4cb2b9Sbouyer 
283e7985a6aSmaxv 	m_tag_delete_chain(m);
2846e4cb2b9Sbouyer 	if (sotag)
2856e4cb2b9Sbouyer 		m_tag_prepend(m, sotag);
2866e4cb2b9Sbouyer }
2876e4cb2b9Sbouyer 
2886e4cb2b9Sbouyer /*
2896e4cb2b9Sbouyer  * Process a received CAN frame
2906e4cb2b9Sbouyer  * the packet is in the mbuf chain m with
2916e4cb2b9Sbouyer  * the CAN header.
2926e4cb2b9Sbouyer  */
2936e4cb2b9Sbouyer void
can_input(struct ifnet * ifp,struct mbuf * m)2946e4cb2b9Sbouyer can_input(struct ifnet *ifp, struct mbuf *m)
2956e4cb2b9Sbouyer {
2966e4cb2b9Sbouyer 	if ((ifp->if_flags & IFF_UP) == 0) {
2976e4cb2b9Sbouyer 		m_freem(m);
2986e4cb2b9Sbouyer 		return;
2996e4cb2b9Sbouyer 	}
3006e4cb2b9Sbouyer 
301ca257ba4Sthorpej 	const int pktlen = m->m_pkthdr.len;
302ca257ba4Sthorpej 	if (__predict_false(!pktq_enqueue(can_pktq, m, 0))) {
3036e4cb2b9Sbouyer 		m_freem(m);
3046e4cb2b9Sbouyer 	} else {
305ca257ba4Sthorpej 		if_statadd2(ifp, if_ipackets, 1, if_ibytes, pktlen);
3066e4cb2b9Sbouyer 	}
3076e4cb2b9Sbouyer }
3086e4cb2b9Sbouyer 
309ca257ba4Sthorpej static void
canintr(void * arg __unused)310ca257ba4Sthorpej canintr(void *arg __unused)
3116e4cb2b9Sbouyer {
3126e4cb2b9Sbouyer 	int		rcv_ifindex;
3136e4cb2b9Sbouyer 	struct mbuf    *m;
3146e4cb2b9Sbouyer 
3156e4cb2b9Sbouyer 	struct sockaddr_can from;
3166e4cb2b9Sbouyer 	struct canpcb   *canp;
3176e4cb2b9Sbouyer 	struct m_tag	*sotag;
3186e4cb2b9Sbouyer 	struct canpcb	*sender_canp;
3196e4cb2b9Sbouyer 
3206e4cb2b9Sbouyer 	mutex_enter(softnet_lock);
321ca257ba4Sthorpej 	while ((m = pktq_dequeue(can_pktq)) != NULL) {
3226e4cb2b9Sbouyer #if 0
3236e4cb2b9Sbouyer 		m_claim(m, &can_rx_mowner);
3246e4cb2b9Sbouyer #endif
3255c987100Smaxv 		sotag = m_tag_find(m, PACKET_TAG_SO);
3266e4cb2b9Sbouyer 		if (sotag) {
3276e4cb2b9Sbouyer 			sender_canp = *(struct canpcb **)(sotag + 1);
3286e4cb2b9Sbouyer 			m_tag_delete(m, sotag);
3296e4cb2b9Sbouyer 			KASSERT(sender_canp != NULL);
3306e4cb2b9Sbouyer 			/* if the sender doesn't want loopback, don't do it */
3316e4cb2b9Sbouyer 			if ((sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) {
3326e4cb2b9Sbouyer 				m_freem(m);
3336e4cb2b9Sbouyer 				canp_unref(sender_canp);
3346e4cb2b9Sbouyer 				continue;
3356e4cb2b9Sbouyer 			}
3366e4cb2b9Sbouyer 		} else {
3376e4cb2b9Sbouyer 			sender_canp = NULL;
3386e4cb2b9Sbouyer 		}
3396e4cb2b9Sbouyer 		memset(&from, 0, sizeof(struct sockaddr_can));
3406e4cb2b9Sbouyer 		rcv_ifindex = m->m_pkthdr.rcvif_index;
3416e4cb2b9Sbouyer 		from.can_ifindex = rcv_ifindex;
3426e4cb2b9Sbouyer 		from.can_len = sizeof(struct sockaddr_can);
3436e4cb2b9Sbouyer 		from.can_family = AF_CAN;
3446e4cb2b9Sbouyer 
3456e4cb2b9Sbouyer 		TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
3466e4cb2b9Sbouyer 			struct mbuf *mc;
3476e4cb2b9Sbouyer 
3486e4cb2b9Sbouyer 			mutex_enter(&canp->canp_mtx);
3496e4cb2b9Sbouyer 			/* skip if we're detached */
3506e4cb2b9Sbouyer 			if (canp->canp_state == CANP_DETACHED) {
3516e4cb2b9Sbouyer 				mutex_exit(&canp->canp_mtx);
3526e4cb2b9Sbouyer 				continue;
3536e4cb2b9Sbouyer 			}
3546e4cb2b9Sbouyer 
3556e4cb2b9Sbouyer 			/* don't loop back to sockets on other interfaces */
3566e4cb2b9Sbouyer 			if (canp->canp_ifp != NULL &&
3576e4cb2b9Sbouyer 			    canp->canp_ifp->if_index != rcv_ifindex) {
3586e4cb2b9Sbouyer 				mutex_exit(&canp->canp_mtx);
3596e4cb2b9Sbouyer 				continue;
3606e4cb2b9Sbouyer 			}
3616e4cb2b9Sbouyer 			/* don't loop back to myself if I don't want it */
3626e4cb2b9Sbouyer 			if (canp == sender_canp &&
3636e4cb2b9Sbouyer 			    (canp->canp_flags & CANP_RECEIVE_OWN) == 0) {
3646e4cb2b9Sbouyer 				mutex_exit(&canp->canp_mtx);
3656e4cb2b9Sbouyer 				continue;
3666e4cb2b9Sbouyer 			}
3676e4cb2b9Sbouyer 
3686e4cb2b9Sbouyer 			/* skip if the accept filter doen't match this pkt */
3696e4cb2b9Sbouyer 			if (!can_pcbfilter(canp, m)) {
3706e4cb2b9Sbouyer 				mutex_exit(&canp->canp_mtx);
3716e4cb2b9Sbouyer 				continue;
3726e4cb2b9Sbouyer 			}
3736e4cb2b9Sbouyer 
3746e4cb2b9Sbouyer 			if (TAILQ_NEXT(canp, canp_queue) != NULL) {
3756e4cb2b9Sbouyer 				/*
3766e4cb2b9Sbouyer 				 * we can't be sure we won't need
3776e4cb2b9Sbouyer 				 * the original mbuf later so copy
3786e4cb2b9Sbouyer 				 */
3796e4cb2b9Sbouyer 				mc = m_copypacket(m, M_NOWAIT);
3806e4cb2b9Sbouyer 				if (mc == NULL) {
3816e4cb2b9Sbouyer 					/* deliver this mbuf and abort */
3826e4cb2b9Sbouyer 					mc = m;
3836e4cb2b9Sbouyer 					m = NULL;
3846e4cb2b9Sbouyer 				}
3856e4cb2b9Sbouyer 			} else {
3866e4cb2b9Sbouyer 				mc = m;
3876e4cb2b9Sbouyer 				m = NULL;
3886e4cb2b9Sbouyer 			}
3896e4cb2b9Sbouyer 			if (sbappendaddr(&canp->canp_socket->so_rcv,
3906e4cb2b9Sbouyer 					 (struct sockaddr *) &from, mc,
3916e4cb2b9Sbouyer 					 (struct mbuf *) 0) == 0) {
39238d01a8dSroy 				soroverflow(canp->canp_socket);
3936e4cb2b9Sbouyer 				m_freem(mc);
3946e4cb2b9Sbouyer 			} else
3956e4cb2b9Sbouyer 				sorwakeup(canp->canp_socket);
3966e4cb2b9Sbouyer 			mutex_exit(&canp->canp_mtx);
3976e4cb2b9Sbouyer 			if (m == NULL)
3986e4cb2b9Sbouyer 				break;
3996e4cb2b9Sbouyer 		}
4006e4cb2b9Sbouyer 		if (sender_canp) {
4016e4cb2b9Sbouyer 			canp_unref(sender_canp);
4026e4cb2b9Sbouyer 		}
4036e4cb2b9Sbouyer 		/* If it didn't go anywhere just delete it */
4046e4cb2b9Sbouyer 		m_freem(m);
4056e4cb2b9Sbouyer 	}
4066e4cb2b9Sbouyer 	mutex_exit(softnet_lock);
4076e4cb2b9Sbouyer }
4086e4cb2b9Sbouyer 
4096e4cb2b9Sbouyer void
can_bpf_mtap(struct ifnet * ifp,struct mbuf * m,bool do_softint)4106e4cb2b9Sbouyer can_bpf_mtap(struct ifnet *ifp, struct mbuf *m, bool do_softint)
4116e4cb2b9Sbouyer {
4126e4cb2b9Sbouyer 	/* bpf wants the CAN id in network byte order */
4136e4cb2b9Sbouyer 	struct can_frame *cf;
4146e4cb2b9Sbouyer 	canid_t oid;
4156e4cb2b9Sbouyer 
4166e4cb2b9Sbouyer 	cf = mtod(m, struct can_frame *);
4176e4cb2b9Sbouyer 	oid = cf->can_id;
4186e4cb2b9Sbouyer 	cf->can_id = htonl(oid);
4193cd62456Smsaitoh 	/* Assume the direction is input when do_softint is set. */
4206e4cb2b9Sbouyer 	if (do_softint)
4216e4cb2b9Sbouyer 		bpf_mtap_softint(ifp, m);
4226e4cb2b9Sbouyer 	else
4233cd62456Smsaitoh 		bpf_mtap(ifp, m, BPF_D_OUT);
4246e4cb2b9Sbouyer 	cf->can_id = oid;
4256e4cb2b9Sbouyer }
4266e4cb2b9Sbouyer 
4276e4cb2b9Sbouyer static int
can_attach(struct socket * so,int proto)4286e4cb2b9Sbouyer can_attach(struct socket *so, int proto)
4296e4cb2b9Sbouyer {
4306e4cb2b9Sbouyer 	int error;
4316e4cb2b9Sbouyer 
4326e4cb2b9Sbouyer 	KASSERT(sotocanpcb(so) == NULL);
4336e4cb2b9Sbouyer 
4346e4cb2b9Sbouyer 	/* Assign the lock (must happen even if we will error out). */
4356e4cb2b9Sbouyer 	sosetlock(so);
4366e4cb2b9Sbouyer 
4376e4cb2b9Sbouyer #ifdef MBUFTRACE
4386e4cb2b9Sbouyer 	so->so_mowner = &can_mowner;
4396e4cb2b9Sbouyer 	so->so_rcv.sb_mowner = &can_rx_mowner;
4406e4cb2b9Sbouyer 	so->so_snd.sb_mowner = &can_tx_mowner;
4416e4cb2b9Sbouyer #endif
4426e4cb2b9Sbouyer 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
4436e4cb2b9Sbouyer 		error = soreserve(so, can_sendspace, can_recvspace);
4446e4cb2b9Sbouyer 		if (error) {
4456e4cb2b9Sbouyer 			return error;
4466e4cb2b9Sbouyer 		}
4476e4cb2b9Sbouyer 	}
4486e4cb2b9Sbouyer 
4496e4cb2b9Sbouyer 	error = can_pcballoc(so, &cbtable);
4506e4cb2b9Sbouyer 	if (error) {
4516e4cb2b9Sbouyer 		return error;
4526e4cb2b9Sbouyer 	}
4536e4cb2b9Sbouyer 	KASSERT(solocked(so));
4546e4cb2b9Sbouyer 
4556e4cb2b9Sbouyer 	return error;
4566e4cb2b9Sbouyer }
4576e4cb2b9Sbouyer 
4586e4cb2b9Sbouyer static void
can_detach(struct socket * so)4596e4cb2b9Sbouyer can_detach(struct socket *so)
4606e4cb2b9Sbouyer {
4616e4cb2b9Sbouyer 	struct canpcb *canp;
4626e4cb2b9Sbouyer 
4636e4cb2b9Sbouyer 	KASSERT(solocked(so));
4646e4cb2b9Sbouyer 	canp = sotocanpcb(so);
4656e4cb2b9Sbouyer 	can_pcbdetach(canp);
4666e4cb2b9Sbouyer }
4676e4cb2b9Sbouyer 
4686e4cb2b9Sbouyer static int
can_accept(struct socket * so,struct sockaddr * nam)4696e4cb2b9Sbouyer can_accept(struct socket *so, struct sockaddr *nam)
4706e4cb2b9Sbouyer {
4716e4cb2b9Sbouyer 	KASSERT(solocked(so));
4726e4cb2b9Sbouyer 
4736e4cb2b9Sbouyer 	panic("can_accept");
4746e4cb2b9Sbouyer 
4756e4cb2b9Sbouyer 	return EOPNOTSUPP;
4766e4cb2b9Sbouyer }
4776e4cb2b9Sbouyer 
4786e4cb2b9Sbouyer static int
can_bind(struct socket * so,struct sockaddr * nam,struct lwp * l)4796e4cb2b9Sbouyer can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
4806e4cb2b9Sbouyer {
4816e4cb2b9Sbouyer 	struct canpcb *canp = sotocanpcb(so);
4826e4cb2b9Sbouyer 	struct sockaddr_can *scan = (struct sockaddr_can *)nam;
4836e4cb2b9Sbouyer 
4846e4cb2b9Sbouyer 	KASSERT(solocked(so));
4856e4cb2b9Sbouyer 	KASSERT(nam != NULL);
4866e4cb2b9Sbouyer 
4876e4cb2b9Sbouyer 	return can_pcbbind(canp, scan, l);
4886e4cb2b9Sbouyer }
4896e4cb2b9Sbouyer 
4906e4cb2b9Sbouyer static int
can_listen(struct socket * so,struct lwp * l)4916e4cb2b9Sbouyer can_listen(struct socket *so, struct lwp *l)
4926e4cb2b9Sbouyer {
4936e4cb2b9Sbouyer 	KASSERT(solocked(so));
4946e4cb2b9Sbouyer 
4956e4cb2b9Sbouyer 	return EOPNOTSUPP;
4966e4cb2b9Sbouyer }
4976e4cb2b9Sbouyer 
4986e4cb2b9Sbouyer static int
can_connect(struct socket * so,struct sockaddr * nam,struct lwp * l)4996e4cb2b9Sbouyer can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
5006e4cb2b9Sbouyer {
5016e4cb2b9Sbouyer 	struct canpcb *canp = sotocanpcb(so);
5026e4cb2b9Sbouyer 	int error = 0;
5036e4cb2b9Sbouyer 
5046e4cb2b9Sbouyer 	KASSERT(solocked(so));
5056e4cb2b9Sbouyer 	KASSERT(canp != NULL);
5066e4cb2b9Sbouyer 	KASSERT(nam != NULL);
5076e4cb2b9Sbouyer 
5086e4cb2b9Sbouyer 	error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
5096e4cb2b9Sbouyer 	if (! error)
5106e4cb2b9Sbouyer 		soisconnected(so);
5116e4cb2b9Sbouyer 	return error;
5126e4cb2b9Sbouyer }
5136e4cb2b9Sbouyer 
5146e4cb2b9Sbouyer static int
can_connect2(struct socket * so,struct socket * so2)5156e4cb2b9Sbouyer can_connect2(struct socket *so, struct socket *so2)
5166e4cb2b9Sbouyer {
5176e4cb2b9Sbouyer 	KASSERT(solocked(so));
5186e4cb2b9Sbouyer 
5196e4cb2b9Sbouyer 	return EOPNOTSUPP;
5206e4cb2b9Sbouyer }
5216e4cb2b9Sbouyer 
5226e4cb2b9Sbouyer static int
can_disconnect(struct socket * so)5236e4cb2b9Sbouyer can_disconnect(struct socket *so)
5246e4cb2b9Sbouyer {
5256e4cb2b9Sbouyer 	struct canpcb *canp = sotocanpcb(so);
5266e4cb2b9Sbouyer 
5276e4cb2b9Sbouyer 	KASSERT(solocked(so));
5286e4cb2b9Sbouyer 	KASSERT(canp != NULL);
5296e4cb2b9Sbouyer 
5306e4cb2b9Sbouyer 	/*soisdisconnected(so);*/
5316e4cb2b9Sbouyer 	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
5326e4cb2b9Sbouyer 	can_pcbdisconnect(canp);
5336e4cb2b9Sbouyer 	return 0;
5346e4cb2b9Sbouyer }
5356e4cb2b9Sbouyer 
5366e4cb2b9Sbouyer static int
can_shutdown(struct socket * so)5376e4cb2b9Sbouyer can_shutdown(struct socket *so)
5386e4cb2b9Sbouyer {
5396e4cb2b9Sbouyer 	KASSERT(solocked(so));
5406e4cb2b9Sbouyer 
5416e4cb2b9Sbouyer 	socantsendmore(so);
5426e4cb2b9Sbouyer 	return 0;
5436e4cb2b9Sbouyer }
5446e4cb2b9Sbouyer 
5456e4cb2b9Sbouyer static int
can_abort(struct socket * so)5466e4cb2b9Sbouyer can_abort(struct socket *so)
5476e4cb2b9Sbouyer {
5486e4cb2b9Sbouyer 	KASSERT(solocked(so));
5496e4cb2b9Sbouyer 
5506e4cb2b9Sbouyer 	panic("can_abort");
5516e4cb2b9Sbouyer 
5526e4cb2b9Sbouyer 	return EOPNOTSUPP;
5536e4cb2b9Sbouyer }
5546e4cb2b9Sbouyer 
5556e4cb2b9Sbouyer static int
can_ioctl(struct socket * so,u_long cmd,void * nam,struct ifnet * ifp)5566e4cb2b9Sbouyer can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
5576e4cb2b9Sbouyer {
5586e4cb2b9Sbouyer 	return can_control(so, cmd, nam, ifp);
5596e4cb2b9Sbouyer }
5606e4cb2b9Sbouyer 
5616e4cb2b9Sbouyer static int
can_stat(struct socket * so,struct stat * ub)5626e4cb2b9Sbouyer can_stat(struct socket *so, struct stat *ub)
5636e4cb2b9Sbouyer {
5646e4cb2b9Sbouyer 	KASSERT(solocked(so));
5656e4cb2b9Sbouyer 
5666e4cb2b9Sbouyer 	/* stat: don't bother with a blocksize. */
5676e4cb2b9Sbouyer 	return 0;
5686e4cb2b9Sbouyer }
5696e4cb2b9Sbouyer 
5706e4cb2b9Sbouyer static int
can_peeraddr(struct socket * so,struct sockaddr * nam)5716e4cb2b9Sbouyer can_peeraddr(struct socket *so, struct sockaddr *nam)
5726e4cb2b9Sbouyer {
5736e4cb2b9Sbouyer 	KASSERT(solocked(so));
5746e4cb2b9Sbouyer 	KASSERT(sotocanpcb(so) != NULL);
5756e4cb2b9Sbouyer 	KASSERT(nam != NULL);
5766e4cb2b9Sbouyer 
5776e4cb2b9Sbouyer 	return EOPNOTSUPP;
5786e4cb2b9Sbouyer }
5796e4cb2b9Sbouyer 
5806e4cb2b9Sbouyer static int
can_sockaddr(struct socket * so,struct sockaddr * nam)5816e4cb2b9Sbouyer can_sockaddr(struct socket *so, struct sockaddr *nam)
5826e4cb2b9Sbouyer {
5836e4cb2b9Sbouyer 	KASSERT(solocked(so));
5846e4cb2b9Sbouyer 	KASSERT(sotocanpcb(so) != NULL);
5856e4cb2b9Sbouyer 	KASSERT(nam != NULL);
5866e4cb2b9Sbouyer 
5876e4cb2b9Sbouyer 	can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
5886e4cb2b9Sbouyer 
5896e4cb2b9Sbouyer 	return 0;
5906e4cb2b9Sbouyer }
5916e4cb2b9Sbouyer 
5926e4cb2b9Sbouyer static int
can_rcvd(struct socket * so,int flags,struct lwp * l)5936e4cb2b9Sbouyer can_rcvd(struct socket *so, int flags, struct lwp *l)
5946e4cb2b9Sbouyer {
5956e4cb2b9Sbouyer 	KASSERT(solocked(so));
5966e4cb2b9Sbouyer 
5976e4cb2b9Sbouyer 	return EOPNOTSUPP;
5986e4cb2b9Sbouyer }
5996e4cb2b9Sbouyer 
6006e4cb2b9Sbouyer static int
can_recvoob(struct socket * so,struct mbuf * m,int flags)6016e4cb2b9Sbouyer can_recvoob(struct socket *so, struct mbuf *m, int flags)
6026e4cb2b9Sbouyer {
6036e4cb2b9Sbouyer 	KASSERT(solocked(so));
6046e4cb2b9Sbouyer 
6056e4cb2b9Sbouyer 	return EOPNOTSUPP;
6066e4cb2b9Sbouyer }
6076e4cb2b9Sbouyer 
6086e4cb2b9Sbouyer static int
can_send(struct socket * so,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct lwp * l)6096e4cb2b9Sbouyer can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
6106e4cb2b9Sbouyer     struct mbuf *control, struct lwp *l)
6116e4cb2b9Sbouyer {
6126e4cb2b9Sbouyer 	struct canpcb *canp = sotocanpcb(so);
6136e4cb2b9Sbouyer 	int error = 0;
6146e4cb2b9Sbouyer 	int s;
6156e4cb2b9Sbouyer 
6166e4cb2b9Sbouyer 	if (control && control->m_len) {
6176e4cb2b9Sbouyer 		m_freem(control);
6186e4cb2b9Sbouyer 		error = EINVAL;
6196e4cb2b9Sbouyer 		goto err;
6206e4cb2b9Sbouyer 	}
6216e4cb2b9Sbouyer 	if (m->m_len > sizeof(struct can_frame) ||
6226e4cb2b9Sbouyer 	   m->m_len < offsetof(struct can_frame, can_dlc)) {
6236e4cb2b9Sbouyer 		error = EINVAL;
6246e4cb2b9Sbouyer 		goto err;
6256e4cb2b9Sbouyer 	}
6266e4cb2b9Sbouyer 
6276e4cb2b9Sbouyer 	/* we expect all data in the first mbuf */
6286e4cb2b9Sbouyer 	KASSERT((m->m_flags & M_PKTHDR) != 0);
6296e4cb2b9Sbouyer 	KASSERT(m->m_len == m->m_pkthdr.len);
6306e4cb2b9Sbouyer 
6316e4cb2b9Sbouyer 	if (nam) {
6326e4cb2b9Sbouyer 		if ((so->so_state & SS_ISCONNECTED) != 0) {
6336e4cb2b9Sbouyer 			error = EISCONN;
6346e4cb2b9Sbouyer 			goto err;
6356e4cb2b9Sbouyer 		}
6366e4cb2b9Sbouyer 		s = splnet();
6376e4cb2b9Sbouyer 		error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
6386e4cb2b9Sbouyer 		if (error) {
6396e4cb2b9Sbouyer 			splx(s);
6406e4cb2b9Sbouyer 			goto err;
6416e4cb2b9Sbouyer 		}
6426e4cb2b9Sbouyer 	} else {
6436e4cb2b9Sbouyer 		if ((so->so_state & SS_ISCONNECTED) == 0) {
6446e4cb2b9Sbouyer 			error =  EDESTADDRREQ;
6456e4cb2b9Sbouyer 			goto err;
6466e4cb2b9Sbouyer 		}
6476e4cb2b9Sbouyer 	}
6486e4cb2b9Sbouyer 	error = can_output(m, canp);
6496e4cb2b9Sbouyer 	if (nam) {
6506e4cb2b9Sbouyer 		struct sockaddr_can lscan;
6516e4cb2b9Sbouyer 		memset(&lscan, 0, sizeof(lscan));
6526e4cb2b9Sbouyer 		lscan.can_family = AF_CAN;
6536e4cb2b9Sbouyer 		lscan.can_len = sizeof(lscan);
6546e4cb2b9Sbouyer 		can_pcbbind(canp, &lscan, l);
6556e4cb2b9Sbouyer 	}
6566e4cb2b9Sbouyer 	if (error)
6576e4cb2b9Sbouyer 		goto err;
6586e4cb2b9Sbouyer 	return 0;
6596e4cb2b9Sbouyer 
6606e4cb2b9Sbouyer err:
6616e4cb2b9Sbouyer 	m_freem(m);
6626e4cb2b9Sbouyer 	return error;
6636e4cb2b9Sbouyer }
6646e4cb2b9Sbouyer 
6656e4cb2b9Sbouyer static int
can_sendoob(struct socket * so,struct mbuf * m,struct mbuf * control)6666e4cb2b9Sbouyer can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
6676e4cb2b9Sbouyer {
6686e4cb2b9Sbouyer 	KASSERT(solocked(so));
6696e4cb2b9Sbouyer 
6706e4cb2b9Sbouyer 	m_freem(m);
6716e4cb2b9Sbouyer 	m_freem(control);
6726e4cb2b9Sbouyer 
6736e4cb2b9Sbouyer 	return EOPNOTSUPP;
6746e4cb2b9Sbouyer }
6756e4cb2b9Sbouyer 
6766e4cb2b9Sbouyer #if 0
6776e4cb2b9Sbouyer int
6786e4cb2b9Sbouyer can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
6796e4cb2b9Sbouyer 	   struct mbuf *control, struct lwp *l)
6806e4cb2b9Sbouyer {
6816e4cb2b9Sbouyer 	struct canpcb *canp;
6826e4cb2b9Sbouyer 	int s;
6836e4cb2b9Sbouyer 	int error = 0;
6846e4cb2b9Sbouyer 
6856e4cb2b9Sbouyer 	if (req == PRU_CONTROL)
6866e4cb2b9Sbouyer 		 return (can_control(so, (long)m, nam,
6876e4cb2b9Sbouyer 		     (struct ifnet *)control));
6886e4cb2b9Sbouyer 
6896e4cb2b9Sbouyer 	if (req == PRU_PURGEIF) {
6906e4cb2b9Sbouyer #if 0
6916e4cb2b9Sbouyer 		can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
6926e4cb2b9Sbouyer 		can_purgeif((struct ifnet *)control);
6936e4cb2b9Sbouyer 		can_pcbpurgeif(&udbtable, (struct ifnet *)control);
6946e4cb2b9Sbouyer #endif
6956e4cb2b9Sbouyer 		return (0);
6966e4cb2b9Sbouyer 	}
6976e4cb2b9Sbouyer 
6986e4cb2b9Sbouyer 	s = splsoftnet();
6996e4cb2b9Sbouyer 	canp = sotocanpcb(so);
7006e4cb2b9Sbouyer #ifdef DIAGNOSTIC
7016e4cb2b9Sbouyer 	if (req != PRU_SEND && req != PRU_SENDOOB && control)
7026e4cb2b9Sbouyer 		panic("can_usrreq: unexpected control mbuf");
7036e4cb2b9Sbouyer #endif
7046e4cb2b9Sbouyer 	if (canp == 0 && req != PRU_ATTACH) {
7056e4cb2b9Sbouyer 		printf("can_usrreq: no pcb %p %d\n", canp, req);
7066e4cb2b9Sbouyer 		error = EINVAL;
7076e4cb2b9Sbouyer 		goto release;
7086e4cb2b9Sbouyer 	}
7096e4cb2b9Sbouyer 
7106e4cb2b9Sbouyer 	/*
7116e4cb2b9Sbouyer 	 * Note: need to block can_input while changing
7126e4cb2b9Sbouyer 	 * the can pcb queue and/or pcb addresses.
7136e4cb2b9Sbouyer 	 */
7146e4cb2b9Sbouyer 	switch (req) {
7156e4cb2b9Sbouyer 
7166e4cb2b9Sbouyer 	  case PRU_ATTACH:
7176e4cb2b9Sbouyer 	      if (canp != 0) {
7186e4cb2b9Sbouyer 			 error = EISCONN;
7196e4cb2b9Sbouyer 			 break;
7206e4cb2b9Sbouyer 		 }
7216e4cb2b9Sbouyer #ifdef MBUFTRACE
7226e4cb2b9Sbouyer 		so->so_mowner = &can_mowner;
7236e4cb2b9Sbouyer 		so->so_rcv.sb_mowner = &can_rx_mowner;
7246e4cb2b9Sbouyer 		so->so_snd.sb_mowner = &can_tx_mowner;
7256e4cb2b9Sbouyer #endif
7266e4cb2b9Sbouyer 		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
7276e4cb2b9Sbouyer 			error = soreserve(so, can_sendspace, can_recvspace);
7286e4cb2b9Sbouyer 			if (error)
7296e4cb2b9Sbouyer 				break;
7306e4cb2b9Sbouyer 		}
7316e4cb2b9Sbouyer 		error = can_pcballoc(so, &cbtable);
7326e4cb2b9Sbouyer 		if (error)
7336e4cb2b9Sbouyer 			break;
7346e4cb2b9Sbouyer 		canp = sotocanpcb(so);
7356e4cb2b9Sbouyer #if 0
7366e4cb2b9Sbouyer 		inp->inp_ip.ip_ttl = ip_defttl;
7376e4cb2b9Sbouyer #endif
7386e4cb2b9Sbouyer 		break;
7396e4cb2b9Sbouyer 
7406e4cb2b9Sbouyer 	case PRU_DETACH:
7416e4cb2b9Sbouyer 		can_pcbdetach(canp);
7426e4cb2b9Sbouyer 		break;
7436e4cb2b9Sbouyer 
7446e4cb2b9Sbouyer 	case PRU_BIND:
7456e4cb2b9Sbouyer 		error = can_pcbbind(canp, nam, l);
7466e4cb2b9Sbouyer 		break;
7476e4cb2b9Sbouyer 
7486e4cb2b9Sbouyer 	case PRU_LISTEN:
7496e4cb2b9Sbouyer 		error = EOPNOTSUPP;
7506e4cb2b9Sbouyer 		break;
7516e4cb2b9Sbouyer 
7526e4cb2b9Sbouyer 	case PRU_CONNECT:
7536e4cb2b9Sbouyer 		error = can_pcbconnect(canp, nam);
7546e4cb2b9Sbouyer 		if (error)
7556e4cb2b9Sbouyer 			break;
7566e4cb2b9Sbouyer 		soisconnected(so);
7576e4cb2b9Sbouyer 		break;
7586e4cb2b9Sbouyer 
7596e4cb2b9Sbouyer 	case PRU_CONNECT2:
7606e4cb2b9Sbouyer 		error = EOPNOTSUPP;
7616e4cb2b9Sbouyer 		break;
7626e4cb2b9Sbouyer 
7636e4cb2b9Sbouyer 	case PRU_DISCONNECT:
7646e4cb2b9Sbouyer 		/*soisdisconnected(so);*/
7656e4cb2b9Sbouyer 		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
7666e4cb2b9Sbouyer 		can_pcbdisconnect(canp);
7676e4cb2b9Sbouyer 		can_pcbstate(canp, CANP_BOUND);		/* XXX */
7686e4cb2b9Sbouyer 		break;
7696e4cb2b9Sbouyer 
7706e4cb2b9Sbouyer 	case PRU_SHUTDOWN:
7716e4cb2b9Sbouyer 		socantsendmore(so);
7726e4cb2b9Sbouyer 		break;
7736e4cb2b9Sbouyer 
7746e4cb2b9Sbouyer 	case PRU_RCVD:
7756e4cb2b9Sbouyer 		error = EOPNOTSUPP;
7766e4cb2b9Sbouyer 		break;
7776e4cb2b9Sbouyer 
7786e4cb2b9Sbouyer 	case PRU_SEND:
7796e4cb2b9Sbouyer 		break;
7806e4cb2b9Sbouyer 
7816e4cb2b9Sbouyer 	case PRU_SENSE:
7826e4cb2b9Sbouyer 		/*
7836e4cb2b9Sbouyer 		 * stat: don't bother with a blocksize.
7846e4cb2b9Sbouyer 		 */
7856e4cb2b9Sbouyer 		splx(s);
7866e4cb2b9Sbouyer 		return (0);
7876e4cb2b9Sbouyer 
7886e4cb2b9Sbouyer 	case PRU_RCVOOB:
7896e4cb2b9Sbouyer 		error =  EOPNOTSUPP;
7906e4cb2b9Sbouyer 		break;
7916e4cb2b9Sbouyer 
7926e4cb2b9Sbouyer 	case PRU_SENDOOB:
7936e4cb2b9Sbouyer 		m_freem(control);
7946e4cb2b9Sbouyer 		m_freem(m);
7956e4cb2b9Sbouyer 		error =  EOPNOTSUPP;
7966e4cb2b9Sbouyer 		break;
7976e4cb2b9Sbouyer 
7986e4cb2b9Sbouyer 	case PRU_SOCKADDR:
7996e4cb2b9Sbouyer 
8006e4cb2b9Sbouyer 		break;
8016e4cb2b9Sbouyer 
8026e4cb2b9Sbouyer 	case PRU_PEERADDR:
8036e4cb2b9Sbouyer 		error =  EOPNOTSUPP;
8046e4cb2b9Sbouyer 		break;
8056e4cb2b9Sbouyer 
8066e4cb2b9Sbouyer 	default:
8076e4cb2b9Sbouyer 		panic("can_usrreq");
8086e4cb2b9Sbouyer 	}
8096e4cb2b9Sbouyer 
8106e4cb2b9Sbouyer release:
8116e4cb2b9Sbouyer 	splx(s);
8126e4cb2b9Sbouyer 	return (error);
8136e4cb2b9Sbouyer }
8146e4cb2b9Sbouyer #endif
8156e4cb2b9Sbouyer 
8166e4cb2b9Sbouyer #if 0
8176e4cb2b9Sbouyer static void
8186e4cb2b9Sbouyer can_notify(struct canpcb *canp, int errno)
8196e4cb2b9Sbouyer {
8206e4cb2b9Sbouyer 
8216e4cb2b9Sbouyer 	canp->canp_socket->so_error = errno;
8226e4cb2b9Sbouyer 	sorwakeup(canp->canp_socket);
8236e4cb2b9Sbouyer 	sowwakeup(canp->canp_socket);
8246e4cb2b9Sbouyer }
8256e4cb2b9Sbouyer 
8266e4cb2b9Sbouyer void *
8276e4cb2b9Sbouyer can_ctlinput(int cmd, struct sockaddr *sa, void *v)
8286e4cb2b9Sbouyer {
8296e4cb2b9Sbouyer 	struct ip *ip = v;
8306e4cb2b9Sbouyer 	struct canhdr *uh;
8316e4cb2b9Sbouyer 	void (*notify) __P((struct inpcb *, int)) = can_notify;
8326e4cb2b9Sbouyer 	int errno;
8336e4cb2b9Sbouyer 
8346e4cb2b9Sbouyer 	if (sa->sa_family != AF_CAN
8356e4cb2b9Sbouyer 	 || sa->sa_len != sizeof(struct sockaddr_can))
8366e4cb2b9Sbouyer 		return NULL;
8376e4cb2b9Sbouyer 	if ((unsigned)cmd >= PRC_NCMDS)
8386e4cb2b9Sbouyer 		return NULL;
8396e4cb2b9Sbouyer 	errno = inetctlerrmap[cmd];
8406e4cb2b9Sbouyer 	if (PRC_IS_REDIRECT(cmd))
8412ba9f052Sozaki-r 		notify = inpcb_rtchange, ip = 0;
8426e4cb2b9Sbouyer 	else if (cmd == PRC_HOSTDEAD)
8436e4cb2b9Sbouyer 		ip = 0;
8446e4cb2b9Sbouyer 	else if (errno == 0)
8456e4cb2b9Sbouyer 		return NULL;
8466e4cb2b9Sbouyer 	if (ip) {
8476e4cb2b9Sbouyer 		uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
8482ba9f052Sozaki-r 		inpcb_notify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
8496e4cb2b9Sbouyer 		    ip->ip_src, uh->uh_sport, errno, notify);
8506e4cb2b9Sbouyer 
8516e4cb2b9Sbouyer 		/* XXX mapped address case */
8526e4cb2b9Sbouyer 	} else
8536e4cb2b9Sbouyer 		can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
8546e4cb2b9Sbouyer 		    notify);
8556e4cb2b9Sbouyer 	return NULL;
8566e4cb2b9Sbouyer }
8576e4cb2b9Sbouyer #endif
8586e4cb2b9Sbouyer 
8596e4cb2b9Sbouyer static int
can_raw_getop(struct canpcb * canp,struct sockopt * sopt)8606e4cb2b9Sbouyer can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
8616e4cb2b9Sbouyer {
8626e4cb2b9Sbouyer 	int optval = 0;
8636e4cb2b9Sbouyer 	int error;
8646e4cb2b9Sbouyer 
8656e4cb2b9Sbouyer 	switch (sopt->sopt_name) {
8666e4cb2b9Sbouyer 	case CAN_RAW_LOOPBACK:
8676e4cb2b9Sbouyer 		optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
8686e4cb2b9Sbouyer 		error = sockopt_set(sopt, &optval, sizeof(optval));
8696e4cb2b9Sbouyer 		break;
8706e4cb2b9Sbouyer 	case CAN_RAW_RECV_OWN_MSGS:
8716e4cb2b9Sbouyer 		optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
8726e4cb2b9Sbouyer 		error = sockopt_set(sopt, &optval, sizeof(optval));
8736e4cb2b9Sbouyer 		break;
8746e4cb2b9Sbouyer 	case CAN_RAW_FILTER:
8756e4cb2b9Sbouyer 		error = sockopt_set(sopt, canp->canp_filters,
8766e4cb2b9Sbouyer 		    sizeof(struct can_filter) * canp->canp_nfilters);
8776e4cb2b9Sbouyer 		break;
8786e4cb2b9Sbouyer 	default:
8796e4cb2b9Sbouyer 		error = ENOPROTOOPT;
8806e4cb2b9Sbouyer 		break;
8816e4cb2b9Sbouyer 	}
8826e4cb2b9Sbouyer 	return error;
8836e4cb2b9Sbouyer }
8846e4cb2b9Sbouyer 
8856e4cb2b9Sbouyer static int
can_raw_setop(struct canpcb * canp,struct sockopt * sopt)8866e4cb2b9Sbouyer can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
8876e4cb2b9Sbouyer {
8886e4cb2b9Sbouyer 	int optval = 0;
8896e4cb2b9Sbouyer 	int error;
8906e4cb2b9Sbouyer 
8916e4cb2b9Sbouyer 	switch (sopt->sopt_name) {
8926e4cb2b9Sbouyer 	case CAN_RAW_LOOPBACK:
8936e4cb2b9Sbouyer 		error = sockopt_getint(sopt, &optval);
8946e4cb2b9Sbouyer 		if (error == 0) {
8956e4cb2b9Sbouyer 			if (optval) {
8966e4cb2b9Sbouyer 				canp->canp_flags &= ~CANP_NO_LOOPBACK;
8976e4cb2b9Sbouyer 			} else {
8986e4cb2b9Sbouyer 				canp->canp_flags |= CANP_NO_LOOPBACK;
8996e4cb2b9Sbouyer 			}
9006e4cb2b9Sbouyer 		}
9016e4cb2b9Sbouyer 		break;
9026e4cb2b9Sbouyer 	case CAN_RAW_RECV_OWN_MSGS:
9036e4cb2b9Sbouyer 		error = sockopt_getint(sopt, &optval);
9046e4cb2b9Sbouyer 		if (error == 0) {
9056e4cb2b9Sbouyer 			if (optval) {
9066e4cb2b9Sbouyer 				canp->canp_flags |= CANP_RECEIVE_OWN;
9076e4cb2b9Sbouyer 			} else {
9086e4cb2b9Sbouyer 				canp->canp_flags &= ~CANP_RECEIVE_OWN;
9096e4cb2b9Sbouyer 			}
9106e4cb2b9Sbouyer 		}
9116e4cb2b9Sbouyer 		break;
9126e4cb2b9Sbouyer 	case CAN_RAW_FILTER:
9136e4cb2b9Sbouyer 		{
9146e4cb2b9Sbouyer 		int nfilters = sopt->sopt_size / sizeof(struct can_filter);
9156e4cb2b9Sbouyer 		if (sopt->sopt_size % sizeof(struct can_filter) != 0)
9166e4cb2b9Sbouyer 			return EINVAL;
9176e4cb2b9Sbouyer 		error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
9186e4cb2b9Sbouyer 		break;
9196e4cb2b9Sbouyer 		}
9206e4cb2b9Sbouyer 	default:
9216e4cb2b9Sbouyer 		error = ENOPROTOOPT;
9226e4cb2b9Sbouyer 		break;
9236e4cb2b9Sbouyer 	}
9246e4cb2b9Sbouyer 	return error;
9256e4cb2b9Sbouyer }
9266e4cb2b9Sbouyer 
9276e4cb2b9Sbouyer /*
9286e4cb2b9Sbouyer  * Called by getsockopt and setsockopt.
9296e4cb2b9Sbouyer  *
9306e4cb2b9Sbouyer  */
9316e4cb2b9Sbouyer int
can_ctloutput(int op,struct socket * so,struct sockopt * sopt)9326e4cb2b9Sbouyer can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
9336e4cb2b9Sbouyer {
9346e4cb2b9Sbouyer 	struct canpcb *canp;
9356e4cb2b9Sbouyer 	int error;
9366e4cb2b9Sbouyer 	int s;
9376e4cb2b9Sbouyer 
9386e4cb2b9Sbouyer 	if (so->so_proto->pr_domain->dom_family != PF_CAN)
9396e4cb2b9Sbouyer 		return EAFNOSUPPORT;
9406e4cb2b9Sbouyer 
9416e4cb2b9Sbouyer 	if (sopt->sopt_level != SOL_CAN_RAW)
9426e4cb2b9Sbouyer 		return EINVAL;
9436e4cb2b9Sbouyer 
9446e4cb2b9Sbouyer 	s = splsoftnet();
9456e4cb2b9Sbouyer 	canp = sotocanpcb(so);
9466e4cb2b9Sbouyer 	if (canp == NULL) {
9476e4cb2b9Sbouyer 		splx(s);
9486e4cb2b9Sbouyer 		return ECONNRESET;
9496e4cb2b9Sbouyer 	}
9506e4cb2b9Sbouyer 
9516e4cb2b9Sbouyer 	if (op == PRCO_SETOPT) {
9526e4cb2b9Sbouyer 		error = can_raw_setop(canp, sopt);
9536e4cb2b9Sbouyer 	} else if (op ==  PRCO_GETOPT) {
9546e4cb2b9Sbouyer 		error = can_raw_getop(canp, sopt);
9556e4cb2b9Sbouyer 	} else {
9566e4cb2b9Sbouyer 		error = EINVAL;
9576e4cb2b9Sbouyer 	}
9586e4cb2b9Sbouyer 	splx(s);
9596e4cb2b9Sbouyer 	return error;
9606e4cb2b9Sbouyer }
9616e4cb2b9Sbouyer 
9626e4cb2b9Sbouyer PR_WRAP_USRREQS(can)
9636e4cb2b9Sbouyer #define	can_attach	can_attach_wrapper
9646e4cb2b9Sbouyer #define	can_detach	can_detach_wrapper
9656e4cb2b9Sbouyer #define	can_accept	can_accept_wrapper
9666e4cb2b9Sbouyer #define	can_bind	can_bind_wrapper
9676e4cb2b9Sbouyer #define	can_listen	can_listen_wrapper
9686e4cb2b9Sbouyer #define	can_connect	can_connect_wrapper
9696e4cb2b9Sbouyer #define	can_connect2	can_connect2_wrapper
9706e4cb2b9Sbouyer #define	can_disconnect	can_disconnect_wrapper
9716e4cb2b9Sbouyer #define	can_shutdown	can_shutdown_wrapper
9726e4cb2b9Sbouyer #define	can_abort	can_abort_wrapper
9736e4cb2b9Sbouyer #define	can_ioctl	can_ioctl_wrapper
9746e4cb2b9Sbouyer #define	can_stat	can_stat_wrapper
9756e4cb2b9Sbouyer #define	can_peeraddr	can_peeraddr_wrapper
9766e4cb2b9Sbouyer #define	can_sockaddr	can_sockaddr_wrapper
9776e4cb2b9Sbouyer #define	can_rcvd	can_rcvd_wrapper
9786e4cb2b9Sbouyer #define	can_recvoob	can_recvoob_wrapper
9796e4cb2b9Sbouyer #define	can_send	can_send_wrapper
9806e4cb2b9Sbouyer #define	can_sendoob	can_sendoob_wrapper
9816e4cb2b9Sbouyer #define	can_purgeif	can_purgeif_wrapper
9826e4cb2b9Sbouyer 
9836e4cb2b9Sbouyer const struct pr_usrreqs can_usrreqs = {
9846e4cb2b9Sbouyer 	.pr_attach	= can_attach,
9856e4cb2b9Sbouyer 	.pr_detach	= can_detach,
9866e4cb2b9Sbouyer 	.pr_accept	= can_accept,
9876e4cb2b9Sbouyer 	.pr_bind	= can_bind,
9886e4cb2b9Sbouyer 	.pr_listen	= can_listen,
9896e4cb2b9Sbouyer 	.pr_connect	= can_connect,
9906e4cb2b9Sbouyer 	.pr_connect2	= can_connect2,
9916e4cb2b9Sbouyer 	.pr_disconnect	= can_disconnect,
9926e4cb2b9Sbouyer 	.pr_shutdown	= can_shutdown,
9936e4cb2b9Sbouyer 	.pr_abort	= can_abort,
9946e4cb2b9Sbouyer 	.pr_ioctl	= can_ioctl,
9956e4cb2b9Sbouyer 	.pr_stat	= can_stat,
9966e4cb2b9Sbouyer 	.pr_peeraddr	= can_peeraddr,
9976e4cb2b9Sbouyer 	.pr_sockaddr	= can_sockaddr,
9986e4cb2b9Sbouyer 	.pr_rcvd	= can_rcvd,
9996e4cb2b9Sbouyer 	.pr_recvoob	= can_recvoob,
10006e4cb2b9Sbouyer 	.pr_send	= can_send,
10016e4cb2b9Sbouyer 	.pr_sendoob	= can_sendoob,
10026e4cb2b9Sbouyer 	.pr_purgeif	= can_purgeif,
10036e4cb2b9Sbouyer };
1004