1 /* $NetBSD: natm.c,v 1.21 2009/03/18 17:06:53 cegger Exp $ */
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor and
19 * Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * natm.c: native mode ATM access (both aal0 and aal5).
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: natm.c,v 1.21 2009/03/18 17:06:53 cegger Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/domain.h>
46 #include <sys/ioctl.h>
48 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
54 #include <net/if_atm.h>
55 #include <net/netisr.h>
56 #include <net/radix.h>
57 #include <net/route.h>
59 #include <netinet/in.h>
61 #include <netnatm/natm.h>
63 u_long natm5_sendspace
= 16*1024;
64 u_long natm5_recvspace
= 16*1024;
66 u_long natm0_sendspace
= 16*1024;
67 u_long natm0_recvspace
= 16*1024;
73 #if defined(__NetBSD__)
74 int natm_usrreq(so
, req
, m
, nam
, control
, l
)
75 #elif defined(__OpenBSD__)
76 int natm_usrreq(so
, req
, m
, nam
, control
, p
)
77 #elif defined(__FreeBSD__)
78 int natm_usrreq(so
, req
, m
, nam
, control
)
83 struct mbuf
*m
, *nam
, *control
;
84 #if defined(__NetBSD__)
86 #elif deifned(__OpenBSD__)
93 struct sockaddr_natm
*snatm
;
94 struct atm_pseudoioctl api
;
95 struct atm_pseudohdr
*aph
;
96 struct atm_rawioctl ario
;
98 int proto
= so
->so_proto
->pr_protocol
;
102 npcb
= (struct natmpcb
*) so
->so_pcb
;
104 if (npcb
== NULL
&& req
!= PRU_ATTACH
) {
111 case PRU_ATTACH
: /* attach protocol to up */
118 if (so
->so_snd
.sb_hiwat
== 0 || so
->so_rcv
.sb_hiwat
== 0) {
119 if (proto
== PROTO_NATMAAL5
)
120 error
= soreserve(so
, natm5_sendspace
, natm5_recvspace
);
122 error
= soreserve(so
, natm0_sendspace
, natm0_recvspace
);
127 so
->so_pcb
= (void *) (npcb
= npcb_alloc(M_WAITOK
));
128 npcb
->npcb_socket
= so
;
132 case PRU_DETACH
: /* detach protocol from up */
135 * we turn on 'drain' *before* we sofree.
138 npcb_free(npcb
, NPCB_DESTROY
); /* drain */
140 /* sofree drops the lock */
142 mutex_enter(softnet_lock
);
146 case PRU_CONNECT
: /* establish connection to peer */
149 * validate nam and npcb
152 if (nam
->m_len
!= sizeof(*snatm
)) {
156 snatm
= mtod(nam
, struct sockaddr_natm
*);
157 if (snatm
->snatm_len
!= sizeof(*snatm
) ||
158 (npcb
->npcb_flags
& NPCB_FREE
) == 0) {
162 if (snatm
->snatm_family
!= AF_NATM
) {
163 error
= EAFNOSUPPORT
;
167 snatm
->snatm_if
[IFNAMSIZ
-1] = '\0'; /* XXX ensure null termination
168 since ifunit() uses strcmp */
171 * convert interface string to ifp, validate.
174 ifp
= ifunit(snatm
->snatm_if
);
175 if (ifp
== NULL
|| (ifp
->if_flags
& IFF_RUNNING
) == 0) {
179 if (ifp
->if_output
!= atm_output
) {
180 error
= EAFNOSUPPORT
;
186 * register us with the NATM PCB layer
189 if (npcb_add(npcb
, ifp
, snatm
->snatm_vci
, snatm
->snatm_vpi
) != npcb
) {
198 ATM_PH_FLAGS(&api
.aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
199 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
200 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
203 if (ifp
->if_ioctl(ifp
, SIOCATMENA
, &api
) != 0) {
205 npcb_free(npcb
, NPCB_REMOVE
);
215 case PRU_DISCONNECT
: /* disconnect from peer */
217 if ((npcb
->npcb_flags
& NPCB_CONNECTED
) == 0) {
218 printf("natm: disconnected check\n");
222 ifp
= npcb
->npcb_ifp
;
228 ATM_PH_FLAGS(&api
.aph
) = ATM_PH_AAL5
;
229 ATM_PH_VPI(&api
.aph
) = npcb
->npcb_vpi
;
230 ATM_PH_SETVCI(&api
.aph
, npcb
->npcb_vci
);
233 ifp
->if_ioctl(ifp
, SIOCATMDIS
, &api
);
236 npcb_free(npcb
, NPCB_REMOVE
);
237 soisdisconnected(so
);
241 case PRU_SHUTDOWN
: /* won't send any more data */
245 case PRU_SEND
: /* send this data */
246 if (control
&& control
->m_len
) {
254 * send the data. we must put an atm_pseudohdr on first
257 M_PREPEND(m
, sizeof(*aph
), M_WAITOK
);
262 aph
= mtod(m
, struct atm_pseudohdr
*);
263 ATM_PH_VPI(aph
) = npcb
->npcb_vpi
;
264 ATM_PH_SETVCI(aph
, npcb
->npcb_vci
);
265 ATM_PH_FLAGS(aph
) = (proto
== PROTO_NATMAAL5
) ? ATM_PH_AAL5
: 0;
267 error
= atm_output(npcb
->npcb_ifp
, m
, NULL
, NULL
);
271 case PRU_SENSE
: /* return status into m */
275 case PRU_PEERADDR
: /* fetch peer's address */
276 snatm
= mtod(nam
, struct sockaddr_natm
*);
277 memset(snatm
, 0, sizeof(*snatm
));
278 nam
->m_len
= snatm
->snatm_len
= sizeof(*snatm
);
279 snatm
->snatm_family
= AF_NATM
;
280 #if defined(__NetBSD__) || defined(__OpenBSD__)
281 memcpy(snatm
->snatm_if
, npcb
->npcb_ifp
->if_xname
, sizeof(snatm
->snatm_if
));
282 #elif defined(__FreeBSD__)
283 snprintf(snatm
->snatm_if
, sizeof(snatm
->snatm_if
), "%s%d",
284 npcb
->npcb_ifp
->if_name
, npcb
->npcb_ifp
->if_unit
);
286 snatm
->snatm_vci
= npcb
->npcb_vci
;
287 snatm
->snatm_vpi
= npcb
->npcb_vpi
;
290 case PRU_CONTROL
: /* control operations on protocol */
292 * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
293 * SIOCXRAWATM and pass it to the driver.
295 if ((u_long
)m
== SIOCRAWATM
) {
296 if (npcb
->npcb_ifp
== NULL
) {
301 ario
.rawvalue
= *((int *)nam
);
302 error
= npcb
->npcb_ifp
->if_ioctl(npcb
->npcb_ifp
, SIOCXRAWATM
, &ario
);
305 npcb
->npcb_flags
|= NPCB_RAW
;
307 npcb
->npcb_flags
&= ~(NPCB_RAW
);
316 case PRU_BIND
: /* bind socket to address */
317 case PRU_LISTEN
: /* listen for connection */
318 case PRU_ACCEPT
: /* accept connection from peer */
319 case PRU_CONNECT2
: /* connect two sockets */
320 case PRU_ABORT
: /* abort (fast DISCONNECT, DETATCH) */
321 /* (only happens if LISTEN socket) */
322 case PRU_RCVD
: /* have taken data; more room now */
323 case PRU_FASTTIMO
: /* 200ms timeout */
324 case PRU_SLOWTIMO
: /* 500ms timeout */
325 case PRU_RCVOOB
: /* retrieve out of band data */
326 case PRU_SENDOOB
: /* send out of band data */
327 case PRU_PROTORCV
: /* receive from below */
328 case PRU_PROTOSEND
: /* send to below */
329 case PRU_SOCKADDR
: /* fetch socket's address */
331 printf("natm: PRU #%d unsupported\n", req
);
336 default: panic("natm usrreq");
345 * natmintr: splsoftnet interrupt
347 * note: we expect a socket pointer in rcvif rather than an interface
348 * pointer. we can get the interface pointer from the so's PCB if
359 struct natmpcb
*npcb
;
361 mutex_enter(softnet_lock
);
364 IF_DEQUEUE(&natmintrq
, m
);
367 mutex_exit(softnet_lock
);
372 if ((m
->m_flags
& M_PKTHDR
) == 0)
373 panic("natmintr no HDR");
376 npcb
= (struct natmpcb
*) m
->m_pkthdr
.rcvif
; /* XXX: overloaded */
377 so
= npcb
->npcb_socket
;
379 s
= splnet(); /* could have atm devs @ different levels */
383 if (npcb
->npcb_flags
& NPCB_DRAIN
) {
385 if (npcb
->npcb_inq
== 0)
386 free(npcb
, M_PCB
); /* done! */
390 if (npcb
->npcb_flags
& NPCB_FREE
) {
391 m_freem(m
); /* drop */
395 #ifdef NEED_TO_RESTORE_IFP
396 m
->m_pkthdr
.rcvif
= npcb
->npcb_ifp
;
399 m
->m_pkthdr
.rcvif
= NULL
; /* null it out to be safe */
403 if (sbspace(&so
->so_rcv
) > m
->m_pkthdr
.len
||
404 ((npcb
->npcb_flags
& NPCB_RAW
) != 0 && so
->so_rcv
.sb_cc
< NPCB_RAWCC
) ) {
407 natm_sookbytes
+= m
->m_pkthdr
.len
;
409 sbappendrecord(&so
->so_rcv
, m
);
414 natm_sodropbytes
+= m
->m_pkthdr
.len
;
422 #if defined(__FreeBSD__)
423 NETISR_SET(NETISR_NATM
, natmintr
);
429 * natm0_sysctl: not used, but here in case we want to add something
433 int natm0_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
)
443 /* All sysctl names at this level are terminal. */
446 return (ENOPROTOOPT
);
450 * natm5_sysctl: not used, but here in case we want to add something
454 int natm5_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
)
464 /* All sysctl names at this level are terminal. */
467 return (ENOPROTOOPT
);