No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netnatm / natm.c
blob273272919931433800a53f34b71bd241f6995eb6
1 /* $NetBSD: natm.c,v 1.21 2009/03/18 17:06:53 cegger Exp $ */
3 /*
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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>
47 #include <sys/proc.h>
48 #include <sys/protosw.h>
49 #include <sys/mbuf.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
53 #include <net/if.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;
70 * user requests
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)
79 #endif
81 struct socket *so;
82 int req;
83 struct mbuf *m, *nam, *control;
84 #if defined(__NetBSD__)
85 struct lwp *l;
86 #elif deifned(__OpenBSD__)
87 struct proc *p;
88 #endif
91 int error = 0, s, s2;
92 struct natmpcb *npcb;
93 struct sockaddr_natm *snatm;
94 struct atm_pseudoioctl api;
95 struct atm_pseudohdr *aph;
96 struct atm_rawioctl ario;
97 struct ifnet *ifp;
98 int proto = so->so_proto->pr_protocol;
100 s = SPLSOFTNET();
102 npcb = (struct natmpcb *) so->so_pcb;
104 if (npcb == NULL && req != PRU_ATTACH) {
105 error = EINVAL;
106 goto done;
110 switch (req) {
111 case PRU_ATTACH: /* attach protocol to up */
113 if (npcb) {
114 error = EISCONN;
115 break;
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);
121 else
122 error = soreserve(so, natm0_sendspace, natm0_recvspace);
123 if (error)
124 break;
127 so->so_pcb = (void *) (npcb = npcb_alloc(M_WAITOK));
128 npcb->npcb_socket = so;
130 break;
132 case PRU_DETACH: /* detach protocol from up */
135 * we turn on 'drain' *before* we sofree.
138 npcb_free(npcb, NPCB_DESTROY); /* drain */
139 so->so_pcb = NULL;
140 /* sofree drops the lock */
141 sofree(so);
142 mutex_enter(softnet_lock);
144 break;
146 case PRU_CONNECT: /* establish connection to peer */
149 * validate nam and npcb
152 if (nam->m_len != sizeof(*snatm)) {
153 error = EINVAL;
154 break;
156 snatm = mtod(nam, struct sockaddr_natm *);
157 if (snatm->snatm_len != sizeof(*snatm) ||
158 (npcb->npcb_flags & NPCB_FREE) == 0) {
159 error = EINVAL;
160 break;
162 if (snatm->snatm_family != AF_NATM) {
163 error = EAFNOSUPPORT;
164 break;
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) {
176 error = ENXIO;
177 break;
179 if (ifp->if_output != atm_output) {
180 error = EAFNOSUPPORT;
181 break;
186 * register us with the NATM PCB layer
189 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
190 error = EADDRINUSE;
191 break;
195 * enable rx
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);
201 api.rxhand = npcb;
202 s2 = splnet();
203 if (ifp->if_ioctl(ifp, SIOCATMENA, &api) != 0) {
204 splx(s2);
205 npcb_free(npcb, NPCB_REMOVE);
206 error = EIO;
207 break;
209 splx(s2);
211 soisconnected(so);
213 break;
215 case PRU_DISCONNECT: /* disconnect from peer */
217 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
218 printf("natm: disconnected check\n");
219 error = EIO;
220 break;
222 ifp = npcb->npcb_ifp;
225 * disable rx
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);
231 api.rxhand = npcb;
232 s2 = splnet();
233 ifp->if_ioctl(ifp, SIOCATMDIS, &api);
234 splx(s);
236 npcb_free(npcb, NPCB_REMOVE);
237 soisdisconnected(so);
239 break;
241 case PRU_SHUTDOWN: /* won't send any more data */
242 socantsendmore(so);
243 break;
245 case PRU_SEND: /* send this data */
246 if (control && control->m_len) {
247 m_freem(control);
248 m_freem(m);
249 error = EINVAL;
250 break;
254 * send the data. we must put an atm_pseudohdr on first
257 M_PREPEND(m, sizeof(*aph), M_WAITOK);
258 if (m == NULL) {
259 error = ENOBUFS;
260 break;
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);
269 break;
271 case PRU_SENSE: /* return status into m */
272 /* return zero? */
273 break;
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);
285 #endif
286 snatm->snatm_vci = npcb->npcb_vci;
287 snatm->snatm_vpi = npcb->npcb_vpi;
288 break;
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) {
297 error = ENOTCONN;
298 break;
300 ario.npcb = npcb;
301 ario.rawvalue = *((int *)nam);
302 error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM, &ario);
303 if (!error) {
304 if (ario.rawvalue)
305 npcb->npcb_flags |= NPCB_RAW;
306 else
307 npcb->npcb_flags &= ~(NPCB_RAW);
310 break;
313 error = EOPNOTSUPP;
314 break;
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 */
330 #ifdef DIAGNOSTIC
331 printf("natm: PRU #%d unsupported\n", req);
332 #endif
333 error = EOPNOTSUPP;
334 break;
336 default: panic("natm usrreq");
339 done:
340 splx(s);
341 return(error);
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
349 * we really need it.
352 void
353 natmintr(void)
356 int s;
357 struct mbuf *m;
358 struct socket *so;
359 struct natmpcb *npcb;
361 mutex_enter(softnet_lock);
362 next:
363 s = splnet();
364 IF_DEQUEUE(&natmintrq, m);
365 splx(s);
366 if (m == NULL) {
367 mutex_exit(softnet_lock);
368 return;
371 #ifdef DIAGNOSTIC
372 if ((m->m_flags & M_PKTHDR) == 0)
373 panic("natmintr no HDR");
374 #endif
376 npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
377 so = npcb->npcb_socket;
379 s = splnet(); /* could have atm devs @ different levels */
380 npcb->npcb_inq--;
381 splx(s);
383 if (npcb->npcb_flags & NPCB_DRAIN) {
384 m_freem(m);
385 if (npcb->npcb_inq == 0)
386 free(npcb, M_PCB); /* done! */
387 goto next;
390 if (npcb->npcb_flags & NPCB_FREE) {
391 m_freem(m); /* drop */
392 goto next;
395 #ifdef NEED_TO_RESTORE_IFP
396 m->m_pkthdr.rcvif = npcb->npcb_ifp;
397 #else
398 #ifdef DIAGNOSTIC
399 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
400 #endif
401 #endif
403 if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
404 ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
405 #ifdef NATM_STAT
406 natm_sookcnt++;
407 natm_sookbytes += m->m_pkthdr.len;
408 #endif
409 sbappendrecord(&so->so_rcv, m);
410 sorwakeup(so);
411 } else {
412 #ifdef NATM_STAT
413 natm_sodropcnt++;
414 natm_sodropbytes += m->m_pkthdr.len;
415 #endif
416 m_freem(m);
419 goto next;
422 #if defined(__FreeBSD__)
423 NETISR_SET(NETISR_NATM, natmintr);
424 #endif
427 #ifdef notyet
429 * natm0_sysctl: not used, but here in case we want to add something
430 * later...
433 int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
435 int *name;
436 u_int namelen;
437 void *oldp;
438 size_t *oldlenp;
439 void *newp;
440 size_t newlen;
443 /* All sysctl names at this level are terminal. */
444 if (namelen != 1)
445 return (ENOTDIR);
446 return (ENOPROTOOPT);
450 * natm5_sysctl: not used, but here in case we want to add something
451 * later...
454 int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
456 int *name;
457 u_int namelen;
458 void *oldp;
459 size_t *oldlenp;
460 void *newp;
461 size_t newlen;
464 /* All sysctl names at this level are terminal. */
465 if (namelen != 1)
466 return (ENOTDIR);
467 return (ENOPROTOOPT);
469 #endif