Home | History | Annotate | Line # | Download | only in netcan
can.c revision 1.1.2.13
      1 /*	$NetBSD: can.c,v 1.1.2.13 2017/04/23 21:05:09 bouyer Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Robert Swindells and Manuel Bouyer
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.13 2017/04/23 21:05:09 bouyer Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/mbuf.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/domain.h>
     40 #include <sys/protosw.h>
     41 #include <sys/errno.h>
     42 #include <sys/socket.h>
     43 #include <sys/socketvar.h>
     44 #include <sys/proc.h>
     45 #include <sys/kauth.h>
     46 
     47 #include <net/if.h>
     48 #include <net/if_types.h>
     49 #include <net/netisr.h>
     50 #include <net/route.h>
     51 
     52 #include <netcan/can.h>
     53 #include <netcan/can_pcb.h>
     54 #include <netcan/can_var.h>
     55 
     56 struct canpcb canpcb;
     57 #if 0
     58 struct canpcb canrawpcb;
     59 #endif
     60 
     61 struct	canpcbtable cbtable;
     62 
     63 struct ifqueue	canintrq;
     64 int	canqmaxlen = IFQ_MAXLEN;
     65 
     66 int can_copy_output = 0;
     67 int can_output_cnt = 0;
     68 struct mbuf *can_lastout;
     69 
     70 int	can_sendspace = 4096;		/* really max datagram size */
     71 int	can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
     72 					/* 40 1K datagrams */
     73 #ifndef CANHASHSIZE
     74 #define	CANHASHSIZE	128
     75 #endif
     76 int	canhashsize = CANHASHSIZE;
     77 
     78 static int can_output(struct mbuf *, struct canpcb *);
     79 
     80 static int can_control(struct socket *, u_long, void *, struct ifnet *);
     81 
     82 void
     83 can_init(void)
     84 {
     85 	canintrq.ifq_maxlen = canqmaxlen;
     86 	IFQ_LOCK_INIT(&canintrq);
     87 	can_pcbinit(&cbtable, canhashsize, canhashsize);
     88 }
     89 
     90 /*
     91  * Generic control operations (ioctl's).
     92  */
     93 static int
     94 can_get_netlink(struct ifnet *ifp, struct ifdrv *ifd)
     95 {
     96 	struct canif_softc *csc = ifp->if_softc;
     97 
     98 	if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL)
     99 		return EOPNOTSUPP;
    100 
    101 	switch(ifd->ifd_cmd) {
    102 	case CANGLINKTIMECAP:
    103 		if (ifd->ifd_len != sizeof(struct can_link_timecaps))
    104 			return EINVAL;
    105 		return copyout(&csc->csc_timecaps, ifd->ifd_data, ifd->ifd_len);
    106 	case CANGLINKTIMINGS:
    107 		if (ifd->ifd_len != sizeof(struct can_link_timings))
    108 			return EINVAL;
    109 		return copyout(&csc->csc_timings, ifd->ifd_data, ifd->ifd_len);
    110 	case CANGLINKMODE:
    111 		if (ifd->ifd_len != sizeof(uint32_t))
    112 			return EINVAL;
    113 		return copyout(&csc->csc_linkmodes, ifd->ifd_data, ifd->ifd_len);
    114 	}
    115 	return EOPNOTSUPP;
    116 }
    117 
    118 static int
    119 can_set_netlink(struct ifnet *ifp, struct ifdrv *ifd)
    120 {
    121 	struct canif_softc *csc = ifp->if_softc;
    122 	uint32_t mode;
    123 	int error;
    124 
    125 	if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL)
    126 		return EOPNOTSUPP;
    127 
    128 	error = kauth_authorize_network(curlwp->l_cred,
    129 		    KAUTH_NETWORK_INTERFACE,
    130 		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp,
    131 	            (void *)SIOCSDRVSPEC, NULL);
    132 	if (error != 0)
    133 		return error;
    134 
    135 	if ((ifp->if_flags & IFF_UP) != 0) {
    136 		return EBUSY;
    137 	}
    138 
    139 	switch(ifd->ifd_cmd) {
    140 	case CANSLINKTIMINGS:
    141 		if (ifd->ifd_len != sizeof(struct can_link_timings))
    142 			return EINVAL;
    143 		return copyin(ifd->ifd_data, &csc->csc_timings, ifd->ifd_len);
    144 
    145 	case CANSLINKMODE:
    146 	case CANCLINKMODE:
    147 		if (ifd->ifd_len != sizeof(uint32_t))
    148 			return EINVAL;
    149 		error = copyin(ifd->ifd_data, &mode, ifd->ifd_len);
    150 		if (error)
    151 			return error;
    152 		if ((mode & csc->csc_timecaps.cltc_linkmode_caps) != mode)
    153 			return EINVAL;
    154 		/* XXX locking */
    155 		if (ifd->ifd_cmd == CANSLINKMODE)
    156 			csc->csc_linkmodes |= mode;
    157 		else
    158 			csc->csc_linkmodes &= ~mode;
    159 		return 0;
    160 	}
    161 	return EOPNOTSUPP;
    162 }
    163 
    164 /* ARGSUSED */
    165 static int
    166 can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
    167 {
    168 #if 0
    169 	struct can_ifreq *cfr = (struct can_ifreq *)data;
    170 	int error = 0;
    171 #endif
    172 	if (ifp == NULL)
    173 		return (EOPNOTSUPP);
    174 
    175 	switch (cmd) {
    176 	case SIOCGDRVSPEC:
    177 		return can_get_netlink(ifp, (struct ifdrv *) data);
    178 	case SIOCSDRVSPEC:
    179 		return can_set_netlink(ifp, (struct ifdrv *) data);
    180 	default:
    181 		if (ifp->if_ioctl == 0)
    182 			return (EOPNOTSUPP);
    183 		return ((*ifp->if_ioctl)(ifp, cmd, data));
    184 	}
    185 	return (0);
    186 }
    187 
    188 static int
    189 can_purgeif(struct socket *so, struct ifnet *ifp)
    190 {
    191 	return 0;
    192 }
    193 
    194 void
    195 can_ifattach(struct ifnet *ifp) {
    196 	ifp->if_mtu = sizeof(struct can_frame);
    197 	ifp->if_type = IFT_OTHER;
    198 	ifp->if_hdrlen = 0;
    199 	ifp->if_addrlen = 0;
    200 	ifp->if_dlt = DLT_CAN_SOCKETCAN;
    201 	ifp->if_output = NULL; /* unused */
    202 	IFQ_SET_READY(&ifp->if_snd);
    203 	if_alloc_sadl(ifp);
    204 }
    205 
    206 void
    207 can_ifinit_timings(struct canif_softc *csc)
    208 {
    209 	/* uninitialized parameters is all-one */
    210 	memset(&csc->csc_timings, 0xff, sizeof(struct can_link_timings));
    211 }
    212 
    213 static int
    214 can_output(struct mbuf *m, struct canpcb *canp)
    215 {
    216 	struct ifnet *ifp;
    217 	struct m_tag *sotag;
    218 	struct canif_softc *csc;
    219 
    220 	if (canp == NULL) {
    221 		printf("can_output: no pcb\n");
    222 		return EINVAL;
    223 	}
    224 	ifp = canp->canp_ifp;
    225 	if (ifp == 0) {
    226 		return EDESTADDRREQ;
    227 	}
    228 	csc = ifp->if_softc;
    229 	if (csc && (csc->csc_linkmodes & CAN_LINKMODE_LISTENONLY)) {
    230 		return ENETUNREACH;
    231 	}
    232 
    233 	sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
    234 	if (sotag == NULL) {
    235 		ifp->if_oerrors++;
    236 		return ENOMEM;
    237 	}
    238 	mutex_enter(&canp->canp_mtx);
    239 	canp_ref(canp);
    240 	mutex_exit(&canp->canp_mtx);
    241 	*(struct canpcb **)(sotag + 1) = canp;
    242 	m_tag_prepend(m, sotag);
    243 
    244 	if (m->m_len <= ifp->if_mtu) {
    245 		can_output_cnt++;
    246 		return ifq_enqueue(ifp, m);
    247 	} else
    248 		return EMSGSIZE;
    249 }
    250 
    251 /*
    252  * cleanup mbuf tag, keeping the PACKET_TAG_SO tag
    253  */
    254 void
    255 can_mbuf_tag_clean(struct mbuf *m)
    256 {
    257 	struct m_tag *sotag;
    258 
    259 	sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
    260 	if (sotag)
    261 		m_tag_unlink(m, sotag);
    262 
    263 	m_tag_delete_nonpersistent(m);
    264 	if (sotag)
    265 		m_tag_prepend(m, sotag);
    266 }
    267 
    268 /*
    269  * Process a received CAN frame
    270  * the packet is in the mbuf chain m with
    271  * the CAN header.
    272  */
    273 void
    274 can_input(struct ifnet *ifp, struct mbuf *m)
    275 {
    276 	struct ifqueue *inq;
    277 
    278 	if ((ifp->if_flags & IFF_UP) == 0) {
    279 		m_freem(m);
    280 		return;
    281 	}
    282 
    283 	inq = &canintrq;
    284 
    285 	IFQ_LOCK(inq);
    286 	if (IF_QFULL(inq)) {
    287 		IF_DROP(inq);
    288 		IFQ_UNLOCK(inq);
    289 		m_freem(m);
    290 	} else {
    291 		IF_ENQUEUE(inq, m);
    292 		IFQ_UNLOCK(inq);
    293 		ifp->if_ipackets++;
    294 		ifp->if_ibytes += m->m_pkthdr.len;
    295 		schednetisr(NETISR_CAN);
    296 	}
    297 }
    298 
    299 void
    300 canintr(void)
    301 {
    302 	int		rcv_ifindex;
    303 	struct mbuf    *m;
    304 
    305 	struct sockaddr_can from;
    306 	struct canpcb   *canp;
    307 	struct m_tag	*sotag;
    308 	struct canpcb	*sender_canp;
    309 
    310 	mutex_enter(softnet_lock);
    311 	for (;;) {
    312 		IFQ_LOCK(&canintrq);
    313 		IF_DEQUEUE(&canintrq, m);
    314 		IFQ_UNLOCK(&canintrq);
    315 
    316 		if (m == NULL)	/* no more queued packets */
    317 			break;
    318 
    319 #if 0
    320 		m_claim(m, &can_rx_mowner);
    321 #endif
    322 		sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
    323 		if (sotag) {
    324 			sender_canp = *(struct canpcb **)(sotag + 1);
    325 			m_tag_delete(m, sotag);
    326 			KASSERT(sender_canp != NULL);
    327 			/* if the sender doesn't want loopback, don't do it */
    328 			if ((sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) {
    329 				m_freem(m);
    330 				canp_unref(sender_canp);
    331 				continue;
    332 			}
    333 		} else {
    334 			sender_canp = NULL;
    335 		}
    336 		memset(&from, 0, sizeof(struct sockaddr_can));
    337 		rcv_ifindex = m->m_pkthdr.rcvif_index;
    338 		from.can_ifindex = rcv_ifindex;
    339 		from.can_len = sizeof(struct sockaddr_can);
    340 		from.can_family = AF_CAN;
    341 
    342 		TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
    343 			struct mbuf *mc;
    344 
    345 			mutex_enter(&canp->canp_mtx);
    346 			/* skip if we're detached */
    347 			if (canp->canp_state == CANP_DETACHED) {
    348 				mutex_exit(&canp->canp_mtx);
    349 				continue;
    350 			}
    351 
    352 			/* don't loop back to sockets on other interfaces */
    353 			if (canp->canp_ifp != NULL &&
    354 			    canp->canp_ifp->if_index != rcv_ifindex) {
    355 				mutex_exit(&canp->canp_mtx);
    356 				continue;
    357 			}
    358 			/* don't loop back to myself if I don't want it */
    359 			if (canp == sender_canp &&
    360 			    (canp->canp_flags & CANP_RECEIVE_OWN) == 0) {
    361 				mutex_exit(&canp->canp_mtx);
    362 				continue;
    363 			}
    364 
    365 			/* skip if the accept filter doen't match this pkt */
    366 			if (!can_pcbfilter(canp, m)) {
    367 				mutex_exit(&canp->canp_mtx);
    368 				continue;
    369 			}
    370 
    371 			if (TAILQ_NEXT(canp, canp_queue) != NULL) {
    372 				/*
    373 				 * we can't be sure we won't need
    374 				 * the original mbuf later so copy
    375 				 */
    376 				mc = m_copypacket(m, M_NOWAIT);
    377 				if (mc == NULL) {
    378 					/* deliver this mbuf and abort */
    379 					mc = m;
    380 					m = NULL;
    381 				}
    382 			} else {
    383 				mc = m;
    384 				m = NULL;
    385 			}
    386 			if (sbappendaddr(&canp->canp_socket->so_rcv,
    387 					 (struct sockaddr *) &from, mc,
    388 					 (struct mbuf *) 0) == 0) {
    389 				m_freem(mc);
    390 			} else
    391 				sorwakeup(canp->canp_socket);
    392 			mutex_exit(&canp->canp_mtx);
    393 			if (m == NULL)
    394 				break;
    395 		}
    396 		if (sender_canp) {
    397 			canp_unref(sender_canp);
    398 		}
    399 		/* If it didn't go anywhere just delete it */
    400 		if (m) {
    401 			m_freem(m);
    402 		}
    403 	}
    404 	mutex_exit(softnet_lock);
    405 }
    406 
    407 static int
    408 can_attach(struct socket *so, int proto)
    409 {
    410 	int error;
    411 
    412 	KASSERT(sotocanpcb(so) == NULL);
    413 
    414 	/* Assign the lock (must happen even if we will error out). */
    415 	sosetlock(so);
    416 
    417 #ifdef MBUFTRACE
    418 	so->so_mowner = &can_mowner;
    419 	so->so_rcv.sb_mowner = &can_rx_mowner;
    420 	so->so_snd.sb_mowner = &can_tx_mowner;
    421 #endif
    422 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
    423 		error = soreserve(so, can_sendspace, can_recvspace);
    424 		if (error) {
    425 			return error;
    426 		}
    427 	}
    428 
    429 	error = can_pcballoc(so, &cbtable);
    430 	if (error) {
    431 		return error;
    432 	}
    433 	KASSERT(solocked(so));
    434 
    435 	return error;
    436 }
    437 
    438 static void
    439 can_detach(struct socket *so)
    440 {
    441 	struct canpcb *canp;
    442 
    443 	KASSERT(solocked(so));
    444 	canp = sotocanpcb(so);
    445 	can_pcbdetach(canp);
    446 }
    447 
    448 static int
    449 can_accept(struct socket *so, struct sockaddr *nam)
    450 {
    451 	KASSERT(solocked(so));
    452 
    453 	panic("can_accept");
    454 
    455 	return EOPNOTSUPP;
    456 }
    457 
    458 static int
    459 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
    460 {
    461 	struct canpcb *canp = sotocanpcb(so);
    462 	struct sockaddr_can *scan = (struct sockaddr_can *)nam;
    463 
    464 	KASSERT(solocked(so));
    465 	KASSERT(nam != NULL);
    466 
    467 	return can_pcbbind(canp, scan, l);
    468 }
    469 
    470 static int
    471 can_listen(struct socket *so, struct lwp *l)
    472 {
    473 	KASSERT(solocked(so));
    474 
    475 	return EOPNOTSUPP;
    476 }
    477 
    478 static int
    479 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
    480 {
    481 	struct canpcb *canp = sotocanpcb(so);
    482 	int error = 0;
    483 
    484 	KASSERT(solocked(so));
    485 	KASSERT(canp != NULL);
    486 	KASSERT(nam != NULL);
    487 
    488 	error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
    489 	if (! error)
    490 		soisconnected(so);
    491 	return error;
    492 }
    493 
    494 static int
    495 can_connect2(struct socket *so, struct socket *so2)
    496 {
    497 	KASSERT(solocked(so));
    498 
    499 	return EOPNOTSUPP;
    500 }
    501 
    502 static int
    503 can_disconnect(struct socket *so)
    504 {
    505 	struct canpcb *canp = sotocanpcb(so);
    506 
    507 	KASSERT(solocked(so));
    508 	KASSERT(canp != NULL);
    509 
    510 	/*soisdisconnected(so);*/
    511 	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
    512 	can_pcbdisconnect(canp);
    513 	return 0;
    514 }
    515 
    516 static int
    517 can_shutdown(struct socket *so)
    518 {
    519 	KASSERT(solocked(so));
    520 
    521 	socantsendmore(so);
    522 	return 0;
    523 }
    524 
    525 static int
    526 can_abort(struct socket *so)
    527 {
    528 	KASSERT(solocked(so));
    529 
    530 	panic("can_abort");
    531 
    532 	return EOPNOTSUPP;
    533 }
    534 
    535 static int
    536 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
    537 {
    538 	return can_control(so, cmd, nam, ifp);
    539 }
    540 
    541 static int
    542 can_stat(struct socket *so, struct stat *ub)
    543 {
    544 	KASSERT(solocked(so));
    545 
    546 	/* stat: don't bother with a blocksize. */
    547 	return 0;
    548 }
    549 
    550 static int
    551 can_peeraddr(struct socket *so, struct sockaddr *nam)
    552 {
    553 	KASSERT(solocked(so));
    554 	KASSERT(sotocanpcb(so) != NULL);
    555 	KASSERT(nam != NULL);
    556 
    557 	return EOPNOTSUPP;
    558 }
    559 
    560 static int
    561 can_sockaddr(struct socket *so, struct sockaddr *nam)
    562 {
    563 	KASSERT(solocked(so));
    564 	KASSERT(sotocanpcb(so) != NULL);
    565 	KASSERT(nam != NULL);
    566 
    567 	can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
    568 
    569 	return 0;
    570 }
    571 
    572 static int
    573 can_rcvd(struct socket *so, int flags, struct lwp *l)
    574 {
    575 	KASSERT(solocked(so));
    576 
    577 	return EOPNOTSUPP;
    578 }
    579 
    580 static int
    581 can_recvoob(struct socket *so, struct mbuf *m, int flags)
    582 {
    583 	KASSERT(solocked(so));
    584 
    585 	return EOPNOTSUPP;
    586 }
    587 
    588 static int
    589 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
    590     struct mbuf *control, struct lwp *l)
    591 {
    592 	struct canpcb *canp = sotocanpcb(so);
    593 	int error = 0;
    594 	int s;
    595 
    596 	if (control && control->m_len) {
    597 		m_freem(control);
    598 		error = EINVAL;
    599 		goto err;
    600 	}
    601 	if (m->m_len > sizeof(struct can_frame) ||
    602 	   m->m_len < offsetof(struct can_frame, can_dlc)) {
    603 		error = EINVAL;
    604 		goto err;
    605 	}
    606 
    607 	/* we expect all data in the first mbuf */
    608 	KASSERT((m->m_flags & M_PKTHDR) != 0);
    609 	KASSERT(m->m_len == m->m_pkthdr.len);
    610 
    611 	if (nam) {
    612 		if ((so->so_state & SS_ISCONNECTED) != 0) {
    613 			error = EISCONN;
    614 			goto err;
    615 		}
    616 		s = splnet();
    617 		error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
    618 		if (error) {
    619 			splx(s);
    620 			goto err;
    621 		}
    622 	} else {
    623 		if ((so->so_state & SS_ISCONNECTED) == 0) {
    624 			error =  EDESTADDRREQ;
    625 			goto err;
    626 		}
    627 	}
    628 	error = can_output(m, canp);
    629 	if (nam) {
    630 		struct sockaddr_can lscan;
    631 		memset(&lscan, 0, sizeof(lscan));
    632 		lscan.can_family = AF_CAN;
    633 		lscan.can_len = sizeof(lscan);
    634 		can_pcbbind(canp, &lscan, l);
    635 	}
    636 	if (error)
    637 		goto err;
    638 	return 0;
    639 
    640 err:
    641 	m_freem(m);
    642 	return error;
    643 }
    644 
    645 static int
    646 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
    647 {
    648 	KASSERT(solocked(so));
    649 
    650 	m_freem(m);
    651 	m_freem(control);
    652 
    653 	return EOPNOTSUPP;
    654 }
    655 
    656 #if 0
    657 int
    658 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
    659 	   struct mbuf *control, struct lwp *l)
    660 {
    661 	struct canpcb *canp;
    662 	int s;
    663 	int error = 0;
    664 
    665 	if (req == PRU_CONTROL)
    666 		 return (can_control(so, (long)m, nam,
    667 		     (struct ifnet *)control));
    668 
    669 	if (req == PRU_PURGEIF) {
    670 #if 0
    671 		can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
    672 		can_purgeif((struct ifnet *)control);
    673 		can_pcbpurgeif(&udbtable, (struct ifnet *)control);
    674 #endif
    675 		return (0);
    676 	}
    677 
    678 	s = splsoftnet();
    679 	canp = sotocanpcb(so);
    680 #ifdef DIAGNOSTIC
    681 	if (req != PRU_SEND && req != PRU_SENDOOB && control)
    682 		panic("can_usrreq: unexpected control mbuf");
    683 #endif
    684 	if (canp == 0 && req != PRU_ATTACH) {
    685 		printf("can_usrreq: no pcb %p %d\n", canp, req);
    686 		error = EINVAL;
    687 		goto release;
    688 	}
    689 
    690 	/*
    691 	 * Note: need to block can_input while changing
    692 	 * the can pcb queue and/or pcb addresses.
    693 	 */
    694 	switch (req) {
    695 
    696 	  case PRU_ATTACH:
    697 	      if (canp != 0) {
    698 			 error = EISCONN;
    699 			 break;
    700 		 }
    701 #ifdef MBUFTRACE
    702 		so->so_mowner = &can_mowner;
    703 		so->so_rcv.sb_mowner = &can_rx_mowner;
    704 		so->so_snd.sb_mowner = &can_tx_mowner;
    705 #endif
    706 		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
    707 			error = soreserve(so, can_sendspace, can_recvspace);
    708 			if (error)
    709 				break;
    710 		}
    711 		error = can_pcballoc(so, &cbtable);
    712 		if (error)
    713 			break;
    714 		canp = sotocanpcb(so);
    715 #if 0
    716 		inp->inp_ip.ip_ttl = ip_defttl;
    717 #endif
    718 		break;
    719 
    720 	case PRU_DETACH:
    721 		can_pcbdetach(canp);
    722 		break;
    723 
    724 	case PRU_BIND:
    725 		error = can_pcbbind(canp, nam, l);
    726 		break;
    727 
    728 	case PRU_LISTEN:
    729 		error = EOPNOTSUPP;
    730 		break;
    731 
    732 	case PRU_CONNECT:
    733 		error = can_pcbconnect(canp, nam);
    734 		if (error)
    735 			break;
    736 		soisconnected(so);
    737 		break;
    738 
    739 	case PRU_CONNECT2:
    740 		error = EOPNOTSUPP;
    741 		break;
    742 
    743 	case PRU_DISCONNECT:
    744 		/*soisdisconnected(so);*/
    745 		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
    746 		can_pcbdisconnect(canp);
    747 		can_pcbstate(canp, CANP_BOUND);		/* XXX */
    748 		break;
    749 
    750 	case PRU_SHUTDOWN:
    751 		socantsendmore(so);
    752 		break;
    753 
    754 	case PRU_RCVD:
    755 		error = EOPNOTSUPP;
    756 		break;
    757 
    758 	case PRU_SEND:
    759 		break;
    760 
    761 	case PRU_SENSE:
    762 		/*
    763 		 * stat: don't bother with a blocksize.
    764 		 */
    765 		splx(s);
    766 		return (0);
    767 
    768 	case PRU_RCVOOB:
    769 		error =  EOPNOTSUPP;
    770 		break;
    771 
    772 	case PRU_SENDOOB:
    773 		m_freem(control);
    774 		m_freem(m);
    775 		error =  EOPNOTSUPP;
    776 		break;
    777 
    778 	case PRU_SOCKADDR:
    779 
    780 		break;
    781 
    782 	case PRU_PEERADDR:
    783 		error =  EOPNOTSUPP;
    784 		break;
    785 
    786 	default:
    787 		panic("can_usrreq");
    788 	}
    789 
    790 release:
    791 	splx(s);
    792 	return (error);
    793 }
    794 #endif
    795 
    796 #if 0
    797 static void
    798 can_notify(struct canpcb *canp, int errno)
    799 {
    800 
    801 	canp->canp_socket->so_error = errno;
    802 	sorwakeup(canp->canp_socket);
    803 	sowwakeup(canp->canp_socket);
    804 }
    805 
    806 void *
    807 can_ctlinput(int cmd, struct sockaddr *sa, void *v)
    808 {
    809 	struct ip *ip = v;
    810 	struct canhdr *uh;
    811 	void (*notify) __P((struct inpcb *, int)) = can_notify;
    812 	int errno;
    813 
    814 	if (sa->sa_family != AF_CAN
    815 	 || sa->sa_len != sizeof(struct sockaddr_can))
    816 		return NULL;
    817 	if ((unsigned)cmd >= PRC_NCMDS)
    818 		return NULL;
    819 	errno = inetctlerrmap[cmd];
    820 	if (PRC_IS_REDIRECT(cmd))
    821 		notify = in_rtchange, ip = 0;
    822 	else if (cmd == PRC_HOSTDEAD)
    823 		ip = 0;
    824 	else if (errno == 0)
    825 		return NULL;
    826 	if (ip) {
    827 		uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
    828 		in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
    829 		    ip->ip_src, uh->uh_sport, errno, notify);
    830 
    831 		/* XXX mapped address case */
    832 	} else
    833 		can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
    834 		    notify);
    835 	return NULL;
    836 }
    837 #endif
    838 
    839 static int
    840 can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
    841 {
    842 	int optval = 0;
    843 	int error;
    844 
    845 	switch (sopt->sopt_name) {
    846 	case CAN_RAW_LOOPBACK:
    847 		optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
    848 		error = sockopt_set(sopt, &optval, sizeof(optval));
    849 		break;
    850 	case CAN_RAW_RECV_OWN_MSGS:
    851 		optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
    852 		error = sockopt_set(sopt, &optval, sizeof(optval));
    853 		break;
    854 	case CAN_RAW_FILTER:
    855 		error = sockopt_set(sopt, canp->canp_filters,
    856 		    sizeof(struct can_filter) * canp->canp_nfilters);
    857 		break;
    858 	default:
    859 		error = ENOPROTOOPT;
    860 		break;
    861 	}
    862 	return error;
    863 }
    864 
    865 static int
    866 can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
    867 {
    868 	int optval = 0;
    869 	int error;
    870 
    871 	switch (sopt->sopt_name) {
    872 	case CAN_RAW_LOOPBACK:
    873 		error = sockopt_getint(sopt, &optval);
    874 		if (error == 0) {
    875 			if (optval) {
    876 				canp->canp_flags &= ~CANP_NO_LOOPBACK;
    877 			} else {
    878 				canp->canp_flags |= CANP_NO_LOOPBACK;
    879 			}
    880 		}
    881 		break;
    882 	case CAN_RAW_RECV_OWN_MSGS:
    883 		error = sockopt_getint(sopt, &optval);
    884 		if (error == 0) {
    885 			if (optval) {
    886 				canp->canp_flags |= CANP_RECEIVE_OWN;
    887 			} else {
    888 				canp->canp_flags &= ~CANP_RECEIVE_OWN;
    889 			}
    890 		}
    891 		break;
    892 	case CAN_RAW_FILTER:
    893 		{
    894 		int nfilters = sopt->sopt_size / sizeof(struct can_filter);
    895 		if (sopt->sopt_size % sizeof(struct can_filter) != 0)
    896 			return EINVAL;
    897 		mutex_enter(&canp->canp_mtx);
    898 		error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
    899 		mutex_exit(&canp->canp_mtx);
    900 		break;
    901 		}
    902 	default:
    903 		error = ENOPROTOOPT;
    904 		break;
    905 	}
    906 	return error;
    907 }
    908 
    909 /*
    910  * Called by getsockopt and setsockopt.
    911  *
    912  */
    913 int
    914 can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
    915 {
    916 	struct canpcb *canp;
    917 	int error;
    918 	int s;
    919 
    920 	if (so->so_proto->pr_domain->dom_family != PF_CAN)
    921 		return EAFNOSUPPORT;
    922 
    923 	if (sopt->sopt_level != SOL_CAN_RAW)
    924 		return EINVAL;
    925 
    926 	s = splsoftnet();
    927 	canp = sotocanpcb(so);
    928 	if (canp == NULL) {
    929 		splx(s);
    930 		return ECONNRESET;
    931 	}
    932 
    933 	if (op == PRCO_SETOPT) {
    934 		error = can_raw_setop(canp, sopt);
    935 	} else if (op ==  PRCO_GETOPT) {
    936 		error = can_raw_getop(canp, sopt);
    937 	} else {
    938 		error = EINVAL;
    939 	}
    940 	splx(s);
    941 	return error;
    942 }
    943 
    944 PR_WRAP_USRREQS(can)
    945 #define	can_attach	can_attach_wrapper
    946 #define	can_detach	can_detach_wrapper
    947 #define	can_accept	can_accept_wrapper
    948 #define	can_bind	can_bind_wrapper
    949 #define	can_listen	can_listen_wrapper
    950 #define	can_connect	can_connect_wrapper
    951 #define	can_connect2	can_connect2_wrapper
    952 #define	can_disconnect	can_disconnect_wrapper
    953 #define	can_shutdown	can_shutdown_wrapper
    954 #define	can_abort	can_abort_wrapper
    955 #define	can_ioctl	can_ioctl_wrapper
    956 #define	can_stat	can_stat_wrapper
    957 #define	can_peeraddr	can_peeraddr_wrapper
    958 #define	can_sockaddr	can_sockaddr_wrapper
    959 #define	can_rcvd	can_rcvd_wrapper
    960 #define	can_recvoob	can_recvoob_wrapper
    961 #define	can_send	can_send_wrapper
    962 #define	can_sendoob	can_sendoob_wrapper
    963 #define	can_purgeif	can_purgeif_wrapper
    964 
    965 const struct pr_usrreqs can_usrreqs = {
    966 	.pr_attach	= can_attach,
    967 	.pr_detach	= can_detach,
    968 	.pr_accept	= can_accept,
    969 	.pr_bind	= can_bind,
    970 	.pr_listen	= can_listen,
    971 	.pr_connect	= can_connect,
    972 	.pr_connect2	= can_connect2,
    973 	.pr_disconnect	= can_disconnect,
    974 	.pr_shutdown	= can_shutdown,
    975 	.pr_abort	= can_abort,
    976 	.pr_ioctl	= can_ioctl,
    977 	.pr_stat	= can_stat,
    978 	.pr_peeraddr	= can_peeraddr,
    979 	.pr_sockaddr	= can_sockaddr,
    980 	.pr_rcvd	= can_rcvd,
    981 	.pr_recvoob	= can_recvoob,
    982 	.pr_send	= can_send,
    983 	.pr_sendoob	= can_sendoob,
    984 	.pr_purgeif	= can_purgeif,
    985 };
    986