can.c revision 1.1.2.4 1 /* $NetBSD: can.c,v 1.1.2.4 2017/02/05 11:45:11 bouyer Exp $ */
2
3 /*-
4 * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Robert Swindells and Manuel Bouyer
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.4 2017/02/05 11:45:11 bouyer Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/mbuf.h>
38 #include <sys/ioctl.h>
39 #include <sys/domain.h>
40 #include <sys/protosw.h>
41 #include <sys/errno.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/proc.h>
45 #include <sys/kauth.h>
46
47 #include <net/if.h>
48 #include <net/netisr.h>
49 #include <net/route.h>
50
51 #include <netcan/can.h>
52 #include <netcan/can_pcb.h>
53 #include <netcan/can_var.h>
54
55 struct canpcb canpcb;
56 #if 0
57 struct canpcb canrawpcb;
58 #endif
59
60 struct canpcbtable cbtable;
61
62 struct ifqueue canintrq;
63 int canqmaxlen = IFQ_MAXLEN;
64
65 int can_copy_output = 0;
66 int can_output_cnt = 0;
67 struct mbuf *can_lastout;
68
69 int can_sendspace = 4096; /* really max datagram size */
70 int can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can));
71 /* 40 1K datagrams */
72 #ifndef CANHASHSIZE
73 #define CANHASHSIZE 128
74 #endif
75 int canhashsize = CANHASHSIZE;
76
77 static int can_output(struct mbuf *, struct canpcb *);
78
79 static int can_control(struct socket *, u_long, void *, struct ifnet *);
80
81 void
82 can_init(void)
83 {
84 canintrq.ifq_maxlen = canqmaxlen;
85 IFQ_LOCK_INIT(&canintrq);
86 can_pcbinit(&cbtable, canhashsize, canhashsize);
87 }
88
89 /*
90 * Generic control operations (ioctl's).
91 */
92 /* ARGSUSED */
93 static int
94 can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
95 {
96 #if 0
97 struct can_ifreq *cfr = (struct can_ifreq *)data;
98 int error = 0;
99 #endif
100
101
102 switch (cmd) {
103
104 default:
105 if (ifp == 0 || ifp->if_ioctl == 0)
106 return (EOPNOTSUPP);
107 return ((*ifp->if_ioctl)(ifp, cmd, data));
108 }
109 return (0);
110 }
111
112 static int
113 can_purgeif(struct socket *so, struct ifnet *ifp)
114 {
115 return 0;
116 }
117
118 static int
119 can_output(struct mbuf *m, struct canpcb *canp)
120 {
121 struct ifnet *ifp;
122 int error = 0;
123 struct m_tag *sotag;
124
125 if (canp == NULL) {
126 printf("can_output: no pcb\n");
127 error = EINVAL;
128 return error;
129 }
130 ifp = canp->canp_ifp;
131 if (ifp == 0) {
132 error = EDESTADDRREQ;
133 goto bad;
134 }
135 sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
136 if (sotag == NULL) {
137 ifp->if_oerrors++;
138 error = ENOMEM;
139 goto bad;
140 }
141 *(struct socket **)(sotag + 1) = canp->canp_socket;
142 m_tag_prepend(m, sotag);
143
144 if (m->m_len <= ifp->if_mtu) {
145 can_output_cnt++;
146 error = (*ifp->if_output)(ifp, m, NULL, 0);
147 return error;
148 } else
149 error = EMSGSIZE;
150 bad:
151 m_freem(m);
152 return (error);
153 }
154
155 /*
156 * cleanup mbuf tag, keeping the PACKET_TAG_SO tag
157 */
158 void
159 can_mbuf_tag_clean(struct mbuf *m)
160 {
161 struct m_tag *sotag;
162
163 sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
164 m_tag_delete_nonpersistent(m);
165 if (sotag)
166 m_tag_prepend(m, sotag);
167 }
168
169 /*
170 * Process a received CAN frame
171 * the packet is in the mbuf chain m with
172 * the CAN header.
173 */
174 void
175 can_input(struct ifnet *ifp, struct mbuf *m)
176 {
177 struct ifqueue *inq;
178
179 if ((ifp->if_flags & IFF_UP) == 0) {
180 m_freem(m);
181 return;
182 }
183
184 inq = &canintrq;
185
186 IFQ_LOCK(inq);
187 if (IF_QFULL(inq)) {
188 IF_DROP(inq);
189 IFQ_UNLOCK(inq);
190 m_freem(m);
191 } else {
192 IF_ENQUEUE(inq, m);
193 IFQ_UNLOCK(inq);
194 schednetisr(NETISR_CAN);
195 ifp->if_ipackets++;
196 ifp->if_ibytes += m->m_pkthdr.len;
197 }
198 }
199
200 void
201 canintr(void)
202 {
203 int rcv_ifindex;
204 struct mbuf *m;
205
206 struct sockaddr_can from;
207 struct canpcb *canp;
208 struct m_tag *sotag;
209 struct socket *so;
210 struct canpcb *sender_canp;
211
212 mutex_enter(softnet_lock);
213 for (;;) {
214 IFQ_LOCK(&canintrq);
215 IF_DEQUEUE(&canintrq, m);
216 IFQ_UNLOCK(&canintrq);
217
218 if (m == NULL) /* no more queued packets */
219 break;
220
221 #if 0
222 m_claim(m, &can_rx_mowner);
223 #endif
224 sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
225 if (sotag) {
226 so = *(struct socket **)(sotag + 1);
227 sender_canp = sotocanpcb(so);
228 m_tag_delete(m, sotag);
229 /* if the sender doesn't want loopback, don't do it */
230 if (sender_canp->canp_flags & CANP_NO_LOOPBACK) {
231 m_freem(m);
232 continue;
233 }
234 } else {
235 sender_canp = NULL;
236 }
237 memset(&from, 0, sizeof(struct sockaddr_can));
238 rcv_ifindex = m->m_pkthdr.rcvif_index;
239 from.can_ifindex = rcv_ifindex;
240 from.can_len = sizeof(struct sockaddr_can);
241 from.can_family = AF_CAN;
242
243 TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) {
244 struct mbuf *mc;
245
246 /* don't loop back to sockets on other interfaces */
247 if (canp->canp_ifp != NULL &&
248 canp->canp_ifp->if_index != rcv_ifindex) {
249 continue;
250 }
251 /* don't loop back to myself if I don't want it */
252 if (canp == sender_canp &&
253 (canp->canp_flags & CANP_RECEIVE_OWN) == 0)
254 continue;
255
256 /* skip if the accept filter doen't match this pkt */
257 if (!can_pcbfilter(canp, m))
258 continue;
259
260 if (TAILQ_NEXT(canp, canp_queue) != NULL) {
261 /*
262 * we can't be sure we won't need
263 * the original mbuf later so copy
264 */
265 mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
266 if (mc == NULL) {
267 /* deliver this mbuf and abort */
268 mc = m;
269 m = NULL;
270 }
271 } else {
272 mc = m;
273 m = NULL;
274 }
275 if (sbappendaddr(&canp->canp_socket->so_rcv,
276 (struct sockaddr *) &from, mc,
277 (struct mbuf *) 0) == 0) {
278 m_freem(mc);
279 } else
280 sorwakeup(canp->canp_socket);
281 if (m == NULL)
282 break;
283 }
284 /* If it didn't go anywhere just delete it */
285 if (m) {
286 m_freem(m);
287 }
288 }
289 mutex_exit(softnet_lock);
290 }
291
292 static int
293 can_attach(struct socket *so, int proto)
294 {
295 int error;
296
297 KASSERT(sotocanpcb(so) == NULL);
298
299 /* Assign the lock (must happen even if we will error out). */
300 sosetlock(so);
301
302 #ifdef MBUFTRACE
303 so->so_mowner = &can_mowner;
304 so->so_rcv.sb_mowner = &can_rx_mowner;
305 so->so_snd.sb_mowner = &can_tx_mowner;
306 #endif
307 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
308 error = soreserve(so, can_sendspace, can_recvspace);
309 if (error) {
310 return error;
311 }
312 }
313
314 error = can_pcballoc(so, &cbtable);
315 if (error) {
316 return error;
317 }
318 KASSERT(solocked(so));
319
320 return error;
321 }
322
323 static void
324 can_detach(struct socket *so)
325 {
326 struct canpcb *canp;
327
328 KASSERT(solocked(so));
329 canp = sotocanpcb(so);
330 can_pcbdetach(canp);
331 }
332
333 static int
334 can_accept(struct socket *so, struct sockaddr *nam)
335 {
336 KASSERT(solocked(so));
337
338 panic("can_accept");
339
340 return EOPNOTSUPP;
341 }
342
343 static int
344 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
345 {
346 struct canpcb *canp = sotocanpcb(so);
347 struct sockaddr_can *scan = (struct sockaddr_can *)nam;
348
349 KASSERT(solocked(so));
350 KASSERT(nam != NULL);
351
352 return can_pcbbind(canp, scan, l);
353 }
354
355 static int
356 can_listen(struct socket *so, struct lwp *l)
357 {
358 KASSERT(solocked(so));
359
360 return EOPNOTSUPP;
361 }
362
363 static int
364 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
365 {
366 struct canpcb *canp = sotocanpcb(so);
367 int error = 0;
368
369 KASSERT(solocked(so));
370 KASSERT(canp != NULL);
371 KASSERT(nam != NULL);
372
373 error = can_pcbconnect(canp, (struct sockaddr_can *)nam);
374 if (! error)
375 soisconnected(so);
376 return error;
377 }
378
379 static int
380 can_connect2(struct socket *so, struct socket *so2)
381 {
382 KASSERT(solocked(so));
383
384 return EOPNOTSUPP;
385 }
386
387 static int
388 can_disconnect(struct socket *so)
389 {
390 struct canpcb *canp = sotocanpcb(so);
391
392 KASSERT(solocked(so));
393 KASSERT(canp != NULL);
394
395 /*soisdisconnected(so);*/
396 so->so_state &= ~SS_ISCONNECTED; /* XXX */
397 can_pcbdisconnect(canp);
398 can_pcbstate(canp, CANP_BOUND); /* XXX */
399 return 0;
400 }
401
402 static int
403 can_shutdown(struct socket *so)
404 {
405 KASSERT(solocked(so));
406
407 socantsendmore(so);
408 return 0;
409 }
410
411 static int
412 can_abort(struct socket *so)
413 {
414 KASSERT(solocked(so));
415
416 panic("can_abort");
417
418 return EOPNOTSUPP;
419 }
420
421 static int
422 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
423 {
424 return can_control(so, cmd, nam, ifp);
425 }
426
427 static int
428 can_stat(struct socket *so, struct stat *ub)
429 {
430 KASSERT(solocked(so));
431
432 /* stat: don't bother with a blocksize. */
433 return 0;
434 }
435
436 static int
437 can_peeraddr(struct socket *so, struct sockaddr *nam)
438 {
439 KASSERT(solocked(so));
440 KASSERT(sotocanpcb(so) != NULL);
441 KASSERT(nam != NULL);
442
443 return EOPNOTSUPP;
444 }
445
446 static int
447 can_sockaddr(struct socket *so, struct sockaddr *nam)
448 {
449 KASSERT(solocked(so));
450 KASSERT(sotocanpcb(so) != NULL);
451 KASSERT(nam != NULL);
452
453 can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam);
454
455 return 0;
456 }
457
458 static int
459 can_rcvd(struct socket *so, int flags, struct lwp *l)
460 {
461 KASSERT(solocked(so));
462
463 return EOPNOTSUPP;
464 }
465
466 static int
467 can_recvoob(struct socket *so, struct mbuf *m, int flags)
468 {
469 KASSERT(solocked(so));
470
471 return EOPNOTSUPP;
472 }
473
474 static int
475 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
476 struct mbuf *control, struct lwp *l)
477 {
478 struct canpcb *canp = sotocanpcb(so);
479 int error = 0;
480 int s;
481
482 if (control && control->m_len) {
483 return EINVAL;
484 }
485
486 if (nam) {
487 if ((so->so_state & SS_ISCONNECTED) != 0) {
488 return EISCONN;
489 }
490 s = splnet();
491 error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
492 if (error) {
493 splx(s);
494 return error;
495 }
496 } else {
497 if ((so->so_state & SS_ISCONNECTED) == 0) {
498 return EDESTADDRREQ;
499 }
500 }
501 error = can_output(m, canp);
502 if (nam) {
503 struct sockaddr_can lscan;
504 memset(&lscan, 0, sizeof(lscan));
505 lscan.can_family = AF_CAN;
506 lscan.can_len = sizeof(lscan);
507 can_pcbbind(canp, &lscan, l);
508 }
509 return error;
510 }
511
512 static int
513 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
514 {
515 KASSERT(solocked(so));
516
517 m_freem(m);
518 m_freem(control);
519
520 return EOPNOTSUPP;
521 }
522
523 #if 0
524 int
525 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
526 struct mbuf *control, struct lwp *l)
527 {
528 struct canpcb *canp;
529 int s;
530 int error = 0;
531
532 if (req == PRU_CONTROL)
533 return (can_control(so, (long)m, nam,
534 (struct ifnet *)control));
535
536 if (req == PRU_PURGEIF) {
537 #if 0
538 can_pcbpurgeif0(&udbtable, (struct ifnet *)control);
539 can_purgeif((struct ifnet *)control);
540 can_pcbpurgeif(&udbtable, (struct ifnet *)control);
541 #endif
542 return (0);
543 }
544
545 s = splsoftnet();
546 canp = sotocanpcb(so);
547 #ifdef DIAGNOSTIC
548 if (req != PRU_SEND && req != PRU_SENDOOB && control)
549 panic("can_usrreq: unexpected control mbuf");
550 #endif
551 if (canp == 0 && req != PRU_ATTACH) {
552 printf("can_usrreq: no pcb %p %d\n", canp, req);
553 error = EINVAL;
554 goto release;
555 }
556
557 /*
558 * Note: need to block can_input while changing
559 * the can pcb queue and/or pcb addresses.
560 */
561 switch (req) {
562
563 case PRU_ATTACH:
564 if (canp != 0) {
565 error = EISCONN;
566 break;
567 }
568 #ifdef MBUFTRACE
569 so->so_mowner = &can_mowner;
570 so->so_rcv.sb_mowner = &can_rx_mowner;
571 so->so_snd.sb_mowner = &can_tx_mowner;
572 #endif
573 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
574 error = soreserve(so, can_sendspace, can_recvspace);
575 if (error)
576 break;
577 }
578 error = can_pcballoc(so, &cbtable);
579 if (error)
580 break;
581 canp = sotocanpcb(so);
582 #if 0
583 inp->inp_ip.ip_ttl = ip_defttl;
584 #endif
585 break;
586
587 case PRU_DETACH:
588 can_pcbdetach(canp);
589 break;
590
591 case PRU_BIND:
592 error = can_pcbbind(canp, nam, l);
593 break;
594
595 case PRU_LISTEN:
596 error = EOPNOTSUPP;
597 break;
598
599 case PRU_CONNECT:
600 error = can_pcbconnect(canp, nam);
601 if (error)
602 break;
603 soisconnected(so);
604 break;
605
606 case PRU_CONNECT2:
607 error = EOPNOTSUPP;
608 break;
609
610 case PRU_DISCONNECT:
611 /*soisdisconnected(so);*/
612 so->so_state &= ~SS_ISCONNECTED; /* XXX */
613 can_pcbdisconnect(canp);
614 can_pcbstate(canp, CANP_BOUND); /* XXX */
615 break;
616
617 case PRU_SHUTDOWN:
618 socantsendmore(so);
619 break;
620
621 case PRU_RCVD:
622 error = EOPNOTSUPP;
623 break;
624
625 case PRU_SEND:
626 break;
627
628 case PRU_SENSE:
629 /*
630 * stat: don't bother with a blocksize.
631 */
632 splx(s);
633 return (0);
634
635 case PRU_RCVOOB:
636 error = EOPNOTSUPP;
637 break;
638
639 case PRU_SENDOOB:
640 m_freem(control);
641 m_freem(m);
642 error = EOPNOTSUPP;
643 break;
644
645 case PRU_SOCKADDR:
646
647 break;
648
649 case PRU_PEERADDR:
650 error = EOPNOTSUPP;
651 break;
652
653 default:
654 panic("can_usrreq");
655 }
656
657 release:
658 splx(s);
659 return (error);
660 }
661 #endif
662
663 #if 0
664 static void
665 can_notify(struct canpcb *canp, int errno)
666 {
667
668 canp->canp_socket->so_error = errno;
669 sorwakeup(canp->canp_socket);
670 sowwakeup(canp->canp_socket);
671 }
672
673 void *
674 can_ctlinput(int cmd, struct sockaddr *sa, void *v)
675 {
676 struct ip *ip = v;
677 struct canhdr *uh;
678 void (*notify) __P((struct inpcb *, int)) = can_notify;
679 int errno;
680
681 if (sa->sa_family != AF_CAN
682 || sa->sa_len != sizeof(struct sockaddr_can))
683 return NULL;
684 if ((unsigned)cmd >= PRC_NCMDS)
685 return NULL;
686 errno = inetctlerrmap[cmd];
687 if (PRC_IS_REDIRECT(cmd))
688 notify = in_rtchange, ip = 0;
689 else if (cmd == PRC_HOSTDEAD)
690 ip = 0;
691 else if (errno == 0)
692 return NULL;
693 if (ip) {
694 uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2));
695 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
696 ip->ip_src, uh->uh_sport, errno, notify);
697
698 /* XXX mapped address case */
699 } else
700 can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno,
701 notify);
702 return NULL;
703 }
704 #endif
705
706 static int
707 can_raw_getop(struct canpcb *canp, struct sockopt *sopt)
708 {
709 int optval = 0;
710 int error;
711
712 switch (sopt->sopt_name) {
713 case CAN_RAW_LOOPBACK:
714 optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1;
715 error = sockopt_set(sopt, &optval, sizeof(optval));
716 break;
717 case CAN_RAW_RECV_OWN_MSGS:
718 optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0;
719 error = sockopt_set(sopt, &optval, sizeof(optval));
720 break;
721 case CAN_RAW_FILTER:
722 error = sockopt_set(sopt, canp->canp_filters,
723 sizeof(struct can_filter) * canp->canp_nfilters);
724 break;
725 default:
726 error = ENOPROTOOPT;
727 break;
728 }
729 return error;
730 }
731
732 static int
733 can_raw_setop(struct canpcb *canp, struct sockopt *sopt)
734 {
735 int optval = 0;
736 int error;
737
738 switch (sopt->sopt_name) {
739 case CAN_RAW_LOOPBACK:
740 error = sockopt_getint(sopt, &optval);
741 if (error == 0) {
742 if (optval) {
743 canp->canp_flags &= ~CANP_NO_LOOPBACK;
744 } else {
745 canp->canp_flags |= CANP_NO_LOOPBACK;
746 }
747 }
748 break;
749 case CAN_RAW_RECV_OWN_MSGS:
750 error = sockopt_getint(sopt, &optval);
751 if (error == 0) {
752 if (optval) {
753 canp->canp_flags |= CANP_RECEIVE_OWN;
754 } else {
755 canp->canp_flags &= ~CANP_RECEIVE_OWN;
756 }
757 }
758 break;
759 case CAN_RAW_FILTER:
760 {
761 int nfilters = sopt->sopt_size / sizeof(struct can_filter);
762 if (sopt->sopt_size % sizeof(struct can_filter) != 0)
763 return EINVAL;
764 error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters);
765 break;
766 }
767 default:
768 error = ENOPROTOOPT;
769 break;
770 }
771 return error;
772 }
773
774 /*
775 * Called by getsockopt and setsockopt.
776 *
777 */
778 int
779 can_ctloutput(int op, struct socket *so, struct sockopt *sopt)
780 {
781 struct canpcb *canp;
782 int error;
783 int s;
784
785 if (so->so_proto->pr_domain->dom_family != PF_CAN)
786 return EAFNOSUPPORT;
787
788 if (sopt->sopt_level != SOL_CAN_RAW)
789 return EINVAL;
790
791 s = splsoftnet();
792 canp = sotocanpcb(so);
793 if (canp == NULL) {
794 splx(s);
795 return ECONNRESET;
796 }
797
798 if (op == PRCO_SETOPT) {
799 error = can_raw_setop(canp, sopt);
800 } else if (op == PRCO_GETOPT) {
801 error = can_raw_getop(canp, sopt);
802 } else {
803 error = EINVAL;
804 }
805 splx(s);
806 return error;
807 }
808
809 PR_WRAP_USRREQS(can)
810 #define can_attach can_attach_wrapper
811 #define can_detach can_detach_wrapper
812 #define can_accept can_accept_wrapper
813 #define can_bind can_bind_wrapper
814 #define can_listen can_listen_wrapper
815 #define can_connect can_connect_wrapper
816 #define can_connect2 can_connect2_wrapper
817 #define can_disconnect can_disconnect_wrapper
818 #define can_shutdown can_shutdown_wrapper
819 #define can_abort can_abort_wrapper
820 #define can_ioctl can_ioctl_wrapper
821 #define can_stat can_stat_wrapper
822 #define can_peeraddr can_peeraddr_wrapper
823 #define can_sockaddr can_sockaddr_wrapper
824 #define can_rcvd can_rcvd_wrapper
825 #define can_recvoob can_recvoob_wrapper
826 #define can_send can_send_wrapper
827 #define can_sendoob can_sendoob_wrapper
828 #define can_purgeif can_purgeif_wrapper
829
830 const struct pr_usrreqs can_usrreqs = {
831 .pr_attach = can_attach,
832 .pr_detach = can_detach,
833 .pr_accept = can_accept,
834 .pr_bind = can_bind,
835 .pr_listen = can_listen,
836 .pr_connect = can_connect,
837 .pr_connect2 = can_connect2,
838 .pr_disconnect = can_disconnect,
839 .pr_shutdown = can_shutdown,
840 .pr_abort = can_abort,
841 .pr_ioctl = can_ioctl,
842 .pr_stat = can_stat,
843 .pr_peeraddr = can_peeraddr,
844 .pr_sockaddr = can_sockaddr,
845 .pr_rcvd = can_rcvd,
846 .pr_recvoob = can_recvoob,
847 .pr_send = can_send,
848 .pr_sendoob = can_sendoob,
849 .pr_purgeif = can_purgeif,
850 };
851