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