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