if_atmsubr.c revision 243882
1139804Simp/*      $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $       */
240711Swollman
340711Swollman/*-
440711Swollman *
540711Swollman * Copyright (c) 1996 Charles D. Cranor and Washington University.
640711Swollman * All rights reserved.
740711Swollman *
840711Swollman * Redistribution and use in source and binary forms, with or without
940711Swollman * modification, are permitted provided that the following conditions
1040711Swollman * are met:
1140711Swollman * 1. Redistributions of source code must retain the above copyright
1240711Swollman *    notice, this list of conditions and the following disclaimer.
1340711Swollman * 2. Redistributions in binary form must reproduce the above copyright
1440711Swollman *    notice, this list of conditions and the following disclaimer in the
15152543Syongari *    documentation and/or other materials provided with the distribution.
1640711Swollman * 3. All advertising materials mentioning features or use of this software
1740711Swollman *    must display the following acknowledgement:
1840711Swollman *      This product includes software developed by Charles D. Cranor and
1940711Swollman *	Washington University.
2040711Swollman * 4. The name of the author may not be used to endorse or promote products
2140711Swollman *    derived from this software without specific prior written permission.
2240711Swollman *
2340711Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2440711Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2540711Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2640711Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2740711Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2840711Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2940711Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3040711Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3140711Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3240711Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3340711Swollman *
3440711Swollman * if_atmsubr.c
3540711Swollman */
3640711Swollman
3740711Swollman#include <sys/cdefs.h>
3840711Swollman__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 243882 2012-12-05 08:04:20Z glebius $");
3940711Swollman
4040711Swollman#include "opt_inet.h"
4140711Swollman#include "opt_inet6.h"
4240711Swollman#include "opt_natm.h"
4340711Swollman
4440711Swollman#include <sys/param.h>
4540711Swollman#include <sys/systm.h>
4640711Swollman#include <sys/kernel.h>
4740711Swollman#include <sys/module.h>
4840711Swollman#include <sys/mbuf.h>
4940711Swollman#include <sys/socket.h>
5040711Swollman#include <sys/sockio.h>
5140711Swollman#include <sys/errno.h>
5240711Swollman#include <sys/sysctl.h>
5340711Swollman#include <sys/malloc.h>
5440711Swollman
5540711Swollman#include <net/if.h>
5640711Swollman#include <net/netisr.h>
5740711Swollman#include <net/route.h>
58168791Sjhb#include <net/if_dl.h>
59168791Sjhb#include <net/if_types.h>
60116182Sobrien#include <net/if_atm.h>
61116182Sobrien
62116182Sobrien#include <netinet/in.h>
6340711Swollman#include <netinet/if_atm.h>
6440711Swollman#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
6541304Sbde#if defined(INET) || defined(INET6)
66164881Sjhb#include <netinet/in_var.h>
6740711Swollman#endif
6840711Swollman#ifdef NATM
6971576Sjasone#include <netnatm/natm.h>
7045720Speter#endif
7145720Speter
7240711Swollman#include <security/mac/mac_framework.h>
73102962Siwasaki
7440711Swollman/*
75168791Sjhb * Netgraph interface functions.
76168791Sjhb * These need not be protected by a lock, because ng_atm nodes are persitent.
77168791Sjhb * The ng_atm module can be unloaded only if all ATM interfaces have been
78168791Sjhb * unloaded, so nobody should be in the code paths accessing these function
79151037Sphk * pointers.
80151037Sphk */
81151037Sphkvoid	(*ng_atm_attach_p)(struct ifnet *);
82151037Sphkvoid	(*ng_atm_detach_p)(struct ifnet *);
83151037Sphkint	(*ng_atm_output_p)(struct ifnet *, struct mbuf **);
84151037Sphkvoid	(*ng_atm_input_p)(struct ifnet *, struct mbuf **,
85151037Sphk	    struct atm_pseudohdr *, void *);
86151037Sphkvoid	(*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
87151037Sphk	    struct atm_pseudohdr *, void *);
88151037Sphkvoid	(*ng_atm_event_p)(struct ifnet *, uint32_t, void *);
89151037Sphk
90151037Sphk/*
91151037Sphk * Harp pseudo interface hooks
92151037Sphk */
93151037Sphkvoid	(*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m,
94151037Sphk	    struct atm_pseudohdr *ah, void *rxhand);
95151037Sphkvoid	(*atm_harp_attach_p)(struct ifnet *);
96151037Sphkvoid	(*atm_harp_detach_p)(struct ifnet *);
97151037Sphkvoid	(*atm_harp_event_p)(struct ifnet *, uint32_t, void *);
98151037Sphk
99151037SphkSYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware");
100151037Sphk
101151037Sphkstatic MALLOC_DEFINE(M_IFATM, "ifatm", "atm interface internals");
102188061Simp
103102962Siwasaki#ifndef ETHERTYPE_IPV6
104102962Siwasaki#define	ETHERTYPE_IPV6	0x86dd
105102962Siwasaki#endif
10659910Spaul
107102962Siwasaki#define	senderr(e) do { error = (e); goto bad; } while (0)
108102962Siwasaki
10945569Seivind/*
11040711Swollman * atm_output: ATM output routine
11140711Swollman *   inputs:
11271576Sjasone *     "ifp" = ATM interface to output to
113150523Sphk *     "m0" = the packet to output
114150523Sphk *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
115150523Sphk *     "ro" = the route to use
116150523Sphk *   returns: error code   [0 == ok]
11740711Swollman *
118150523Sphk *   note: special semantic: if (dst == NULL) then we assume "m" already
119150523Sphk *		has an atm_pseudohdr on it and just send it directly.
120150523Sphk *		[for native mode ATM output]   if dst is null, then
121150523Sphk *		ro->ro_rt must also be NULL.
122150523Sphk */
123150523Sphkint
124150523Sphkatm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
125150523Sphk    struct route *ro)
126150523Sphk{
127150523Sphk	u_int16_t etype = 0;			/* if using LLC/SNAP */
128150523Sphk	int error = 0, sz;
129150523Sphk	struct atm_pseudohdr atmdst, *ad;
13040711Swollman	struct mbuf *m = m0;
13140711Swollman	struct atmllc *atmllc;
13240711Swollman	struct atmllc *llc_hdr = NULL;
133152543Syongari	u_int32_t atm_flags;
13440711Swollman
13540711Swollman#ifdef MAC
13640711Swollman	error = mac_ifnet_check_transmit(ifp, m);
13740711Swollman	if (error)
13893818Sjhb		senderr(error);
13940711Swollman#endif
14040711Swollman
141221218Sjhb	if (!((ifp->if_flags & IFF_UP) &&
142221218Sjhb	    (ifp->if_drv_flags & IFF_DRV_RUNNING)))
14340711Swollman		senderr(ENETDOWN);
14440711Swollman
14540711Swollman	/*
14640711Swollman	 * check for non-native ATM traffic   (dst != NULL)
14740711Swollman	 */
14868727Smckusick	if (dst) {
14984781Sjhb		switch (dst->sa_family) {
150152543Syongari
15140711Swollman#if defined(INET) || defined(INET6)
15293818Sjhb		case AF_INET:
15340711Swollman		case AF_INET6:
15472200Sbmilekic		{
15540711Swollman			if (dst->sa_family == AF_INET6)
15672200Sbmilekic			        etype = ETHERTYPE_IPV6;
15740711Swollman			else
15840711Swollman			        etype = ETHERTYPE_IP;
15940711Swollman			if (!atmresolve(ro->ro_rt, m, dst, &atmdst)) {
16040711Swollman				m = NULL;
16140711Swollman				/* XXX: atmresolve already free'd it */
16240711Swollman				senderr(EHOSTUNREACH);
163162224Sjhb				/* XXX: put ATMARP stuff here */
164236359Simp				/* XXX: watch who frees m on failure */
16540711Swollman			}
166134040Snjl		}
167134021Snjl			break;
168221218Sjhb#endif /* INET || INET6 */
169221218Sjhb
170150523Sphk		case AF_UNSPEC:
171152543Syongari			/*
17240711Swollman			 * XXX: bpfwrite. assuming dst contains 12 bytes
17340711Swollman			 * (atm pseudo header (4) + LLC/SNAP (8))
17440711Swollman			 */
17540711Swollman			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
17640711Swollman			llc_hdr = (struct atmllc *)(dst->sa_data +
17772200Sbmilekic			    sizeof(atmdst));
178162224Sjhb			break;
179162224Sjhb
180164881Sjhb		default:
181164881Sjhb			printf("%s: can't handle af%d\n", ifp->if_xname,
182164881Sjhb			    dst->sa_family);
183164881Sjhb			senderr(EAFNOSUPPORT);
184164881Sjhb		}
185164881Sjhb
18640711Swollman		/*
187162224Sjhb		 * must add atm_pseudohdr to data
18868727Smckusick		 */
18968727Smckusick		sz = sizeof(atmdst);
19040711Swollman		atm_flags = ATM_PH_FLAGS(&atmdst);
191162224Sjhb		if (atm_flags & ATM_PH_LLCSNAP)
192236359Simp			sz += 8;	/* sizeof snap == 8 */
193236359Simp		M_PREPEND(m, sz, M_NOWAIT);
194236359Simp		if (m == 0)
195236359Simp			senderr(ENOBUFS);
196162224Sjhb		ad = mtod(m, struct atm_pseudohdr *);
197162224Sjhb		*ad = atmdst;
198162224Sjhb		if (atm_flags & ATM_PH_LLCSNAP) {
199236359Simp			atmllc = (struct atmllc *)(ad + 1);
200236359Simp			if (llc_hdr == NULL) {
201236359Simp			        bcopy(ATMLLC_HDR, atmllc->llchdr,
202236359Simp				      sizeof(atmllc->llchdr));
203162224Sjhb				/* note: in host order */
204162224Sjhb				ATM_LLC_SETTYPE(atmllc, etype);
205162224Sjhb			}
206162224Sjhb			else
207162224Sjhb			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
208162224Sjhb		}
209162224Sjhb	}
210162224Sjhb
211162224Sjhb	if (ng_atm_output_p != NULL) {
212162224Sjhb		if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) {
213162224Sjhb			if (m != NULL)
214162224Sjhb				m_freem(m);
215162224Sjhb			return (error);
216162224Sjhb		}
217162224Sjhb		if (m == NULL)
218162224Sjhb			return (0);
219162224Sjhb	}
220162224Sjhb
221162224Sjhb	/*
222162224Sjhb	 * Queue message on interface, and start output if interface
223166932Sscottl	 * not yet active.
224166932Sscottl	 */
225166932Sscottl	if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp,
226166932Sscottl	    -(int)sizeof(struct atm_pseudohdr)))
227166932Sscottl		return (ENOBUFS);
228166932Sscottl	return (error);
229162224Sjhb
230166932Sscottlbad:
231162224Sjhb	if (m)
23240711Swollman		m_freem(m);
233236359Simp	return (error);
23472200Sbmilekic}
235236359Simp
23640711Swollman/*
23740711Swollman * Process a received ATM packet;
23840711Swollman * the packet is in the mbuf chain m.
239159536Simp */
240159536Simpvoid
241159536Simpatm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
242159536Simp    void *rxhand)
243159536Simp{
244159536Simp	int isr;
245159536Simp	u_int16_t etype = ETHERTYPE_IP;		/* default */
246159536Simp
247159536Simp	if ((ifp->if_flags & IFF_UP) == 0) {
248159536Simp		m_freem(m);
24940711Swollman		return;
25040711Swollman	}
251150523Sphk#ifdef MAC
25240711Swollman	mac_ifnet_create_mbuf(ifp, m);
25372200Sbmilekic#endif
25468727Smckusick	ifp->if_ibytes += m->m_pkthdr.len;
25545720Speter
25672200Sbmilekic	if (ng_atm_input_p != NULL) {
25740711Swollman		(*ng_atm_input_p)(ifp, &m, ah, rxhand);
25845720Speter		if (m == NULL)
25940711Swollman			return;
26040711Swollman	}
26140711Swollman
26240711Swollman	/* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */
26340711Swollman	if (atm_harp_input_p != NULL) {
26440711Swollman		(*atm_harp_input_p)(ifp, &m, ah, rxhand);
26568727Smckusick		if (m == NULL)
26668727Smckusick			return;
26768727Smckusick	}
26840711Swollman
26940711Swollman	if (rxhand) {
27072200Sbmilekic#ifdef NATM
27172200Sbmilekic		struct natmpcb *npcb;
27240711Swollman
27372200Sbmilekic		/*
27471576Sjasone		 * XXXRW: this use of 'rxhand' is not a very good idea, and
27571576Sjasone		 * was subject to races even before SMPng due to the release
27640711Swollman		 * of spl here.
27740711Swollman		 */
27840711Swollman		NATM_LOCK();
27940711Swollman		npcb = rxhand;
280221220Sjhb		npcb->npcb_inq++;	/* count # in queue */
281221220Sjhb		isr = NETISR_NATM;
282221220Sjhb		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
283221220Sjhb		NATM_UNLOCK();
284221220Sjhb#else
285221220Sjhb		printf("atm_input: NATM detected but not "
286221220Sjhb		    "configured in kernel\n");
287221220Sjhb		goto dropit;
288221220Sjhb#endif
289221220Sjhb	} else {
290221220Sjhb		/*
291221220Sjhb		 * handle LLC/SNAP header, if present
292221220Sjhb		 */
293221220Sjhb		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
294221220Sjhb			struct atmllc *alc;
295221220Sjhb
296221220Sjhb			if (m->m_len < sizeof(*alc) &&
297221220Sjhb			    (m = m_pullup(m, sizeof(*alc))) == 0)
298221220Sjhb				return; /* failed */
299221220Sjhb			alc = mtod(m, struct atmllc *);
300221220Sjhb			if (bcmp(alc, ATMLLC_HDR, 6)) {
301221220Sjhb				printf("%s: recv'd invalid LLC/SNAP frame "
302221220Sjhb				    "[vp=%d,vc=%d]\n", ifp->if_xname,
303221220Sjhb				    ATM_PH_VPI(ah), ATM_PH_VCI(ah));
304221220Sjhb				m_freem(m);
305221220Sjhb				return;
306221220Sjhb			}
307221220Sjhb			etype = ATM_LLC_TYPE(alc);
308221220Sjhb			m_adj(m, sizeof(*alc));
309221220Sjhb		}
310221220Sjhb
311221220Sjhb		switch (etype) {
312221220Sjhb
313221220Sjhb#ifdef INET
314221220Sjhb		case ETHERTYPE_IP:
315221220Sjhb			isr = NETISR_IP;
316221220Sjhb			break;
317221220Sjhb#endif
318221220Sjhb
319221220Sjhb#ifdef INET6
320221220Sjhb		case ETHERTYPE_IPV6:
321221220Sjhb			isr = NETISR_IPV6;
322221220Sjhb			break;
323221220Sjhb#endif
324221220Sjhb		default:
325221220Sjhb#ifndef NATM
326221220Sjhb  dropit:
327221220Sjhb#endif
328221220Sjhb			if (ng_atm_input_orphan_p != NULL)
329221220Sjhb				(*ng_atm_input_orphan_p)(ifp, m, ah, rxhand);
330221220Sjhb			else
331221220Sjhb				m_freem(m);
332221220Sjhb			return;
333221220Sjhb		}
334221220Sjhb	}
335221220Sjhb	M_SETFIB(m, ifp->if_fib);
336221220Sjhb	netisr_dispatch(isr, m);
337221220Sjhb}
338221220Sjhb
339221220Sjhb/*
340221220Sjhb * Perform common duties while attaching to interface list.
341221220Sjhb */
342221220Sjhbvoid
343221220Sjhbatm_ifattach(struct ifnet *ifp)
344221220Sjhb{
345221220Sjhb	struct ifaddr *ifa;
346221220Sjhb	struct sockaddr_dl *sdl;
347221220Sjhb	struct ifatm *ifatm = ifp->if_l2com;
348221220Sjhb
349221220Sjhb	ifp->if_addrlen = 0;
350221220Sjhb	ifp->if_hdrlen = 0;
351221220Sjhb	if_attach(ifp);
352221220Sjhb	ifp->if_mtu = ATMMTU;
353221220Sjhb	ifp->if_output = atm_output;
354221220Sjhb#if 0
355221220Sjhb	ifp->if_input = atm_input;
356221220Sjhb#endif
357221220Sjhb	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
358221220Sjhb
359221220Sjhb	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
360221220Sjhb		if (ifa->ifa_addr->sa_family == AF_LINK) {
361221220Sjhb			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
362221220Sjhb			sdl->sdl_type = IFT_ATM;
363221220Sjhb			sdl->sdl_alen = ifp->if_addrlen;
364221220Sjhb#ifdef notyet /* if using ATMARP, store hardware address using the next line */
365221220Sjhb			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
366221220Sjhb#endif
367221220Sjhb			break;
368221220Sjhb		}
369221220Sjhb
370221220Sjhb	ifp->if_linkmib = &ifatm->mib;
371221220Sjhb	ifp->if_linkmiblen = sizeof(ifatm->mib);
372221220Sjhb
373221220Sjhb	if(ng_atm_attach_p)
374221220Sjhb		(*ng_atm_attach_p)(ifp);
375221220Sjhb	if (atm_harp_attach_p)
376221220Sjhb		(*atm_harp_attach_p)(ifp);
377221220Sjhb}
378221220Sjhb
379221220Sjhb/*
380221220Sjhb * Common stuff for detaching an ATM interface
381221220Sjhb */
382221220Sjhbvoid
383221220Sjhbatm_ifdetach(struct ifnet *ifp)
384221220Sjhb{
385221220Sjhb	if (atm_harp_detach_p)
386221220Sjhb		(*atm_harp_detach_p)(ifp);
387221220Sjhb	if(ng_atm_detach_p)
388221220Sjhb		(*ng_atm_detach_p)(ifp);
389221220Sjhb	if_detach(ifp);
390221220Sjhb}
391221220Sjhb
392221220Sjhb/*
393221220Sjhb * Support routine for the SIOCATMGVCCS ioctl().
394221220Sjhb *
395221220Sjhb * This routine assumes, that the private VCC structures used by the driver
396221220Sjhb * begin with a struct atmio_vcc.
397221220Sjhb *
398221220Sjhb * Return a table of VCCs in a freshly allocated memory area.
399221220Sjhb * Here we have a problem: we first count, how many vccs we need
400221220Sjhb * to return. The we allocate the memory and finally fill it in.
401221220Sjhb * Because we cannot lock while calling malloc, the number of active
402221220Sjhb * vccs may change while we're in malloc. So we allocate a couple of
403221220Sjhb * vccs more and if space anyway is not enough re-iterate.
404221220Sjhb *
405221220Sjhb * We could use an sx lock for the vcc tables.
406221220Sjhb */
407221220Sjhbstruct atmio_vcctable *
408221220Sjhbatm_getvccs(struct atmio_vcc **table, u_int size, u_int start,
409221220Sjhb    struct mtx *lock, int waitok)
410221220Sjhb{
411221220Sjhb	u_int cid, alloc;
412221220Sjhb	size_t len;
413221220Sjhb	struct atmio_vcctable *vccs;
414221220Sjhb	struct atmio_vcc *v;
415221220Sjhb
416221220Sjhb	alloc = start + 10;
417221220Sjhb	vccs = NULL;
418221220Sjhb
419221220Sjhb	for (;;) {
420221220Sjhb		len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]);
421221220Sjhb		vccs = reallocf(vccs, len, M_TEMP,
422221220Sjhb		    waitok ? M_WAITOK : M_NOWAIT);
423221220Sjhb		if (vccs == NULL)
424221220Sjhb			return (NULL);
425221220Sjhb		bzero(vccs, len);
426221220Sjhb
427221220Sjhb		vccs->count = 0;
428221220Sjhb		v = vccs->vccs;
429221220Sjhb
430221220Sjhb		mtx_lock(lock);
431221220Sjhb		for (cid = 0; cid < size; cid++)
432221220Sjhb			if (table[cid] != NULL) {
433221220Sjhb				if (++vccs->count == alloc)
434221220Sjhb					/* too many - try again */
435221220Sjhb					break;
436221220Sjhb				*v++ = *table[cid];
437221220Sjhb			}
43840711Swollman		mtx_unlock(lock);
43988372Stmm
44088372Stmm		if (cid == size)
44188372Stmm			break;
44240711Swollman
44340711Swollman		alloc *= 2;
444150523Sphk	}
44588372Stmm	return (vccs);
44640711Swollman}
447152543Syongari
44840711Swollman/*
449160958Sjb * Driver or channel state has changed. Inform whoever is interested
450160958Sjb * in these events.
451160958Sjb */
452160958Sjbvoid
45340711Swollmanatm_event(struct ifnet *ifp, u_int event, void *arg)
45440711Swollman{
45540711Swollman	if (ng_atm_event_p != NULL)
45672200Sbmilekic		(*ng_atm_event_p)(ifp, event, arg);
45740711Swollman	if (atm_harp_event_p != NULL)
458152543Syongari		(*atm_harp_event_p)(ifp, event, arg);
459265363Struckman}
46068727Smckusick
46140711Swollmanstatic void *
46240711Swollmanatm_alloc(u_char type, struct ifnet *ifp)
46368727Smckusick{
46459910Spaul	struct ifatm	*ifatm;
46540711Swollman
46640711Swollman	ifatm = malloc(sizeof(struct ifatm), M_IFATM, M_WAITOK | M_ZERO);
46740711Swollman	ifatm->ifp = ifp;
46888372Stmm
469265931Struckman	return (ifatm);
470265931Struckman}
471265363Struckman
472265363Struckmanstatic void
473265363Struckmanatm_free(void *com, u_char type)
47488372Stmm{
47588372Stmm
47640711Swollman	free(com, M_IFATM);
47740711Swollman}
47840711Swollman
47968727Smckusickstatic int
48059910Spaulatm_modevent(module_t mod, int type, void *data)
481265363Struckman{
482265363Struckman	switch (type) {
483265363Struckman	case MOD_LOAD:
484265363Struckman		if_register_com_alloc(IFT_ATM, atm_alloc, atm_free);
485265363Struckman		break;
486143665Simp	case MOD_UNLOAD:
487143665Simp		if_deregister_com_alloc(IFT_ATM);
48840711Swollman		break;
48940711Swollman	default:
490265931Struckman		return (EOPNOTSUPP);
491265931Struckman	}
492265363Struckman
493265363Struckman	return (0);
494265363Struckman}
49540711Swollman
49659910Spaulstatic moduledata_t atm_mod = {
49740711Swollman        "atm",
49840711Swollman        atm_modevent,
49988372Stmm        0
50088372Stmm};
50188372Stmm
50288372StmmDECLARE_MODULE(atm, atm_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
50388372StmmMODULE_VERSION(atm, 1);
50488372Stmm