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