if_atmsubr.c revision 147256
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 147256 2005-06-10 16:49:24Z brooks $");
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
101147256SbrooksMALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals");
102147256Sbrooks
10337939Skjc#ifndef ETHERTYPE_IPV6
104116720Sharti#define	ETHERTYPE_IPV6	0x86dd
10537939Skjc#endif
10625603Skjc
107116720Sharti#define	senderr(e) do { error = (e); goto bad; } while (0)
10825603Skjc
10925603Skjc/*
11025603Skjc * atm_output: ATM output routine
11125603Skjc *   inputs:
11225603Skjc *     "ifp" = ATM interface to output to
11325603Skjc *     "m0" = the packet to output
11425603Skjc *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
11525603Skjc *     "rt0" = the route to use
11625603Skjc *   returns: error code   [0 == ok]
11725603Skjc *
11825603Skjc *   note: special semantic: if (dst == NULL) then we assume "m" already
11925603Skjc *		has an atm_pseudohdr on it and just send it directly.
12025603Skjc *		[for native mode ATM output]   if dst is null, then
12125603Skjc *		rt0 must also be NULL.
12225603Skjc */
12325603Skjcint
124116720Shartiatm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
125116720Sharti    struct rtentry *rt0)
12625603Skjc{
12725603Skjc	u_int16_t etype = 0;			/* if using LLC/SNAP */
12878249Speter	int error = 0, sz;
12925603Skjc	struct atm_pseudohdr atmdst, *ad;
13059633Skjc	struct mbuf *m = m0;
13125603Skjc	struct atmllc *atmllc;
13237939Skjc	struct atmllc *llc_hdr = NULL;
13325603Skjc	u_int32_t atm_flags;
13425603Skjc
135105576Srwatson#ifdef MAC
136105576Srwatson	error = mac_check_ifnet_transmit(ifp, m);
137105576Srwatson	if (error)
138105576Srwatson		senderr(error);
139105576Srwatson#endif
140105576Srwatson
141116720Sharti	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
14225603Skjc		senderr(ENETDOWN);
14325603Skjc
14425603Skjc	/*
14525603Skjc	 * check for non-native ATM traffic   (dst != NULL)
14625603Skjc	 */
14725603Skjc	if (dst) {
14825603Skjc		switch (dst->sa_family) {
149116720Sharti
15037939Skjc#if defined(INET) || defined(INET6)
15125603Skjc		case AF_INET:
15237939Skjc		case AF_INET6:
153128636Sluigi		{
154128636Sluigi			struct rtentry *rt;
155128636Sluigi			/*
156128636Sluigi			 * check route
157128636Sluigi			 */
158128636Sluigi			error = rt_check(&rt, &rt0, dst);
159128636Sluigi			if (error)
160128636Sluigi				goto bad;
161128636Sluigi
16246695Skjc			if (dst->sa_family == AF_INET6)
163112193Sharti			        etype = ETHERTYPE_IPV6;
16446695Skjc			else
165112193Sharti			        etype = ETHERTYPE_IP;
16625603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
16725603Skjc				m = NULL;
16825603Skjc				/* XXX: atmresolve already free'd it */
16925603Skjc				senderr(EHOSTUNREACH);
17025603Skjc				/* XXX: put ATMARP stuff here */
17125603Skjc				/* XXX: watch who frees m on failure */
17225603Skjc			}
173128636Sluigi		}
17425603Skjc			break;
17537939Skjc#endif /* INET || INET6 */
17625603Skjc
17737939Skjc		case AF_UNSPEC:
17837939Skjc			/*
17946695Skjc			 * XXX: bpfwrite. assuming dst contains 12 bytes
18046695Skjc			 * (atm pseudo header (4) + LLC/SNAP (8))
18137939Skjc			 */
18237939Skjc			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
183116720Sharti			llc_hdr = (struct atmllc *)(dst->sa_data +
184116720Sharti			    sizeof(atmdst));
18537939Skjc			break;
18637939Skjc
18725603Skjc		default:
188121816Sbrooks#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \
189121816Sbrooks    defined(__NetBSD__) || defined(__OpenBSD__)
19025603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
19125603Skjc			    dst->sa_family);
19225603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
19325603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
19425603Skjc			    ifp->if_unit, dst->sa_family);
19525603Skjc#endif
19625603Skjc			senderr(EAFNOSUPPORT);
19725603Skjc		}
19825603Skjc
19925603Skjc		/*
20025603Skjc		 * must add atm_pseudohdr to data
20125603Skjc		 */
20225603Skjc		sz = sizeof(atmdst);
20325603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
204116720Sharti		if (atm_flags & ATM_PH_LLCSNAP)
205116720Sharti			sz += 8;	/* sizeof snap == 8 */
206111119Simp		M_PREPEND(m, sz, M_DONTWAIT);
20725603Skjc		if (m == 0)
20825603Skjc			senderr(ENOBUFS);
20925603Skjc		ad = mtod(m, struct atm_pseudohdr *);
21025603Skjc		*ad = atmdst;
21125603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
21225603Skjc			atmllc = (struct atmllc *)(ad + 1);
21337939Skjc			if (llc_hdr == NULL) {
21437939Skjc			        bcopy(ATMLLC_HDR, atmllc->llchdr,
21537939Skjc				      sizeof(atmllc->llchdr));
216116720Sharti				/* note: in host order */
21737939Skjc				ATM_LLC_SETTYPE(atmllc, etype);
21837939Skjc			}
21937939Skjc			else
22037939Skjc			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
22125603Skjc		}
22225603Skjc	}
22325603Skjc
224116741Sharti	if (ng_atm_output_p != NULL) {
225116741Sharti		if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) {
226116741Sharti			if (m != NULL)
227116741Sharti				m_freem(m);
228116741Sharti			return (error);
229116741Sharti		}
230116741Sharti		if (m == NULL)
231116741Sharti			return (0);
232116741Sharti	}
233116741Sharti
23425603Skjc	/*
23525603Skjc	 * Queue message on interface, and start output if interface
23625603Skjc	 * not yet active.
23725603Skjc	 */
238117629Sharti	if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp,
239117629Sharti	    -(int)sizeof(struct atm_pseudohdr)))
24069152Sjlemon		return (ENOBUFS);
24125603Skjc	return (error);
24225603Skjc
24325603Skjcbad:
24425603Skjc	if (m)
24525603Skjc		m_freem(m);
24625603Skjc	return (error);
24725603Skjc}
24825603Skjc
24925603Skjc/*
25025603Skjc * Process a received ATM packet;
25125603Skjc * the packet is in the mbuf chain m.
25225603Skjc */
25325603Skjcvoid
254116720Shartiatm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
255116720Sharti    void *rxhand)
25625603Skjc{
257111888Sjlemon	int isr;
258116720Sharti	u_int16_t etype = ETHERTYPE_IP;		/* default */
259124283Sharti#ifdef NATM
26025603Skjc	int s;
261124283Sharti#endif
26225603Skjc
26325603Skjc	if ((ifp->if_flags & IFF_UP) == 0) {
26425603Skjc		m_freem(m);
26525603Skjc		return;
26625603Skjc	}
267105576Srwatson#ifdef MAC
268105576Srwatson	mac_create_mbuf_from_ifnet(ifp, m);
269105576Srwatson#endif
27025603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
27125603Skjc
272116741Sharti	if (ng_atm_input_p != NULL) {
273116741Sharti		(*ng_atm_input_p)(ifp, &m, ah, rxhand);
274116741Sharti		if (m == NULL)
275116741Sharti			return;
276116741Sharti	}
277116741Sharti
278116741Sharti	/* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */
279116741Sharti	if (atm_harp_input_p != NULL) {
280116741Sharti		(*atm_harp_input_p)(ifp, &m, ah, rxhand);
281116741Sharti		if (m == NULL)
282116741Sharti			return;
283116741Sharti	}
284116741Sharti
28525603Skjc	if (rxhand) {
28625603Skjc#ifdef NATM
28737939Skjc		struct natmpcb *npcb = rxhand;
288116720Sharti
28937939Skjc		s = splimp();		/* in case 2 atm cards @ diff lvls */
29037939Skjc		npcb->npcb_inq++;	/* count # in queue */
29137939Skjc		splx(s);
292111888Sjlemon		isr = NETISR_NATM;
29337939Skjc		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
29425603Skjc#else
295116720Sharti		printf("atm_input: NATM detected but not "
296116720Sharti		    "configured in kernel\n");
297116741Sharti		goto dropit;
29825603Skjc#endif
29925603Skjc	} else {
30037939Skjc		/*
30137939Skjc		 * handle LLC/SNAP header, if present
30237939Skjc		 */
30337939Skjc		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
30437939Skjc			struct atmllc *alc;
305116720Sharti
30637939Skjc			if (m->m_len < sizeof(*alc) &&
30737939Skjc			    (m = m_pullup(m, sizeof(*alc))) == 0)
30837939Skjc				return; /* failed */
30937939Skjc			alc = mtod(m, struct atmllc *);
31037939Skjc			if (bcmp(alc, ATMLLC_HDR, 6)) {
311121816Sbrooks#if (defined(__FreeBSD__) && __FreeBSD_version >= 501113) || \
312121816Sbrooks    defined(__NetBSD__) || defined(__OpenBSD__)
313116720Sharti				printf("%s: recv'd invalid LLC/SNAP frame "
314116720Sharti				    "[vp=%d,vc=%d]\n", ifp->if_xname,
315116720Sharti				    ATM_PH_VPI(ah), ATM_PH_VCI(ah));
31625603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
317116720Sharti				printf("%s%d: recv'd invalid LLC/SNAP frame "
318116720Sharti				    "[vp=%d,vc=%d]\n", ifp->if_name,
319116720Sharti				    ifp->if_unit, ATM_PH_VPI(ah),
320116720Sharti				    ATM_PH_VCI(ah));
32125603Skjc#endif
32237939Skjc				m_freem(m);
32337939Skjc				return;
32437939Skjc			}
32537939Skjc			etype = ATM_LLC_TYPE(alc);
32637939Skjc			m_adj(m, sizeof(*alc));
32737939Skjc		}
32825603Skjc
32937939Skjc		switch (etype) {
330116720Sharti
33125603Skjc#ifdef INET
33237939Skjc		case ETHERTYPE_IP:
333111888Sjlemon			isr = NETISR_IP;
33437939Skjc			break;
33525603Skjc#endif
336116720Sharti
33737939Skjc#ifdef INET6
33837939Skjc		case ETHERTYPE_IPV6:
339111888Sjlemon			isr = NETISR_IPV6;
34037939Skjc			break;
34137939Skjc#endif
34237939Skjc		default:
343116741Sharti#ifndef NATM
344116741Sharti  dropit:
345116741Sharti#endif
346116741Sharti			if (ng_atm_input_orphan_p != NULL)
347116741Sharti				(*ng_atm_input_orphan_p)(ifp, m, ah, rxhand);
348116741Sharti			else
349116741Sharti				m_freem(m);
35037939Skjc			return;
35137939Skjc		}
35225603Skjc	}
353111888Sjlemon	netisr_dispatch(isr, m);
35425603Skjc}
35525603Skjc
35625603Skjc/*
357114201Sharti * Perform common duties while attaching to interface list.
35825603Skjc */
35925603Skjcvoid
360116720Shartiatm_ifattach(struct ifnet *ifp)
36125603Skjc{
362111774Smdodd	struct ifaddr *ifa;
363111774Smdodd	struct sockaddr_dl *sdl;
364147256Sbrooks	struct ifatm *ifatm = ifp->if_l2com;
36525603Skjc
36625603Skjc	ifp->if_addrlen = 0;
36725603Skjc	ifp->if_hdrlen = 0;
368114201Sharti	if_attach(ifp);
36925603Skjc	ifp->if_mtu = ATMMTU;
37025603Skjc	ifp->if_output = atm_output;
371106939Ssam#if 0
372106939Ssam	ifp->if_input = atm_input;
373106939Ssam#endif
37446695Skjc	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
37525603Skjc
37625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
37772012Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
37837939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
37971959Sphk	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
38071959Sphk	    ifa = TAILQ_NEXT(ifa, ifa_link))
38125603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
38225603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
38325603Skjc#endif
38425603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
38525603Skjc		    sdl->sdl_family == AF_LINK) {
38625603Skjc			sdl->sdl_type = IFT_ATM;
38725603Skjc			sdl->sdl_alen = ifp->if_addrlen;
38825603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
38925603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
39025603Skjc#endif
39125603Skjc			break;
39225603Skjc		}
39337939Skjc
394114739Sharti	ifp->if_linkmib = &ifatm->mib;
395114739Sharti	ifp->if_linkmiblen = sizeof(ifatm->mib);
396116741Sharti
397116741Sharti	if(ng_atm_attach_p)
398116741Sharti		(*ng_atm_attach_p)(ifp);
399116741Sharti	if (atm_harp_attach_p)
400116741Sharti		(*atm_harp_attach_p)(ifp);
40137939Skjc}
402114201Sharti
403114201Sharti/*
404114201Sharti * Common stuff for detaching an ATM interface
405114201Sharti */
406114201Shartivoid
407114201Shartiatm_ifdetach(struct ifnet *ifp)
408114201Sharti{
409116741Sharti	if (atm_harp_detach_p)
410116741Sharti		(*atm_harp_detach_p)(ifp);
411116741Sharti	if(ng_atm_detach_p)
412116741Sharti		(*ng_atm_detach_p)(ifp);
413114201Sharti	if_detach(ifp);
414114201Sharti}
415114201Sharti
416117630Sharti/*
417117630Sharti * Support routine for the SIOCATMGVCCS ioctl().
418117630Sharti *
419117630Sharti * This routine assumes, that the private VCC structures used by the driver
420117630Sharti * begin with a struct atmio_vcc.
421117630Sharti *
422117630Sharti * Return a table of VCCs in a freshly allocated memory area.
423117630Sharti * Here we have a problem: we first count, how many vccs we need
424117630Sharti * to return. The we allocate the memory and finally fill it in.
425117630Sharti * Because we cannot lock while calling malloc, the number of active
426117630Sharti * vccs may change while we're in malloc. So we allocate a couple of
427117630Sharti * vccs more and if space anyway is not enough re-iterate.
428117630Sharti *
429117630Sharti * We could use an sx lock for the vcc tables.
430117630Sharti */
431117630Shartistruct atmio_vcctable *
432117630Shartiatm_getvccs(struct atmio_vcc **table, u_int size, u_int start,
433117630Sharti    struct mtx *lock, int waitok)
434117630Sharti{
435117630Sharti	u_int cid, alloc;
436117630Sharti	size_t len;
437117630Sharti	struct atmio_vcctable *vccs;
438117630Sharti	struct atmio_vcc *v;
439117630Sharti
440117630Sharti	alloc = start + 10;
441117630Sharti	vccs = NULL;
442117630Sharti
443117630Sharti	for (;;) {
444117630Sharti		len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]);
445117630Sharti		vccs = reallocf(vccs, len, M_TEMP,
446117630Sharti		    waitok ? M_WAITOK : M_NOWAIT);
447117630Sharti		if (vccs == NULL)
448117630Sharti			return (NULL);
449117630Sharti		bzero(vccs, len);
450117630Sharti
451117630Sharti		vccs->count = 0;
452117630Sharti		v = vccs->vccs;
453117630Sharti
454117630Sharti		mtx_lock(lock);
455117630Sharti		for (cid = 0; cid < size; cid++)
456117630Sharti			if (table[cid] != NULL) {
457117630Sharti				if (++vccs->count == alloc)
458117630Sharti					/* too many - try again */
459117630Sharti					break;
460117630Sharti				*v++ = *table[cid];
461117630Sharti			}
462117630Sharti		mtx_unlock(lock);
463117630Sharti
464117630Sharti		if (cid == size)
465117630Sharti			break;
466117630Sharti
467117630Sharti		alloc *= 2;
468117630Sharti	}
469117630Sharti	return (vccs);
470117630Sharti}
471117630Sharti
472118157Sharti/*
473118157Sharti * Driver or channel state has changed. Inform whoever is interested
474118157Sharti * in these events.
475118157Sharti */
476118157Shartivoid
477118157Shartiatm_event(struct ifnet *ifp, u_int event, void *arg)
478118157Sharti{
479118157Sharti	if (ng_atm_event_p != NULL)
480118157Sharti		(*ng_atm_event_p)(ifp, event, arg);
481118157Sharti	if (atm_harp_event_p != NULL)
482118157Sharti		(*atm_harp_event_p)(ifp, event, arg);
483118157Sharti}
484118157Sharti
485147256Sbrooksstatic void *
486147256Sbrooksatm_alloc(u_char type, struct ifnet *ifp)
487147256Sbrooks{
488147256Sbrooks	struct ifatm	*ifatm;
489147256Sbrooks
490147256Sbrooks	ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO);
491147256Sbrooks	ifatm->ifp = ifp;
492147256Sbrooks
493147256Sbrooks	return (ifatm);
494147256Sbrooks}
495147256Sbrooks
496147256Sbrooksstatic void
497147256Sbrooksatm_free(void *com, u_char type)
498147256Sbrooks{
499147256Sbrooks
500147256Sbrooks	free(com, M_IFATM);
501147256Sbrooks}
502147256Sbrooks
503147256Sbrooksstatic int
504147256Sbrooksatm_modevent(module_t mod, int type, void *data)
505147256Sbrooks{
506147256Sbrooks	switch (type) {
507147256Sbrooks	case MOD_LOAD:
508147256Sbrooks		if_register_com_alloc(IFT_ATM, atm_alloc, atm_free);
509147256Sbrooks		break;
510147256Sbrooks	case MOD_UNLOAD:
511147256Sbrooks		if_deregister_com_alloc(IFT_ATM);
512147256Sbrooks		break;
513147256Sbrooks	default:
514147256Sbrooks		return (EOPNOTSUPP);
515147256Sbrooks	}
516147256Sbrooks
517147256Sbrooks	return (0);
518147256Sbrooks}
519147256Sbrooks
520114201Shartistatic moduledata_t atm_mod = {
521114201Sharti        "atm",
522147256Sbrooks        atm_modevent,
523114201Sharti        0
524114201Sharti};
525114201Sharti
526147256SbrooksDECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
527114201ShartiMODULE_VERSION(atm, 1);
528