natm.c revision 148125
1/*	$NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $	*/
2/*-
3 *
4 * Copyright (c) 1996 Charles D. Cranor and Washington University.
5 * Copyright (c) 2005 Robert N. M. Watson
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/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/netnatm/natm.c 148125 2005-07-18 16:55:46Z rwatson $");
41
42#include <sys/param.h>
43#include <sys/conf.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
48#include <sys/protosw.h>
49#include <sys/signalvar.h>
50#include <sys/socket.h>
51#include <sys/socketvar.h>
52#include <sys/sockio.h>
53#include <sys/sx.h>
54#include <sys/systm.h>
55#include <sys/sysctl.h>
56
57#include <net/if.h>
58#include <net/if_atm.h>
59#include <net/netisr.h>
60
61#include <netinet/in.h>
62
63#include <netnatm/natm.h>
64
65static const u_long natm5_sendspace = 16*1024;
66static const u_long natm5_recvspace = 16*1024;
67
68static const u_long natm0_sendspace = 16*1024;
69static const u_long natm0_recvspace = 16*1024;
70
71struct mtx natm_mtx;
72
73/*
74 * user requests
75 */
76#ifdef FREEBSD_USRREQS
77/*
78 * FreeBSD new usrreqs supersedes pr_usrreq.
79 */
80static int natm_usr_attach(struct socket *, int, d_thread_t *);
81static int natm_usr_detach(struct socket *);
82static int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *);
83static int natm_usr_disconnect(struct socket *);
84static int natm_usr_shutdown(struct socket *);
85static int natm_usr_send(struct socket *, int, struct mbuf *,
86    struct sockaddr *, struct mbuf *, d_thread_t *);
87static int natm_usr_peeraddr(struct socket *, struct sockaddr **);
88static int natm_usr_control(struct socket *, u_long, caddr_t,
89    struct ifnet *, d_thread_t *);
90static int natm_usr_abort(struct socket *);
91static int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *);
92static int natm_usr_sockaddr(struct socket *, struct sockaddr **);
93
94static int
95natm_usr_attach(struct socket *so, int proto, d_thread_t *p)
96{
97    struct natmpcb *npcb;
98    int error = 0;
99
100    npcb = (struct natmpcb *)so->so_pcb;
101
102    KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL"));
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	else
108	    error = soreserve(so, natm0_sendspace, natm0_recvspace);
109        if (error)
110          goto out;
111    }
112
113    so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
114    npcb->npcb_socket = so;
115out:
116    return (error);
117}
118
119static int
120natm_usr_detach(struct socket *so)
121{
122    struct natmpcb *npcb;
123    int error = 0;
124
125    NATM_LOCK();
126    npcb = (struct natmpcb *)so->so_pcb;
127    if (npcb == NULL) {
128	/* XXXRW: Does this case ever actually happen? */
129	error = EINVAL;
130	goto out;
131    }
132
133    /*
134     * we turn on 'drain' *before* we sofree.
135     */
136    npcb_free(npcb, NPCB_DESTROY);	/* drain */
137    ACCEPT_LOCK();
138    SOCK_LOCK(so);
139    so->so_pcb = NULL;
140    sotryfree(so);
141 out:
142    NATM_UNLOCK();
143    return (error);
144}
145
146static int
147natm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p)
148{
149    struct natmpcb *npcb;
150    struct sockaddr_natm *snatm;
151    struct atmio_openvcc op;
152    struct ifnet *ifp;
153    int error = 0;
154    int proto = so->so_proto->pr_protocol;
155
156    NATM_LOCK();
157    npcb = (struct natmpcb *)so->so_pcb;
158    if (npcb == NULL) {
159	/* XXXRW: Does this case ever actually happen? */
160	error = EINVAL;
161	goto out;
162    }
163
164    /*
165     * validate nam and npcb
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    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    if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
198        error = EADDRINUSE;
199        goto out;
200    }
201    NATM_UNLOCK();
202
203    /*
204     * open the channel
205     */
206    bzero(&op, sizeof(op));
207    op.rxhand = npcb;
208    op.param.flags = ATMIO_FLAG_PVC;
209    op.param.vpi = npcb->npcb_vpi;
210    op.param.vci = npcb->npcb_vci;
211    op.param.rmtu = op.param.tmtu = ifp->if_mtu;
212    op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0;
213    op.param.traffic = ATMIO_TRAFFIC_UBR;
214
215    IFF_LOCKGIANT(ifp);
216    if (ifp->if_ioctl == NULL ||
217	ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) {
218	IFF_UNLOCKGIANT(ifp);
219	NATM_LOCK();
220	npcb_free(npcb, NPCB_REMOVE);
221        error = EIO;
222	goto out;
223    }
224    IFF_UNLOCKGIANT(ifp);
225
226    NATM_LOCK();
227    soisconnected(so);
228
229 out:
230    NATM_UNLOCK();
231    return (error);
232}
233
234static int
235natm_usr_disconnect(struct socket *so)
236{
237    struct natmpcb *npcb;
238    struct atmio_closevcc cl;
239    struct ifnet *ifp;
240    int error = 0;
241
242    NATM_LOCK();
243    npcb = (struct natmpcb *)so->so_pcb;
244    if (npcb == NULL) {
245	/* XXXRW: Does this case ever actually happen? */
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    cl.vpi = npcb->npcb_vpi;
261    cl.vci = npcb->npcb_vci;
262    NATM_UNLOCK();
263    if (ifp->if_ioctl != NULL) {
264	IFF_LOCKGIANT(ifp);
265	ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl);
266	IFF_UNLOCKGIANT(ifp);
267    }
268    NATM_LOCK();
269
270    npcb_free(npcb, NPCB_REMOVE);
271    soisdisconnected(so);
272
273 out:
274    NATM_UNLOCK();
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, d_thread_t *p)
288{
289    struct natmpcb *npcb;
290    struct atm_pseudohdr *aph;
291    int error = 0;
292    int proto = so->so_proto->pr_protocol;
293
294    NATM_LOCK();
295    npcb = (struct natmpcb *)so->so_pcb;
296    if (npcb == NULL) {
297	/* XXXRW: Does this case ever actually happen? */
298	error = EINVAL;
299	goto out;
300    }
301
302    if (control && control->m_len) {
303	m_freem(control);
304	m_freem(m);
305	error = EINVAL;
306	goto out;
307    }
308
309    /*
310     * send the data.   we must put an atm_pseudohdr on first
311     */
312    M_PREPEND(m, sizeof(*aph), M_DONTWAIT);
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    NATM_UNLOCK();
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
335    NATM_LOCK();
336    npcb = (struct natmpcb *)so->so_pcb;
337    if (npcb == NULL) {
338	/* XXXRW: Does this case ever actually happen? */
339    	NATM_UNLOCK();
340	return (EINVAL);
341    }
342
343    snatm = &ssnatm;
344    bzero(snatm, sizeof(*snatm));
345    snatm->snatm_len = sizeof(*snatm);
346    snatm->snatm_family = AF_NATM;
347    strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname,
348        sizeof(snatm->snatm_if));
349    snatm->snatm_vci = npcb->npcb_vci;
350    snatm->snatm_vpi = npcb->npcb_vpi;
351    NATM_UNLOCK();
352    *nam = sodupsockaddr((struct sockaddr *)snatm, M_WAITOK);
353    return (0);
354}
355
356static int
357natm_usr_control(struct socket *so, u_long cmd, caddr_t arg,
358    struct ifnet *ifp, d_thread_t *p)
359{
360    struct natmpcb *npcb;
361    int error;
362
363    /*
364     * XXXRW: Does this case ever actually happen?  And does it even matter
365     * given that npcb is unused?
366     */
367    npcb = (struct natmpcb *)so->so_pcb;
368    if (npcb == NULL)
369	return (EINVAL);
370
371    if (ifp == NULL || ifp->if_ioctl == NULL)
372	return (EOPNOTSUPP);
373
374    IFF_LOCKGIANT(ifp);
375    error = ((*ifp->if_ioctl)(ifp, cmd, arg));
376    IFF_UNLOCKGIANT(ifp);
377    return (error);
378}
379
380static int
381natm_usr_abort(struct socket *so)
382{
383    return (natm_usr_shutdown(so));
384}
385
386static int
387natm_usr_bind(struct socket *so, struct sockaddr *nam, d_thread_t *p)
388{
389    return (EOPNOTSUPP);
390}
391
392static int
393natm_usr_sockaddr(struct socket *so, struct sockaddr **nam)
394{
395    return (EOPNOTSUPP);
396}
397
398/* xxx - should be const */
399struct pr_usrreqs natm_usrreqs = {
400	.pru_abort =		natm_usr_abort,
401	.pru_attach =		natm_usr_attach,
402	.pru_bind =		natm_usr_bind,
403	.pru_connect =		natm_usr_connect,
404	.pru_control =		natm_usr_control,
405	.pru_detach =		natm_usr_detach,
406	.pru_disconnect =	natm_usr_disconnect,
407	.pru_peeraddr =		natm_usr_peeraddr,
408	.pru_send =		natm_usr_send,
409	.pru_shutdown =		natm_usr_shutdown,
410	.pru_sockaddr =		natm_usr_sockaddr,
411};
412
413#else  /* !FREEBSD_USRREQS */
414#error "!FREEBSD_USRREQS not implemented - locking"
415
416#if defined(__NetBSD__) || defined(__OpenBSD__)
417int natm_usrreq(so, req, m, nam, control, p)
418#elif defined(__FreeBSD__)
419int natm_usrreq(so, req, m, nam, control)
420#endif
421
422struct socket *so;
423int req;
424struct mbuf *m, *nam, *control;
425#if defined(__NetBSD__) || defined(__OpenBSD__)
426struct proc *p;
427#endif
428
429{
430  int error = 0, s, s2;
431  struct natmpcb *npcb;
432  struct sockaddr_natm *snatm;
433  struct atm_pseudoioctl api;
434  struct atm_pseudohdr *aph;
435  struct atm_rawioctl ario;
436  struct ifnet *ifp;
437  int proto = so->so_proto->pr_protocol;
438
439  s = SPLSOFTNET();
440
441  npcb = (struct natmpcb *) so->so_pcb;
442
443  if (npcb == NULL && req != PRU_ATTACH) {
444    error = EINVAL;
445    goto done;
446  }
447
448
449  switch (req) {
450    case PRU_ATTACH:			/* attach protocol to up */
451
452      if (npcb) {
453	error = EISCONN;
454	break;
455      }
456
457      if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
458	if (proto == PROTO_NATMAAL5)
459          error = soreserve(so, natm5_sendspace, natm5_recvspace);
460	else
461          error = soreserve(so, natm0_sendspace, natm0_recvspace);
462        if (error)
463          break;
464      }
465
466      so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
467      npcb->npcb_socket = so;
468
469      break;
470
471    case PRU_DETACH:			/* detach protocol from up */
472
473      /*
474       * we turn on 'drain' *before* we sofree.
475       */
476
477      npcb_free(npcb, NPCB_DESTROY);	/* drain */
478      ACCEPT_LOCK();
479      SOCK_LOCK(so);
480      so->so_pcb = NULL;
481      sotryfree(so);
482
483      break;
484
485    case PRU_CONNECT:			/* establish connection to peer */
486
487      /*
488       * validate nam and npcb
489       */
490
491      if (nam->m_len != sizeof(*snatm)) {
492        error = EINVAL;
493	break;
494      }
495      snatm = mtod(nam, struct sockaddr_natm *);
496      if (snatm->snatm_len != sizeof(*snatm) ||
497		(npcb->npcb_flags & NPCB_FREE) == 0) {
498	error = EINVAL;
499	break;
500      }
501      if (snatm->snatm_family != AF_NATM) {
502	error = EAFNOSUPPORT;
503	break;
504      }
505
506      snatm->snatm_if[IFNAMSIZ-1] = '\0';  /* XXX ensure null termination
507						since ifunit() uses strcmp */
508
509      /*
510       * convert interface string to ifp, validate.
511       */
512
513      ifp = ifunit(snatm->snatm_if);
514      if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
515	error = ENXIO;
516	break;
517      }
518      if (ifp->if_output != atm_output) {
519	error = EAFNOSUPPORT;
520	break;
521      }
522
523
524      /*
525       * register us with the NATM PCB layer
526       */
527
528      if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
529        error = EADDRINUSE;
530        break;
531      }
532
533      /*
534       * enable rx
535       */
536
537      ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
538      ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
539      ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
540      api.rxhand = npcb;
541      s2 = splimp();
542      if (ifp->if_ioctl == NULL ||
543	  ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
544	splx(s2);
545	npcb_free(npcb, NPCB_REMOVE);
546        error = EIO;
547	break;
548      }
549      splx(s2);
550
551      soisconnected(so);
552
553      break;
554
555    case PRU_DISCONNECT:		/* disconnect from peer */
556
557      if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
558        printf("natm: disconnected check\n");
559        error = EIO;
560	break;
561      }
562      ifp = npcb->npcb_ifp;
563
564      /*
565       * disable rx
566       */
567
568      ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
569      ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
570      ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
571      api.rxhand = npcb;
572      s2 = splimp();
573      if (ifp->if_ioctl != NULL)
574	  ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
575      splx(s2);
576
577      npcb_free(npcb, NPCB_REMOVE);
578      soisdisconnected(so);
579
580      break;
581
582    case PRU_SHUTDOWN:			/* won't send any more data */
583      socantsendmore(so);
584      break;
585
586    case PRU_SEND:			/* send this data */
587      if (control && control->m_len) {
588	m_freem(control);
589	m_freem(m);
590	error = EINVAL;
591	break;
592      }
593
594      /*
595       * send the data.   we must put an atm_pseudohdr on first
596       */
597
598      M_PREPEND(m, sizeof(*aph), M_TRYWAIT);
599      if (m == NULL) {
600        error = ENOBUFS;
601	break;
602      }
603      aph = mtod(m, struct atm_pseudohdr *);
604      ATM_PH_VPI(aph) = npcb->npcb_vpi;
605      ATM_PH_SETVCI(aph, npcb->npcb_vci);
606      ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
607
608      error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
609
610      break;
611
612    case PRU_SENSE:			/* return status into m */
613      /* return zero? */
614      break;
615
616    case PRU_PEERADDR:			/* fetch peer's address */
617      snatm = mtod(nam, struct sockaddr_natm *);
618      bzero(snatm, sizeof(*snatm));
619      nam->m_len = snatm->snatm_len = sizeof(*snatm);
620      snatm->snatm_family = AF_NATM;
621#if defined(__NetBSD__) || defined(__OpenBSD__)
622      bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
623#elif defined(__FreeBSD__)
624      snprintf(snatm->snatm_if, sizeof(snatm->snatm_if),
625	"%s%d", npcb->npcb_ifp->if_name, npcb->npcb_ifp->if_unit);
626#endif
627      snatm->snatm_vci = npcb->npcb_vci;
628      snatm->snatm_vpi = npcb->npcb_vpi;
629      break;
630
631    case PRU_CONTROL:			/* control operations on protocol */
632      /*
633       * raw atm ioctl.   comes in as a SIOCRAWATM.   we convert it to
634       * SIOCXRAWATM and pass it to the driver.
635       */
636      if ((u_long)m == SIOCRAWATM) {
637        if (npcb->npcb_ifp == NULL) {
638          error = ENOTCONN;
639          break;
640        }
641        ario.npcb = npcb;
642        ario.rawvalue = *((int *)nam);
643        error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
644				SIOCXRAWATM, (caddr_t) &ario);
645	if (!error) {
646          if (ario.rawvalue)
647	    npcb->npcb_flags |= NPCB_RAW;
648	  else
649	    npcb->npcb_flags &= ~(NPCB_RAW);
650	}
651
652        break;
653      }
654
655      error = EOPNOTSUPP;
656      break;
657
658    case PRU_BIND:			/* bind socket to address */
659    case PRU_LISTEN:			/* listen for connection */
660    case PRU_ACCEPT:			/* accept connection from peer */
661    case PRU_CONNECT2:			/* connect two sockets */
662    case PRU_ABORT:			/* abort (fast DISCONNECT, DETATCH) */
663					/* (only happens if LISTEN socket) */
664    case PRU_RCVD:			/* have taken data; more room now */
665    case PRU_FASTTIMO:			/* 200ms timeout */
666    case PRU_SLOWTIMO:			/* 500ms timeout */
667    case PRU_RCVOOB:			/* retrieve out of band data */
668    case PRU_SENDOOB:			/* send out of band data */
669    case PRU_PROTORCV:			/* receive from below */
670    case PRU_PROTOSEND:			/* send to below */
671    case PRU_SOCKADDR:			/* fetch socket's address */
672#ifdef DIAGNOSTIC
673      printf("natm: PRU #%d unsupported\n", req);
674#endif
675      error = EOPNOTSUPP;
676      break;
677
678    default: panic("natm usrreq");
679  }
680
681done:
682  splx(s);
683  return(error);
684}
685
686#endif  /* !FREEBSD_USRREQS */
687
688/*
689 * natmintr: splsoftnet interrupt
690 *
691 * note: we expect a socket pointer in rcvif rather than an interface
692 * pointer.    we can get the interface pointer from the so's PCB if
693 * we really need it.
694 */
695void
696natmintr(struct mbuf *m)
697{
698	struct socket *so;
699	struct natmpcb *npcb;
700
701#ifdef DIAGNOSTIC
702	M_ASSERTPKTHDR(m);
703#endif
704
705	NATM_LOCK();
706	npcb = (struct natmpcb *)m->m_pkthdr.rcvif;	/* XXX: overloaded */
707	so = npcb->npcb_socket;
708
709	npcb->npcb_inq--;
710
711	if (npcb->npcb_flags & NPCB_DRAIN) {
712		if (npcb->npcb_inq == 0)
713			FREE(npcb, M_PCB);			/* done! */
714		NATM_UNLOCK();
715		m_freem(m);
716		return;
717	}
718
719	if (npcb->npcb_flags & NPCB_FREE) {
720		NATM_UNLOCK();
721		m_freem(m);					/* drop */
722		return;
723	}
724
725#ifdef NEED_TO_RESTORE_IFP
726	m->m_pkthdr.rcvif = npcb->npcb_ifp;
727#else
728#ifdef DIAGNOSTIC
729	m->m_pkthdr.rcvif = NULL;	/* null it out to be safe */
730#endif
731#endif
732
733	if (sbspace(&so->so_rcv) > m->m_pkthdr.len) {
734#ifdef NATM_STAT
735		natm_sookcnt++;
736		natm_sookbytes += m->m_pkthdr.len;
737#endif
738		sbappendrecord(&so->so_rcv, m);
739		sorwakeup(so);
740		NATM_UNLOCK();
741	} else {
742#ifdef NATM_STAT
743		natm_sodropcnt++;
744		natm_sodropbytes += m->m_pkthdr.len;
745#endif
746		NATM_UNLOCK();
747		m_freem(m);
748	}
749}
750
751/*
752 * natm0_sysctl: not used, but here in case we want to add something
753 * later...
754 */
755int
756natm0_sysctl(SYSCTL_HANDLER_ARGS)
757{
758	/* All sysctl names at this level are terminal. */
759	return (ENOENT);
760}
761
762/*
763 * natm5_sysctl: not used, but here in case we want to add something
764 * later...
765 */
766int
767natm5_sysctl(SYSCTL_HANDLER_ARGS)
768{
769	/* All sysctl names at this level are terminal. */
770	return (ENOENT);
771}
772