Change pr_output's signature to take two fixed arguments and possible
[dragonfly.git] / sys / netproto / natm / natm.c
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.16 2004/04/21 18:14:03 dillon Exp $ */
4
5 /*
6  *
7  * Copyright (c) 1996 Charles D. Cranor and Washington University.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
24  *
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.
35  */
36
37 /*
38  * natm.c: native mode ATM access (both aal0 and aal5).
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/proc.h>
45 #include <sys/sockio.h>
46 #include <sys/protosw.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51
52 #include <sys/thread2.h>
53 #include <sys/msgport2.h>
54
55 #include <net/if.h>
56 #include <net/if_atm.h>
57 #include <net/netisr.h>
58
59 #include <netinet/in.h>
60
61 #include "natm.h"
62
63 static u_long natm5_sendspace = 16*1024;
64 static u_long natm5_recvspace = 16*1024;
65
66 static u_long natm0_sendspace = 16*1024;
67 static u_long natm0_recvspace = 16*1024;
68
69 /*
70  * user requests
71  */
72 #ifdef FREEBSD_USRREQS
73 /*
74  * FreeBSD new usrreqs supersedes pr_usrreq.
75  */
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 *,
79                                  struct thread *);
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 *, 
84                               struct thread *);
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 *, 
90                               struct thread *);
91 static int natm_usr_sockaddr (struct socket *, struct sockaddr **);
92
93 static int
94 natm_usr_attach(struct socket *so, int proto, struct pru_attach_info *ai)
95 {
96     struct natmpcb *npcb;
97     int error = 0;
98     int s = SPLSOFTNET();
99
100     npcb = (struct natmpcb *) so->so_pcb;
101
102     if (npcb) {
103         error = EISCONN;
104         goto out;
105     }
106
107     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
108         if (proto == PROTO_NATMAAL5) 
109             error = soreserve(so, natm5_sendspace, natm5_recvspace,
110                               ai->sb_rlimit);
111         else
112             error = soreserve(so, natm0_sendspace, natm0_recvspace,
113                               ai->sb_rlimit);
114         if (error)
115           goto out;
116     }
117
118     so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
119     npcb->npcb_socket = so;
120  out:
121     splx(s);
122     return (error);
123 }
124
125 static int
126 natm_usr_detach(struct socket *so)
127 {
128     struct natmpcb *npcb;
129     int error = 0;
130     int s = SPLSOFTNET();
131
132     npcb = (struct natmpcb *) so->so_pcb;
133     if (npcb == NULL) {
134         error = EINVAL;
135         goto out;
136     }
137
138     /*
139      * we turn on 'drain' *before* we sofree.
140      */
141     npcb_free(npcb, NPCB_DESTROY);      /* drain */
142     so->so_pcb = NULL;
143     sofree(so);
144  out:
145     splx(s);
146     return (error);
147 }
148
149 static int
150 natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
151 {
152     struct natmpcb *npcb;
153     struct sockaddr_natm *snatm;
154     struct atm_pseudoioctl api;
155     struct ifnet *ifp;
156     int error = 0;
157     int s2, s = SPLSOFTNET();
158     int proto = so->so_proto->pr_protocol;
159
160     npcb = (struct natmpcb *) so->so_pcb;
161     if (npcb == NULL) {
162         error = EINVAL;
163         goto out;
164     }
165
166     /*
167      * validate nam and npcb
168      */
169
170     snatm = (struct sockaddr_natm *)nam;
171     if (snatm->snatm_len != sizeof(*snatm) ||
172         (npcb->npcb_flags & NPCB_FREE) == 0) {
173         error = EINVAL;
174         goto out;
175     }
176     if (snatm->snatm_family != AF_NATM) {
177         error = EAFNOSUPPORT;
178         goto out;
179     }
180
181     snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
182                                             since ifunit() uses strcmp */
183
184     /*
185      * convert interface string to ifp, validate.
186      */
187
188     ifp = ifunit(snatm->snatm_if);
189     if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
190         error = ENXIO;
191         goto out;
192     }
193     if (ifp->if_output != atm_output) {
194         error = EAFNOSUPPORT;
195         goto out;
196     }
197
198     /*
199      * register us with the NATM PCB layer
200      */
201
202     if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
203         error = EADDRINUSE;
204         goto out;
205     }
206
207     /*
208      * enable rx
209      */
210
211     ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
212     ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
213     ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
214     api.rxhand = npcb;
215     s2 = splimp();
216     if (ifp->if_ioctl == NULL || 
217         ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
218                       td->td_proc->p_ucred) != 0) {
219         splx(s2);
220         npcb_free(npcb, NPCB_REMOVE);
221         error = EIO;
222         goto out;
223     }
224     splx(s2);
225
226     soisconnected(so);
227
228  out:
229     splx(s);
230     return (error);
231 }
232
233 static int
234 natm_usr_disconnect(struct socket *so)
235 {
236     struct natmpcb *npcb;
237     struct atm_pseudoioctl api;
238     struct ifnet *ifp;
239     int error = 0;
240     int s2, s = SPLSOFTNET();
241
242     npcb = (struct natmpcb *) so->so_pcb;
243     if (npcb == NULL) {
244         error = EINVAL;
245         goto out;
246     }
247
248     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
249         printf("natm: disconnected check\n");
250         error = EIO;
251         goto out;
252     }
253     ifp = npcb->npcb_ifp;
254
255     /*
256      * disable rx
257      */
258
259     ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
260     ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
261     ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
262     api.rxhand = npcb;
263     s2 = splimp();
264     if (ifp->if_ioctl != NULL)
265         ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
266     splx(s2);
267
268     npcb_free(npcb, NPCB_REMOVE);
269     soisdisconnected(so);
270
271  out:
272     splx(s);
273     return (error);
274 }
275
276 static int
277 natm_usr_shutdown(struct socket *so)
278 {
279     socantsendmore(so);
280     return 0;
281 }
282
283 static int
284 natm_usr_send(struct socket *so, int flags, struct mbuf *m, 
285               struct sockaddr *nam, struct mbuf *control, struct thread *td)
286 {
287     struct natmpcb *npcb;
288     struct atm_pseudohdr *aph;
289     int error = 0;
290     int s = SPLSOFTNET();
291     int proto = so->so_proto->pr_protocol;
292
293     npcb = (struct natmpcb *) so->so_pcb;
294     if (npcb == NULL) {
295         error = EINVAL;
296         goto out;
297     }
298
299     if (control && control->m_len) {
300         m_freem(control);
301         m_freem(m);
302         error = EINVAL;
303         goto out;
304     }
305
306     /*
307      * send the data.   we must put an atm_pseudohdr on first
308      */
309
310     M_PREPEND(m, sizeof(*aph), M_WAITOK);
311     if (m == NULL) {
312         error = ENOBUFS;
313         goto out;
314     }
315     aph = mtod(m, struct atm_pseudohdr *);
316     ATM_PH_VPI(aph) = npcb->npcb_vpi;
317     ATM_PH_SETVCI(aph, npcb->npcb_vci);
318     ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
319
320     error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
321
322  out:
323     splx(s);
324     return (error);
325 }
326
327 static int
328 natm_usr_peeraddr(struct socket *so, struct sockaddr **nam)
329 {
330     struct natmpcb *npcb;
331     struct sockaddr_natm *snatm, ssnatm;
332     int error = 0;
333     int s = SPLSOFTNET();
334
335     npcb = (struct natmpcb *) so->so_pcb;
336     if (npcb == NULL) {
337         error = EINVAL;
338         goto out;
339     }
340
341     snatm = &ssnatm;
342     bzero(snatm, sizeof(*snatm));
343     snatm->snatm_len = sizeof(*snatm);
344     snatm->snatm_family = AF_NATM;
345     strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
346         sizeof(snatm->snatm_if));
347     snatm->snatm_vci = npcb->npcb_vci;
348     snatm->snatm_vpi = npcb->npcb_vpi;
349     *nam = dup_sockaddr((struct sockaddr *)snatm, 0);
350
351  out:
352     splx(s);
353     return (error);
354 }
355
356 static int
357 natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
358                  struct ifnet *ifp, struct thread *td)
359 {
360     struct natmpcb *npcb;
361     struct atm_rawioctl ario;
362     int error = 0;
363     int s = SPLSOFTNET();
364
365     npcb = (struct natmpcb *) so->so_pcb;
366     if (npcb == NULL) {
367         error = EINVAL;
368         goto out;
369     }
370
371     /*
372      * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
373      * SIOCXRAWATM and pass it to the driver.
374      */
375     if (cmd == SIOCRAWATM) {
376         if (npcb->npcb_ifp == NULL) {
377             error = ENOTCONN;
378             goto out;
379         }
380         ario.npcb = npcb;
381         ario.rawvalue = *((int *)arg);
382         error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, 
383                                          SIOCXRAWATM, (caddr_t) &ario,
384                                          td->td_proc->p_ucred);
385         if (!error) {
386             if (ario.rawvalue) 
387                 npcb->npcb_flags |= NPCB_RAW;
388             else
389                 npcb->npcb_flags &= ~(NPCB_RAW);
390         }
391     }
392     else
393         error = EOPNOTSUPP;
394
395  out:
396     splx(s);
397     return (error);
398 }
399
400 static int
401 natm_usr_abort(struct socket *so)
402 {
403     return natm_usr_shutdown(so);
404 }
405
406 static int
407 natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
408 {
409     return EOPNOTSUPP;
410 }
411
412 static int
413 natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
414 {
415     return EOPNOTSUPP;
416 }
417
418 /* xxx - should be const */
419 struct pr_usrreqs natm_usrreqs = {
420         natm_usr_abort, pru_accept_notsupp, natm_usr_attach, natm_usr_bind,
421         natm_usr_connect, pru_connect2_notsupp, natm_usr_control,
422         natm_usr_detach, natm_usr_disconnect, pru_listen_notsupp,
423         natm_usr_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
424         natm_usr_send, pru_sense_null, natm_usr_shutdown,
425         natm_usr_sockaddr, sosend, soreceive, sopoll
426 };
427
428 #else  /* !FREEBSD_USRREQS */
429
430 #if defined(__NetBSD__) || defined(__OpenBSD__)
431 int natm_usrreq(so, req, m, nam, control, p)
432 #elif defined(__DragonFly__)
433 int natm_usrreq(so, req, m, nam, control)
434 #endif
435
436 struct socket *so;
437 int req;
438 struct mbuf *m, *nam, *control;
439 #if defined(__NetBSD__) || defined(__OpenBSD__)
440 struct proc *p;
441 #endif
442
443 {
444   int error = 0, s, s2;
445   struct natmpcb *npcb;
446   struct sockaddr_natm *snatm;
447   struct atm_pseudoioctl api;
448   struct atm_pseudohdr *aph;
449   struct atm_rawioctl ario;
450   struct ifnet *ifp;
451   int proto = so->so_proto->pr_protocol;
452
453   s = SPLSOFTNET();
454
455   npcb = (struct natmpcb *) so->so_pcb;
456
457   if (npcb == NULL && req != PRU_ATTACH) {
458     error = EINVAL;
459     goto done;
460   }
461     
462
463   switch (req) {
464     case PRU_ATTACH:                    /* attach protocol to up */
465
466       if (npcb) {
467         error = EISCONN;
468         break;
469       }
470
471       if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
472         if (proto == PROTO_NATMAAL5) 
473           error = soreserve(so, natm5_sendspace, natm5_recvspace);
474         else
475           error = soreserve(so, natm0_sendspace, natm0_recvspace);
476         if (error)
477           break;
478       }
479
480       so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
481       npcb->npcb_socket = so;
482
483       break;
484
485     case PRU_DETACH:                    /* detach protocol from up */
486
487       /*
488        * we turn on 'drain' *before* we sofree.
489        */
490
491       npcb_free(npcb, NPCB_DESTROY);    /* drain */
492       so->so_pcb = NULL;
493       sofree(so);
494
495       break;
496
497     case PRU_CONNECT:                   /* establish connection to peer */
498
499       /*
500        * validate nam and npcb
501        */
502
503       if (nam->m_len != sizeof(*snatm)) {
504         error = EINVAL;
505         break;
506       }
507       snatm = mtod(nam, struct sockaddr_natm *);
508       if (snatm->snatm_len != sizeof(*snatm) ||
509                 (npcb->npcb_flags & NPCB_FREE) == 0) {
510         error = EINVAL;
511         break;
512       }
513       if (snatm->snatm_family != AF_NATM) {
514         error = EAFNOSUPPORT;
515         break;
516       }
517
518       snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
519                                                 since ifunit() uses strcmp */
520
521       /*
522        * convert interface string to ifp, validate.
523        */
524
525       ifp = ifunit(snatm->snatm_if);
526       if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
527         error = ENXIO;
528         break;
529       }
530       if (ifp->if_output != atm_output) {
531         error = EAFNOSUPPORT;
532         break;
533       }
534
535
536       /*
537        * register us with the NATM PCB layer
538        */
539
540       if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
541         error = EADDRINUSE;
542         break;
543       }
544
545       /*
546        * enable rx
547        */
548
549       ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
550       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
551       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
552       api.rxhand = npcb;
553       s2 = splimp();
554       if (ifp->if_ioctl == NULL || 
555           ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api,
556                         (struct ucred *)NULL) != 0) {
557         splx(s2);
558         npcb_free(npcb, NPCB_REMOVE);
559         error = EIO;
560         break;
561       }
562       splx(s2);
563
564       soisconnected(so);
565
566       break;
567
568     case PRU_DISCONNECT:                /* disconnect from peer */
569
570       if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
571         printf("natm: disconnected check\n");
572         error = EIO;
573         break;
574       }
575       ifp = npcb->npcb_ifp;
576
577       /*
578        * disable rx
579        */
580
581       ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
582       ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
583       ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
584       api.rxhand = npcb;
585       s2 = splimp();
586       if (ifp->if_ioctl != NULL)
587           ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api, (struct ucred *)NULL);
588       splx(s2);
589
590       npcb_free(npcb, NPCB_REMOVE);
591       soisdisconnected(so);
592
593       break;
594
595     case PRU_SHUTDOWN:                  /* won't send any more data */
596       socantsendmore(so);
597       break;
598
599     case PRU_SEND:                      /* send this data */
600       if (control && control->m_len) {
601         m_freem(control);
602         m_freem(m);
603         error = EINVAL;
604         break;
605       }
606
607       /*
608        * send the data.   we must put an atm_pseudohdr on first
609        */
610
611       M_PREPEND(m, sizeof(*aph), M_WAITOK);
612       if (m == NULL) {
613         error = ENOBUFS;
614         break;
615       }
616       aph = mtod(m, struct atm_pseudohdr *);
617       ATM_PH_VPI(aph) = npcb->npcb_vpi;
618       ATM_PH_SETVCI(aph, npcb->npcb_vci);
619       ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
620
621       error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
622
623       break;
624
625     case PRU_SENSE:                     /* return status into m */
626       /* return zero? */
627       break;
628
629     case PRU_PEERADDR:                  /* fetch peer's address */
630       snatm = mtod(nam, struct sockaddr_natm *);
631       bzero(snatm, sizeof(*snatm));
632       nam->m_len = snatm->snatm_len = sizeof(*snatm);
633       snatm->snatm_family = AF_NATM;
634 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
635       bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
636 #elif defined(__DragonFly__)
637       snprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
638         "%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
639 #endif
640       snatm->snatm_vci = npcb->npcb_vci;
641       snatm->snatm_vpi = npcb->npcb_vpi;
642       break;
643
644     case PRU_CONTROL:                   /* control operations on protocol */
645       /*
646        * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
647        * SIOCXRAWATM and pass it to the driver.
648        */
649       if ((u_long)m == SIOCRAWATM) {
650         if (npcb->npcb_ifp == NULL) {
651           error = ENOTCONN;
652           break;
653         }
654         ario.npcb = npcb;
655         ario.rawvalue = *((int *)nam);
656         error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp, SIOCXRAWATM,
657                                          (caddr_t) &ario, (struct ucred *)NULL);
658         if (!error) {
659           if (ario.rawvalue) 
660             npcb->npcb_flags |= NPCB_RAW;
661           else
662             npcb->npcb_flags &= ~(NPCB_RAW);
663         }
664
665         break;
666       }
667
668       error = EOPNOTSUPP;
669       break;
670
671     case PRU_BIND:                      /* bind socket to address */
672     case PRU_LISTEN:                    /* listen for connection */
673     case PRU_ACCEPT:                    /* accept connection from peer */
674     case PRU_CONNECT2:                  /* connect two sockets */
675     case PRU_ABORT:                     /* abort (fast DISCONNECT, DETATCH) */
676                                         /* (only happens if LISTEN socket) */
677     case PRU_RCVD:                      /* have taken data; more room now */
678     case PRU_FASTTIMO:                  /* 200ms timeout */
679     case PRU_SLOWTIMO:                  /* 500ms timeout */
680     case PRU_RCVOOB:                    /* retrieve out of band data */
681     case PRU_SENDOOB:                   /* send out of band data */
682     case PRU_PROTORCV:                  /* receive from below */
683     case PRU_PROTOSEND:                 /* send to below */
684     case PRU_SOCKADDR:                  /* fetch socket's address */
685 #ifdef DIAGNOSTIC
686       printf("natm: PRU #%d unsupported\n", req);
687 #endif
688       error = EOPNOTSUPP;
689       break;
690    
691     default: panic("natm usrreq");
692   }
693
694 done:
695   splx(s);
696   return(error);
697 }
698
699 #endif  /* !FREEBSD_USRREQS */
700
701 /* 
702  * natm0_sysctl: not used, but here in case we want to add something
703  * later...
704  */
705
706 int natm0_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
707     void *newp, size_t newlen)
708 {
709   /* All sysctl names at this level are terminal. */
710   if (namelen != 1)
711     return (ENOTDIR);
712   return (ENOPROTOOPT);
713 }
714
715 /* 
716  * natm5_sysctl: not used, but here in case we want to add something
717  * later...
718  */
719
720 int natm5_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
721     void *newp, size_t newlen)
722 {
723   /* All sysctl names at this level are terminal. */
724   if (namelen != 1)
725     return (ENOTDIR);
726   return (ENOPROTOOPT);
727 }
728
729 static int natmintr(struct netmsg *);
730
731 #if defined(__DragonFly__)
732 static void
733 netisr_natm_setup(void *dummy __unused)
734 {
735
736         netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
737 }
738 SYSINIT(natm_setup, SI_SUB_CPU, SI_ORDER_ANY, netisr_natm_setup, NULL);
739 #endif
740
741 void
742 natm_init()
743 {
744   LIST_INIT(&natm_pcbs);
745
746   netisr_register(NETISR_NATM, cpu0_portfn, natmintr);
747 }
748
749 /*
750  * natmintr: splsoftnet interrupt
751  *
752  * note: we expect a socket pointer in rcvif rather than an interface
753  * pointer.    we can get the interface pointer from the so's PCB if
754  * we really need it.
755  */
756 static int
757 natmintr(struct netmsg *msg)
758 {
759   struct mbuf *m = ((struct netmsg_packet *)msg)->nm_packet;
760   int s;
761   struct socket *so;
762   struct natmpcb *npcb;
763
764 #ifdef DIAGNOSTIC
765   if ((m->m_flags & M_PKTHDR) == 0)
766     panic("natmintr no HDR");
767 #endif
768
769   npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
770   so = npcb->npcb_socket;
771
772   s = splimp();                 /* could have atm devs @ different levels */
773   npcb->npcb_inq--;
774   splx(s);
775
776   if (npcb->npcb_flags & NPCB_DRAIN) {
777     m_freem(m);
778     if (npcb->npcb_inq == 0)
779       FREE(npcb, M_PCB);                        /* done! */
780     goto out;
781   }
782
783   if (npcb->npcb_flags & NPCB_FREE) {
784     m_freem(m);                                 /* drop */
785     goto out;
786   }
787
788 #ifdef NEED_TO_RESTORE_IFP
789   m->m_pkthdr.rcvif = npcb->npcb_ifp;
790 #else
791 #ifdef DIAGNOSTIC
792 m->m_pkthdr.rcvif = NULL;       /* null it out to be safe */
793 #endif
794 #endif
795
796   if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
797      ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
798 #ifdef NATM_STAT
799     natm_sookcnt++;
800     natm_sookbytes += m->m_pkthdr.len;
801 #endif
802     sbappendrecord(&so->so_rcv, m);
803     sorwakeup(so);
804   } else {
805 #ifdef NATM_STAT
806     natm_sodropcnt++;
807     natm_sodropbytes += m->m_pkthdr.len;
808 #endif
809     m_freem(m);
810   }
811 out:
812   lwkt_replymsg(&msg->nm_lmsg, 0);
813   return(EASYNC);
814 }
815