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