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