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