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