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