if_ef.c revision 106939
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 106939 2002-11-15 00:00:15Z sam $
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	}
16654558Sbp
16754558Sbp	TAILQ_REMOVE(&ifnet, ifp, if_link);
16854558Sbp	splx(s);
16954558Sbp	return 0;
17054558Sbp}
17154558Sbp
17254558Sbpstatic void
17354558Sbpef_init(void *foo) {
17454558Sbp	return;
17554558Sbp}
17654558Sbp
17754558Sbpstatic int
17854558Sbpef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
17954558Sbp{
18054558Sbp/*	struct ef_link *sc = (struct ef_link*)ifp->if_softc;*/
18154558Sbp	struct ifaddr *ifa = (struct ifaddr*)data;
18254558Sbp	int s, error;
18354558Sbp
18454558Sbp	EFDEBUG("IOCTL %ld for %s%d\n", cmd, ifp->if_name, ifp->if_unit);
18554558Sbp	error = 0;
18654558Sbp	s = splimp();
18754558Sbp	switch (cmd) {
188106939Ssam	    case SIOCSIFFLAGS:
189106939Ssam		error = 0;
190106939Ssam		break;
19154558Sbp	    case SIOCSIFADDR:
19254558Sbp		if (ifp->if_unit == ETHER_FT_8023 &&
19354558Sbp		    ifa->ifa_addr->sa_family != AF_IPX) {
19454558Sbp			error = EAFNOSUPPORT;
19554558Sbp			break;
19654558Sbp		}
19754558Sbp		ifp->if_flags |= IFF_UP;
19854558Sbp		/* FALL THROUGH */
199106939Ssam	    default:
20054558Sbp		error = ether_ioctl(ifp, cmd, data);
20154558Sbp		break;
20254558Sbp	}
20354558Sbp	splx(s);
20454558Sbp	return error;
20554558Sbp}
20654558Sbp
20754558Sbp/*
20854558Sbp * Currently packet prepared in the ether_output(), but this can be a better
20954558Sbp * place.
21054558Sbp */
21154558Sbpstatic void
21254558Sbpef_start(struct ifnet *ifp)
21354558Sbp{
21454558Sbp	struct efnet *sc = (struct efnet*)ifp->if_softc;
21554558Sbp	struct ifnet *p;
21654558Sbp	struct mbuf *m;
21754558Sbp
21854558Sbp	ifp->if_flags |= IFF_OACTIVE;
21954558Sbp	p = sc->ef_ifp;
22054558Sbp
22154558Sbp	EFDEBUG("\n");
22254558Sbp	for (;;) {
22354558Sbp		IF_DEQUEUE(&ifp->if_snd, m);
22454558Sbp		if (m == 0)
22554558Sbp			break;
226106939Ssam		BPF_MTAP(ifp, m);
22771891Sbp		if (! IF_HANDOFF(&p->if_snd, m, p)) {
22859681Sbp			ifp->if_oerrors++;
22959681Sbp			continue;
23054558Sbp		}
23169152Sjlemon		ifp->if_opackets++;
23254558Sbp	}
23354558Sbp	ifp->if_flags &= ~IFF_OACTIVE;
23454558Sbp	return;
23554558Sbp}
23654558Sbp
23754558Sbp/*
23854558Sbp * Inline functions do not put additional overhead to procedure call or
23954558Sbp * parameter passing but simplify the code
24054558Sbp */
24154558Sbpstatic int __inline
24297220Speteref_inputEII(struct mbuf *m, struct ether_header *eh,
24354558Sbp	u_short ether_type, struct ifqueue **inq)
24454558Sbp{
24554558Sbp	switch(ether_type) {
24654558Sbp#ifdef IPX
24754558Sbp	    case ETHERTYPE_IPX:
24854558Sbp		schednetisr(NETISR_IPX);
24954558Sbp		*inq = &ipxintrq;
25054558Sbp		break;
25154558Sbp#endif
25254558Sbp#ifdef INET
25354558Sbp	    case ETHERTYPE_IP:
25454558Sbp		if (ipflow_fastforward(m))
25554558Sbp			return 1;
25654558Sbp		schednetisr(NETISR_IP);
25754558Sbp		*inq = &ipintrq;
25854558Sbp		break;
25954558Sbp
26054558Sbp	    case ETHERTYPE_ARP:
26154558Sbp		schednetisr(NETISR_ARP);
26254558Sbp		*inq = &arpintrq;
26354558Sbp		break;
26454558Sbp#endif
26559681Sbp	    default:
26659681Sbp		return EPROTONOSUPPORT;
26754558Sbp	}
26854558Sbp	return 0;
26954558Sbp}
27054558Sbp
27154558Sbpstatic int __inline
27254558Sbpef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
27354558Sbp	u_short ether_type, struct ifqueue **inq)
27454558Sbp{
27554558Sbp	switch(ether_type) {
27654558Sbp#ifdef IPX
27754558Sbp	    case ETHERTYPE_IPX:
27854558Sbp		m_adj(m, 8);
27954558Sbp		schednetisr(NETISR_IPX);
28054558Sbp		*inq = &ipxintrq;
28154558Sbp		break;
28254558Sbp#endif
28359681Sbp	    default:
28459681Sbp		return EPROTONOSUPPORT;
28554558Sbp	}
28654558Sbp	return 0;
28754558Sbp}
28854558Sbp
28954558Sbpstatic int __inline
29054558Sbpef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
29154558Sbp	u_short ether_type, struct ifqueue **inq)
29254558Sbp{
29354558Sbp	switch(ether_type) {
29454558Sbp#ifdef IPX
29554558Sbp	    case 0xe0:
29654558Sbp		m_adj(m, 3);
29754558Sbp		schednetisr(NETISR_IPX);
29854558Sbp		*inq = &ipxintrq;
29954558Sbp		break;
30054558Sbp#endif
30159681Sbp	    default:
30259681Sbp		return EPROTONOSUPPORT;
30354558Sbp	}
30454558Sbp	return 0;
30554558Sbp}
30654558Sbp/*
30754558Sbp * Called from ether_input()
30854558Sbp */
30954558Sbpstatic int
31054558Sbpef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
31154558Sbp{
31254558Sbp	u_short ether_type;
31371891Sbp	int ft = -1;
31454558Sbp	struct ifqueue *inq;
31554558Sbp	struct efnet *efp;
31654558Sbp	struct ifnet *eifp;
31754558Sbp	struct llc *l;
31854558Sbp	struct ef_link *efl;
31954558Sbp
32054558Sbp	ether_type = ntohs(eh->ether_type);
32154558Sbp	if (ether_type < ETHERMTU) {
32254558Sbp		l = mtod(m, struct llc*);
32354558Sbp		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
32454558Sbp			/*
32554558Sbp			 * Novell's "802.3" frame
32654558Sbp			 */
32754558Sbp			ft = ETHER_FT_8023;
32854558Sbp		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
32954558Sbp			/*
33054558Sbp			 * 802.2/SNAP
33154558Sbp			 */
33254558Sbp			ft = ETHER_FT_SNAP;
33354558Sbp			ether_type = ntohs(l->llc_un.type_snap.ether_type);
33454558Sbp		} else if (l->llc_dsap == l->llc_ssap) {
33554558Sbp			/*
33654558Sbp			 * 802.3/802.2
33754558Sbp			 */
33854558Sbp			ft = ETHER_FT_8022;
33954558Sbp			ether_type = l->llc_ssap;
34054558Sbp		}
34154558Sbp	} else
34254558Sbp		ft = ETHER_FT_EII;
34354558Sbp
34454558Sbp	if (ft == -1) {
34554558Sbp		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
34659681Sbp		return EPROTONOSUPPORT;
34754558Sbp	}
34854558Sbp
34954558Sbp	/*
35054558Sbp	 * Check if interface configured for the given frame
35154558Sbp	 */
35254558Sbp	efp = NULL;
35354558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
35454558Sbp		if (efl->el_ifp == ifp) {
35554558Sbp			efp = efl->el_units[ft];
35654558Sbp			break;
35754558Sbp		}
35854558Sbp	}
35954558Sbp	if (efp == NULL) {
36054558Sbp		EFDEBUG("Can't find if for %d\n", ft);
36159681Sbp		return EPROTONOSUPPORT;
36254558Sbp	}
36354558Sbp	eifp = &efp->ef_ac.ac_if;
36454558Sbp	if ((eifp->if_flags & IFF_UP) == 0)
36559681Sbp		return EPROTONOSUPPORT;
36654558Sbp	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
36754558Sbp	m->m_pkthdr.rcvif = eifp;
36854558Sbp
36954558Sbp	if (eifp->if_bpf) {
37054558Sbp		struct mbuf m0;
37154558Sbp		m0.m_next = m;
37254558Sbp		m0.m_len = sizeof(struct ether_header);
37354558Sbp		m0.m_data = (char *)eh;
374106939Ssam		BPF_MTAP(eifp, &m0);
37554558Sbp	}
37654558Sbp	/*
37754558Sbp	 * Now we ready to adjust mbufs and pass them to protocol intr's
37854558Sbp	 */
37954558Sbp	inq = NULL;
38054558Sbp	switch(ft) {
38154558Sbp	    case ETHER_FT_EII:
38297220Speter		if (ef_inputEII(m, eh, ether_type, &inq) != 0)
38359681Sbp			return EPROTONOSUPPORT;
38454558Sbp		break;
38554558Sbp#ifdef IPX
38654558Sbp	    case ETHER_FT_8023:		/* only IPX can be here */
38754558Sbp		schednetisr(NETISR_IPX);
38854558Sbp		inq = &ipxintrq;
38954558Sbp		break;
39054558Sbp#endif
39154558Sbp	    case ETHER_FT_SNAP:
39259681Sbp		if (ef_inputSNAP(m, eh, l, ether_type, &inq) != 0)
39359681Sbp			return EPROTONOSUPPORT;
39454558Sbp		break;
39554558Sbp	    case ETHER_FT_8022:
39659681Sbp		if (ef_input8022(m, eh, l, ether_type, &inq) != 0)
39759681Sbp			return EPROTONOSUPPORT;
39854558Sbp		break;
39954558Sbp	}
40054558Sbp
40154558Sbp	if (inq == NULL) {
40254558Sbp		EFDEBUG("No support for frame %d and proto %04x\n",
40354558Sbp			ft, ether_type);
40459681Sbp		return EPROTONOSUPPORT;
40554558Sbp	}
40669152Sjlemon	(void) IF_HANDOFF(inq, m, NULL);
40754558Sbp	return 0;
40854558Sbp}
40954558Sbp
41054558Sbpstatic int
41166479Sbpef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
41266479Sbp	int *hlen)
41354558Sbp{
41459681Sbp	struct mbuf *m = *mp;
41554558Sbp	u_char *cp;
41654558Sbp	short type;
41754558Sbp
41854558Sbp	if (ifp->if_type != IFT_XETHER)
41959681Sbp		return ENETDOWN;
42054558Sbp	switch (ifp->if_unit) {
42154558Sbp	    case ETHER_FT_EII:
42254558Sbp#ifdef IPX
42354558Sbp		type = htons(ETHERTYPE_IPX);
42454558Sbp#else
42559681Sbp		return EPFNOSUPPORT;
42654558Sbp#endif
42754558Sbp		break;
42854558Sbp	    case ETHER_FT_8023:
42954558Sbp		type = htons(m->m_pkthdr.len);
43054558Sbp		break;
43154558Sbp	    case ETHER_FT_8022:
43270254Sbmilekic		M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
43359681Sbp		if (m == NULL) {
43459681Sbp			*mp = NULL;
43559681Sbp			return ENOBUFS;
43659681Sbp		}
43759681Sbp		/*
43859681Sbp		 * Ensure that ethernet header and next three bytes
43959681Sbp		 * will fit into single mbuf
44059681Sbp		 */
44159681Sbp		m = m_pullup(m, ETHER_HDR_LEN + 3);
44259681Sbp		if (m == NULL) {
44359681Sbp			*mp = NULL;
44459681Sbp			return ENOBUFS;
44559681Sbp		}
44659681Sbp		m_adj(m, ETHER_HDR_LEN);
44754558Sbp		type = htons(m->m_pkthdr.len);
44854558Sbp		cp = mtod(m, u_char *);
44954558Sbp		*cp++ = 0xE0;
45054558Sbp		*cp++ = 0xE0;
45154558Sbp		*cp++ = 0x03;
45266479Sbp		*hlen += 3;
45354558Sbp		break;
45454558Sbp	    case ETHER_FT_SNAP:
45570254Sbmilekic		M_PREPEND(m, 8, M_TRYWAIT);
45659681Sbp		if (m == NULL) {
45759681Sbp			*mp = NULL;
45859681Sbp			return ENOBUFS;
45959681Sbp		}
46054558Sbp		type = htons(m->m_pkthdr.len);
46154558Sbp		cp = mtod(m, u_char *);
46254558Sbp		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
46366479Sbp		*hlen += 8;
46454558Sbp		break;
46554558Sbp	    default:
46659681Sbp		return EPFNOSUPPORT;
46754558Sbp	}
46859681Sbp	*mp = m;
46954558Sbp	*tp = type;
47054558Sbp	return 0;
47154558Sbp}
47254558Sbp
47354558Sbp/*
47454558Sbp * Create clone from the given interface
47554558Sbp */
47654558Sbpstatic int
47754558Sbpef_clone(struct ef_link *efl, int ft)
47854558Sbp{
47954558Sbp	struct efnet *efp;
48054558Sbp	struct ifnet *eifp;
48154558Sbp	struct ifnet *ifp = efl->el_ifp;
48254558Sbp	char cbuf[IFNAMSIZ], *ifname;
48354558Sbp	int ifnlen;
48454558Sbp
48569781Sdwmalone	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
48669781Sdwmalone	    M_WAITOK | M_ZERO);
48754558Sbp	if (efp == NULL)
48854558Sbp		return ENOMEM;
48954558Sbp	efp->ef_ifp = ifp;
49054558Sbp	eifp = &efp->ef_ac.ac_if;
49154558Sbp	ifnlen = 1 + snprintf(cbuf, sizeof(cbuf), "%s%df", ifp->if_name,
49254558Sbp	    ifp->if_unit);
49354558Sbp	ifname = (char*)malloc(ifnlen, M_IFADDR, M_WAITOK);
49454558Sbp	eifp->if_name = strcpy(ifname, cbuf);
49554558Sbp	eifp->if_unit = ft;
49654558Sbp	eifp->if_softc = efp;
49754558Sbp	if (ifp->if_ioctl)
49854558Sbp		eifp->if_ioctl = ef_ioctl;
49954558Sbp	efl->el_units[ft] = efp;
50054558Sbp	return 0;
50154558Sbp}
50254558Sbp
50354558Sbpstatic int
50454558Sbpef_load(void)
50554558Sbp{
50654558Sbp	struct ifnet *ifp;
50754558Sbp	struct efnet *efp;
50854558Sbp	struct ef_link *efl = NULL;
50954558Sbp	int error = 0, d;
51054558Sbp
51171999Sphk	TAILQ_FOREACH(ifp, &ifnet, if_link) {
51254558Sbp		if (ifp->if_type != IFT_ETHER) continue;
51354558Sbp		EFDEBUG("Found interface %s%d\n", ifp->if_name, ifp->if_unit);
51454558Sbp		efl = (struct ef_link*)malloc(sizeof(struct ef_link),
51594385Sdwmalone		    M_IFADDR, M_WAITOK | M_ZERO);
51654558Sbp		if (efl == NULL) {
51754558Sbp			error = ENOMEM;
51854558Sbp			break;
51954558Sbp		}
52054558Sbp
52154558Sbp		efl->el_ifp = ifp;
52254558Sbp#ifdef ETHER_II
52354558Sbp		error = ef_clone(efl, ETHER_FT_EII);
52454558Sbp		if (error) break;
52554558Sbp#endif
52654558Sbp#ifdef ETHER_8023
52754558Sbp		error = ef_clone(efl, ETHER_FT_8023);
52854558Sbp		if (error) break;
52954558Sbp#endif
53054558Sbp#ifdef ETHER_8022
53154558Sbp		error = ef_clone(efl, ETHER_FT_8022);
53254558Sbp		if (error) break;
53354558Sbp#endif
53454558Sbp#ifdef ETHER_SNAP
53554558Sbp		error = ef_clone(efl, ETHER_FT_SNAP);
53654558Sbp		if (error) break;
53754558Sbp#endif
53854558Sbp		efcount++;
53954558Sbp		SLIST_INSERT_HEAD(&efdev, efl, el_next);
54054558Sbp	}
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