can.c revision 1.2.10.2 1 /* $NetBSD: can.c,v 1.2.10.2 2017/12/03 11:39:03 jdolecek 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.2.10.2 2017/12/03 11:39:03 jdolecek 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_nonpersistent(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 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 if (do_softint)
429 bpf_mtap_softint(ifp, m);
430 else
431 bpf_mtap(ifp, m);
432 cf->can_id = oid;
433 }
434
435 static int
436 can_attach(struct socket *so, int proto)
437 {
438 int error;
439
440 KASSERT(sotocanpcb(so) == NULL);
441
442 /* Assign the lock (must happen even if we will error out). */
443 sosetlock(so);
444
445 #ifdef MBUFTRACE
446 so->so_mowner = &can_mowner;
447 so->so_rcv.sb_mowner = &can_rx_mowner;
448 so->so_snd.sb_mowner = &can_tx_mowner;
449 #endif
450 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
451 error = soreserve(so, can_sendspace, can_recvspace);
452 if (error) {
453 return error;
454 }
455 }
456
457 error = can_pcballoc(so, &cbtable);
458 if (error) {
459 return error;
460 }
461 KASSERT(solocked(so));
462
463 return error;
464 }
465
466 static void
467 can_detach(struct socket *so)
468 {
469 struct canpcb *canp;
470
471 KASSERT(solocked(so));
472 canp = sotocanpcb(so);
473 can_pcbdetach(canp);
474 }
475
476 static int
477 can_accept(struct socket *so, struct sockaddr *nam)
478 {
479 KASSERT(solocked(so));
480
481 panic("can_accept");
482
483 return EOPNOTSUPP;
484 }
485
486 static int
487 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
488 {
489 struct canpcb *canp = sotocanpcb(so);
490 struct sockaddr_can *scan = (struct sockaddr_can *)nam;
491
492 KASSERT(solocked(so));
493 KASSERT(nam != NULL);
494
495 return can_pcbbind(canp, scan, l);
496 }
497
498 static int
499 can_listen(struct socket *so, struct lwp *l)
500 {
501 KASSERT(solocked(so));
502
503 return EOPNOTSUPP;
504 }
505
506 static int
507 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
508 {
509 struct canpcb *canp = sotocanpcb(so);
510 int error = 0;
511
512 KASSERT(solocked(so));
513 KASSERT(canp != NULL);
514 KASSERT(nam != NULL);
515
516 error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
517 if (! error)
518 soisconnected(so);
519 return error;
520 }
521
522 static int
523 can_connect2(struct socket *so, struct socket *so2)
524 {
525 KASSERT(solocked(so));
526
527 return EOPNOTSUPP;
528 }
529
530 static int
531 can_disconnect(struct socket *so)
532 {
533 struct canpcb *canp = sotocanpcb(so);
534
535 KASSERT(solocked(so));
536 KASSERT(canp != NULL);
537
538 /*soisdisconnected(so);*/
539 so->so_state &= ~SS_ISCONNECTED; /* XXX */
540 can_pcbdisconnect(canp);
541 return 0;
542 }
543
544 static int
545 can_shutdown(struct socket *so)
546 {
547 KASSERT(solocked(so));
548
549 socantsendmore(so);
550 return 0;
551 }
552
553 static int
554 can_abort(struct socket *so)
555 {
556 KASSERT(solocked(so));
557
558 panic("can_abort");
559
560 return EOPNOTSUPP;
561 }
562
563 static int
564 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
565 {
566 return can_control(so, cmd, nam, ifp);
567 }
568
569 static int
570 can_stat(struct socket *so, struct stat *ub)
571 {
572 KASSERT(solocked(so));
573
574 /* stat: don't bother with a blocksize. */
575 return 0;
576 }
577
578 static int
579 can_peeraddr(struct socket *so, struct sockaddr *nam)
580 {
581 KASSERT(solocked(so));
582 KASSERT(sotocanpcb(so) != NULL);
583 KASSERT(nam != NULL);
584
585 return EOPNOTSUPP;
586 }
587
588 static int
589 can_sockaddr(struct socket *so, struct sockaddr *nam)
590 {
591 KASSERT(solocked(so));
592 KASSERT(sotocanpcb(so) != NULL);
593 KASSERT(nam != NULL);
594
595 can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
596
597 return 0;
598 }
599
600 static int
601 can_rcvd(struct socket *so, int flags, struct lwp *l)
602 {
603 KASSERT(solocked(so));
604
605 return EOPNOTSUPP;
606 }
607
608 static int
609 can_recvoob(struct socket *so, struct mbuf *m, int flags)
610 {
611 KASSERT(solocked(so));
612
613 return EOPNOTSUPP;
614 }
615
616 static int
617 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
618 struct mbuf *control, struct lwp *l)
619 {
620 struct canpcb *canp = sotocanpcb(so);
621 int error = 0;
622 int s;
623
624 if (control && control->m_len) {
625 m_freem(control);
626 error = EINVAL;
627 goto err;
628 }
629 if (m->m_len > sizeof(struct can_frame) ||
630 m->m_len < offsetof(struct can_frame, can_dlc)) {
631 error = EINVAL;
632 goto err;
633 }
634
635 /* we expect all data in the first mbuf */
636 KASSERT((m->m_flags & M_PKTHDR) != 0);
637 KASSERT(m->m_len == m->m_pkthdr.len);
638
639 if (nam) {
640 if ((so->so_state & SS_ISCONNECTED) != 0) {
641 error = EISCONN;
642 goto err;
643 }
644 s = splnet();
645 error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
646 if (error) {
647 splx(s);
648 goto err;
649 }
650 } else {
651 if ((so->so_state & SS_ISCONNECTED) == 0) {
652 error = EDESTADDRREQ;
653 goto err;
654 }
655 }
656 error = can_output(m, canp);
657 if (nam) {
658 struct sockaddr_can lscan;
659 memset(&lscan, 0, sizeof(lscan));
660 lscan.can_family = AF_CAN;
661 lscan.can_len = sizeof(lscan);
662 can_pcbbind(canp, &lscan, l);
663 }
664 if (error)
665 goto err;
666 return 0;
667
668 err:
669 m_freem(m);
670 return error;
671 }
672
673 static int
674 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
675 {
676 KASSERT(solocked(so));
677
678 m_freem(m);
679 m_freem(control);
680
681 return EOPNOTSUPP;
682 }
683
684 #if 0
685 int
686 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
687 struct mbuf *control, struct lwp *l)
688 {
689 struct canpcb *canp;
690 int s;
691 int error = 0;
692
693 if (req == PRU_CONTROL)
694 return (can_control(so, (long)m, nam,
695 (struct ifnet *)control));
696
697 if (req == PRU_PURGEIF) {
698 #if 0
699 can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
700 can_purgeif((struct ifnet *)control);
701 can_pcbpurgeif(&udbtable, (struct ifnet *)control);
702 #endif
703 return (0);
704 }
705
706 s = splsoftnet();
707 canp = sotocanpcb(so);
708 #ifdef DIAGNOSTIC
709 if (req != PRU_SEND && req != PRU_SENDOOB && control)
710 panic("can_usrreq: unexpected control mbuf");
711 #endif
712 if (canp == 0 && req != PRU_ATTACH) {
713 printf("can_usrreq: no pcb %p %d\n", canp, req);
714 error = EINVAL;
715 goto release;
716 }
717
718 /*
719 * Note: need to block can_input while changing
720 * the can pcb queue and/or pcb addresses.
721 */
722 switch (req) {
723
724 case PRU_ATTACH:
725 if (canp != 0) {
726 error = EISCONN;
727 break;
728 }
729 #ifdef MBUFTRACE
730 so->so_mowner = &can_mowner;
731 so->so_rcv.sb_mowner = &can_rx_mowner;
732 so->so_snd.sb_mowner = &can_tx_mowner;
733 #endif
734 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
735 error = soreserve(so, can_sendspace, can_recvspace);
736 if (error)
737 break;
738 }
739 error = can_pcballoc(so, &cbtable);
740 if (error)
741 break;
742 canp = sotocanpcb(so);
743 #if 0
744 inp->inp_ip.ip_ttl = ip_defttl;
745 #endif
746 break;
747
748 case PRU_DETACH:
749 can_pcbdetach(canp);
750 break;
751
752 case PRU_BIND:
753 error = can_pcbbind(canp, nam, l);
754 break;
755
756 case PRU_LISTEN:
757 error = EOPNOTSUPP;
758 break;
759
760 case PRU_CONNECT:
761 error = can_pcbconnect(canp, nam);
762 if (error)
763 break;
764 soisconnected(so);
765 break;
766
767 case PRU_CONNECT2:
768 error = EOPNOTSUPP;
769 break;
770
771 case PRU_DISCONNECT:
772 /*soisdisconnected(so);*/
773 so->so_state &= ~SS_ISCONNECTED; /* XXX */
774 can_pcbdisconnect(canp);
775 can_pcbstate(canp, CANP_BOUND); /* XXX */
776 break;
777
778 case PRU_SHUTDOWN:
779 socantsendmore(so);
780 break;
781
782 case PRU_RCVD:
783 error = EOPNOTSUPP;
784 break;
785
786 case PRU_SEND:
787 break;
788
789 case PRU_SENSE:
790 /*
791 * stat: don't bother with a blocksize.
792 */
793 splx(s);
794 return (0);
795
796 case PRU_RCVOOB:
797 error = EOPNOTSUPP;
798 break;
799
800 case PRU_SENDOOB:
801 m_freem(control);
802 m_freem(m);
803 error = EOPNOTSUPP;
804 break;
805
806 case PRU_SOCKADDR:
807
808 break;
809
810 case PRU_PEERADDR:
811 error = EOPNOTSUPP;
812 break;
813
814 default:
815 panic("can_usrreq");
816 }
817
818 release:
819 splx(s);
820 return (error);
821 }
822 #endif
823
824 #if 0
825 static void
826 can_notify(struct canpcb *canp, int errno)
827 {
828
829 canp->canp_socket->so_error = errno;
830 sorwakeup(canp->canp_socket);
831 sowwakeup(canp->canp_socket);
832 }
833
834 void *
835 can_ctlinput(int cmd, struct sockaddr *sa, void *v)
836 {
837 struct ip *ip = v;
838 struct canhdr *uh;
839 void (*notify) __P((struct inpcb *, int)) = can_notify;
840 int errno;
841
842 if (sa->sa_family != AF_CAN
843 || sa->sa_len != sizeof(struct sockaddr_can))
844 return NULL;
845 if ((unsigned)cmd >= PRC_NCMDS)
846 return NULL;
847 errno = inetctlerrmap[cmd];
848 if (PRC_IS_REDIRECT(cmd))
849 notify = in_rtchange, ip = 0;
850 else if (cmd == PRC_HOSTDEAD)
851 ip = 0;
852 else if (errno == 0)
853 return NULL;
854 if (ip) {
855 uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
856 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
857 ip->ip_src, uh->uh_sport, errno, notify);
858
859 /* XXX mapped address case */
860 } else
861 can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
862 notify);
863 return NULL;
864 }
865 #endif
866
867 static int
868 can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
869 {
870 int optval = 0;
871 int error;
872
873 switch (sopt->sopt_name) {
874 case CAN_RAW_LOOPBACK:
875 optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
876 error = sockopt_set(sopt, &optval, sizeof(optval));
877 break;
878 case CAN_RAW_RECV_OWN_MSGS:
879 optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
880 error = sockopt_set(sopt, &optval, sizeof(optval));
881 break;
882 case CAN_RAW_FILTER:
883 error = sockopt_set(sopt, canp->canp_filters,
884 sizeof(struct can_filter) * canp->canp_nfilters);
885 break;
886 default:
887 error = ENOPROTOOPT;
888 break;
889 }
890 return error;
891 }
892
893 static int
894 can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
895 {
896 int optval = 0;
897 int error;
898
899 switch (sopt->sopt_name) {
900 case CAN_RAW_LOOPBACK:
901 error = sockopt_getint(sopt, &optval);
902 if (error == 0) {
903 if (optval) {
904 canp->canp_flags &= ~CANP_NO_LOOPBACK;
905 } else {
906 canp->canp_flags |= CANP_NO_LOOPBACK;
907 }
908 }
909 break;
910 case CAN_RAW_RECV_OWN_MSGS:
911 error = sockopt_getint(sopt, &optval);
912 if (error == 0) {
913 if (optval) {
914 canp->canp_flags |= CANP_RECEIVE_OWN;
915 } else {
916 canp->canp_flags &= ~CANP_RECEIVE_OWN;
917 }
918 }
919 break;
920 case CAN_RAW_FILTER:
921 {
922 int nfilters = sopt->sopt_size / sizeof(struct can_filter);
923 if (sopt->sopt_size % sizeof(struct can_filter) != 0)
924 return EINVAL;
925 mutex_enter(&canp->canp_mtx);
926 error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
927 mutex_exit(&canp->canp_mtx);
928 break;
929 }
930 default:
931 error = ENOPROTOOPT;
932 break;
933 }
934 return error;
935 }
936
937 /*
938 * Called by getsockopt and setsockopt.
939 *
940 */
941 int
942 can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
943 {
944 struct canpcb *canp;
945 int error;
946 int s;
947
948 if (so->so_proto->pr_domain->dom_family != PF_CAN)
949 return EAFNOSUPPORT;
950
951 if (sopt->sopt_level != SOL_CAN_RAW)
952 return EINVAL;
953
954 s = splsoftnet();
955 canp = sotocanpcb(so);
956 if (canp == NULL) {
957 splx(s);
958 return ECONNRESET;
959 }
960
961 if (op == PRCO_SETOPT) {
962 error = can_raw_setop(canp, sopt);
963 } else if (op == PRCO_GETOPT) {
964 error = can_raw_getop(canp, sopt);
965 } else {
966 error = EINVAL;
967 }
968 splx(s);
969 return error;
970 }
971
972 PR_WRAP_USRREQS(can)
973 #define can_attach can_attach_wrapper
974 #define can_detach can_detach_wrapper
975 #define can_accept can_accept_wrapper
976 #define can_bind can_bind_wrapper
977 #define can_listen can_listen_wrapper
978 #define can_connect can_connect_wrapper
979 #define can_connect2 can_connect2_wrapper
980 #define can_disconnect can_disconnect_wrapper
981 #define can_shutdown can_shutdown_wrapper
982 #define can_abort can_abort_wrapper
983 #define can_ioctl can_ioctl_wrapper
984 #define can_stat can_stat_wrapper
985 #define can_peeraddr can_peeraddr_wrapper
986 #define can_sockaddr can_sockaddr_wrapper
987 #define can_rcvd can_rcvd_wrapper
988 #define can_recvoob can_recvoob_wrapper
989 #define can_send can_send_wrapper
990 #define can_sendoob can_sendoob_wrapper
991 #define can_purgeif can_purgeif_wrapper
992
993 const struct pr_usrreqs can_usrreqs = {
994 .pr_attach = can_attach,
995 .pr_detach = can_detach,
996 .pr_accept = can_accept,
997 .pr_bind = can_bind,
998 .pr_listen = can_listen,
999 .pr_connect = can_connect,
1000 .pr_connect2 = can_connect2,
1001 .pr_disconnect = can_disconnect,
1002 .pr_shutdown = can_shutdown,
1003 .pr_abort = can_abort,
1004 .pr_ioctl = can_ioctl,
1005 .pr_stat = can_stat,
1006 .pr_peeraddr = can_peeraddr,
1007 .pr_sockaddr = can_sockaddr,
1008 .pr_rcvd = can_rcvd,
1009 .pr_recvoob = can_recvoob,
1010 .pr_send = can_send,
1011 .pr_sendoob = can_sendoob,
1012 .pr_purgeif = can_purgeif,
1013 };
1014