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