if_ef.c revision 111888
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 111888 2003-03-04 23:19:55Z jlemon $
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;
8254558Sbp};
8354558Sbp
8454558Sbpstruct ef_link {
8560938Sjake	SLIST_ENTRY(ef_link) el_next;
8654558Sbp	struct ifnet	*el_ifp;		/* raw device for this clones */
8754558Sbp	struct efnet	*el_units[EF_NFT];	/* our clones */
8854558Sbp};
8954558Sbp
9060938Sjakestatic SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
9154558Sbpstatic int efcount;
9254558Sbp
9354558Sbpextern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m);
9459681Sbpextern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
9566479Sbp		struct sockaddr *dst, short *tp, int *hlen);
9654558Sbp
9754558Sbp/*
9854558Sbpstatic void ef_reset (struct ifnet *);
9954558Sbp*/
10054558Sbpstatic int ef_attach(struct efnet *sc);
10154558Sbpstatic int ef_detach(struct efnet *sc);
10254558Sbpstatic void ef_init(void *);
10354558Sbpstatic int ef_ioctl(struct ifnet *, u_long, caddr_t);
10454558Sbpstatic void ef_start(struct ifnet *);
10554558Sbpstatic int ef_input(struct ifnet*, struct ether_header *, struct mbuf *);
10659681Sbpstatic int ef_output(struct ifnet *ifp, struct mbuf **mp,
10766479Sbp		struct sockaddr *dst, short *tp, int *hlen);
10854558Sbp
10954558Sbpstatic int ef_load(void);
11054558Sbpstatic int ef_unload(void);
11154558Sbp
11254558Sbp/*
11354558Sbp * Install the interface, most of structure initialization done in ef_clone()
11454558Sbp */
11554558Sbpstatic int
11654558Sbpef_attach(struct efnet *sc)
11754558Sbp{
11854558Sbp	struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
119106939Ssam	struct ifaddr *ifa2;
120106939Ssam	struct sockaddr_dl *sdl2;
12154558Sbp
12254558Sbp	ifp->if_output = ether_output;
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
14154558Sbp	EFDEBUG("%s%d: attached\n", ifp->if_name, ifp->if_unit);
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{
18154558Sbp/*	struct ef_link *sc = (struct ef_link*)ifp->if_softc;*/
18254558Sbp	struct ifaddr *ifa = (struct ifaddr*)data;
18354558Sbp	int s, error;
18454558Sbp
18554558Sbp	EFDEBUG("IOCTL %ld for %s%d\n", cmd, ifp->if_name, ifp->if_unit);
18654558Sbp	error = 0;
18754558Sbp	s = splimp();
18854558Sbp	switch (cmd) {
189106939Ssam	    case SIOCSIFFLAGS:
190106939Ssam		error = 0;
191106939Ssam		break;
19254558Sbp	    case SIOCSIFADDR:
19354558Sbp		if (ifp->if_unit == 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;
21854558Sbp
21954558Sbp	ifp->if_flags |= IFF_OACTIVE;
22054558Sbp	p = sc->ef_ifp;
22154558Sbp
22254558Sbp	EFDEBUG("\n");
22354558Sbp	for (;;) {
22454558Sbp		IF_DEQUEUE(&ifp->if_snd, m);
22554558Sbp		if (m == 0)
22654558Sbp			break;
227106939Ssam		BPF_MTAP(ifp, m);
22871891Sbp		if (! IF_HANDOFF(&p->if_snd, m, p)) {
22959681Sbp			ifp->if_oerrors++;
23059681Sbp			continue;
23154558Sbp		}
23269152Sjlemon		ifp->if_opackets++;
23354558Sbp	}
23454558Sbp	ifp->if_flags &= ~IFF_OACTIVE;
23554558Sbp	return;
23654558Sbp}
23754558Sbp
23854558Sbp/*
23954558Sbp * Inline functions do not put additional overhead to procedure call or
24054558Sbp * parameter passing but simplify the code
24154558Sbp */
24254558Sbpstatic int __inline
243111888Sjlemonef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
24454558Sbp{
245111888Sjlemon	int isr;
246111888Sjlemon
24754558Sbp	switch(ether_type) {
24854558Sbp#ifdef IPX
249111888Sjlemon	case ETHERTYPE_IPX:
250111888Sjlemon		isr = NETISR_IPX;
25154558Sbp		break;
25254558Sbp#endif
25354558Sbp#ifdef INET
254111888Sjlemon	case ETHERTYPE_IP:
25554558Sbp		if (ipflow_fastforward(m))
256111888Sjlemon			return (0);
257111888Sjlemon		isr = NETISR_IP;
25854558Sbp		break;
25954558Sbp
260111888Sjlemon	case ETHERTYPE_ARP:
261111888Sjlemon		isr = NETISR_ARP;
26254558Sbp		break;
26354558Sbp#endif
264111888Sjlemon	default:
265111888Sjlemon		return (EPROTONOSUPPORT);
26654558Sbp	}
267111888Sjlemon	netisr_dispatch(isr, m);
268111888Sjlemon	return (0);
26954558Sbp}
27054558Sbp
27154558Sbpstatic int __inline
27254558Sbpef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
273111888Sjlemon	u_short ether_type)
27454558Sbp{
275111888Sjlemon	int isr;
276111888Sjlemon
27754558Sbp	switch(ether_type) {
27854558Sbp#ifdef IPX
279111888Sjlemon	case ETHERTYPE_IPX:
28054558Sbp		m_adj(m, 8);
281111888Sjlemon		isr = NETISR_IPX;
28254558Sbp		break;
28354558Sbp#endif
284111888Sjlemon	default:
285111888Sjlemon		return (EPROTONOSUPPORT);
28654558Sbp	}
287111888Sjlemon	netisr_dispatch(isr, m);
288111888Sjlemon	return (0);
28954558Sbp}
29054558Sbp
29154558Sbpstatic int __inline
29254558Sbpef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
293111888Sjlemon	u_short ether_type)
29454558Sbp{
295111888Sjlemon	int isr;
296111888Sjlemon
29754558Sbp	switch(ether_type) {
29854558Sbp#ifdef IPX
299111888Sjlemon	case 0xe0:
30054558Sbp		m_adj(m, 3);
301111888Sjlemon		isr = NETISR_IPX;
30254558Sbp		break;
30354558Sbp#endif
304111888Sjlemon	default:
305111888Sjlemon		return (EPROTONOSUPPORT);
30654558Sbp	}
307111888Sjlemon	netisr_dispatch(isr, m);
308111888Sjlemon	return (0);
30954558Sbp}
310111888Sjlemon
31154558Sbp/*
31254558Sbp * Called from ether_input()
31354558Sbp */
31454558Sbpstatic int
31554558Sbpef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
31654558Sbp{
31754558Sbp	u_short ether_type;
31871891Sbp	int ft = -1;
31954558Sbp	struct efnet *efp;
32054558Sbp	struct ifnet *eifp;
32154558Sbp	struct llc *l;
32254558Sbp	struct ef_link *efl;
323111888Sjlemon	int isr;
32454558Sbp
32554558Sbp	ether_type = ntohs(eh->ether_type);
32654558Sbp	if (ether_type < ETHERMTU) {
32754558Sbp		l = mtod(m, struct llc*);
32854558Sbp		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
32954558Sbp			/*
33054558Sbp			 * Novell's "802.3" frame
33154558Sbp			 */
33254558Sbp			ft = ETHER_FT_8023;
33354558Sbp		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
33454558Sbp			/*
33554558Sbp			 * 802.2/SNAP
33654558Sbp			 */
33754558Sbp			ft = ETHER_FT_SNAP;
33854558Sbp			ether_type = ntohs(l->llc_un.type_snap.ether_type);
33954558Sbp		} else if (l->llc_dsap == l->llc_ssap) {
34054558Sbp			/*
34154558Sbp			 * 802.3/802.2
34254558Sbp			 */
34354558Sbp			ft = ETHER_FT_8022;
34454558Sbp			ether_type = l->llc_ssap;
34554558Sbp		}
34654558Sbp	} else
34754558Sbp		ft = ETHER_FT_EII;
34854558Sbp
34954558Sbp	if (ft == -1) {
35054558Sbp		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
35159681Sbp		return EPROTONOSUPPORT;
35254558Sbp	}
35354558Sbp
35454558Sbp	/*
35554558Sbp	 * Check if interface configured for the given frame
35654558Sbp	 */
35754558Sbp	efp = NULL;
35854558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
35954558Sbp		if (efl->el_ifp == ifp) {
36054558Sbp			efp = efl->el_units[ft];
36154558Sbp			break;
36254558Sbp		}
36354558Sbp	}
36454558Sbp	if (efp == NULL) {
36554558Sbp		EFDEBUG("Can't find if for %d\n", ft);
36659681Sbp		return EPROTONOSUPPORT;
36754558Sbp	}
36854558Sbp	eifp = &efp->ef_ac.ac_if;
36954558Sbp	if ((eifp->if_flags & IFF_UP) == 0)
37059681Sbp		return EPROTONOSUPPORT;
37154558Sbp	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
37254558Sbp	m->m_pkthdr.rcvif = eifp;
37354558Sbp
37454558Sbp	if (eifp->if_bpf) {
37554558Sbp		struct mbuf m0;
37654558Sbp		m0.m_next = m;
377111790Smdodd		m0.m_len = ETHER_HDR_LEN;
37854558Sbp		m0.m_data = (char *)eh;
379106939Ssam		BPF_MTAP(eifp, &m0);
38054558Sbp	}
38154558Sbp	/*
38254558Sbp	 * Now we ready to adjust mbufs and pass them to protocol intr's
38354558Sbp	 */
38454558Sbp	switch(ft) {
385111888Sjlemon	case ETHER_FT_EII:
386111888Sjlemon		return (ef_inputEII(m, eh, ether_type));
38754558Sbp		break;
38854558Sbp#ifdef IPX
389111888Sjlemon	case ETHER_FT_8023:		/* only IPX can be here */
390111888Sjlemon		isr = NETISR_IPX;
39154558Sbp		break;
39254558Sbp#endif
393111888Sjlemon	case ETHER_FT_SNAP:
394111888Sjlemon		return (ef_inputSNAP(m, eh, l, ether_type));
39554558Sbp		break;
396111888Sjlemon	case ETHER_FT_8022:
397111888Sjlemon		return (ef_input8022(m, eh, l, ether_type));
39854558Sbp		break;
399111888Sjlemon	default:
40054558Sbp		EFDEBUG("No support for frame %d and proto %04x\n",
40154558Sbp			ft, ether_type);
402111888Sjlemon		return (EPROTONOSUPPORT);
40354558Sbp	}
404111888Sjlemon	netisr_dispatch(isr, m);
405111888Sjlemon	return (0);
40654558Sbp}
40754558Sbp
40854558Sbpstatic int
40966479Sbpef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
41066479Sbp	int *hlen)
41154558Sbp{
41259681Sbp	struct mbuf *m = *mp;
41354558Sbp	u_char *cp;
41454558Sbp	short type;
41554558Sbp
41654558Sbp	if (ifp->if_type != IFT_XETHER)
41759681Sbp		return ENETDOWN;
41854558Sbp	switch (ifp->if_unit) {
41954558Sbp	    case ETHER_FT_EII:
42054558Sbp#ifdef IPX
42154558Sbp		type = htons(ETHERTYPE_IPX);
42254558Sbp#else
42359681Sbp		return EPFNOSUPPORT;
42454558Sbp#endif
42554558Sbp		break;
42654558Sbp	    case ETHER_FT_8023:
42754558Sbp		type = htons(m->m_pkthdr.len);
42854558Sbp		break;
42954558Sbp	    case ETHER_FT_8022:
430111119Simp		M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
43159681Sbp		if (m == NULL) {
43259681Sbp			*mp = NULL;
43359681Sbp			return ENOBUFS;
43459681Sbp		}
43559681Sbp		/*
43659681Sbp		 * Ensure that ethernet header and next three bytes
43759681Sbp		 * will fit into single mbuf
43859681Sbp		 */
43959681Sbp		m = m_pullup(m, ETHER_HDR_LEN + 3);
44059681Sbp		if (m == NULL) {
44159681Sbp			*mp = NULL;
44259681Sbp			return ENOBUFS;
44359681Sbp		}
44459681Sbp		m_adj(m, ETHER_HDR_LEN);
44554558Sbp		type = htons(m->m_pkthdr.len);
44654558Sbp		cp = mtod(m, u_char *);
44754558Sbp		*cp++ = 0xE0;
44854558Sbp		*cp++ = 0xE0;
44954558Sbp		*cp++ = 0x03;
45066479Sbp		*hlen += 3;
45154558Sbp		break;
45254558Sbp	    case ETHER_FT_SNAP:
453111119Simp		M_PREPEND(m, 8, M_TRYWAIT);
45459681Sbp		if (m == NULL) {
45559681Sbp			*mp = NULL;
45659681Sbp			return ENOBUFS;
45759681Sbp		}
45854558Sbp		type = htons(m->m_pkthdr.len);
45954558Sbp		cp = mtod(m, u_char *);
46054558Sbp		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
46166479Sbp		*hlen += 8;
46254558Sbp		break;
46354558Sbp	    default:
46459681Sbp		return EPFNOSUPPORT;
46554558Sbp	}
46659681Sbp	*mp = m;
46754558Sbp	*tp = type;
46854558Sbp	return 0;
46954558Sbp}
47054558Sbp
47154558Sbp/*
47254558Sbp * Create clone from the given interface
47354558Sbp */
47454558Sbpstatic int
47554558Sbpef_clone(struct ef_link *efl, int ft)
47654558Sbp{
47754558Sbp	struct efnet *efp;
47854558Sbp	struct ifnet *eifp;
47954558Sbp	struct ifnet *ifp = efl->el_ifp;
48054558Sbp	char cbuf[IFNAMSIZ], *ifname;
48154558Sbp	int ifnlen;
48254558Sbp
48369781Sdwmalone	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
484111119Simp	    M_WAITOK | M_ZERO);
48554558Sbp	if (efp == NULL)
48654558Sbp		return ENOMEM;
48754558Sbp	efp->ef_ifp = ifp;
48854558Sbp	eifp = &efp->ef_ac.ac_if;
48954558Sbp	ifnlen = 1 + snprintf(cbuf, sizeof(cbuf), "%s%df", ifp->if_name,
49054558Sbp	    ifp->if_unit);
491111119Simp	ifname = (char*)malloc(ifnlen, M_IFADDR, M_WAITOK);
49254558Sbp	eifp->if_name = strcpy(ifname, cbuf);
49354558Sbp	eifp->if_unit = ft;
49454558Sbp	eifp->if_softc = efp;
49554558Sbp	if (ifp->if_ioctl)
49654558Sbp		eifp->if_ioctl = ef_ioctl;
49754558Sbp	efl->el_units[ft] = efp;
49854558Sbp	return 0;
49954558Sbp}
50054558Sbp
50154558Sbpstatic int
50254558Sbpef_load(void)
50354558Sbp{
50454558Sbp	struct ifnet *ifp;
50554558Sbp	struct efnet *efp;
50654558Sbp	struct ef_link *efl = NULL;
50754558Sbp	int error = 0, d;
50854558Sbp
509108172Shsu	IFNET_RLOCK();
51071999Sphk	TAILQ_FOREACH(ifp, &ifnet, if_link) {
51154558Sbp		if (ifp->if_type != IFT_ETHER) continue;
51254558Sbp		EFDEBUG("Found interface %s%d\n", ifp->if_name, ifp->if_unit);
51354558Sbp		efl = (struct ef_link*)malloc(sizeof(struct ef_link),
514111119Simp		    M_IFADDR, M_WAITOK | M_ZERO);
51554558Sbp		if (efl == NULL) {
51654558Sbp			error = ENOMEM;
51754558Sbp			break;
51854558Sbp		}
51954558Sbp
52054558Sbp		efl->el_ifp = ifp;
52154558Sbp#ifdef ETHER_II
52254558Sbp		error = ef_clone(efl, ETHER_FT_EII);
52354558Sbp		if (error) break;
52454558Sbp#endif
52554558Sbp#ifdef ETHER_8023
52654558Sbp		error = ef_clone(efl, ETHER_FT_8023);
52754558Sbp		if (error) break;
52854558Sbp#endif
52954558Sbp#ifdef ETHER_8022
53054558Sbp		error = ef_clone(efl, ETHER_FT_8022);
53154558Sbp		if (error) break;
53254558Sbp#endif
53354558Sbp#ifdef ETHER_SNAP
53454558Sbp		error = ef_clone(efl, ETHER_FT_SNAP);
53554558Sbp		if (error) break;
53654558Sbp#endif
53754558Sbp		efcount++;
53854558Sbp		SLIST_INSERT_HEAD(&efdev, efl, el_next);
53954558Sbp	}
540108172Shsu	IFNET_RUNLOCK();
54154558Sbp	if (error) {
54254558Sbp		if (efl)
54354558Sbp			SLIST_INSERT_HEAD(&efdev, efl, el_next);
54454558Sbp		SLIST_FOREACH(efl, &efdev, el_next) {
54554558Sbp			for (d = 0; d < EF_NFT; d++)
54654558Sbp				if (efl->el_units[d])
54754558Sbp					free(efl->el_units[d], M_IFADDR);
54854558Sbp			free(efl, M_IFADDR);
54954558Sbp		}
55054558Sbp		return error;
55154558Sbp	}
55254558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
55354558Sbp		for (d = 0; d < EF_NFT; d++) {
55454558Sbp			efp = efl->el_units[d];
55554558Sbp			if (efp)
55654558Sbp				ef_attach(efp);
55754558Sbp		}
55854558Sbp	}
55954558Sbp	ef_inputp = ef_input;
56054558Sbp	ef_outputp = ef_output;
56154558Sbp	EFDEBUG("Loaded\n");
56254558Sbp	return 0;
56354558Sbp}
56454558Sbp
56554558Sbpstatic int
56654558Sbpef_unload(void)
56754558Sbp{
56854558Sbp	struct efnet *efp;
56954558Sbp	struct ef_link *efl;
57054558Sbp	int d;
57154558Sbp
57254558Sbp	ef_inputp = NULL;
57354558Sbp	ef_outputp = NULL;
57454558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
57554558Sbp		for (d = 0; d < EF_NFT; d++) {
57654558Sbp			efp = efl->el_units[d];
57754558Sbp			if (efp) {
57854558Sbp				ef_detach(efp);
57954558Sbp			}
58054558Sbp		}
58154558Sbp	}
58254558Sbp	EFDEBUG("Unloaded\n");
58354558Sbp	return 0;
58454558Sbp}
58554558Sbp
58654558Sbpstatic int
58754558Sbpif_ef_modevent(module_t mod, int type, void *data)
58854558Sbp{
58954558Sbp	switch ((modeventtype_t)type) {
59054558Sbp	    case MOD_LOAD:
59154558Sbp		return ef_load();
59254558Sbp	    case MOD_UNLOAD:
59354558Sbp		return ef_unload();
59454558Sbp	    default:
59554558Sbp		break;
59654558Sbp	}
59754558Sbp	return 0;
59854558Sbp}
59954558Sbp
60054558Sbpstatic moduledata_t if_ef_mod = {
60154558Sbp	"if_ef", if_ef_modevent, NULL
60254558Sbp};
60354558Sbp
60454558SbpDECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
605