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