Home | History | Annotate | Line # | Download | only in netcan
can.c revision 1.1.2.4
      1 /*	$NetBSD: can.c,v 1.1.2.4 2017/02/05 11:45:11 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.4 2017/02/05 11:45:11 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/netisr.h>
     49 #include <net/route.h>
     50 
     51 #include <netcan/can.h>
     52 #include <netcan/can_pcb.h>
     53 #include <netcan/can_var.h>
     54 
     55 struct canpcb canpcb;
     56 #if 0
     57 struct canpcb canrawpcb;
     58 #endif
     59 
     60 struct	canpcbtable cbtable;
     61 
     62 struct ifqueue	canintrq;
     63 int	canqmaxlen = IFQ_MAXLEN;
     64 
     65 int can_copy_output = 0;
     66 int can_output_cnt = 0;
     67 struct mbuf *can_lastout;
     68 
     69 int	can_sendspace = 4096;		/* really max datagram size */
     70 int	can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
     71 					/* 40 1K datagrams */
     72 #ifndef CANHASHSIZE
     73 #define	CANHASHSIZE	128
     74 #endif
     75 int	canhashsize = CANHASHSIZE;
     76 
     77 static int can_output(struct mbuf *, struct canpcb *);
     78 
     79 static int can_control(struct socket *, u_long, void *, struct ifnet *);
     80 
     81 void
     82 can_init(void)
     83 {
     84 	canintrq.ifq_maxlen = canqmaxlen;
     85 	IFQ_LOCK_INIT(&canintrq);
     86 	can_pcbinit(&cbtable, canhashsize, canhashsize);
     87 }
     88 
     89 /*
     90  * Generic control operations (ioctl's).
     91  */
     92 /* ARGSUSED */
     93 static int
     94 can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
     95 {
     96 #if 0
     97 	struct can_ifreq *cfr = (struct can_ifreq *)data;
     98 	int error = 0;
     99 #endif
    100 
    101 
    102 	switch (cmd) {
    103 
    104 	default:
    105 		if (ifp == 0 || ifp->if_ioctl == 0)
    106 			return (EOPNOTSUPP);
    107 		return ((*ifp->if_ioctl)(ifp, cmd, data));
    108 	}
    109 	return (0);
    110 }
    111 
    112 static int
    113 can_purgeif(struct socket *so, struct ifnet *ifp)
    114 {
    115 	return 0;
    116 }
    117 
    118 static int
    119 can_output(struct mbuf *m, struct canpcb *canp)
    120 {
    121 	struct ifnet *ifp;
    122 	int error = 0;
    123 	struct m_tag *sotag;
    124 
    125 	if (canp == NULL) {
    126 		printf("can_output: no pcb\n");
    127 		error = EINVAL;
    128 		return error;
    129 	}
    130 	ifp = canp->canp_ifp;
    131 	if (ifp == 0) {
    132 		error = EDESTADDRREQ;
    133 		goto bad;
    134 	}
    135 	sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
    136 	if (sotag == NULL) {
    137 		ifp->if_oerrors++;
    138 		error = ENOMEM;
    139 		goto bad;
    140 	}
    141 	*(struct socket **)(sotag + 1) = canp->canp_socket;
    142 	m_tag_prepend(m, sotag);
    143 
    144 	if (m->m_len <= ifp->if_mtu) {
    145 		can_output_cnt++;
    146 		error = (*ifp->if_output)(ifp, m, NULL, 0);
    147 		return error;
    148 	} else
    149 		error = EMSGSIZE;
    150 bad:
    151 	m_freem(m);
    152 	return (error);
    153 }
    154 
    155 /*
    156  * cleanup mbuf tag, keeping the PACKET_TAG_SO tag
    157  */
    158 void
    159 can_mbuf_tag_clean(struct mbuf *m)
    160 {
    161 	struct m_tag *sotag;
    162 
    163 	sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
    164 	m_tag_delete_nonpersistent(m);
    165 	if (sotag)
    166 		m_tag_prepend(m, sotag);
    167 }
    168 
    169 /*
    170  * Process a received CAN frame
    171  * the packet is in the mbuf chain m with
    172  * the CAN header.
    173  */
    174 void
    175 can_input(struct ifnet *ifp, struct mbuf *m)
    176 {
    177 	struct ifqueue *inq;
    178 
    179 	if ((ifp->if_flags & IFF_UP) == 0) {
    180 		m_freem(m);
    181 		return;
    182 	}
    183 
    184 	inq = &canintrq;
    185 
    186 	IFQ_LOCK(inq);
    187 	if (IF_QFULL(inq)) {
    188 		IF_DROP(inq);
    189 		IFQ_UNLOCK(inq);
    190 		m_freem(m);
    191 	} else {
    192 		IF_ENQUEUE(inq, m);
    193 		IFQ_UNLOCK(inq);
    194 		schednetisr(NETISR_CAN);
    195 		ifp->if_ipackets++;
    196 		ifp->if_ibytes += m->m_pkthdr.len;
    197 	}
    198 }
    199 
    200 void
    201 canintr(void)
    202 {
    203 	int		rcv_ifindex;
    204 	struct mbuf    *m;
    205 
    206 	struct sockaddr_can from;
    207 	struct canpcb   *canp;
    208 	struct m_tag	*sotag;
    209 	struct socket	*so;
    210 	struct canpcb	*sender_canp;
    211 
    212 	mutex_enter(softnet_lock);
    213 	for (;;) {
    214 		IFQ_LOCK(&canintrq);
    215 		IF_DEQUEUE(&canintrq, m);
    216 		IFQ_UNLOCK(&canintrq);
    217 
    218 		if (m == NULL)	/* no more queued packets */
    219 			break;
    220 
    221 #if 0
    222 		m_claim(m, &can_rx_mowner);
    223 #endif
    224 		sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
    225 		if (sotag) {
    226 			so = *(struct socket **)(sotag + 1);
    227 			sender_canp = sotocanpcb(so);
    228 			m_tag_delete(m, sotag);
    229 			/* if the sender doesn't want loopback, don't do it */
    230 			if (sender_canp->canp_flags & CANP_NO_LOOPBACK) {
    231 				m_freem(m);
    232 				continue;
    233 			}
    234 		} else {
    235 			sender_canp = NULL;
    236 		}
    237 		memset(&from, 0, sizeof(struct sockaddr_can));
    238 		rcv_ifindex = m->m_pkthdr.rcvif_index;
    239 		from.can_ifindex = rcv_ifindex;
    240 		from.can_len = sizeof(struct sockaddr_can);
    241 		from.can_family = AF_CAN;
    242 
    243 		TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
    244 			struct mbuf *mc;
    245 
    246 			/* don't loop back to sockets on other interfaces */
    247 			if (canp->canp_ifp != NULL &&
    248 			    canp->canp_ifp->if_index != rcv_ifindex) {
    249 				continue;
    250 			}
    251 			/* don't loop back to myself if I don't want it */
    252 			if (canp == sender_canp &&
    253 			    (canp->canp_flags & CANP_RECEIVE_OWN) == 0)
    254 				continue;
    255 
    256 			/* skip if the accept filter doen't match this pkt */
    257 			if (!can_pcbfilter(canp, m))
    258 				continue;
    259 
    260 			if (TAILQ_NEXT(canp, canp_queue) != NULL) {
    261 				/*
    262 				 * we can't be sure we won't need
    263 				 * the original mbuf later so copy
    264 				 */
    265 				mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
    266 				if (mc == NULL) {
    267 					/* deliver this mbuf and abort */
    268 					mc = m;
    269 					m = NULL;
    270 				}
    271 			} else {
    272 				mc = m;
    273 				m = NULL;
    274 			}
    275 			if (sbappendaddr(&canp->canp_socket->so_rcv,
    276 					 (struct sockaddr *) &from, mc,
    277 					 (struct mbuf *) 0) == 0) {
    278 				m_freem(mc);
    279 			} else
    280 				sorwakeup(canp->canp_socket);
    281 			if (m == NULL)
    282 				break;
    283 		}
    284 		/* If it didn't go anywhere just delete it */
    285 		if (m) {
    286 			m_freem(m);
    287 		}
    288 	}
    289 	mutex_exit(softnet_lock);
    290 }
    291 
    292 static int
    293 can_attach(struct socket *so, int proto)
    294 {
    295 	int error;
    296 
    297 	KASSERT(sotocanpcb(so) == NULL);
    298 
    299 	/* Assign the lock (must happen even if we will error out). */
    300 	sosetlock(so);
    301 
    302 #ifdef MBUFTRACE
    303 	so->so_mowner = &can_mowner;
    304 	so->so_rcv.sb_mowner = &can_rx_mowner;
    305 	so->so_snd.sb_mowner = &can_tx_mowner;
    306 #endif
    307 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
    308 		error = soreserve(so, can_sendspace, can_recvspace);
    309 		if (error) {
    310 			return error;
    311 		}
    312 	}
    313 
    314 	error = can_pcballoc(so, &cbtable);
    315 	if (error) {
    316 		return error;
    317 	}
    318 	KASSERT(solocked(so));
    319 
    320 	return error;
    321 }
    322 
    323 static void
    324 can_detach(struct socket *so)
    325 {
    326 	struct canpcb *canp;
    327 
    328 	KASSERT(solocked(so));
    329 	canp = sotocanpcb(so);
    330 	can_pcbdetach(canp);
    331 }
    332 
    333 static int
    334 can_accept(struct socket *so, struct sockaddr *nam)
    335 {
    336 	KASSERT(solocked(so));
    337 
    338 	panic("can_accept");
    339 
    340 	return EOPNOTSUPP;
    341 }
    342 
    343 static int
    344 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
    345 {
    346 	struct canpcb *canp = sotocanpcb(so);
    347 	struct sockaddr_can *scan = (struct sockaddr_can *)nam;
    348 
    349 	KASSERT(solocked(so));
    350 	KASSERT(nam != NULL);
    351 
    352 	return can_pcbbind(canp, scan, l);
    353 }
    354 
    355 static int
    356 can_listen(struct socket *so, struct lwp *l)
    357 {
    358 	KASSERT(solocked(so));
    359 
    360 	return EOPNOTSUPP;
    361 }
    362 
    363 static int
    364 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
    365 {
    366 	struct canpcb *canp = sotocanpcb(so);
    367 	int error = 0;
    368 
    369 	KASSERT(solocked(so));
    370 	KASSERT(canp != NULL);
    371 	KASSERT(nam != NULL);
    372 
    373 	error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
    374 	if (! error)
    375 		soisconnected(so);
    376 	return error;
    377 }
    378 
    379 static int
    380 can_connect2(struct socket *so, struct socket *so2)
    381 {
    382 	KASSERT(solocked(so));
    383 
    384 	return EOPNOTSUPP;
    385 }
    386 
    387 static int
    388 can_disconnect(struct socket *so)
    389 {
    390 	struct canpcb *canp = sotocanpcb(so);
    391 
    392 	KASSERT(solocked(so));
    393 	KASSERT(canp != NULL);
    394 
    395 	/*soisdisconnected(so);*/
    396 	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
    397 	can_pcbdisconnect(canp);
    398 	can_pcbstate(canp, CANP_BOUND);		/* XXX */
    399 	return 0;
    400 }
    401 
    402 static int
    403 can_shutdown(struct socket *so)
    404 {
    405 	KASSERT(solocked(so));
    406 
    407 	socantsendmore(so);
    408 	return 0;
    409 }
    410 
    411 static int
    412 can_abort(struct socket *so)
    413 {
    414 	KASSERT(solocked(so));
    415 
    416 	panic("can_abort");
    417 
    418 	return EOPNOTSUPP;
    419 }
    420 
    421 static int
    422 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
    423 {
    424 	return can_control(so, cmd, nam, ifp);
    425 }
    426 
    427 static int
    428 can_stat(struct socket *so, struct stat *ub)
    429 {
    430 	KASSERT(solocked(so));
    431 
    432 	/* stat: don't bother with a blocksize. */
    433 	return 0;
    434 }
    435 
    436 static int
    437 can_peeraddr(struct socket *so, struct sockaddr *nam)
    438 {
    439 	KASSERT(solocked(so));
    440 	KASSERT(sotocanpcb(so) != NULL);
    441 	KASSERT(nam != NULL);
    442 
    443 	return EOPNOTSUPP;
    444 }
    445 
    446 static int
    447 can_sockaddr(struct socket *so, struct sockaddr *nam)
    448 {
    449 	KASSERT(solocked(so));
    450 	KASSERT(sotocanpcb(so) != NULL);
    451 	KASSERT(nam != NULL);
    452 
    453 	can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
    454 
    455 	return 0;
    456 }
    457 
    458 static int
    459 can_rcvd(struct socket *so, int flags, struct lwp *l)
    460 {
    461 	KASSERT(solocked(so));
    462 
    463 	return EOPNOTSUPP;
    464 }
    465 
    466 static int
    467 can_recvoob(struct socket *so, struct mbuf *m, int flags)
    468 {
    469 	KASSERT(solocked(so));
    470 
    471 	return EOPNOTSUPP;
    472 }
    473 
    474 static int
    475 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
    476     struct mbuf *control, struct lwp *l)
    477 {
    478 	struct canpcb *canp = sotocanpcb(so);
    479 	int error = 0;
    480 	int s;
    481 
    482 	if (control && control->m_len) {
    483 		return EINVAL;
    484 	}
    485 
    486 	if (nam) {
    487 		if ((so->so_state & SS_ISCONNECTED) != 0) {
    488 			return EISCONN;
    489 		}
    490 		s = splnet();
    491 		error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
    492 		if (error) {
    493 			splx(s);
    494 			return error;
    495 		}
    496 	} else {
    497 		if ((so->so_state & SS_ISCONNECTED) == 0) {
    498 			return EDESTADDRREQ;
    499 		}
    500 	}
    501 	error = can_output(m, canp);
    502 	if (nam) {
    503 		struct sockaddr_can lscan;
    504 		memset(&lscan, 0, sizeof(lscan));
    505 		lscan.can_family = AF_CAN;
    506 		lscan.can_len = sizeof(lscan);
    507 		can_pcbbind(canp, &lscan, l);
    508 	}
    509 	return error;
    510 }
    511 
    512 static int
    513 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
    514 {
    515 	KASSERT(solocked(so));
    516 
    517 	m_freem(m);
    518 	m_freem(control);
    519 
    520 	return EOPNOTSUPP;
    521 }
    522 
    523 #if 0
    524 int
    525 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
    526 	   struct mbuf *control, struct lwp *l)
    527 {
    528 	struct canpcb *canp;
    529 	int s;
    530 	int error = 0;
    531 
    532 	if (req == PRU_CONTROL)
    533 		 return (can_control(so, (long)m, nam,
    534 		     (struct ifnet *)control));
    535 
    536 	if (req == PRU_PURGEIF) {
    537 #if 0
    538 		can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
    539 		can_purgeif((struct ifnet *)control);
    540 		can_pcbpurgeif(&udbtable, (struct ifnet *)control);
    541 #endif
    542 		return (0);
    543 	}
    544 
    545 	s = splsoftnet();
    546 	canp = sotocanpcb(so);
    547 #ifdef DIAGNOSTIC
    548 	if (req != PRU_SEND && req != PRU_SENDOOB && control)
    549 		panic("can_usrreq: unexpected control mbuf");
    550 #endif
    551 	if (canp == 0 && req != PRU_ATTACH) {
    552 		printf("can_usrreq: no pcb %p %d\n", canp, req);
    553 		error = EINVAL;
    554 		goto release;
    555 	}
    556 
    557 	/*
    558 	 * Note: need to block can_input while changing
    559 	 * the can pcb queue and/or pcb addresses.
    560 	 */
    561 	switch (req) {
    562 
    563 	  case PRU_ATTACH:
    564 	      if (canp != 0) {
    565 			 error = EISCONN;
    566 			 break;
    567 		 }
    568 #ifdef MBUFTRACE
    569 		so->so_mowner = &can_mowner;
    570 		so->so_rcv.sb_mowner = &can_rx_mowner;
    571 		so->so_snd.sb_mowner = &can_tx_mowner;
    572 #endif
    573 		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
    574 			error = soreserve(so, can_sendspace, can_recvspace);
    575 			if (error)
    576 				break;
    577 		}
    578 		error = can_pcballoc(so, &cbtable);
    579 		if (error)
    580 			break;
    581 		canp = sotocanpcb(so);
    582 #if 0
    583 		inp->inp_ip.ip_ttl = ip_defttl;
    584 #endif
    585 		break;
    586 
    587 	case PRU_DETACH:
    588 		can_pcbdetach(canp);
    589 		break;
    590 
    591 	case PRU_BIND:
    592 		error = can_pcbbind(canp, nam, l);
    593 		break;
    594 
    595 	case PRU_LISTEN:
    596 		error = EOPNOTSUPP;
    597 		break;
    598 
    599 	case PRU_CONNECT:
    600 		error = can_pcbconnect(canp, nam);
    601 		if (error)
    602 			break;
    603 		soisconnected(so);
    604 		break;
    605 
    606 	case PRU_CONNECT2:
    607 		error = EOPNOTSUPP;
    608 		break;
    609 
    610 	case PRU_DISCONNECT:
    611 		/*soisdisconnected(so);*/
    612 		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
    613 		can_pcbdisconnect(canp);
    614 		can_pcbstate(canp, CANP_BOUND);		/* XXX */
    615 		break;
    616 
    617 	case PRU_SHUTDOWN:
    618 		socantsendmore(so);
    619 		break;
    620 
    621 	case PRU_RCVD:
    622 		error = EOPNOTSUPP;
    623 		break;
    624 
    625 	case PRU_SEND:
    626 		break;
    627 
    628 	case PRU_SENSE:
    629 		/*
    630 		 * stat: don't bother with a blocksize.
    631 		 */
    632 		splx(s);
    633 		return (0);
    634 
    635 	case PRU_RCVOOB:
    636 		error =  EOPNOTSUPP;
    637 		break;
    638 
    639 	case PRU_SENDOOB:
    640 		m_freem(control);
    641 		m_freem(m);
    642 		error =  EOPNOTSUPP;
    643 		break;
    644 
    645 	case PRU_SOCKADDR:
    646 
    647 		break;
    648 
    649 	case PRU_PEERADDR:
    650 		error =  EOPNOTSUPP;
    651 		break;
    652 
    653 	default:
    654 		panic("can_usrreq");
    655 	}
    656 
    657 release:
    658 	splx(s);
    659 	return (error);
    660 }
    661 #endif
    662 
    663 #if 0
    664 static void
    665 can_notify(struct canpcb *canp, int errno)
    666 {
    667 
    668 	canp->canp_socket->so_error = errno;
    669 	sorwakeup(canp->canp_socket);
    670 	sowwakeup(canp->canp_socket);
    671 }
    672 
    673 void *
    674 can_ctlinput(int cmd, struct sockaddr *sa, void *v)
    675 {
    676 	struct ip *ip = v;
    677 	struct canhdr *uh;
    678 	void (*notify) __P((struct inpcb *, int)) = can_notify;
    679 	int errno;
    680 
    681 	if (sa->sa_family != AF_CAN
    682 	 || sa->sa_len != sizeof(struct sockaddr_can))
    683 		return NULL;
    684 	if ((unsigned)cmd >= PRC_NCMDS)
    685 		return NULL;
    686 	errno = inetctlerrmap[cmd];
    687 	if (PRC_IS_REDIRECT(cmd))
    688 		notify = in_rtchange, ip = 0;
    689 	else if (cmd == PRC_HOSTDEAD)
    690 		ip = 0;
    691 	else if (errno == 0)
    692 		return NULL;
    693 	if (ip) {
    694 		uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
    695 		in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
    696 		    ip->ip_src, uh->uh_sport, errno, notify);
    697 
    698 		/* XXX mapped address case */
    699 	} else
    700 		can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
    701 		    notify);
    702 	return NULL;
    703 }
    704 #endif
    705 
    706 static int
    707 can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
    708 {
    709 	int optval = 0;
    710 	int error;
    711 
    712 	switch (sopt->sopt_name) {
    713 	case CAN_RAW_LOOPBACK:
    714 		optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
    715 		error = sockopt_set(sopt, &optval, sizeof(optval));
    716 		break;
    717 	case CAN_RAW_RECV_OWN_MSGS:
    718 		optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
    719 		error = sockopt_set(sopt, &optval, sizeof(optval));
    720 		break;
    721 	case CAN_RAW_FILTER:
    722 		error = sockopt_set(sopt, canp->canp_filters,
    723 		    sizeof(struct can_filter) * canp->canp_nfilters);
    724 		break;
    725 	default:
    726 		error = ENOPROTOOPT;
    727 		break;
    728 	}
    729 	return error;
    730 }
    731 
    732 static int
    733 can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
    734 {
    735 	int optval = 0;
    736 	int error;
    737 
    738 	switch (sopt->sopt_name) {
    739 	case CAN_RAW_LOOPBACK:
    740 		error = sockopt_getint(sopt, &optval);
    741 		if (error == 0) {
    742 			if (optval) {
    743 				canp->canp_flags &= ~CANP_NO_LOOPBACK;
    744 			} else {
    745 				canp->canp_flags |= CANP_NO_LOOPBACK;
    746 			}
    747 		}
    748 		break;
    749 	case CAN_RAW_RECV_OWN_MSGS:
    750 		error = sockopt_getint(sopt, &optval);
    751 		if (error == 0) {
    752 			if (optval) {
    753 				canp->canp_flags |= CANP_RECEIVE_OWN;
    754 			} else {
    755 				canp->canp_flags &= ~CANP_RECEIVE_OWN;
    756 			}
    757 		}
    758 		break;
    759 	case CAN_RAW_FILTER:
    760 		{
    761 		int nfilters = sopt->sopt_size / sizeof(struct can_filter);
    762 		if (sopt->sopt_size % sizeof(struct can_filter) != 0)
    763 			return EINVAL;
    764 		error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
    765 		break;
    766 		}
    767 	default:
    768 		error = ENOPROTOOPT;
    769 		break;
    770 	}
    771 	return error;
    772 }
    773 
    774 /*
    775  * Called by getsockopt and setsockopt.
    776  *
    777  */
    778 int
    779 can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
    780 {
    781 	struct canpcb *canp;
    782 	int error;
    783 	int s;
    784 
    785 	if (so->so_proto->pr_domain->dom_family != PF_CAN)
    786 		return EAFNOSUPPORT;
    787 
    788 	if (sopt->sopt_level != SOL_CAN_RAW)
    789 		return EINVAL;
    790 
    791 	s = splsoftnet();
    792 	canp = sotocanpcb(so);
    793 	if (canp == NULL) {
    794 		splx(s);
    795 		return ECONNRESET;
    796 	}
    797 
    798 	if (op == PRCO_SETOPT) {
    799 		error = can_raw_setop(canp, sopt);
    800 	} else if (op ==  PRCO_GETOPT) {
    801 		error = can_raw_getop(canp, sopt);
    802 	} else {
    803 		error = EINVAL;
    804 	}
    805 	splx(s);
    806 	return error;
    807 }
    808 
    809 PR_WRAP_USRREQS(can)
    810 #define	can_attach	can_attach_wrapper
    811 #define	can_detach	can_detach_wrapper
    812 #define	can_accept	can_accept_wrapper
    813 #define	can_bind	can_bind_wrapper
    814 #define	can_listen	can_listen_wrapper
    815 #define	can_connect	can_connect_wrapper
    816 #define	can_connect2	can_connect2_wrapper
    817 #define	can_disconnect	can_disconnect_wrapper
    818 #define	can_shutdown	can_shutdown_wrapper
    819 #define	can_abort	can_abort_wrapper
    820 #define	can_ioctl	can_ioctl_wrapper
    821 #define	can_stat	can_stat_wrapper
    822 #define	can_peeraddr	can_peeraddr_wrapper
    823 #define	can_sockaddr	can_sockaddr_wrapper
    824 #define	can_rcvd	can_rcvd_wrapper
    825 #define	can_recvoob	can_recvoob_wrapper
    826 #define	can_send	can_send_wrapper
    827 #define	can_sendoob	can_sendoob_wrapper
    828 #define	can_purgeif	can_purgeif_wrapper
    829 
    830 const struct pr_usrreqs can_usrreqs = {
    831 	.pr_attach	= can_attach,
    832 	.pr_detach	= can_detach,
    833 	.pr_accept	= can_accept,
    834 	.pr_bind	= can_bind,
    835 	.pr_listen	= can_listen,
    836 	.pr_connect	= can_connect,
    837 	.pr_connect2	= can_connect2,
    838 	.pr_disconnect	= can_disconnect,
    839 	.pr_shutdown	= can_shutdown,
    840 	.pr_abort	= can_abort,
    841 	.pr_ioctl	= can_ioctl,
    842 	.pr_stat	= can_stat,
    843 	.pr_peeraddr	= can_peeraddr,
    844 	.pr_sockaddr	= can_sockaddr,
    845 	.pr_rcvd	= can_rcvd,
    846 	.pr_recvoob	= can_recvoob,
    847 	.pr_send	= can_send,
    848 	.pr_sendoob	= can_sendoob,
    849 	.pr_purgeif	= can_purgeif,
    850 };
    851