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