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
57struct canpcb canpcb;
58#if 0
59struct canpcb canrawpcb;
60#endif
61
62struct	canpcbtable cbtable;
63
64pktqueue_t *		can_pktq		__read_mostly;
65int	canqmaxlen = IFQ_MAXLEN;
66
67int can_copy_output = 0;
68int can_output_cnt = 0;
69struct mbuf *can_lastout;
70
71int	can_sendspace = 4096;		/* really max datagram size */
72int	can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
73					/* 40 1K datagrams */
74#ifndef CANHASHSIZE
75#define	CANHASHSIZE	128
76#endif
77int	canhashsize = CANHASHSIZE;
78
79#ifdef MBUFTRACE
80static struct mowner can_mowner = MOWNER_INIT("can", "");
81static struct mowner can_rx_mowner = MOWNER_INIT("can", "rx");
82static struct mowner can_tx_mowner = MOWNER_INIT("can", "tx");
83#endif
84
85static int can_output(struct mbuf *, struct canpcb *);
86
87static int can_control(struct socket *, u_long, void *, struct ifnet *);
88
89static void canintr(void *);
90
91void
92can_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 */
103static int
104can_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
128static int
129can_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 */
175static int
176can_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
198static int
199can_purgeif(struct socket *so, struct ifnet *ifp)
200{
201	return 0;
202}
203
204void
205can_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
219void
220can_ifdetach(struct ifnet *ifp)
221{
222	bpf_detach(ifp);
223	if_detach(ifp);
224}
225
226void
227can_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
233static int
234can_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 */
274void
275can_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 */
293void
294can_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
309static void
310canintr(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
411void
412can_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
429static int
430can_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
460static void
461can_detach(struct socket *so)
462{
463	struct canpcb *canp;
464
465	KASSERT(solocked(so));
466	canp = sotocanpcb(so);
467	can_pcbdetach(canp);
468}
469
470static int
471can_accept(struct socket *so, struct sockaddr *nam)
472{
473	KASSERT(solocked(so));
474
475	panic("can_accept");
476
477	return EOPNOTSUPP;
478}
479
480static int
481can_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
492static int
493can_listen(struct socket *so, struct lwp *l)
494{
495	KASSERT(solocked(so));
496
497	return EOPNOTSUPP;
498}
499
500static int
501can_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
516static int
517can_connect2(struct socket *so, struct socket *so2)
518{
519	KASSERT(solocked(so));
520
521	return EOPNOTSUPP;
522}
523
524static int
525can_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
538static int
539can_shutdown(struct socket *so)
540{
541	KASSERT(solocked(so));
542
543	socantsendmore(so);
544	return 0;
545}
546
547static int
548can_abort(struct socket *so)
549{
550	KASSERT(solocked(so));
551
552	panic("can_abort");
553
554	return EOPNOTSUPP;
555}
556
557static int
558can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
559{
560	return can_control(so, cmd, nam, ifp);
561}
562
563static int
564can_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
572static int
573can_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
582static int
583can_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
594static int
595can_rcvd(struct socket *so, int flags, struct lwp *l)
596{
597	KASSERT(solocked(so));
598
599	return EOPNOTSUPP;
600}
601
602static int
603can_recvoob(struct socket *so, struct mbuf *m, int flags)
604{
605	KASSERT(solocked(so));
606
607	return EOPNOTSUPP;
608}
609
610static int
611can_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
662err:
663	m_freem(m);
664	return error;
665}
666
667static int
668can_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
679int
680can_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
812release:
813	splx(s);
814	return (error);
815}
816#endif
817
818#if 0
819static void
820can_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
828void *
829can_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
861static int
862can_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
887static int
888can_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 */
933int
934can_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
964PR_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
985const 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