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