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