]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netnatm/natm.c
Change protocol switch pru_abort() API so that it returns void rather
[FreeBSD/FreeBSD.git] / 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-2006 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 void 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     KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL"));
98
99     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
100         if (proto == PROTO_NATMAAL5) 
101             error = soreserve(so, natm5_sendspace, natm5_recvspace);
102         else
103             error = soreserve(so, natm0_sendspace, natm0_recvspace);
104         if (error)
105           goto out;
106     }
107
108     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
109     npcb->npcb_socket = so;
110 out:
111     return (error);
112 }
113
114 static int
115 natm_usr_detach(struct socket *so)
116 {
117     struct natmpcb *npcb;
118
119     NATM_LOCK();
120     npcb = (struct natmpcb *)so->so_pcb;
121     KASSERT(npcb != NULL, ("natm_usr_detach: npcb == NULL"));
122     npcb_free(npcb, NPCB_DESTROY);      /* drain */
123     so->so_pcb = NULL;
124     NATM_UNLOCK();
125     return (0);
126 }
127
128 static int
129 natm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p)
130 {
131     struct natmpcb *npcb;
132     struct sockaddr_natm *snatm;
133     struct atmio_openvcc op;
134     struct ifnet *ifp;
135     int error = 0;
136     int proto = so->so_proto->pr_protocol;
137
138     NATM_LOCK();
139     npcb = (struct natmpcb *)so->so_pcb;
140     KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL"));
141
142     /*
143      * validate nam and npcb
144      */
145     snatm = (struct sockaddr_natm *)nam;
146     if (snatm->snatm_len != sizeof(*snatm) ||
147         (npcb->npcb_flags & NPCB_FREE) == 0) {
148         error = EINVAL;
149         goto out;
150     }
151     if (snatm->snatm_family != AF_NATM) {
152         error = EAFNOSUPPORT;
153         goto out;
154     }
155
156     snatm->snatm_if[IFNAMSIZ - 1] = '\0';       /* XXX ensure null termination
157                                                    since ifunit() uses strcmp */
158
159     /*
160      * convert interface string to ifp, validate.
161      */
162     ifp = ifunit(snatm->snatm_if);
163     if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
164         error = ENXIO;
165         goto out;
166     }
167     if (ifp->if_output != atm_output) {
168         error = EAFNOSUPPORT;
169         goto out;
170     }
171
172     /*
173      * register us with the NATM PCB layer
174      */
175     if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
176         error = EADDRINUSE;
177         goto out;
178     }
179     NATM_UNLOCK();
180
181     /*
182      * open the channel
183      */
184     bzero(&op, sizeof(op));
185     op.rxhand = npcb;
186     op.param.flags = ATMIO_FLAG_PVC;
187     op.param.vpi = npcb->npcb_vpi;
188     op.param.vci = npcb->npcb_vci;
189     op.param.rmtu = op.param.tmtu = ifp->if_mtu;
190     op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0;
191     op.param.traffic = ATMIO_TRAFFIC_UBR;
192
193     IFF_LOCKGIANT(ifp);
194     if (ifp->if_ioctl == NULL || 
195         ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) {
196         IFF_UNLOCKGIANT(ifp);
197         error = EIO;
198         goto out;
199     }
200     IFF_UNLOCKGIANT(ifp);
201
202     soisconnected(so);
203
204  out:
205     return (error);
206 }
207
208 static int
209 natm_usr_disconnect(struct socket *so)
210 {
211     struct natmpcb *npcb;
212     struct atmio_closevcc cl;
213     struct ifnet *ifp;
214     int error = 0;
215
216     NATM_LOCK();
217     npcb = (struct natmpcb *)so->so_pcb;
218     KASSERT(npcb != NULL, ("natm_usr_disconnect: npcb == NULL"));
219
220     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
221         printf("natm: disconnected check\n");
222         error = EIO;
223         goto out;
224     }
225     ifp = npcb->npcb_ifp;
226
227     /*
228      * disable rx
229      */
230     cl.vpi = npcb->npcb_vpi;
231     cl.vci = npcb->npcb_vci;
232     NATM_UNLOCK();
233     if (ifp->if_ioctl != NULL) {
234         IFF_LOCKGIANT(ifp);
235         ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl);
236         IFF_UNLOCKGIANT(ifp);
237     }
238     NATM_LOCK();
239
240     soisdisconnected(so);
241
242  out:
243     NATM_UNLOCK();
244     return (error);
245 }
246
247 static int
248 natm_usr_shutdown(struct socket *so)
249 {
250     socantsendmore(so);
251     return (0);
252 }
253
254 static int
255 natm_usr_send(struct socket *so, int flags, struct mbuf *m, 
256     struct sockaddr *nam, struct mbuf *control, d_thread_t *p)
257 {
258     struct natmpcb *npcb;
259     struct atm_pseudohdr *aph;
260     int error = 0;
261     int proto = so->so_proto->pr_protocol;
262
263     NATM_LOCK();
264     npcb = (struct natmpcb *)so->so_pcb;
265     KASSERT(npcb != NULL, ("natm_usr_send: npcb == NULL"));
266
267     if (control && control->m_len) {
268         m_freem(control);
269         m_freem(m);
270         error = EINVAL;
271         goto out;
272     }
273
274     /*
275      * send the data.   we must put an atm_pseudohdr on first
276      */
277     M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
278     if (m == NULL) {
279         error = ENOBUFS;
280         goto out;
281     }
282     aph = mtod(m, struct atm_pseudohdr *);
283     ATM_PH_VPI(aph) = npcb->npcb_vpi;
284     ATM_PH_SETVCI(aph, npcb->npcb_vci);
285     ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
286
287     error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
288
289  out:
290     NATM_UNLOCK();
291     return (error);
292 }
293
294 static int
295 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
296 {
297     struct natmpcb *npcb;
298     struct sockaddr_natm *snatm, ssnatm;
299
300     NATM_LOCK();
301     npcb = (struct natmpcb *)so->so_pcb;
302     KASSERT(npcb != NULL, ("natm_usr_peeraddr: npcb == NULL"));
303
304     snatm = &ssnatm;
305     bzero(snatm, sizeof(*snatm));
306     snatm->snatm_len = sizeof(*snatm);
307     snatm->snatm_family = AF_NATM;
308     strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
309         sizeof(snatm->snatm_if));
310     snatm->snatm_vci = npcb->npcb_vci;
311     snatm->snatm_vpi = npcb->npcb_vpi;
312     NATM_UNLOCK();
313     *nam = sodupsockaddr((struct sockaddr *)snatm, M_WAITOK);
314     return (0);
315 }
316
317 static int
318 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
319     struct ifnet *ifp, d_thread_t *p)
320 {
321     struct natmpcb *npcb;
322     int error;
323
324     npcb = (struct natmpcb *)so->so_pcb;
325     KASSERT(npcb != NULL, ("natm_usr_control: npcb == NULL"));
326
327     if (ifp == NULL || ifp->if_ioctl == NULL)
328         return (EOPNOTSUPP);
329
330     IFF_LOCKGIANT(ifp);
331     error = ((*ifp->if_ioctl)(ifp, cmd, arg));
332     IFF_UNLOCKGIANT(ifp);
333     return (error);
334 }
335
336 static void
337 natm_usr_abort(struct socket *so)
338 {
339     natm_usr_shutdown(so);
340 }
341
342 static int
343 natm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p)
344 {
345     return (EOPNOTSUPP);
346 }
347
348 static int
349 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
350 {
351     return (EOPNOTSUPP);
352 }
353
354 /* xxx - should be const */
355 struct pr_usrreqs natm_usrreqs = {
356         .pru_abort =            natm_usr_abort,
357         .pru_attach =           natm_usr_attach,
358         .pru_bind =             natm_usr_bind,
359         .pru_connect =          natm_usr_connect,
360         .pru_control =          natm_usr_control,
361         .pru_detach =           natm_usr_detach,
362         .pru_disconnect =       natm_usr_disconnect,
363         .pru_peeraddr =         natm_usr_peeraddr,
364         .pru_send =             natm_usr_send,
365         .pru_shutdown =         natm_usr_shutdown,
366         .pru_sockaddr =         natm_usr_sockaddr,
367 };
368
369 /*
370  * natmintr: interrupt
371  *
372  * note: we expect a socket pointer in rcvif rather than an interface
373  * pointer.    we can get the interface pointer from the so's PCB if
374  * we really need it.
375  */
376 void
377 natmintr(struct mbuf *m)
378 {
379         struct socket *so;
380         struct natmpcb *npcb;
381
382 #ifdef DIAGNOSTIC
383         M_ASSERTPKTHDR(m);
384 #endif
385
386         NATM_LOCK();
387         npcb = (struct natmpcb *)m->m_pkthdr.rcvif;     /* XXX: overloaded */
388         so = npcb->npcb_socket;
389
390         npcb->npcb_inq--;
391
392         if (npcb->npcb_flags & NPCB_DRAIN) {
393                 if (npcb->npcb_inq == 0)
394                         FREE(npcb, M_PCB);                      /* done! */
395                 NATM_UNLOCK();
396                 m_freem(m);
397                 return;
398         }
399
400         if (npcb->npcb_flags & NPCB_FREE) {
401                 NATM_UNLOCK();
402                 m_freem(m);                                     /* drop */
403                 return;
404         }
405
406 #ifdef NEED_TO_RESTORE_IFP
407         m->m_pkthdr.rcvif = npcb->npcb_ifp;
408 #else
409 #ifdef DIAGNOSTIC
410         m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
411 #endif
412 #endif
413
414         if (sbspace(&so->so_rcv) > m->m_pkthdr.len) {
415 #ifdef NATM_STAT
416                 natm_sookcnt++;
417                 natm_sookbytes += m->m_pkthdr.len;
418 #endif
419                 sbappendrecord(&so->so_rcv, m);
420                 sorwakeup(so);
421                 NATM_UNLOCK();
422         } else {
423 #ifdef NATM_STAT
424                 natm_sodropcnt++;
425                 natm_sodropbytes += m->m_pkthdr.len;
426 #endif
427                 NATM_UNLOCK();
428                 m_freem(m);
429         }
430 }
431
432 /* 
433  * natm0_sysctl: not used, but here in case we want to add something
434  * later...
435  */
436 int
437 natm0_sysctl(SYSCTL_HANDLER_ARGS)
438 {
439         /* All sysctl names at this level are terminal. */
440         return (ENOENT);
441 }
442
443 /* 
444  * natm5_sysctl: not used, but here in case we want to add something
445  * later...
446  */
447 int
448 natm5_sysctl(SYSCTL_HANDLER_ARGS)
449 {
450         /* All sysctl names at this level are terminal. */
451         return (ENOENT);
452 }