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