natm.c revision 57178
1/*	$NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $	*/
2/* $FreeBSD: head/sys/netnatm/natm.c 57178 2000-02-13 03:32:07Z peter $ */
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
58static u_long natm5_sendspace = 16*1024;
59static u_long natm5_recvspace = 16*1024;
60
61static u_long natm0_sendspace = 16*1024;
62static 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 */
71static int natm_usr_attach __P((struct socket *, int, struct proc *));
72static int natm_usr_detach __P((struct socket *));
73static int natm_usr_connect __P((struct socket *, struct sockaddr *,
74				 struct proc *));
75static int natm_usr_disconnect __P((struct socket *));
76static int natm_usr_shutdown __P((struct socket *));
77static int natm_usr_send __P((struct socket *, int, struct mbuf *,
78			      struct sockaddr *, struct mbuf *,
79			      struct proc *));
80static int natm_usr_peeraddr __P((struct socket *, struct sockaddr **));
81static int natm_usr_control __P((struct socket *, u_long, caddr_t,
82				 struct ifnet *, struct proc *));
83static int natm_usr_abort __P((struct socket *));
84static int natm_usr_bind __P((struct socket *, struct sockaddr *,
85			      struct proc *));
86static int natm_usr_sockaddr __P((struct socket *, struct sockaddr **));
87
88static int
89natm_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
118static int
119natm_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
142static int
143natm_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
225static int
226natm_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
268static int
269natm_usr_shutdown(struct socket *so)
270{
271    socantsendmore(so);
272    return 0;
273}
274
275static int
276natm_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
319static int
320natm_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
348static int
349natm_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
391static int
392natm_usr_abort(struct socket *so)
393{
394    return natm_usr_shutdown(so);
395}
396
397static int
398natm_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
399{
400    return EOPNOTSUPP;
401}
402
403static int
404natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
405{
406    return EOPNOTSUPP;
407}
408
409/* xxx - should be const */
410struct 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__)
422int natm_usrreq(so, req, m, nam, control, p)
423#elif defined(__FreeBSD__)
424int natm_usrreq(so, req, m, nam, control)
425#endif
426
427struct socket *so;
428int req;
429struct mbuf *m, *nam, *control;
430#if defined(__NetBSD__) || defined(__OpenBSD__)
431struct 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
684done:
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
699void
700natmintr()
701
702{
703  int s;
704  struct mbuf *m;
705  struct socket *so;
706  struct natmpcb *npcb;
707
708next:
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
743m->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__)
767static void
768netisr_natm_setup(void *dummy __unused)
769{
770
771	register_netisr(NETISR_NATM, natmintr);
772}
773SYSINIT(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
782int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
783
784int *name;
785u_int namelen;
786void *oldp;
787size_t *oldlenp;
788void *newp;
789size_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
803int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
804
805int *name;
806u_int namelen;
807void *oldp;
808size_t *oldlenp;
809void *newp;
810size_t newlen;
811
812{
813  /* All sysctl names at this level are terminal. */
814  if (namelen != 1)
815    return (ENOTDIR);
816  return (ENOPROTOOPT);
817}
818