1 /* $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ */
2 /* $FreeBSD: src/sys/netnatm/natm.c,v 1.12 2000/02/13 03:32:03 peter Exp $ */
3 /* $DragonFly: src/sys/netproto/natm/natm.c,v 1.29 2008/05/14 11:59:24 sephe Exp $ */
7 * Copyright (c) 1996 Charles D. Cranor and Washington University.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Charles D. Cranor and
21 * Washington University.
22 * 4. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * natm.c: native mode ATM access (both aal0 and aal5).
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
45 #include <sys/sockio.h>
46 #include <sys/protosw.h>
47 #include <sys/malloc.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
56 #include <net/if_atm.h>
57 #include <net/netisr.h>
59 #include <netinet/in.h>
63 static u_long natm5_sendspace
= 16*1024;
64 static u_long natm5_recvspace
= 16*1024;
66 static u_long natm0_sendspace
= 16*1024;
67 static u_long natm0_recvspace
= 16*1024;
72 #ifdef FREEBSD_USRREQS
74 * FreeBSD new usrreqs supersedes pr_usrreq.
76 static int natm_usr_attach (struct socket
*, int, struct pru_attach_info
*);
77 static int natm_usr_detach (struct socket
*);
78 static int natm_usr_connect (struct socket
*, struct sockaddr
*,
80 static int natm_usr_disconnect (struct socket
*);
81 static int natm_usr_shutdown (struct socket
*);
82 static int natm_usr_send (struct socket
*, int, struct mbuf
*,
83 struct sockaddr
*, struct mbuf
*,
85 static int natm_usr_peeraddr (struct socket
*, struct sockaddr
**);
86 static int natm_usr_control (struct socket
*, u_long
, caddr_t
,
87 struct ifnet
*, struct thread
*);
88 static int natm_usr_abort (struct socket
*);
89 static int natm_usr_bind (struct socket
*, struct sockaddr
*,
91 static int natm_usr_sockaddr (struct socket
*, struct sockaddr
**);
94 natm_usr_attach(struct socket
*so
, int proto
, struct pru_attach_info
*ai
)
100 npcb
= (struct natmpcb
*) so
->so_pcb
;
107 if (so
->so_snd
.ssb_hiwat
== 0 || so
->so_rcv
.ssb_hiwat
== 0) {
108 if (proto
== PROTO_NATMAAL5
)
109 error
= soreserve(so
, natm5_sendspace
, natm5_recvspace
,
112 error
= soreserve(so
, natm0_sendspace
, natm0_recvspace
,
118 so
->so_pcb
= (caddr_t
) (npcb
= npcb_alloc(M_WAITOK
));
119 npcb
->npcb_socket
= so
;
126 natm_usr_detach(struct socket
*so
)
128 struct natmpcb
*npcb
;
132 npcb
= (struct natmpcb
*) so
->so_pcb
;
139 * we turn on 'drain' *before* we sofree.
141 npcb_free(npcb
, NPCB_DESTROY
); /* drain */
150 natm_usr_connect(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
152 struct natmpcb
*npcb
;
153 struct sockaddr_natm
*snatm
;
154 struct atm_pseudoioctl api
;
160 proto
= so
->so_proto
->pr_protocol
;
161 npcb
= (struct natmpcb
*) so
->so_pcb
;
168 * validate nam and npcb
171 snatm
= (struct sockaddr_natm
*)nam
;
172 if (snatm
->snatm_len
!= sizeof(*snatm
) ||
173 (npcb
->npcb_flags
& NPCB_FREE
) == 0) {
177 if (snatm
->snatm_family
!= AF_NATM
) {
178 error
= EAFNOSUPPORT
;
182 snatm
->snatm_if
[IFNAMSIZ
-1] = '\0'; /* XXX ensure null termination
183 since ifunit() uses strcmp */
186 * convert interface string to ifp, validate.
189 ifp
= ifunit(snatm
->snatm_if
);
190 if (ifp
== NULL
|| (ifp
->if_flags
& IFF_RUNNING
) == 0) {
194 if (ifp
->if_output
!= atm_output
) {
195 error
= EAFNOSUPPORT
;
200 * register us with the NATM PCB layer
203 if (npcb_add(npcb
, ifp
, snatm
->snatm_vci
, snatm
->snatm_vpi
) != npcb
) {
212 ATM_PH_FLAGS(&api
.aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
213 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
214 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
216 lwkt_serialize_enter(ifp
->if_serializer
);
217 if (ifp
->if_ioctl
== NULL
||
218 ifp
->if_ioctl(ifp
, SIOCATMENA
, (caddr_t
) &api
,
219 td
->td_proc
->p_ucred
) != 0) {
220 lwkt_serialize_exit(ifp
->if_serializer
);
221 npcb_free(npcb
, NPCB_REMOVE
);
225 lwkt_serialize_exit(ifp
->if_serializer
);
235 natm_usr_disconnect(struct socket
*so
)
237 struct natmpcb
*npcb
;
238 struct atm_pseudoioctl api
;
243 npcb
= (struct natmpcb
*) so
->so_pcb
;
249 if ((npcb
->npcb_flags
& NPCB_CONNECTED
) == 0) {
250 kprintf("natm: disconnected check\n");
254 ifp
= npcb
->npcb_ifp
;
260 ATM_PH_FLAGS(&api
.aph
) = ATM_PH_AAL5
;
261 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
262 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
264 if (ifp
->if_ioctl
!= NULL
) {
265 lwkt_serialize_enter(ifp
->if_serializer
);
266 ifp
->if_ioctl(ifp
, SIOCATMDIS
, (caddr_t
) &api
, (struct ucred
*)NULL
);
267 lwkt_serialize_exit(ifp
->if_serializer
);
270 npcb_free(npcb
, NPCB_REMOVE
);
271 soisdisconnected(so
);
279 natm_usr_shutdown(struct socket
*so
)
286 natm_usr_send(struct socket
*so
, int flags
, struct mbuf
*m
,
287 struct sockaddr
*nam
, struct mbuf
*control
, struct thread
*td
)
289 struct natmpcb
*npcb
;
290 struct atm_pseudohdr
*aph
;
292 int proto
= so
->so_proto
->pr_protocol
;
296 npcb
= (struct natmpcb
*) so
->so_pcb
;
302 if (control
&& control
->m_len
) {
310 * send the data. we must put an atm_pseudohdr on first
313 M_PREPEND(m
, sizeof(*aph
), M_WAITOK
);
318 aph
= mtod(m
, struct atm_pseudohdr
*);
319 ATM_PH_VPI(aph
) = npcb
->npcb_vpi
;
320 ATM_PH_SETVCI(aph
, npcb
->npcb_vci
);
321 ATM_PH_FLAGS(aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
323 error
= atm_output(npcb
->npcb_ifp
, m
, NULL
, NULL
);
331 natm_usr_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
333 struct natmpcb
*npcb
;
334 struct sockaddr_natm
*snatm
, ssnatm
;
338 npcb
= (struct natmpcb
*) so
->so_pcb
;
345 bzero(snatm
, sizeof(*snatm
));
346 snatm
->snatm_len
= sizeof(*snatm
);
347 snatm
->snatm_family
= AF_NATM
;
348 strlcpy(snatm
->snatm_if
, npcb
->npcb_ifp
->if_xname
,
349 sizeof(snatm
->snatm_if
));
350 snatm
->snatm_vci
= npcb
->npcb_vci
;
351 snatm
->snatm_vpi
= npcb
->npcb_vpi
;
352 *nam
= dup_sockaddr((struct sockaddr
*)snatm
);
360 natm_usr_control(struct socket
*so
, u_long cmd
, caddr_t arg
,
361 struct ifnet
*ifp
, struct thread
*td
)
363 struct natmpcb
*npcb
;
364 struct atm_rawioctl ario
;
367 npcb
= (struct natmpcb
*) so
->so_pcb
;
374 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
375 * SIOCXRAWATM and pass it to the driver.
377 if (cmd
== SIOCRAWATM
) {
378 if (npcb
->npcb_ifp
== NULL
) {
383 ario
.rawvalue
= *((int *)arg
);
384 lwkt_serialize_enter(ifp
->if_serializer
);
385 error
= npcb
->npcb_ifp
->if_ioctl(npcb
->npcb_ifp
,
386 SIOCXRAWATM
, (caddr_t
) &ario
,
387 td
->td_proc
->p_ucred
);
388 lwkt_serialize_exit(ifp
->if_serializer
);
391 npcb
->npcb_flags
|= NPCB_RAW
;
393 npcb
->npcb_flags
&= ~(NPCB_RAW
);
403 natm_usr_abort(struct socket
*so
)
405 return natm_usr_shutdown(so
);
409 natm_usr_bind(struct socket
*so
, struct sockaddr
*nam
, struct thread
*td
)
415 natm_usr_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
420 /* xxx - should be const */
421 struct pr_usrreqs natm_usrreqs
= {
422 .pru_abort
= natm_usr_abort
,
423 .pru_accept
= pru_accept_notsupp
,
424 .pru_attach
= natm_usr_attach
,
425 .pru_bind
= natm_usr_bind
,
426 .pru_connect
= natm_usr_connect
,
427 .pru_connect2
= pru_connect2_notsupp
,
428 .pru_control
= natm_usr_control
,
429 .pru_detach
= natm_usr_detach
,
430 .pru_disconnect
= natm_usr_disconnect
,
431 .pru_listen
= pru_listen_notsupp
,
432 .pru_peeraddr
= natm_usr_peeraddr
,
433 .pru_rcvd
= pru_rcvd_notsupp
,
434 .pru_rcvoob
= pru_rcvoob_notsupp
,
435 .pru_send
= natm_usr_send
,
436 .pru_sense
= pru_sense_null
,
437 .pru_shutdown
= natm_usr_shutdown
,
438 .pru_sockaddr
= natm_usr_sockaddr
,
439 .pru_sosend
= sosend
,
440 .pru_soreceive
= soreceive
,
444 #else /* !FREEBSD_USRREQS */
446 #if defined(__NetBSD__) || defined(__OpenBSD__)
448 natm_usrreq(struct socket
*so
, int req
, struct mbuf
*m
, struct mbuf
*nam
,
449 struct mbuf
*control
, struct proc
*p
)
450 #elif defined(__DragonFly__)
452 natm_usrreq(struct socket
*so
, int req
, struct mbuf
*m
, struct mbuf
*nam
,
453 struct mbuf
*control
)
457 struct natmpcb
*npcb
;
458 struct sockaddr_natm
*snatm
;
459 struct atm_pseudoioctl api
;
460 struct atm_pseudohdr
*aph
;
461 struct atm_rawioctl ario
;
463 int proto
= so
->so_proto
->pr_protocol
;
467 npcb
= (struct natmpcb
*) so
->so_pcb
;
469 if (npcb
== NULL
&& req
!= PRU_ATTACH
) {
476 case PRU_ATTACH
: /* attach protocol to up */
483 if (so
->so_snd
.ssb_hiwat
== 0 || so
->so_rcv
.ssb_hiwat
== 0) {
484 if (proto
== PROTO_NATMAAL5
)
485 error
= soreserve(so
, natm5_sendspace
, natm5_recvspace
);
487 error
= soreserve(so
, natm0_sendspace
, natm0_recvspace
);
492 so
->so_pcb
= (caddr_t
) (npcb
= npcb_alloc(M_WAITOK
));
493 npcb
->npcb_socket
= so
;
497 case PRU_DETACH
: /* detach protocol from up */
500 * we turn on 'drain' *before* we sofree.
503 npcb_free(npcb
, NPCB_DESTROY
); /* drain */
509 case PRU_CONNECT
: /* establish connection to peer */
512 * validate nam and npcb
515 if (nam
->m_len
!= sizeof(*snatm
)) {
519 snatm
= mtod(nam
, struct sockaddr_natm
*);
520 if (snatm
->snatm_len
!= sizeof(*snatm
) ||
521 (npcb
->npcb_flags
& NPCB_FREE
) == 0) {
525 if (snatm
->snatm_family
!= AF_NATM
) {
526 error
= EAFNOSUPPORT
;
530 snatm
->snatm_if
[IFNAMSIZ
-1] = '\0'; /* XXX ensure null termination
531 since ifunit() uses strcmp */
534 * convert interface string to ifp, validate.
537 ifp
= ifunit(snatm
->snatm_if
);
538 if (ifp
== NULL
|| (ifp
->if_flags
& IFF_RUNNING
) == 0) {
542 if (ifp
->if_output
!= atm_output
) {
543 error
= EAFNOSUPPORT
;
549 * register us with the NATM PCB layer
552 if (npcb_add(npcb
, ifp
, snatm
->snatm_vci
, snatm
->snatm_vpi
) != npcb
) {
561 ATM_PH_FLAGS(&api
.aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
562 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
563 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
565 lwkt_serialize_enter(ifp
->if_serializer
);
566 if (ifp
->if_ioctl
== NULL
||
567 ifp
->if_ioctl(ifp
, SIOCATMENA
, (caddr_t
) &api
,
568 (struct ucred
*)NULL
) != 0) {
569 lwkt_serialize_exit(ifp
->if_serializer
);
570 npcb_free(npcb
, NPCB_REMOVE
);
574 lwkt_serialize_exit(ifp
->if_serializer
);
580 case PRU_DISCONNECT
: /* disconnect from peer */
582 if ((npcb
->npcb_flags
& NPCB_CONNECTED
) == 0) {
583 kprintf("natm: disconnected check\n");
587 ifp
= npcb
->npcb_ifp
;
593 ATM_PH_FLAGS(&api
.aph
) = ATM_PH_AAL5
;
594 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
595 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
597 lwkt_serialize_enter(ifp
->if_serializer
);
598 if (ifp
->if_ioctl
!= NULL
)
599 ifp
->if_ioctl(ifp
, SIOCATMDIS
, (caddr_t
) &api
, (struct ucred
*)NULL
);
600 lwkt_serialize_exit(ifp
->if_serializer
);
602 npcb_free(npcb
, NPCB_REMOVE
);
603 soisdisconnected(so
);
607 case PRU_SHUTDOWN
: /* won't send any more data */
611 case PRU_SEND
: /* send this data */
612 if (control
&& control
->m_len
) {
620 * send the data. we must put an atm_pseudohdr on first
623 M_PREPEND(m
, sizeof(*aph
), M_WAITOK
);
628 aph
= mtod(m
, struct atm_pseudohdr
*);
629 ATM_PH_VPI(aph
) = npcb
->npcb_vpi
;
630 ATM_PH_SETVCI(aph
, npcb
->npcb_vci
);
631 ATM_PH_FLAGS(aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
633 error
= atm_output(npcb
->npcb_ifp
, m
, NULL
, NULL
);
637 case PRU_SENSE
: /* return status into m */
641 case PRU_PEERADDR
: /* fetch peer's address */
642 snatm
= mtod(nam
, struct sockaddr_natm
*);
643 bzero(snatm
, sizeof(*snatm
));
644 nam
->m_len
= snatm
->snatm_len
= sizeof(*snatm
);
645 snatm
->snatm_family
= AF_NATM
;
646 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
647 bcopy(npcb
->npcb_ifp
->if_xname
, snatm
->snatm_if
, sizeof(snatm
->snatm_if
));
648 #elif defined(__DragonFly__)
649 ksnprintf(snatm
->snatm_if
, sizeof(snatm
->snatm_if
),
650 "%s%d", npcb
->npcb_ifp
->if_name
, npcb
->npcb_ifp
->if_unit
);
652 snatm
->snatm_vci
= npcb
->npcb_vci
;
653 snatm
->snatm_vpi
= npcb
->npcb_vpi
;
656 case PRU_CONTROL
: /* control operations on protocol */
658 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
659 * SIOCXRAWATM and pass it to the driver.
661 if ((u_long
)m
== SIOCRAWATM
) {
662 if (npcb
->npcb_ifp
== NULL
) {
667 ario
.rawvalue
= *((int *)nam
);
668 lwkt_serialize_enter(npcb
->npcb_ifp
->if_serializer
);
669 error
= npcb
->npcb_ifp
->if_ioctl(npcb
->npcb_ifp
, SIOCXRAWATM
,
670 (caddr_t
) &ario
, (struct ucred
*)NULL
);
671 lwkt_serialize_exit(npcb
->npcb_ifp
->if_serializer
);
674 npcb
->npcb_flags
|= NPCB_RAW
;
676 npcb
->npcb_flags
&= ~(NPCB_RAW
);
685 case PRU_BIND
: /* bind socket to address */
686 case PRU_LISTEN
: /* listen for connection */
687 case PRU_ACCEPT
: /* accept connection from peer */
688 case PRU_CONNECT2
: /* connect two sockets */
689 case PRU_ABORT
: /* abort (fast DISCONNECT, DETATCH) */
690 /* (only happens if LISTEN socket) */
691 case PRU_RCVD
: /* have taken data; more room now */
692 case PRU_FASTTIMO
: /* 200ms timeout */
693 case PRU_SLOWTIMO
: /* 500ms timeout */
694 case PRU_RCVOOB
: /* retrieve out of band data */
695 case PRU_SENDOOB
: /* send out of band data */
696 case PRU_PROTORCV
: /* receive from below */
697 case PRU_PROTOSEND
: /* send to below */
698 case PRU_SOCKADDR
: /* fetch socket's address */
700 kprintf("natm: PRU #%d unsupported\n", req
);
705 default: panic("natm usrreq");
713 #endif /* !FREEBSD_USRREQS */
716 * natm0_sysctl: not used, but here in case we want to add something
721 natm0_sysctl(int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
,
722 void *newp
, size_t newlen
)
724 /* All sysctl names at this level are terminal. */
727 return (ENOPROTOOPT
);
731 * natm5_sysctl: not used, but here in case we want to add something
736 natm5_sysctl(int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
,
737 void *newp
, size_t newlen
)
739 /* All sysctl names at this level are terminal. */
742 return (ENOPROTOOPT
);
745 static void natmintr(struct netmsg
*);
747 #if defined(__DragonFly__)
749 netisr_natm_setup(void *dummy __unused
)
751 netisr_register(NETISR_NATM
, cpu0_portfn
, natmintr
);
753 SYSINIT(natm_setup
, SI_BOOT2_KLD
, SI_ORDER_ANY
, netisr_natm_setup
, NULL
);
759 LIST_INIT(&natm_pcbs
);
761 netisr_register(NETISR_NATM
, cpu0_portfn
, natmintr
);
765 * natmintr: software interrupt
767 * note: we expect a socket pointer in rcvif rather than an interface
768 * pointer. we can get the interface pointer from the so's PCB if
772 natmintr(struct netmsg
*msg
)
774 struct mbuf
*m
= ((struct netmsg_packet
*)msg
)->nm_packet
;
776 struct natmpcb
*npcb
;
779 if ((m
->m_flags
& M_PKTHDR
) == 0)
780 panic("natmintr no HDR");
783 npcb
= (struct natmpcb
*) m
->m_pkthdr
.rcvif
; /* XXX: overloaded */
784 so
= npcb
->npcb_socket
;
790 if (npcb
->npcb_flags
& NPCB_DRAIN
) {
792 if (npcb
->npcb_inq
== 0)
793 FREE(npcb
, M_PCB
); /* done! */
797 if (npcb
->npcb_flags
& NPCB_FREE
) {
798 m_freem(m
); /* drop */
802 #ifdef NEED_TO_RESTORE_IFP
803 m
->m_pkthdr
.rcvif
= npcb
->npcb_ifp
;
806 m
->m_pkthdr
.rcvif
= NULL
; /* null it out to be safe */
810 if (ssb_space(&so
->so_rcv
) > m
->m_pkthdr
.len
||
811 ((npcb
->npcb_flags
& NPCB_RAW
) != 0 && so
->so_rcv
.ssb_cc
< NPCB_RAWCC
) ) {
814 natm_sookbytes
+= m
->m_pkthdr
.len
;
816 sbappendrecord(&so
->so_rcv
.sb
, m
);
821 natm_sodropbytes
+= m
->m_pkthdr
.len
;
827 /* msg was embedded in the mbuf, do not reply! */