can.c revision 1.13.6.1 1 /* $NetBSD: can.c,v 1.13.6.1 2023/11/15 02:08:34 thorpej 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.6.1 2023/11/15 02:08:34 thorpej 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 if_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