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