]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/netnatm/natm.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / sys / netnatm / natm.c
1 /*      $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $   */
2 /*-
3  *
4  * Copyright (c) 1996 Charles D. Cranor and Washington University.
5  * Copyright (c) 2005 Robert N. M. Watson
6  * All rights reserved.
7  *
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.
22  *
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.
33  */
34
35 /*
36  * natm.c: native mode ATM access (both aal0 and aal5).
37  */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/param.h>
43 #include <sys/conf.h>
44 #include <sys/kernel.h>
45 #include <sys/lock.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/signalvar.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/sockio.h>
53 #include <sys/sx.h>
54 #include <sys/systm.h>
55 #include <sys/sysctl.h>
56
57 #include <net/if.h>
58 #include <net/if_atm.h>
59 #include <net/netisr.h>
60
61 #include <netinet/in.h>
62
63 #include <netnatm/natm.h>
64
65 static const u_long natm5_sendspace = 16*1024;
66 static const u_long natm5_recvspace = 16*1024;
67
68 static const u_long natm0_sendspace = 16*1024;
69 static const u_long natm0_recvspace = 16*1024;
70
71 struct mtx natm_mtx;
72
73 /*
74  * user requests
75  */
76 static int natm_usr_attach(struct socket *, int, d_thread_t *);
77 static int natm_usr_detach(struct socket *);
78 static int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *);
79 static int natm_usr_disconnect(struct socket *);
80 static int natm_usr_shutdown(struct socket *);
81 static int natm_usr_send(struct socket *, int, struct mbuf *,
82     struct sockaddr *, struct mbuf *, d_thread_t *);
83 static int natm_usr_peeraddr(struct socket *, struct sockaddr **);
84 static int natm_usr_control(struct socket *, u_long, caddr_t,
85     struct ifnet *, d_thread_t *);
86 static int natm_usr_abort(struct socket *);
87 static int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *);
88 static int natm_usr_sockaddr(struct socket *, struct sockaddr **);
89
90 static int
91 natm_usr_attach(struct socket *so, int proto, d_thread_t *p)
92 {
93     struct natmpcb *npcb;
94     int error = 0;
95
96     npcb = (struct natmpcb *)so->so_pcb;
97
98     KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL"));
99
100     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
101         if (proto == PROTO_NATMAAL5) 
102             error = soreserve(so, natm5_sendspace, natm5_recvspace);
103         else
104             error = soreserve(so, natm0_sendspace, natm0_recvspace);
105         if (error)
106           goto out;
107     }
108
109     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
110     npcb->npcb_socket = so;
111 out:
112     return (error);
113 }
114
115 static int
116 natm_usr_detach(struct socket *so)
117 {
118     struct natmpcb *npcb;
119     int error = 0;
120
121     NATM_LOCK();
122     npcb = (struct natmpcb *)so->so_pcb;
123     if (npcb == NULL) {
124         /* XXXRW: Does this case ever actually happen? */
125         error = EINVAL;
126         goto out;
127     }
128
129     /*
130      * we turn on 'drain' *before* we sofree.
131      */
132     npcb_free(npcb, NPCB_DESTROY);      /* drain */
133     ACCEPT_LOCK();
134     SOCK_LOCK(so);
135     so->so_pcb = NULL;
136     sotryfree(so);
137  out:
138     NATM_UNLOCK();
139     return (error);
140 }
141
142 static int
143 natm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p)
144 {
145     struct natmpcb *npcb;
146     struct sockaddr_natm *snatm;
147     struct atmio_openvcc op;
148     struct ifnet *ifp;
149     int error = 0;
150     int proto = so->so_proto->pr_protocol;
151
152     NATM_LOCK();
153     npcb = (struct natmpcb *)so->so_pcb;
154     if (npcb == NULL) {
155         /* XXXRW: Does this case ever actually happen? */
156         error = EINVAL;
157         goto out;
158     }
159
160     /*
161      * validate nam and npcb
162      */
163     snatm = (struct sockaddr_natm *)nam;
164     if (snatm->snatm_len != sizeof(*snatm) ||
165         (npcb->npcb_flags & NPCB_FREE) == 0) {
166         error = EINVAL;
167         goto out;
168     }
169     if (snatm->snatm_family != AF_NATM) {
170         error = EAFNOSUPPORT;
171         goto out;
172     }
173
174     snatm->snatm_if[IFNAMSIZ - 1] = '\0';       /* XXX ensure null termination
175                                                    since ifunit() uses strcmp */
176
177     /*
178      * convert interface string to ifp, validate.
179      */
180     ifp = ifunit(snatm->snatm_if);
181     if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
182         error = ENXIO;
183         goto out;
184     }
185     if (ifp->if_output != atm_output) {
186         error = EAFNOSUPPORT;
187         goto out;
188     }
189
190     /*
191      * register us with the NATM PCB layer
192      */
193     if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
194         error = EADDRINUSE;
195         goto out;
196     }
197     NATM_UNLOCK();
198
199     /*
200      * open the channel
201      */
202     bzero(&op, sizeof(op));
203     op.rxhand = npcb;
204     op.param.flags = ATMIO_FLAG_PVC;
205     op.param.vpi = npcb->npcb_vpi;
206     op.param.vci = npcb->npcb_vci;
207     op.param.rmtu = op.param.tmtu = ifp->if_mtu;
208     op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0;
209     op.param.traffic = ATMIO_TRAFFIC_UBR;
210
211     IFF_LOCKGIANT(ifp);
212     if (ifp->if_ioctl == NULL || 
213         ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) {
214         IFF_UNLOCKGIANT(ifp);
215         NATM_LOCK();
216         npcb_free(npcb, NPCB_REMOVE);
217         error = EIO;
218         goto out;
219     }
220     IFF_UNLOCKGIANT(ifp);
221
222     NATM_LOCK();
223     soisconnected(so);
224
225  out:
226     NATM_UNLOCK();
227     return (error);
228 }
229
230 static int
231 natm_usr_disconnect(struct socket *so)
232 {
233     struct natmpcb *npcb;
234     struct atmio_closevcc cl;
235     struct ifnet *ifp;
236     int error = 0;
237
238     NATM_LOCK();
239     npcb = (struct natmpcb *)so->so_pcb;
240     if (npcb == NULL) {
241         /* XXXRW: Does this case ever actually happen? */
242         error = EINVAL;
243         goto out;
244     }
245
246     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
247         printf("natm: disconnected check\n");
248         error = EIO;
249         goto out;
250     }
251     ifp = npcb->npcb_ifp;
252
253     /*
254      * disable rx
255      */
256     cl.vpi = npcb->npcb_vpi;
257     cl.vci = npcb->npcb_vci;
258     NATM_UNLOCK();
259     if (ifp->if_ioctl != NULL) {
260         IFF_LOCKGIANT(ifp);
261         ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl);
262         IFF_UNLOCKGIANT(ifp);
263     }
264     NATM_LOCK();
265
266     npcb_free(npcb, NPCB_REMOVE);
267     soisdisconnected(so);
268
269  out:
270     NATM_UNLOCK();
271     return (error);
272 }
273
274 static int
275 natm_usr_shutdown(struct socket *so)
276 {
277     socantsendmore(so);
278     return (0);
279 }
280
281 static int
282 natm_usr_send(struct socket *so, int flags, struct mbuf *m, 
283     struct sockaddr *nam, struct mbuf *control, d_thread_t *p)
284 {
285     struct natmpcb *npcb;
286     struct atm_pseudohdr *aph;
287     int error = 0;
288     int proto = so->so_proto->pr_protocol;
289
290     NATM_LOCK();
291     npcb = (struct natmpcb *)so->so_pcb;
292     if (npcb == NULL) {
293         /* XXXRW: Does this case ever actually happen? */
294         error = EINVAL;
295         goto out;
296     }
297
298     if (control && control->m_len) {
299         m_freem(control);
300         m_freem(m);
301         error = EINVAL;
302         goto out;
303     }
304
305     /*
306      * send the data.   we must put an atm_pseudohdr on first
307      */
308     M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
309     if (m == NULL) {
310         error = ENOBUFS;
311         goto out;
312     }
313     aph = mtod(m, struct atm_pseudohdr *);
314     ATM_PH_VPI(aph) = npcb->npcb_vpi;
315     ATM_PH_SETVCI(aph, npcb->npcb_vci);
316     ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
317
318     error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
319
320  out:
321     NATM_UNLOCK();
322     return (error);
323 }
324
325 static int
326 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
327 {
328     struct natmpcb *npcb;
329     struct sockaddr_natm *snatm, ssnatm;
330
331     NATM_LOCK();
332     npcb = (struct natmpcb *)so->so_pcb;
333     if (npcb == NULL) {
334         /* XXXRW: Does this case ever actually happen? */
335         NATM_UNLOCK();
336         return (EINVAL);
337     }
338
339     snatm = &ssnatm;
340     bzero(snatm, sizeof(*snatm));
341     snatm->snatm_len = sizeof(*snatm);
342     snatm->snatm_family = AF_NATM;
343     strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
344         sizeof(snatm->snatm_if));
345     snatm->snatm_vci = npcb->npcb_vci;
346     snatm->snatm_vpi = npcb->npcb_vpi;
347     NATM_UNLOCK();
348     *nam = sodupsockaddr((struct sockaddr *)snatm, M_WAITOK);
349     return (0);
350 }
351
352 static int
353 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
354     struct ifnet *ifp, d_thread_t *p)
355 {
356     struct natmpcb *npcb;
357     int error;
358
359     /*
360      * XXXRW: Does this case ever actually happen?  And does it even matter
361      * given that npcb is unused?
362      */
363     npcb = (struct natmpcb *)so->so_pcb;
364     if (npcb == NULL)
365         return (EINVAL);
366
367     if (ifp == NULL || ifp->if_ioctl == NULL)
368         return (EOPNOTSUPP);
369
370     IFF_LOCKGIANT(ifp);
371     error = ((*ifp->if_ioctl)(ifp, cmd, arg));
372     IFF_UNLOCKGIANT(ifp);
373     return (error);
374 }
375
376 static int
377 natm_usr_abort(struct socket *so)
378 {
379     return (natm_usr_shutdown(so));
380 }
381
382 static int
383 natm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p)
384 {
385     return (EOPNOTSUPP);
386 }
387
388 static int
389 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
390 {
391     return (EOPNOTSUPP);
392 }
393
394 /* xxx - should be const */
395 struct pr_usrreqs natm_usrreqs = {
396         .pru_abort =            natm_usr_abort,
397         .pru_attach =           natm_usr_attach,
398         .pru_bind =             natm_usr_bind,
399         .pru_connect =          natm_usr_connect,
400         .pru_control =          natm_usr_control,
401         .pru_detach =           natm_usr_detach,
402         .pru_disconnect =       natm_usr_disconnect,
403         .pru_peeraddr =         natm_usr_peeraddr,
404         .pru_send =             natm_usr_send,
405         .pru_shutdown =         natm_usr_shutdown,
406         .pru_sockaddr =         natm_usr_sockaddr,
407 };
408
409 /*
410  * natmintr: interrupt
411  *
412  * note: we expect a socket pointer in rcvif rather than an interface
413  * pointer.    we can get the interface pointer from the so's PCB if
414  * we really need it.
415  */
416 void
417 natmintr(struct mbuf *m)
418 {
419         struct socket *so;
420         struct natmpcb *npcb;
421
422 #ifdef DIAGNOSTIC
423         M_ASSERTPKTHDR(m);
424 #endif
425
426         NATM_LOCK();
427         npcb = (struct natmpcb *)m->m_pkthdr.rcvif;     /* XXX: overloaded */
428         so = npcb->npcb_socket;
429
430         npcb->npcb_inq--;
431
432         if (npcb->npcb_flags & NPCB_DRAIN) {
433                 if (npcb->npcb_inq == 0)
434                         FREE(npcb, M_PCB);                      /* done! */
435                 NATM_UNLOCK();
436                 m_freem(m);
437                 return;
438         }
439
440         if (npcb->npcb_flags & NPCB_FREE) {
441                 NATM_UNLOCK();
442                 m_freem(m);                                     /* drop */
443                 return;
444         }
445
446 #ifdef NEED_TO_RESTORE_IFP
447         m->m_pkthdr.rcvif = npcb->npcb_ifp;
448 #else
449 #ifdef DIAGNOSTIC
450         m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
451 #endif
452 #endif
453
454         if (sbspace(&so->so_rcv) > m->m_pkthdr.len) {
455 #ifdef NATM_STAT
456                 natm_sookcnt++;
457                 natm_sookbytes += m->m_pkthdr.len;
458 #endif
459                 sbappendrecord(&so->so_rcv, m);
460                 sorwakeup(so);
461                 NATM_UNLOCK();
462         } else {
463 #ifdef NATM_STAT
464                 natm_sodropcnt++;
465                 natm_sodropbytes += m->m_pkthdr.len;
466 #endif
467                 NATM_UNLOCK();
468                 m_freem(m);
469         }
470 }
471
472 /* 
473  * natm0_sysctl: not used, but here in case we want to add something
474  * later...
475  */
476 int
477 natm0_sysctl(SYSCTL_HANDLER_ARGS)
478 {
479         /* All sysctl names at this level are terminal. */
480         return (ENOENT);
481 }
482
483 /* 
484  * natm5_sysctl: not used, but here in case we want to add something
485  * later...
486  */
487 int
488 natm5_sysctl(SYSCTL_HANDLER_ARGS)
489 {
490         /* All sysctl names at this level are terminal. */
491         return (ENOENT);
492 }