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