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