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