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