if_atmsubr.c revision 139823
125603Skjc/*      $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $       */
225603Skjc
3139823Simp/*-
425603Skjc *
525603Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University.
625603Skjc * All rights reserved.
725603Skjc *
825603Skjc * Redistribution and use in source and binary forms, with or without
925603Skjc * modification, are permitted provided that the following conditions
1025603Skjc * are met:
1125603Skjc * 1. Redistributions of source code must retain the above copyright
1225603Skjc *    notice, this list of conditions and the following disclaimer.
1325603Skjc * 2. Redistributions in binary form must reproduce the above copyright
1425603Skjc *    notice, this list of conditions and the following disclaimer in the
1525603Skjc *    documentation and/or other materials provided with the distribution.
1625603Skjc * 3. All advertising materials mentioning features or use of this software
1725603Skjc *    must display the following acknowledgement:
1825603Skjc *      This product includes software developed by Charles D. Cranor and
1925603Skjc *	Washington University.
2025603Skjc * 4. The name of the author may not be used to endorse or promote products
2125603Skjc *    derived from this software without specific prior written permission.
2225603Skjc *
2325603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2425603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2525603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2625603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2725603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2825603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2925603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3025603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3125603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3225603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3354263Sshin *
3425603Skjc * if_atmsubr.c
3525603Skjc */
3625603Skjc
37116720Sharti#include <sys/cdefs.h>
38116720Sharti__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 139823 2005-01-07 01:45:51Z imp $");
39116720Sharti
4032350Seivind#include "opt_inet.h"
4154263Sshin#include "opt_inet6.h"
42105576Srwatson#include "opt_mac.h"
4332925Seivind#include "opt_natm.h"
4432350Seivind
4525603Skjc#include <sys/param.h>
4625603Skjc#include <sys/systm.h>
47114201Sharti#include <sys/kernel.h>
48114201Sharti#include <sys/module.h>
49105576Srwatson#include <sys/mac.h>
5025603Skjc#include <sys/mbuf.h>
5125603Skjc#include <sys/socket.h>
5237939Skjc#include <sys/sockio.h>
5337939Skjc#include <sys/errno.h>
54114201Sharti#include <sys/sysctl.h>
55117630Sharti#include <sys/malloc.h>
5625603Skjc
5725603Skjc#include <net/if.h>
5825603Skjc#include <net/netisr.h>
5925603Skjc#include <net/route.h>
6025603Skjc#include <net/if_dl.h>
6125603Skjc#include <net/if_types.h>
6225603Skjc#include <net/if_atm.h>
6325603Skjc
6425603Skjc#include <netinet/in.h>
6525603Skjc#include <netinet/if_atm.h>
6625603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
6737939Skjc#if defined(INET) || defined(INET6)
6825603Skjc#include <netinet/in_var.h>
6925603Skjc#endif
7025603Skjc#ifdef NATM
7125603Skjc#include <netnatm/natm.h>
7225603Skjc#endif
7325603Skjc
74116741Sharti/*
75116741Sharti * Netgraph interface functions.
76116741Sharti * These need not be protected by a lock, because ng_atm nodes are persitent.
77116741Sharti * The ng_atm module can be unloaded only if all ATM interfaces have been
78116741Sharti * unloaded, so nobody should be in the code paths accessing these function
79116741Sharti * pointers.
80116741Sharti */
81116741Shartivoid	(*ng_atm_attach_p)(struct ifnet *);
82116741Shartivoid	(*ng_atm_detach_p)(struct ifnet *);
83116741Shartiint	(*ng_atm_output_p)(struct ifnet *, struct mbuf **);
84116741Shartivoid	(*ng_atm_input_p)(struct ifnet *, struct mbuf **,
85116741Sharti	    struct atm_pseudohdr *, void *);
86116741Shartivoid	(*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
87116741Sharti	    struct atm_pseudohdr *, void *);
88118157Shartivoid	(*ng_atm_event_p)(struct ifnet *, uint32_t, void *);
89116741Sharti
90116741Sharti/*
91116741Sharti * Harp pseudo interface hooks
92116741Sharti */
93116741Shartivoid	(*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m,
94116741Sharti	    struct atm_pseudohdr *ah, void *rxhand);
95116741Shartivoid	(*atm_harp_attach_p)(struct ifnet *);
96116741Shartivoid	(*atm_harp_detach_p)(struct ifnet *);
97118157Shartivoid	(*atm_harp_event_p)(struct ifnet *, uint32_t, void *);
98116741Sharti
99114201ShartiSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware");
100114201Sharti
10137939Skjc#ifndef ETHERTYPE_IPV6
102116720Sharti#define	ETHERTYPE_IPV6	0x86dd
10337939Skjc#endif
10425603Skjc
105116720Sharti#define	senderr(e) do { error = (e); goto bad; } while (0)
10625603Skjc
10725603Skjc/*
10825603Skjc * atm_output: ATM output routine
10925603Skjc *   inputs:
11025603Skjc *     "ifp" = ATM interface to output to
11125603Skjc *     "m0" = the packet to output
11225603Skjc *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
11325603Skjc *     "rt0" = the route to use
11425603Skjc *   returns: error code   [0 == ok]
11525603Skjc *
11625603Skjc *   note: special semantic: if (dst == NULL) then we assume "m" already
11725603Skjc *		has an atm_pseudohdr on it and just send it directly.
11825603Skjc *		[for native mode ATM output]   if dst is null, then
11925603Skjc *		rt0 must also be NULL.
12025603Skjc */
12125603Skjcint
122116720Shartiatm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
123116720Sharti    struct rtentry *rt0)
12425603Skjc{
12525603Skjc	u_int16_t etype = 0;			/* if using LLC/SNAP */
12678249Speter	int error = 0, sz;
12725603Skjc	struct atm_pseudohdr atmdst, *ad;
12859633Skjc	struct mbuf *m = m0;
12925603Skjc	struct atmllc *atmllc;
13037939Skjc	struct atmllc *llc_hdr = NULL;
13125603Skjc	u_int32_t atm_flags;
13225603Skjc
133105576Srwatson#ifdef MAC
134105576Srwatson	error = mac_check_ifnet_transmit(ifp, m);
135105576Srwatson	if (error)
136105576Srwatson		senderr(error);
137105576Srwatson#endif
138105576Srwatson
139116720Sharti	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
14025603Skjc		senderr(ENETDOWN);
14125603Skjc
14225603Skjc	/*
14325603Skjc	 * check for non-native ATM traffic   (dst != NULL)
14425603Skjc	 */
14525603Skjc	if (dst) {
14625603Skjc		switch (dst->sa_family) {
147116720Sharti
14837939Skjc#if defined(INET) || defined(INET6)
14925603Skjc		case AF_INET:
15037939Skjc		case AF_INET6:
151128636Sluigi		{
152128636Sluigi			struct rtentry *rt;
153128636Sluigi			/*
154128636Sluigi			 * check route
155128636Sluigi			 */
156128636Sluigi			error = rt_check(&rt, &rt0, dst);
157128636Sluigi			if (error)
158128636Sluigi				goto bad;
159128636Sluigi
16046695Skjc			if (dst->sa_family == AF_INET6)
161112193Sharti			        etype = ETHERTYPE_IPV6;
16246695Skjc			else
163112193Sharti			        etype = ETHERTYPE_IP;
16425603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
16525603Skjc				m = NULL;
16625603Skjc				/* XXX: atmresolve already free'd it */
16725603Skjc				senderr(EHOSTUNREACH);
16825603Skjc				/* XXX: put ATMARP stuff here */
16925603Skjc				/* XXX: watch who frees m on failure */
17025603Skjc			}
171128636Sluigi		}
17225603Skjc			break;
17337939Skjc#endif /* INET || INET6 */
17425603Skjc
17537939Skjc		case AF_UNSPEC:
17637939Skjc			/*
17746695Skjc			 * XXX: bpfwrite. assuming dst contains 12 bytes
17846695Skjc			 * (atm pseudo header (4) + LLC/SNAP (8))
17937939Skjc			 */
18037939Skjc			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
181116720Sharti			llc_hdr = (struct atmllc *)(dst->sa_data +
182116720Sharti			    sizeof(atmdst));
18337939Skjc			break;
18437939Skjc
18525603Skjc		default:
186121816Sbrooks#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \
187121816Sbrooks    defined(__NetBSD__) || defined(__OpenBSD__)
18825603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
18925603Skjc			    dst->sa_family);
19025603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
19125603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
19225603Skjc			    ifp->if_unit, dst->sa_family);
19325603Skjc#endif
19425603Skjc			senderr(EAFNOSUPPORT);
19525603Skjc		}
19625603Skjc
19725603Skjc		/*
19825603Skjc		 * must add atm_pseudohdr to data
19925603Skjc		 */
20025603Skjc		sz = sizeof(atmdst);
20125603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
202116720Sharti		if (atm_flags & ATM_PH_LLCSNAP)
203116720Sharti			sz += 8;	/* sizeof snap == 8 */
204111119Simp		M_PREPEND(m, sz, M_DONTWAIT);
20525603Skjc		if (m == 0)
20625603Skjc			senderr(ENOBUFS);
20725603Skjc		ad = mtod(m, struct atm_pseudohdr *);
20825603Skjc		*ad = atmdst;
20925603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
21025603Skjc			atmllc = (struct atmllc *)(ad + 1);
21137939Skjc			if (llc_hdr == NULL) {
21237939Skjc			        bcopy(ATMLLC_HDR, atmllc->llchdr,
21337939Skjc				      sizeof(atmllc->llchdr));
214116720Sharti				/* note: in host order */
21537939Skjc				ATM_LLC_SETTYPE(atmllc, etype);
21637939Skjc			}
21737939Skjc			else
21837939Skjc			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
21925603Skjc		}
22025603Skjc	}
22125603Skjc
222116741Sharti	if (ng_atm_output_p != NULL) {
223116741Sharti		if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) {
224116741Sharti			if (m != NULL)
225116741Sharti				m_freem(m);
226116741Sharti			return (error);
227116741Sharti		}
228116741Sharti		if (m == NULL)
229116741Sharti			return (0);
230116741Sharti	}
231116741Sharti
23225603Skjc	/*
23325603Skjc	 * Queue message on interface, and start output if interface
23425603Skjc	 * not yet active.
23525603Skjc	 */
236117629Sharti	if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp,
237117629Sharti	    -(int)sizeof(struct atm_pseudohdr)))
23869152Sjlemon		return (ENOBUFS);
23925603Skjc	return (error);
24025603Skjc
24125603Skjcbad:
24225603Skjc	if (m)
24325603Skjc		m_freem(m);
24425603Skjc	return (error);
24525603Skjc}
24625603Skjc
24725603Skjc/*
24825603Skjc * Process a received ATM packet;
24925603Skjc * the packet is in the mbuf chain m.
25025603Skjc */
25125603Skjcvoid
252116720Shartiatm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
253116720Sharti    void *rxhand)
25425603Skjc{
255111888Sjlemon	int isr;
256116720Sharti	u_int16_t etype = ETHERTYPE_IP;		/* default */
257124283Sharti#ifdef NATM
25825603Skjc	int s;
259124283Sharti#endif
26025603Skjc
26125603Skjc	if ((ifp->if_flags & IFF_UP) == 0) {
26225603Skjc		m_freem(m);
26325603Skjc		return;
26425603Skjc	}
265105576Srwatson#ifdef MAC
266105576Srwatson	mac_create_mbuf_from_ifnet(ifp, m);
267105576Srwatson#endif
26825603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
26925603Skjc
270116741Sharti	if (ng_atm_input_p != NULL) {
271116741Sharti		(*ng_atm_input_p)(ifp, &m, ah, rxhand);
272116741Sharti		if (m == NULL)
273116741Sharti			return;
274116741Sharti	}
275116741Sharti
276116741Sharti	/* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */
277116741Sharti	if (atm_harp_input_p != NULL) {
278116741Sharti		(*atm_harp_input_p)(ifp, &m, ah, rxhand);
279116741Sharti		if (m == NULL)
280116741Sharti			return;
281116741Sharti	}
282116741Sharti
28325603Skjc	if (rxhand) {
28425603Skjc#ifdef NATM
28537939Skjc		struct natmpcb *npcb = rxhand;
286116720Sharti
28737939Skjc		s = splimp();		/* in case 2 atm cards @ diff lvls */
28837939Skjc		npcb->npcb_inq++;	/* count # in queue */
28937939Skjc		splx(s);
290111888Sjlemon		isr = NETISR_NATM;
29137939Skjc		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
29225603Skjc#else
293116720Sharti		printf("atm_input: NATM detected but not "
294116720Sharti		    "configured in kernel\n");
295116741Sharti		goto dropit;
29625603Skjc#endif
29725603Skjc	} else {
29837939Skjc		/*
29937939Skjc		 * handle LLC/SNAP header, if present
30037939Skjc		 */
30137939Skjc		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
30237939Skjc			struct atmllc *alc;
303116720Sharti
30437939Skjc			if (m->m_len < sizeof(*alc) &&
30537939Skjc			    (m = m_pullup(m, sizeof(*alc))) == 0)
30637939Skjc				return; /* failed */
30737939Skjc			alc = mtod(m, struct atmllc *);
30837939Skjc			if (bcmp(alc, ATMLLC_HDR, 6)) {
309121816Sbrooks#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \
310121816Sbrooks    defined(__NetBSD__) || defined(__OpenBSD__)
311116720Sharti				printf("%s: recv'd invalid LLC/SNAP frame "
312116720Sharti				    "[vp=%d,vc=%d]\n", ifp->if_xname,
313116720Sharti				    ATM_PH_VPI(ah), ATM_PH_VCI(ah));
31425603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
315116720Sharti				printf("%s%d: recv'd invalid LLC/SNAP frame "
316116720Sharti				    "[vp=%d,vc=%d]\n", ifp->if_name,
317116720Sharti				    ifp->if_unit, ATM_PH_VPI(ah),
318116720Sharti				    ATM_PH_VCI(ah));
31925603Skjc#endif
32037939Skjc				m_freem(m);
32137939Skjc				return;
32237939Skjc			}
32337939Skjc			etype = ATM_LLC_TYPE(alc);
32437939Skjc			m_adj(m, sizeof(*alc));
32537939Skjc		}
32625603Skjc
32737939Skjc		switch (etype) {
328116720Sharti
32925603Skjc#ifdef INET
33037939Skjc		case ETHERTYPE_IP:
331111888Sjlemon			isr = NETISR_IP;
33237939Skjc			break;
33325603Skjc#endif
334116720Sharti
33537939Skjc#ifdef INET6
33637939Skjc		case ETHERTYPE_IPV6:
337111888Sjlemon			isr = NETISR_IPV6;
33837939Skjc			break;
33937939Skjc#endif
34037939Skjc		default:
341116741Sharti#ifndef NATM
342116741Sharti  dropit:
343116741Sharti#endif
344116741Sharti			if (ng_atm_input_orphan_p != NULL)
345116741Sharti				(*ng_atm_input_orphan_p)(ifp, m, ah, rxhand);
346116741Sharti			else
347116741Sharti				m_freem(m);
34837939Skjc			return;
34937939Skjc		}
35025603Skjc	}
351111888Sjlemon	netisr_dispatch(isr, m);
35225603Skjc}
35325603Skjc
35425603Skjc/*
355114201Sharti * Perform common duties while attaching to interface list.
35625603Skjc */
35725603Skjcvoid
358116720Shartiatm_ifattach(struct ifnet *ifp)
35925603Skjc{
360111774Smdodd	struct ifaddr *ifa;
361111774Smdodd	struct sockaddr_dl *sdl;
362114739Sharti	struct ifatm *ifatm = ifp->if_softc;
36325603Skjc
36425603Skjc	ifp->if_type = IFT_ATM;
36525603Skjc	ifp->if_addrlen = 0;
36625603Skjc	ifp->if_hdrlen = 0;
367114201Sharti	if_attach(ifp);
36825603Skjc	ifp->if_mtu = ATMMTU;
36925603Skjc	ifp->if_output = atm_output;
370106939Ssam#if 0
371106939Ssam	ifp->if_input = atm_input;
372106939Ssam#endif
37346695Skjc	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
37425603Skjc
37525603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
37672012Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
37737939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
37871959Sphk	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
37971959Sphk	    ifa = TAILQ_NEXT(ifa, ifa_link))
38025603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
38125603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
38225603Skjc#endif
38325603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
38425603Skjc		    sdl->sdl_family == AF_LINK) {
38525603Skjc			sdl->sdl_type = IFT_ATM;
38625603Skjc			sdl->sdl_alen = ifp->if_addrlen;
38725603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
38825603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
38925603Skjc#endif
39025603Skjc			break;
39125603Skjc		}
39237939Skjc
393114739Sharti	ifp->if_linkmib = &ifatm->mib;
394114739Sharti	ifp->if_linkmiblen = sizeof(ifatm->mib);
395116741Sharti
396116741Sharti	if(ng_atm_attach_p)
397116741Sharti		(*ng_atm_attach_p)(ifp);
398116741Sharti	if (atm_harp_attach_p)
399116741Sharti		(*atm_harp_attach_p)(ifp);
40037939Skjc}
401114201Sharti
402114201Sharti/*
403114201Sharti * Common stuff for detaching an ATM interface
404114201Sharti */
405114201Shartivoid
406114201Shartiatm_ifdetach(struct ifnet *ifp)
407114201Sharti{
408116741Sharti	if (atm_harp_detach_p)
409116741Sharti		(*atm_harp_detach_p)(ifp);
410116741Sharti	if(ng_atm_detach_p)
411116741Sharti		(*ng_atm_detach_p)(ifp);
412114201Sharti	if_detach(ifp);
413114201Sharti}
414114201Sharti
415117630Sharti/*
416117630Sharti * Support routine for the SIOCATMGVCCS ioctl().
417117630Sharti *
418117630Sharti * This routine assumes, that the private VCC structures used by the driver
419117630Sharti * begin with a struct atmio_vcc.
420117630Sharti *
421117630Sharti * Return a table of VCCs in a freshly allocated memory area.
422117630Sharti * Here we have a problem: we first count, how many vccs we need
423117630Sharti * to return. The we allocate the memory and finally fill it in.
424117630Sharti * Because we cannot lock while calling malloc, the number of active
425117630Sharti * vccs may change while we're in malloc. So we allocate a couple of
426117630Sharti * vccs more and if space anyway is not enough re-iterate.
427117630Sharti *
428117630Sharti * We could use an sx lock for the vcc tables.
429117630Sharti */
430117630Shartistruct atmio_vcctable *
431117630Shartiatm_getvccs(struct atmio_vcc **table, u_int size, u_int start,
432117630Sharti    struct mtx *lock, int waitok)
433117630Sharti{
434117630Sharti	u_int cid, alloc;
435117630Sharti	size_t len;
436117630Sharti	struct atmio_vcctable *vccs;
437117630Sharti	struct atmio_vcc *v;
438117630Sharti
439117630Sharti	alloc = start + 10;
440117630Sharti	vccs = NULL;
441117630Sharti
442117630Sharti	for (;;) {
443117630Sharti		len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]);
444117630Sharti		vccs = reallocf(vccs, len, M_TEMP,
445117630Sharti		    waitok ? M_WAITOK : M_NOWAIT);
446117630Sharti		if (vccs == NULL)
447117630Sharti			return (NULL);
448117630Sharti		bzero(vccs, len);
449117630Sharti
450117630Sharti		vccs->count = 0;
451117630Sharti		v = vccs->vccs;
452117630Sharti
453117630Sharti		mtx_lock(lock);
454117630Sharti		for (cid = 0; cid < size; cid++)
455117630Sharti			if (table[cid] != NULL) {
456117630Sharti				if (++vccs->count == alloc)
457117630Sharti					/* too many - try again */
458117630Sharti					break;
459117630Sharti				*v++ = *table[cid];
460117630Sharti			}
461117630Sharti		mtx_unlock(lock);
462117630Sharti
463117630Sharti		if (cid == size)
464117630Sharti			break;
465117630Sharti
466117630Sharti		alloc *= 2;
467117630Sharti	}
468117630Sharti	return (vccs);
469117630Sharti}
470117630Sharti
471118157Sharti/*
472118157Sharti * Driver or channel state has changed. Inform whoever is interested
473118157Sharti * in these events.
474118157Sharti */
475118157Shartivoid
476118157Shartiatm_event(struct ifnet *ifp, u_int event, void *arg)
477118157Sharti{
478118157Sharti	if (ng_atm_event_p != NULL)
479118157Sharti		(*ng_atm_event_p)(ifp, event, arg);
480118157Sharti	if (atm_harp_event_p != NULL)
481118157Sharti		(*atm_harp_event_p)(ifp, event, arg);
482118157Sharti}
483118157Sharti
484114201Shartistatic moduledata_t atm_mod = {
485114201Sharti        "atm",
486114201Sharti        NULL,
487114201Sharti        0
488114201Sharti};
489114201Sharti
490114201ShartiDECLARE_MODULE(atm, atm_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
491114201ShartiMODULE_VERSION(atm, 1);
492