xref: /netbsd-src/sys/netcan/can.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /*	$NetBSD: can.c,v 1.10 2021/09/21 15:04:27 christos 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.10 2021/09/21 15:04:27 christos 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(kauth_cred_get(),
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 		if_statinc(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 		if_statadd2(ifp, if_ipackets, 1, if_ibytes, m->m_pkthdr.len);
311 		schednetisr(NETISR_CAN);
312 	}
313 }
314 
315 void
316 canintr(void)
317 {
318 	int		rcv_ifindex;
319 	struct mbuf    *m;
320 
321 	struct sockaddr_can from;
322 	struct canpcb   *canp;
323 	struct m_tag	*sotag;
324 	struct canpcb	*sender_canp;
325 
326 	mutex_enter(softnet_lock);
327 	for (;;) {
328 		IFQ_LOCK(&canintrq);
329 		IF_DEQUEUE(&canintrq, m);
330 		IFQ_UNLOCK(&canintrq);
331 
332 		if (m == NULL)	/* no more queued packets */
333 			break;
334 
335 #if 0
336 		m_claim(m, &can_rx_mowner);
337 #endif
338 		sotag = m_tag_find(m, PACKET_TAG_SO);
339 		if (sotag) {
340 			sender_canp = *(struct canpcb **)(sotag + 1);
341 			m_tag_delete(m, sotag);
342 			KASSERT(sender_canp != NULL);
343 			/* if the sender doesn't want loopback, don't do it */
344 			if ((sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) {
345 				m_freem(m);
346 				canp_unref(sender_canp);
347 				continue;
348 			}
349 		} else {
350 			sender_canp = NULL;
351 		}
352 		memset(&from, 0, sizeof(struct sockaddr_can));
353 		rcv_ifindex = m->m_pkthdr.rcvif_index;
354 		from.can_ifindex = rcv_ifindex;
355 		from.can_len = sizeof(struct sockaddr_can);
356 		from.can_family = AF_CAN;
357 
358 		TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
359 			struct mbuf *mc;
360 
361 			mutex_enter(&canp->canp_mtx);
362 			/* skip if we're detached */
363 			if (canp->canp_state == CANP_DETACHED) {
364 				mutex_exit(&canp->canp_mtx);
365 				continue;
366 			}
367 
368 			/* don't loop back to sockets on other interfaces */
369 			if (canp->canp_ifp != NULL &&
370 			    canp->canp_ifp->if_index != rcv_ifindex) {
371 				mutex_exit(&canp->canp_mtx);
372 				continue;
373 			}
374 			/* don't loop back to myself if I don't want it */
375 			if (canp == sender_canp &&
376 			    (canp->canp_flags & CANP_RECEIVE_OWN) == 0) {
377 				mutex_exit(&canp->canp_mtx);
378 				continue;
379 			}
380 
381 			/* skip if the accept filter doen't match this pkt */
382 			if (!can_pcbfilter(canp, m)) {
383 				mutex_exit(&canp->canp_mtx);
384 				continue;
385 			}
386 
387 			if (TAILQ_NEXT(canp, canp_queue) != NULL) {
388 				/*
389 				 * we can't be sure we won't need
390 				 * the original mbuf later so copy
391 				 */
392 				mc = m_copypacket(m, M_NOWAIT);
393 				if (mc == NULL) {
394 					/* deliver this mbuf and abort */
395 					mc = m;
396 					m = NULL;
397 				}
398 			} else {
399 				mc = m;
400 				m = NULL;
401 			}
402 			if (sbappendaddr(&canp->canp_socket->so_rcv,
403 					 (struct sockaddr *) &from, mc,
404 					 (struct mbuf *) 0) == 0) {
405 				soroverflow(canp->canp_socket);
406 				m_freem(mc);
407 			} else
408 				sorwakeup(canp->canp_socket);
409 			mutex_exit(&canp->canp_mtx);
410 			if (m == NULL)
411 				break;
412 		}
413 		if (sender_canp) {
414 			canp_unref(sender_canp);
415 		}
416 		/* If it didn't go anywhere just delete it */
417 		if (m) {
418 			m_freem(m);
419 		}
420 	}
421 	mutex_exit(softnet_lock);
422 }
423 
424 void
425 can_bpf_mtap(struct ifnet *ifp, struct mbuf *m, bool do_softint)
426 {
427 	/* bpf wants the CAN id in network byte order */
428 	struct can_frame *cf;
429 	canid_t oid;
430 
431 	cf = mtod(m, struct can_frame *);
432 	oid = cf->can_id;
433 	cf->can_id = htonl(oid);
434 	/* Assume the direction is input when do_softint is set. */
435 	if (do_softint)
436 		bpf_mtap_softint(ifp, m);
437 	else
438 		bpf_mtap(ifp, m, BPF_D_OUT);
439 	cf->can_id = oid;
440 }
441 
442 static int
443 can_attach(struct socket *so, int proto)
444 {
445 	int error;
446 
447 	KASSERT(sotocanpcb(so) == NULL);
448 
449 	/* Assign the lock (must happen even if we will error out). */
450 	sosetlock(so);
451 
452 #ifdef MBUFTRACE
453 	so->so_mowner = &can_mowner;
454 	so->so_rcv.sb_mowner = &can_rx_mowner;
455 	so->so_snd.sb_mowner = &can_tx_mowner;
456 #endif
457 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
458 		error = soreserve(so, can_sendspace, can_recvspace);
459 		if (error) {
460 			return error;
461 		}
462 	}
463 
464 	error = can_pcballoc(so, &cbtable);
465 	if (error) {
466 		return error;
467 	}
468 	KASSERT(solocked(so));
469 
470 	return error;
471 }
472 
473 static void
474 can_detach(struct socket *so)
475 {
476 	struct canpcb *canp;
477 
478 	KASSERT(solocked(so));
479 	canp = sotocanpcb(so);
480 	can_pcbdetach(canp);
481 }
482 
483 static int
484 can_accept(struct socket *so, struct sockaddr *nam)
485 {
486 	KASSERT(solocked(so));
487 
488 	panic("can_accept");
489 
490 	return EOPNOTSUPP;
491 }
492 
493 static int
494 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
495 {
496 	struct canpcb *canp = sotocanpcb(so);
497 	struct sockaddr_can *scan = (struct sockaddr_can *)nam;
498 
499 	KASSERT(solocked(so));
500 	KASSERT(nam != NULL);
501 
502 	return can_pcbbind(canp, scan, l);
503 }
504 
505 static int
506 can_listen(struct socket *so, struct lwp *l)
507 {
508 	KASSERT(solocked(so));
509 
510 	return EOPNOTSUPP;
511 }
512 
513 static int
514 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
515 {
516 	struct canpcb *canp = sotocanpcb(so);
517 	int error = 0;
518 
519 	KASSERT(solocked(so));
520 	KASSERT(canp != NULL);
521 	KASSERT(nam != NULL);
522 
523 	error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
524 	if (! error)
525 		soisconnected(so);
526 	return error;
527 }
528 
529 static int
530 can_connect2(struct socket *so, struct socket *so2)
531 {
532 	KASSERT(solocked(so));
533 
534 	return EOPNOTSUPP;
535 }
536 
537 static int
538 can_disconnect(struct socket *so)
539 {
540 	struct canpcb *canp = sotocanpcb(so);
541 
542 	KASSERT(solocked(so));
543 	KASSERT(canp != NULL);
544 
545 	/*soisdisconnected(so);*/
546 	so->so_state &= ~SS_ISCONNECTED;	/* XXX */
547 	can_pcbdisconnect(canp);
548 	return 0;
549 }
550 
551 static int
552 can_shutdown(struct socket *so)
553 {
554 	KASSERT(solocked(so));
555 
556 	socantsendmore(so);
557 	return 0;
558 }
559 
560 static int
561 can_abort(struct socket *so)
562 {
563 	KASSERT(solocked(so));
564 
565 	panic("can_abort");
566 
567 	return EOPNOTSUPP;
568 }
569 
570 static int
571 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
572 {
573 	return can_control(so, cmd, nam, ifp);
574 }
575 
576 static int
577 can_stat(struct socket *so, struct stat *ub)
578 {
579 	KASSERT(solocked(so));
580 
581 	/* stat: don't bother with a blocksize. */
582 	return 0;
583 }
584 
585 static int
586 can_peeraddr(struct socket *so, struct sockaddr *nam)
587 {
588 	KASSERT(solocked(so));
589 	KASSERT(sotocanpcb(so) != NULL);
590 	KASSERT(nam != NULL);
591 
592 	return EOPNOTSUPP;
593 }
594 
595 static int
596 can_sockaddr(struct socket *so, struct sockaddr *nam)
597 {
598 	KASSERT(solocked(so));
599 	KASSERT(sotocanpcb(so) != NULL);
600 	KASSERT(nam != NULL);
601 
602 	can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
603 
604 	return 0;
605 }
606 
607 static int
608 can_rcvd(struct socket *so, int flags, struct lwp *l)
609 {
610 	KASSERT(solocked(so));
611 
612 	return EOPNOTSUPP;
613 }
614 
615 static int
616 can_recvoob(struct socket *so, struct mbuf *m, int flags)
617 {
618 	KASSERT(solocked(so));
619 
620 	return EOPNOTSUPP;
621 }
622 
623 static int
624 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
625     struct mbuf *control, struct lwp *l)
626 {
627 	struct canpcb *canp = sotocanpcb(so);
628 	int error = 0;
629 	int s;
630 
631 	if (control && control->m_len) {
632 		m_freem(control);
633 		error = EINVAL;
634 		goto err;
635 	}
636 	if (m->m_len > sizeof(struct can_frame) ||
637 	   m->m_len < offsetof(struct can_frame, can_dlc)) {
638 		error = EINVAL;
639 		goto err;
640 	}
641 
642 	/* we expect all data in the first mbuf */
643 	KASSERT((m->m_flags & M_PKTHDR) != 0);
644 	KASSERT(m->m_len == m->m_pkthdr.len);
645 
646 	if (nam) {
647 		if ((so->so_state & SS_ISCONNECTED) != 0) {
648 			error = EISCONN;
649 			goto err;
650 		}
651 		s = splnet();
652 		error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
653 		if (error) {
654 			splx(s);
655 			goto err;
656 		}
657 	} else {
658 		if ((so->so_state & SS_ISCONNECTED) == 0) {
659 			error =  EDESTADDRREQ;
660 			goto err;
661 		}
662 	}
663 	error = can_output(m, canp);
664 	if (nam) {
665 		struct sockaddr_can lscan;
666 		memset(&lscan, 0, sizeof(lscan));
667 		lscan.can_family = AF_CAN;
668 		lscan.can_len = sizeof(lscan);
669 		can_pcbbind(canp, &lscan, l);
670 	}
671 	if (error)
672 		goto err;
673 	return 0;
674 
675 err:
676 	m_freem(m);
677 	return error;
678 }
679 
680 static int
681 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
682 {
683 	KASSERT(solocked(so));
684 
685 	m_freem(m);
686 	m_freem(control);
687 
688 	return EOPNOTSUPP;
689 }
690 
691 #if 0
692 int
693 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
694 	   struct mbuf *control, struct lwp *l)
695 {
696 	struct canpcb *canp;
697 	int s;
698 	int error = 0;
699 
700 	if (req == PRU_CONTROL)
701 		 return (can_control(so, (long)m, nam,
702 		     (struct ifnet *)control));
703 
704 	if (req == PRU_PURGEIF) {
705 #if 0
706 		can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
707 		can_purgeif((struct ifnet *)control);
708 		can_pcbpurgeif(&udbtable, (struct ifnet *)control);
709 #endif
710 		return (0);
711 	}
712 
713 	s = splsoftnet();
714 	canp = sotocanpcb(so);
715 #ifdef DIAGNOSTIC
716 	if (req != PRU_SEND && req != PRU_SENDOOB && control)
717 		panic("can_usrreq: unexpected control mbuf");
718 #endif
719 	if (canp == 0 && req != PRU_ATTACH) {
720 		printf("can_usrreq: no pcb %p %d\n", canp, req);
721 		error = EINVAL;
722 		goto release;
723 	}
724 
725 	/*
726 	 * Note: need to block can_input while changing
727 	 * the can pcb queue and/or pcb addresses.
728 	 */
729 	switch (req) {
730 
731 	  case PRU_ATTACH:
732 	      if (canp != 0) {
733 			 error = EISCONN;
734 			 break;
735 		 }
736 #ifdef MBUFTRACE
737 		so->so_mowner = &can_mowner;
738 		so->so_rcv.sb_mowner = &can_rx_mowner;
739 		so->so_snd.sb_mowner = &can_tx_mowner;
740 #endif
741 		if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
742 			error = soreserve(so, can_sendspace, can_recvspace);
743 			if (error)
744 				break;
745 		}
746 		error = can_pcballoc(so, &cbtable);
747 		if (error)
748 			break;
749 		canp = sotocanpcb(so);
750 #if 0
751 		inp->inp_ip.ip_ttl = ip_defttl;
752 #endif
753 		break;
754 
755 	case PRU_DETACH:
756 		can_pcbdetach(canp);
757 		break;
758 
759 	case PRU_BIND:
760 		error = can_pcbbind(canp, nam, l);
761 		break;
762 
763 	case PRU_LISTEN:
764 		error = EOPNOTSUPP;
765 		break;
766 
767 	case PRU_CONNECT:
768 		error = can_pcbconnect(canp, nam);
769 		if (error)
770 			break;
771 		soisconnected(so);
772 		break;
773 
774 	case PRU_CONNECT2:
775 		error = EOPNOTSUPP;
776 		break;
777 
778 	case PRU_DISCONNECT:
779 		/*soisdisconnected(so);*/
780 		so->so_state &= ~SS_ISCONNECTED;	/* XXX */
781 		can_pcbdisconnect(canp);
782 		can_pcbstate(canp, CANP_BOUND);		/* XXX */
783 		break;
784 
785 	case PRU_SHUTDOWN:
786 		socantsendmore(so);
787 		break;
788 
789 	case PRU_RCVD:
790 		error = EOPNOTSUPP;
791 		break;
792 
793 	case PRU_SEND:
794 		break;
795 
796 	case PRU_SENSE:
797 		/*
798 		 * stat: don't bother with a blocksize.
799 		 */
800 		splx(s);
801 		return (0);
802 
803 	case PRU_RCVOOB:
804 		error =  EOPNOTSUPP;
805 		break;
806 
807 	case PRU_SENDOOB:
808 		m_freem(control);
809 		m_freem(m);
810 		error =  EOPNOTSUPP;
811 		break;
812 
813 	case PRU_SOCKADDR:
814 
815 		break;
816 
817 	case PRU_PEERADDR:
818 		error =  EOPNOTSUPP;
819 		break;
820 
821 	default:
822 		panic("can_usrreq");
823 	}
824 
825 release:
826 	splx(s);
827 	return (error);
828 }
829 #endif
830 
831 #if 0
832 static void
833 can_notify(struct canpcb *canp, int errno)
834 {
835 
836 	canp->canp_socket->so_error = errno;
837 	sorwakeup(canp->canp_socket);
838 	sowwakeup(canp->canp_socket);
839 }
840 
841 void *
842 can_ctlinput(int cmd, struct sockaddr *sa, void *v)
843 {
844 	struct ip *ip = v;
845 	struct canhdr *uh;
846 	void (*notify) __P((struct inpcb *, int)) = can_notify;
847 	int errno;
848 
849 	if (sa->sa_family != AF_CAN
850 	 || sa->sa_len != sizeof(struct sockaddr_can))
851 		return NULL;
852 	if ((unsigned)cmd >= PRC_NCMDS)
853 		return NULL;
854 	errno = inetctlerrmap[cmd];
855 	if (PRC_IS_REDIRECT(cmd))
856 		notify = in_rtchange, ip = 0;
857 	else if (cmd == PRC_HOSTDEAD)
858 		ip = 0;
859 	else if (errno == 0)
860 		return NULL;
861 	if (ip) {
862 		uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
863 		in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
864 		    ip->ip_src, uh->uh_sport, errno, notify);
865 
866 		/* XXX mapped address case */
867 	} else
868 		can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
869 		    notify);
870 	return NULL;
871 }
872 #endif
873 
874 static int
875 can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
876 {
877 	int optval = 0;
878 	int error;
879 
880 	switch (sopt->sopt_name) {
881 	case CAN_RAW_LOOPBACK:
882 		optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
883 		error = sockopt_set(sopt, &optval, sizeof(optval));
884 		break;
885 	case CAN_RAW_RECV_OWN_MSGS:
886 		optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
887 		error = sockopt_set(sopt, &optval, sizeof(optval));
888 		break;
889 	case CAN_RAW_FILTER:
890 		error = sockopt_set(sopt, canp->canp_filters,
891 		    sizeof(struct can_filter) * canp->canp_nfilters);
892 		break;
893 	default:
894 		error = ENOPROTOOPT;
895 		break;
896 	}
897 	return error;
898 }
899 
900 static int
901 can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
902 {
903 	int optval = 0;
904 	int error;
905 
906 	switch (sopt->sopt_name) {
907 	case CAN_RAW_LOOPBACK:
908 		error = sockopt_getint(sopt, &optval);
909 		if (error == 0) {
910 			if (optval) {
911 				canp->canp_flags &= ~CANP_NO_LOOPBACK;
912 			} else {
913 				canp->canp_flags |= CANP_NO_LOOPBACK;
914 			}
915 		}
916 		break;
917 	case CAN_RAW_RECV_OWN_MSGS:
918 		error = sockopt_getint(sopt, &optval);
919 		if (error == 0) {
920 			if (optval) {
921 				canp->canp_flags |= CANP_RECEIVE_OWN;
922 			} else {
923 				canp->canp_flags &= ~CANP_RECEIVE_OWN;
924 			}
925 		}
926 		break;
927 	case CAN_RAW_FILTER:
928 		{
929 		int nfilters = sopt->sopt_size / sizeof(struct can_filter);
930 		if (sopt->sopt_size % sizeof(struct can_filter) != 0)
931 			return EINVAL;
932 		error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
933 		break;
934 		}
935 	default:
936 		error = ENOPROTOOPT;
937 		break;
938 	}
939 	return error;
940 }
941 
942 /*
943  * Called by getsockopt and setsockopt.
944  *
945  */
946 int
947 can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
948 {
949 	struct canpcb *canp;
950 	int error;
951 	int s;
952 
953 	if (so->so_proto->pr_domain->dom_family != PF_CAN)
954 		return EAFNOSUPPORT;
955 
956 	if (sopt->sopt_level != SOL_CAN_RAW)
957 		return EINVAL;
958 
959 	s = splsoftnet();
960 	canp = sotocanpcb(so);
961 	if (canp == NULL) {
962 		splx(s);
963 		return ECONNRESET;
964 	}
965 
966 	if (op == PRCO_SETOPT) {
967 		error = can_raw_setop(canp, sopt);
968 	} else if (op ==  PRCO_GETOPT) {
969 		error = can_raw_getop(canp, sopt);
970 	} else {
971 		error = EINVAL;
972 	}
973 	splx(s);
974 	return error;
975 }
976 
977 PR_WRAP_USRREQS(can)
978 #define	can_attach	can_attach_wrapper
979 #define	can_detach	can_detach_wrapper
980 #define	can_accept	can_accept_wrapper
981 #define	can_bind	can_bind_wrapper
982 #define	can_listen	can_listen_wrapper
983 #define	can_connect	can_connect_wrapper
984 #define	can_connect2	can_connect2_wrapper
985 #define	can_disconnect	can_disconnect_wrapper
986 #define	can_shutdown	can_shutdown_wrapper
987 #define	can_abort	can_abort_wrapper
988 #define	can_ioctl	can_ioctl_wrapper
989 #define	can_stat	can_stat_wrapper
990 #define	can_peeraddr	can_peeraddr_wrapper
991 #define	can_sockaddr	can_sockaddr_wrapper
992 #define	can_rcvd	can_rcvd_wrapper
993 #define	can_recvoob	can_recvoob_wrapper
994 #define	can_send	can_send_wrapper
995 #define	can_sendoob	can_sendoob_wrapper
996 #define	can_purgeif	can_purgeif_wrapper
997 
998 const struct pr_usrreqs can_usrreqs = {
999 	.pr_attach	= can_attach,
1000 	.pr_detach	= can_detach,
1001 	.pr_accept	= can_accept,
1002 	.pr_bind	= can_bind,
1003 	.pr_listen	= can_listen,
1004 	.pr_connect	= can_connect,
1005 	.pr_connect2	= can_connect2,
1006 	.pr_disconnect	= can_disconnect,
1007 	.pr_shutdown	= can_shutdown,
1008 	.pr_abort	= can_abort,
1009 	.pr_ioctl	= can_ioctl,
1010 	.pr_stat	= can_stat,
1011 	.pr_peeraddr	= can_peeraddr,
1012 	.pr_sockaddr	= can_sockaddr,
1013 	.pr_rcvd	= can_rcvd,
1014 	.pr_recvoob	= can_recvoob,
1015 	.pr_send	= can_send,
1016 	.pr_sendoob	= can_sendoob,
1017 	.pr_purgeif	= can_purgeif,
1018 };
1019