if_ef.c revision 132778
154558Sbp/*-
266479Sbp * Copyright (c) 1999, 2000 Boris Popov
354558Sbp * All rights reserved.
454558Sbp *
554558Sbp * Redistribution and use in source and binary forms, with or without
654558Sbp * modification, are permitted provided that the following conditions
754558Sbp * are met:
854558Sbp * 1. Redistributions of source code must retain the above copyright
954558Sbp *    notice, this list of conditions and the following disclaimer.
1054558Sbp * 2. Redistributions in binary form must reproduce the above copyright
1154558Sbp *    notice, this list of conditions and the following disclaimer in the
1254558Sbp *    documentation and/or other materials provided with the distribution.
1354558Sbp *
1454558Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1554558Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1654558Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1754558Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1854558Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1954558Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2054558Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2154558Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2254558Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2354558Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2454558Sbp * SUCH DAMAGE.
2554558Sbp *
2654558Sbp * $FreeBSD: head/sys/net/if_ef.c 132778 2004-07-28 06:48:36Z kan $
2754558Sbp */
2854558Sbp
2954558Sbp#include "opt_inet.h"
3054558Sbp#include "opt_ipx.h"
3156424Sbp#include "opt_ef.h"
3254558Sbp
3354558Sbp#include <sys/param.h>
3454558Sbp#include <sys/systm.h>
3554558Sbp#include <sys/sockio.h>
3654558Sbp#include <sys/malloc.h>
3754558Sbp#include <sys/mbuf.h>
3854558Sbp#include <sys/socket.h>
3954558Sbp#include <sys/syslog.h>
4054558Sbp#include <sys/kernel.h>
4154558Sbp#include <sys/module.h>
4254558Sbp
4354558Sbp#include <net/ethernet.h>
4454558Sbp#include <net/if_llc.h>
4554558Sbp#include <net/if.h>
4654558Sbp#include <net/if_arp.h>
4754558Sbp#include <net/if_dl.h>
4854558Sbp#include <net/if_types.h>
4954558Sbp#include <net/netisr.h>
5054558Sbp#include <net/route.h>
5154558Sbp#include <net/bpf.h>
5254558Sbp
5354558Sbp#ifdef INET
5454558Sbp#include <netinet/in.h>
5554558Sbp#include <netinet/in_var.h>
5654558Sbp#include <netinet/if_ether.h>
5754558Sbp#endif
5854558Sbp
5954558Sbp#ifdef IPX
6054558Sbp#include <netipx/ipx.h>
6154558Sbp#include <netipx/ipx_if.h>
6254558Sbp#endif
6354558Sbp
6454558Sbp/* internal frame types */
6554558Sbp#define ETHER_FT_EII		0	/* Ethernet_II - default */
6654558Sbp#define	ETHER_FT_8023		1	/* 802.3 (Novell) */
6754558Sbp#define	ETHER_FT_8022		2	/* 802.2 */
6854558Sbp#define	ETHER_FT_SNAP		3	/* SNAP */
6954558Sbp#define	EF_NFT			4	/* total number of frame types */
7054558Sbp
7154558Sbp#ifdef EF_DEBUG
7287599Sobrien#define EFDEBUG(format, args...) printf("%s: "format, __func__ ,## args)
7354558Sbp#else
7454558Sbp#define EFDEBUG(format, args...)
7554558Sbp#endif
7654558Sbp
7787599Sobrien#define EFERROR(format, args...) printf("%s: "format, __func__ ,## args)
7854558Sbp
7954558Sbpstruct efnet {
8054558Sbp	struct arpcom	ef_ac;
8154558Sbp	struct ifnet *  ef_ifp;
82121816Sbrooks	int		ef_frametype;
8354558Sbp};
8454558Sbp
8554558Sbpstruct ef_link {
8660938Sjake	SLIST_ENTRY(ef_link) el_next;
8754558Sbp	struct ifnet	*el_ifp;		/* raw device for this clones */
8854558Sbp	struct efnet	*el_units[EF_NFT];	/* our clones */
8954558Sbp};
9054558Sbp
9160938Sjakestatic SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
9254558Sbpstatic int efcount;
9354558Sbp
9454558Sbpextern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m);
9559681Sbpextern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
9666479Sbp		struct sockaddr *dst, short *tp, int *hlen);
9754558Sbp
9854558Sbp/*
9954558Sbpstatic void ef_reset (struct ifnet *);
10054558Sbp*/
10154558Sbpstatic int ef_attach(struct efnet *sc);
10254558Sbpstatic int ef_detach(struct efnet *sc);
10354558Sbpstatic void ef_init(void *);
10454558Sbpstatic int ef_ioctl(struct ifnet *, u_long, caddr_t);
10554558Sbpstatic void ef_start(struct ifnet *);
10654558Sbpstatic int ef_input(struct ifnet*, struct ether_header *, struct mbuf *);
10759681Sbpstatic int ef_output(struct ifnet *ifp, struct mbuf **mp,
10866479Sbp		struct sockaddr *dst, short *tp, int *hlen);
10954558Sbp
11054558Sbpstatic int ef_load(void);
11154558Sbpstatic int ef_unload(void);
11254558Sbp
11354558Sbp/*
11454558Sbp * Install the interface, most of structure initialization done in ef_clone()
11554558Sbp */
11654558Sbpstatic int
11754558Sbpef_attach(struct efnet *sc)
11854558Sbp{
11954558Sbp	struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
120106939Ssam	struct ifaddr *ifa2;
121106939Ssam	struct sockaddr_dl *sdl2;
12254558Sbp
12354558Sbp	ifp->if_start = ef_start;
12454558Sbp	ifp->if_watchdog = NULL;
12554558Sbp	ifp->if_init = ef_init;
12654558Sbp	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
12754558Sbp	ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
12854558Sbp	/*
12954558Sbp	 * Attach the interface
13054558Sbp	 */
131106939Ssam	ifa2 = ifaddr_byindex(sc->ef_ifp->if_index);
132106939Ssam	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
133106939Ssam	ether_ifattach(ifp, LLADDR(sdl2));
13454558Sbp
13554558Sbp	ifp->if_resolvemulti = 0;
13654558Sbp	ifp->if_type = IFT_XETHER;
13754558Sbp	ifp->if_flags |= IFF_RUNNING;
13854558Sbp
13954558Sbp	bcopy(LLADDR(sdl2), sc->ef_ac.ac_enaddr, ETHER_ADDR_LEN);
14054558Sbp
141121816Sbrooks	EFDEBUG("%s: attached\n", ifp->if_xname);
14254558Sbp	return 1;
14354558Sbp}
14454558Sbp
14554558Sbp/*
14654558Sbp * This is for _testing_only_, just removes interface from interfaces list
14754558Sbp */
14854558Sbpstatic int
14954558Sbpef_detach(struct efnet *sc)
15054558Sbp{
15154558Sbp	struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
15254558Sbp	int s;
15354558Sbp
15454558Sbp	s = splimp();
15554558Sbp
15654558Sbp	if (ifp->if_flags & IFF_UP) {
15754558Sbp		if_down(ifp);
15854558Sbp		if (ifp->if_flags & IFF_RUNNING) {
15954558Sbp		    /* find internet addresses and delete routes */
16054558Sbp		    register struct ifaddr *ifa;
16172012Sphk		    TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
16254558Sbp			    rtinit(ifa, (int)RTM_DELETE, 0);
16354558Sbp		    }
16454558Sbp		}
16554558Sbp	}
166108172Shsu	IFNET_WLOCK();
16754558Sbp	TAILQ_REMOVE(&ifnet, ifp, if_link);
168108172Shsu	IFNET_WUNLOCK();
16954558Sbp	splx(s);
17054558Sbp	return 0;
17154558Sbp}
17254558Sbp
17354558Sbpstatic void
17454558Sbpef_init(void *foo) {
17554558Sbp	return;
17654558Sbp}
17754558Sbp
17854558Sbpstatic int
17954558Sbpef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
18054558Sbp{
181121816Sbrooks	struct efnet *sc = ifp->if_softc;
18254558Sbp	struct ifaddr *ifa = (struct ifaddr*)data;
18354558Sbp	int s, error;
18454558Sbp
185121816Sbrooks	EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
18654558Sbp	error = 0;
18754558Sbp	s = splimp();
18854558Sbp	switch (cmd) {
189106939Ssam	    case SIOCSIFFLAGS:
190106939Ssam		error = 0;
191106939Ssam		break;
19254558Sbp	    case SIOCSIFADDR:
193121816Sbrooks		if (sc->ef_frametype == ETHER_FT_8023 &&
19454558Sbp		    ifa->ifa_addr->sa_family != AF_IPX) {
19554558Sbp			error = EAFNOSUPPORT;
19654558Sbp			break;
19754558Sbp		}
19854558Sbp		ifp->if_flags |= IFF_UP;
19954558Sbp		/* FALL THROUGH */
200106939Ssam	    default:
20154558Sbp		error = ether_ioctl(ifp, cmd, data);
20254558Sbp		break;
20354558Sbp	}
20454558Sbp	splx(s);
20554558Sbp	return error;
20654558Sbp}
20754558Sbp
20854558Sbp/*
20954558Sbp * Currently packet prepared in the ether_output(), but this can be a better
21054558Sbp * place.
21154558Sbp */
21254558Sbpstatic void
21354558Sbpef_start(struct ifnet *ifp)
21454558Sbp{
21554558Sbp	struct efnet *sc = (struct efnet*)ifp->if_softc;
21654558Sbp	struct ifnet *p;
21754558Sbp	struct mbuf *m;
218130549Smlaier	int error;
21954558Sbp
22054558Sbp	ifp->if_flags |= IFF_OACTIVE;
22154558Sbp	p = sc->ef_ifp;
22254558Sbp
22354558Sbp	EFDEBUG("\n");
22454558Sbp	for (;;) {
22554558Sbp		IF_DEQUEUE(&ifp->if_snd, m);
22654558Sbp		if (m == 0)
22754558Sbp			break;
228106939Ssam		BPF_MTAP(ifp, m);
229130549Smlaier		IFQ_HANDOFF(p, m, error);
230130549Smlaier		if (error) {
23159681Sbp			ifp->if_oerrors++;
23259681Sbp			continue;
23354558Sbp		}
23469152Sjlemon		ifp->if_opackets++;
23554558Sbp	}
23654558Sbp	ifp->if_flags &= ~IFF_OACTIVE;
23754558Sbp	return;
23854558Sbp}
23954558Sbp
24054558Sbp/*
24154558Sbp * Inline functions do not put additional overhead to procedure call or
24254558Sbp * parameter passing but simplify the code
24354558Sbp */
24454558Sbpstatic int __inline
245111888Sjlemonef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
24654558Sbp{
247111888Sjlemon	int isr;
248111888Sjlemon
24954558Sbp	switch(ether_type) {
25054558Sbp#ifdef IPX
251111888Sjlemon	case ETHERTYPE_IPX:
252111888Sjlemon		isr = NETISR_IPX;
25354558Sbp		break;
25454558Sbp#endif
25554558Sbp#ifdef INET
256111888Sjlemon	case ETHERTYPE_IP:
257122702Sandre		if (ip_fastforward(m))
258111888Sjlemon			return (0);
259111888Sjlemon		isr = NETISR_IP;
26054558Sbp		break;
26154558Sbp
262111888Sjlemon	case ETHERTYPE_ARP:
263111888Sjlemon		isr = NETISR_ARP;
26454558Sbp		break;
26554558Sbp#endif
266111888Sjlemon	default:
267111888Sjlemon		return (EPROTONOSUPPORT);
26854558Sbp	}
269111888Sjlemon	netisr_dispatch(isr, m);
270111888Sjlemon	return (0);
27154558Sbp}
27254558Sbp
27354558Sbpstatic int __inline
27454558Sbpef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
275111888Sjlemon	u_short ether_type)
27654558Sbp{
277111888Sjlemon	int isr;
278111888Sjlemon
27954558Sbp	switch(ether_type) {
28054558Sbp#ifdef IPX
281111888Sjlemon	case ETHERTYPE_IPX:
28254558Sbp		m_adj(m, 8);
283111888Sjlemon		isr = NETISR_IPX;
28454558Sbp		break;
28554558Sbp#endif
286111888Sjlemon	default:
287111888Sjlemon		return (EPROTONOSUPPORT);
28854558Sbp	}
289111888Sjlemon	netisr_dispatch(isr, m);
290111888Sjlemon	return (0);
29154558Sbp}
29254558Sbp
29354558Sbpstatic int __inline
29454558Sbpef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
295111888Sjlemon	u_short ether_type)
29654558Sbp{
297111888Sjlemon	int isr;
298111888Sjlemon
29954558Sbp	switch(ether_type) {
30054558Sbp#ifdef IPX
301111888Sjlemon	case 0xe0:
30254558Sbp		m_adj(m, 3);
303111888Sjlemon		isr = NETISR_IPX;
30454558Sbp		break;
30554558Sbp#endif
306111888Sjlemon	default:
307111888Sjlemon		return (EPROTONOSUPPORT);
30854558Sbp	}
309111888Sjlemon	netisr_dispatch(isr, m);
310111888Sjlemon	return (0);
31154558Sbp}
312111888Sjlemon
31354558Sbp/*
31454558Sbp * Called from ether_input()
31554558Sbp */
31654558Sbpstatic int
31754558Sbpef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
31854558Sbp{
31954558Sbp	u_short ether_type;
32071891Sbp	int ft = -1;
32154558Sbp	struct efnet *efp;
32254558Sbp	struct ifnet *eifp;
32354558Sbp	struct llc *l;
32454558Sbp	struct ef_link *efl;
325111888Sjlemon	int isr;
32654558Sbp
32754558Sbp	ether_type = ntohs(eh->ether_type);
328132778Skan	l = NULL;
32954558Sbp	if (ether_type < ETHERMTU) {
33054558Sbp		l = mtod(m, struct llc*);
33154558Sbp		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
33254558Sbp			/*
33354558Sbp			 * Novell's "802.3" frame
33454558Sbp			 */
33554558Sbp			ft = ETHER_FT_8023;
33654558Sbp		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
33754558Sbp			/*
33854558Sbp			 * 802.2/SNAP
33954558Sbp			 */
34054558Sbp			ft = ETHER_FT_SNAP;
34154558Sbp			ether_type = ntohs(l->llc_un.type_snap.ether_type);
34254558Sbp		} else if (l->llc_dsap == l->llc_ssap) {
34354558Sbp			/*
34454558Sbp			 * 802.3/802.2
34554558Sbp			 */
34654558Sbp			ft = ETHER_FT_8022;
34754558Sbp			ether_type = l->llc_ssap;
34854558Sbp		}
34954558Sbp	} else
35054558Sbp		ft = ETHER_FT_EII;
35154558Sbp
35254558Sbp	if (ft == -1) {
35354558Sbp		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
35459681Sbp		return EPROTONOSUPPORT;
35554558Sbp	}
35654558Sbp
35754558Sbp	/*
35854558Sbp	 * Check if interface configured for the given frame
35954558Sbp	 */
36054558Sbp	efp = NULL;
36154558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
36254558Sbp		if (efl->el_ifp == ifp) {
36354558Sbp			efp = efl->el_units[ft];
36454558Sbp			break;
36554558Sbp		}
36654558Sbp	}
36754558Sbp	if (efp == NULL) {
36854558Sbp		EFDEBUG("Can't find if for %d\n", ft);
36959681Sbp		return EPROTONOSUPPORT;
37054558Sbp	}
37154558Sbp	eifp = &efp->ef_ac.ac_if;
37254558Sbp	if ((eifp->if_flags & IFF_UP) == 0)
37359681Sbp		return EPROTONOSUPPORT;
37454558Sbp	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
37554558Sbp	m->m_pkthdr.rcvif = eifp;
37654558Sbp
377123922Ssam	BPF_MTAP2(eifp, eh, ETHER_HDR_LEN, m);
37854558Sbp	/*
37954558Sbp	 * Now we ready to adjust mbufs and pass them to protocol intr's
38054558Sbp	 */
38154558Sbp	switch(ft) {
382111888Sjlemon	case ETHER_FT_EII:
383111888Sjlemon		return (ef_inputEII(m, eh, ether_type));
38454558Sbp#ifdef IPX
385111888Sjlemon	case ETHER_FT_8023:		/* only IPX can be here */
386111888Sjlemon		isr = NETISR_IPX;
38754558Sbp		break;
38854558Sbp#endif
389111888Sjlemon	case ETHER_FT_SNAP:
390111888Sjlemon		return (ef_inputSNAP(m, eh, l, ether_type));
391111888Sjlemon	case ETHER_FT_8022:
392111888Sjlemon		return (ef_input8022(m, eh, l, ether_type));
393111888Sjlemon	default:
39454558Sbp		EFDEBUG("No support for frame %d and proto %04x\n",
39554558Sbp			ft, ether_type);
396111888Sjlemon		return (EPROTONOSUPPORT);
39754558Sbp	}
398111888Sjlemon	netisr_dispatch(isr, m);
399111888Sjlemon	return (0);
40054558Sbp}
40154558Sbp
40254558Sbpstatic int
40366479Sbpef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
40466479Sbp	int *hlen)
40554558Sbp{
406121816Sbrooks	struct efnet *sc = (struct efnet*)ifp->if_softc;
40759681Sbp	struct mbuf *m = *mp;
40854558Sbp	u_char *cp;
40954558Sbp	short type;
41054558Sbp
41154558Sbp	if (ifp->if_type != IFT_XETHER)
41259681Sbp		return ENETDOWN;
413121816Sbrooks	switch (sc->ef_frametype) {
41454558Sbp	    case ETHER_FT_EII:
41554558Sbp#ifdef IPX
41654558Sbp		type = htons(ETHERTYPE_IPX);
41754558Sbp#else
41859681Sbp		return EPFNOSUPPORT;
41954558Sbp#endif
42054558Sbp		break;
42154558Sbp	    case ETHER_FT_8023:
42254558Sbp		type = htons(m->m_pkthdr.len);
42354558Sbp		break;
42454558Sbp	    case ETHER_FT_8022:
425111119Simp		M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
42659681Sbp		if (m == NULL) {
42759681Sbp			*mp = NULL;
42859681Sbp			return ENOBUFS;
42959681Sbp		}
43059681Sbp		/*
43159681Sbp		 * Ensure that ethernet header and next three bytes
43259681Sbp		 * will fit into single mbuf
43359681Sbp		 */
43459681Sbp		m = m_pullup(m, ETHER_HDR_LEN + 3);
43559681Sbp		if (m == NULL) {
43659681Sbp			*mp = NULL;
43759681Sbp			return ENOBUFS;
43859681Sbp		}
43959681Sbp		m_adj(m, ETHER_HDR_LEN);
44054558Sbp		type = htons(m->m_pkthdr.len);
44154558Sbp		cp = mtod(m, u_char *);
44254558Sbp		*cp++ = 0xE0;
44354558Sbp		*cp++ = 0xE0;
44454558Sbp		*cp++ = 0x03;
44566479Sbp		*hlen += 3;
44654558Sbp		break;
44754558Sbp	    case ETHER_FT_SNAP:
448111119Simp		M_PREPEND(m, 8, M_TRYWAIT);
44959681Sbp		if (m == NULL) {
45059681Sbp			*mp = NULL;
45159681Sbp			return ENOBUFS;
45259681Sbp		}
45354558Sbp		type = htons(m->m_pkthdr.len);
45454558Sbp		cp = mtod(m, u_char *);
45554558Sbp		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
45666479Sbp		*hlen += 8;
45754558Sbp		break;
45854558Sbp	    default:
45959681Sbp		return EPFNOSUPPORT;
46054558Sbp	}
46159681Sbp	*mp = m;
46254558Sbp	*tp = type;
46354558Sbp	return 0;
46454558Sbp}
46554558Sbp
46654558Sbp/*
46754558Sbp * Create clone from the given interface
46854558Sbp */
46954558Sbpstatic int
47054558Sbpef_clone(struct ef_link *efl, int ft)
47154558Sbp{
47254558Sbp	struct efnet *efp;
47354558Sbp	struct ifnet *eifp;
47454558Sbp	struct ifnet *ifp = efl->el_ifp;
47554558Sbp
47669781Sdwmalone	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
477111119Simp	    M_WAITOK | M_ZERO);
47854558Sbp	if (efp == NULL)
47954558Sbp		return ENOMEM;
48054558Sbp	efp->ef_ifp = ifp;
481121816Sbrooks	efp->ef_frametype = ft;
48254558Sbp	eifp = &efp->ef_ac.ac_if;
483121816Sbrooks	snprintf(eifp->if_xname, IFNAMSIZ,
484121816Sbrooks	    "%sf%d", ifp->if_xname, efp->ef_frametype);
485121816Sbrooks	eifp->if_dname = "ef";
486121816Sbrooks	eifp->if_dunit = IF_DUNIT_NONE;
48754558Sbp	eifp->if_softc = efp;
48854558Sbp	if (ifp->if_ioctl)
48954558Sbp		eifp->if_ioctl = ef_ioctl;
49054558Sbp	efl->el_units[ft] = efp;
49154558Sbp	return 0;
49254558Sbp}
49354558Sbp
49454558Sbpstatic int
49554558Sbpef_load(void)
49654558Sbp{
49754558Sbp	struct ifnet *ifp;
49854558Sbp	struct efnet *efp;
49954558Sbp	struct ef_link *efl = NULL;
50054558Sbp	int error = 0, d;
50154558Sbp
502108172Shsu	IFNET_RLOCK();
50371999Sphk	TAILQ_FOREACH(ifp, &ifnet, if_link) {
50454558Sbp		if (ifp->if_type != IFT_ETHER) continue;
505121816Sbrooks		EFDEBUG("Found interface %s\n", ifp->if_xname);
50654558Sbp		efl = (struct ef_link*)malloc(sizeof(struct ef_link),
507111119Simp		    M_IFADDR, M_WAITOK | M_ZERO);
50854558Sbp		if (efl == NULL) {
50954558Sbp			error = ENOMEM;
51054558Sbp			break;
51154558Sbp		}
51254558Sbp
51354558Sbp		efl->el_ifp = ifp;
51454558Sbp#ifdef ETHER_II
51554558Sbp		error = ef_clone(efl, ETHER_FT_EII);
51654558Sbp		if (error) break;
51754558Sbp#endif
51854558Sbp#ifdef ETHER_8023
51954558Sbp		error = ef_clone(efl, ETHER_FT_8023);
52054558Sbp		if (error) break;
52154558Sbp#endif
52254558Sbp#ifdef ETHER_8022
52354558Sbp		error = ef_clone(efl, ETHER_FT_8022);
52454558Sbp		if (error) break;
52554558Sbp#endif
52654558Sbp#ifdef ETHER_SNAP
52754558Sbp		error = ef_clone(efl, ETHER_FT_SNAP);
52854558Sbp		if (error) break;
52954558Sbp#endif
53054558Sbp		efcount++;
53154558Sbp		SLIST_INSERT_HEAD(&efdev, efl, el_next);
53254558Sbp	}
533108172Shsu	IFNET_RUNLOCK();
53454558Sbp	if (error) {
53554558Sbp		if (efl)
53654558Sbp			SLIST_INSERT_HEAD(&efdev, efl, el_next);
53754558Sbp		SLIST_FOREACH(efl, &efdev, el_next) {
53854558Sbp			for (d = 0; d < EF_NFT; d++)
53954558Sbp				if (efl->el_units[d])
54054558Sbp					free(efl->el_units[d], M_IFADDR);
54154558Sbp			free(efl, M_IFADDR);
54254558Sbp		}
54354558Sbp		return error;
54454558Sbp	}
54554558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
54654558Sbp		for (d = 0; d < EF_NFT; d++) {
54754558Sbp			efp = efl->el_units[d];
54854558Sbp			if (efp)
54954558Sbp				ef_attach(efp);
55054558Sbp		}
55154558Sbp	}
55254558Sbp	ef_inputp = ef_input;
55354558Sbp	ef_outputp = ef_output;
55454558Sbp	EFDEBUG("Loaded\n");
55554558Sbp	return 0;
55654558Sbp}
55754558Sbp
55854558Sbpstatic int
55954558Sbpef_unload(void)
56054558Sbp{
56154558Sbp	struct efnet *efp;
56254558Sbp	struct ef_link *efl;
56354558Sbp	int d;
56454558Sbp
56554558Sbp	ef_inputp = NULL;
56654558Sbp	ef_outputp = NULL;
56754558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
56854558Sbp		for (d = 0; d < EF_NFT; d++) {
56954558Sbp			efp = efl->el_units[d];
57054558Sbp			if (efp) {
57154558Sbp				ef_detach(efp);
57254558Sbp			}
57354558Sbp		}
57454558Sbp	}
57554558Sbp	EFDEBUG("Unloaded\n");
57654558Sbp	return 0;
57754558Sbp}
57854558Sbp
57954558Sbpstatic int
58054558Sbpif_ef_modevent(module_t mod, int type, void *data)
58154558Sbp{
58254558Sbp	switch ((modeventtype_t)type) {
58354558Sbp	    case MOD_LOAD:
58454558Sbp		return ef_load();
58554558Sbp	    case MOD_UNLOAD:
58654558Sbp		return ef_unload();
58754558Sbp	    default:
588132199Sphk		return EOPNOTSUPP;
58954558Sbp	}
59054558Sbp	return 0;
59154558Sbp}
59254558Sbp
59354558Sbpstatic moduledata_t if_ef_mod = {
59454558Sbp	"if_ef", if_ef_modevent, NULL
59554558Sbp};
59654558Sbp
59754558SbpDECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
598