if_ef.c revision 111119
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 111119 2003-02-19 05:47:46Z imp $
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
24397220Speteref_inputEII(struct mbuf *m, struct ether_header *eh,
24454558Sbp	u_short ether_type, struct ifqueue **inq)
24554558Sbp{
24654558Sbp	switch(ether_type) {
24754558Sbp#ifdef IPX
24854558Sbp	    case ETHERTYPE_IPX:
24954558Sbp		schednetisr(NETISR_IPX);
25054558Sbp		*inq = &ipxintrq;
25154558Sbp		break;
25254558Sbp#endif
25354558Sbp#ifdef INET
25454558Sbp	    case ETHERTYPE_IP:
25554558Sbp		if (ipflow_fastforward(m))
25654558Sbp			return 1;
25754558Sbp		schednetisr(NETISR_IP);
25854558Sbp		*inq = &ipintrq;
25954558Sbp		break;
26054558Sbp
26154558Sbp	    case ETHERTYPE_ARP:
26254558Sbp		schednetisr(NETISR_ARP);
26354558Sbp		*inq = &arpintrq;
26454558Sbp		break;
26554558Sbp#endif
26659681Sbp	    default:
26759681Sbp		return EPROTONOSUPPORT;
26854558Sbp	}
26954558Sbp	return 0;
27054558Sbp}
27154558Sbp
27254558Sbpstatic int __inline
27354558Sbpef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
27454558Sbp	u_short ether_type, struct ifqueue **inq)
27554558Sbp{
27654558Sbp	switch(ether_type) {
27754558Sbp#ifdef IPX
27854558Sbp	    case ETHERTYPE_IPX:
27954558Sbp		m_adj(m, 8);
28054558Sbp		schednetisr(NETISR_IPX);
28154558Sbp		*inq = &ipxintrq;
28254558Sbp		break;
28354558Sbp#endif
28459681Sbp	    default:
28559681Sbp		return EPROTONOSUPPORT;
28654558Sbp	}
28754558Sbp	return 0;
28854558Sbp}
28954558Sbp
29054558Sbpstatic int __inline
29154558Sbpef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
29254558Sbp	u_short ether_type, struct ifqueue **inq)
29354558Sbp{
29454558Sbp	switch(ether_type) {
29554558Sbp#ifdef IPX
29654558Sbp	    case 0xe0:
29754558Sbp		m_adj(m, 3);
29854558Sbp		schednetisr(NETISR_IPX);
29954558Sbp		*inq = &ipxintrq;
30054558Sbp		break;
30154558Sbp#endif
30259681Sbp	    default:
30359681Sbp		return EPROTONOSUPPORT;
30454558Sbp	}
30554558Sbp	return 0;
30654558Sbp}
30754558Sbp/*
30854558Sbp * Called from ether_input()
30954558Sbp */
31054558Sbpstatic int
31154558Sbpef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
31254558Sbp{
31354558Sbp	u_short ether_type;
31471891Sbp	int ft = -1;
31554558Sbp	struct ifqueue *inq;
31654558Sbp	struct efnet *efp;
31754558Sbp	struct ifnet *eifp;
31854558Sbp	struct llc *l;
31954558Sbp	struct ef_link *efl;
32054558Sbp
32154558Sbp	ether_type = ntohs(eh->ether_type);
32254558Sbp	if (ether_type < ETHERMTU) {
32354558Sbp		l = mtod(m, struct llc*);
32454558Sbp		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
32554558Sbp			/*
32654558Sbp			 * Novell's "802.3" frame
32754558Sbp			 */
32854558Sbp			ft = ETHER_FT_8023;
32954558Sbp		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
33054558Sbp			/*
33154558Sbp			 * 802.2/SNAP
33254558Sbp			 */
33354558Sbp			ft = ETHER_FT_SNAP;
33454558Sbp			ether_type = ntohs(l->llc_un.type_snap.ether_type);
33554558Sbp		} else if (l->llc_dsap == l->llc_ssap) {
33654558Sbp			/*
33754558Sbp			 * 802.3/802.2
33854558Sbp			 */
33954558Sbp			ft = ETHER_FT_8022;
34054558Sbp			ether_type = l->llc_ssap;
34154558Sbp		}
34254558Sbp	} else
34354558Sbp		ft = ETHER_FT_EII;
34454558Sbp
34554558Sbp	if (ft == -1) {
34654558Sbp		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
34759681Sbp		return EPROTONOSUPPORT;
34854558Sbp	}
34954558Sbp
35054558Sbp	/*
35154558Sbp	 * Check if interface configured for the given frame
35254558Sbp	 */
35354558Sbp	efp = NULL;
35454558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
35554558Sbp		if (efl->el_ifp == ifp) {
35654558Sbp			efp = efl->el_units[ft];
35754558Sbp			break;
35854558Sbp		}
35954558Sbp	}
36054558Sbp	if (efp == NULL) {
36154558Sbp		EFDEBUG("Can't find if for %d\n", ft);
36259681Sbp		return EPROTONOSUPPORT;
36354558Sbp	}
36454558Sbp	eifp = &efp->ef_ac.ac_if;
36554558Sbp	if ((eifp->if_flags & IFF_UP) == 0)
36659681Sbp		return EPROTONOSUPPORT;
36754558Sbp	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
36854558Sbp	m->m_pkthdr.rcvif = eifp;
36954558Sbp
37054558Sbp	if (eifp->if_bpf) {
37154558Sbp		struct mbuf m0;
37254558Sbp		m0.m_next = m;
37354558Sbp		m0.m_len = sizeof(struct ether_header);
37454558Sbp		m0.m_data = (char *)eh;
375106939Ssam		BPF_MTAP(eifp, &m0);
37654558Sbp	}
37754558Sbp	/*
37854558Sbp	 * Now we ready to adjust mbufs and pass them to protocol intr's
37954558Sbp	 */
38054558Sbp	inq = NULL;
38154558Sbp	switch(ft) {
38254558Sbp	    case ETHER_FT_EII:
38397220Speter		if (ef_inputEII(m, eh, ether_type, &inq) != 0)
38459681Sbp			return EPROTONOSUPPORT;
38554558Sbp		break;
38654558Sbp#ifdef IPX
38754558Sbp	    case ETHER_FT_8023:		/* only IPX can be here */
38854558Sbp		schednetisr(NETISR_IPX);
38954558Sbp		inq = &ipxintrq;
39054558Sbp		break;
39154558Sbp#endif
39254558Sbp	    case ETHER_FT_SNAP:
39359681Sbp		if (ef_inputSNAP(m, eh, l, ether_type, &inq) != 0)
39459681Sbp			return EPROTONOSUPPORT;
39554558Sbp		break;
39654558Sbp	    case ETHER_FT_8022:
39759681Sbp		if (ef_input8022(m, eh, l, ether_type, &inq) != 0)
39859681Sbp			return EPROTONOSUPPORT;
39954558Sbp		break;
40054558Sbp	}
40154558Sbp
40254558Sbp	if (inq == NULL) {
40354558Sbp		EFDEBUG("No support for frame %d and proto %04x\n",
40454558Sbp			ft, ether_type);
40559681Sbp		return EPROTONOSUPPORT;
40654558Sbp	}
40769152Sjlemon	(void) IF_HANDOFF(inq, m, NULL);
40854558Sbp	return 0;
40954558Sbp}
41054558Sbp
41154558Sbpstatic int
41266479Sbpef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
41366479Sbp	int *hlen)
41454558Sbp{
41559681Sbp	struct mbuf *m = *mp;
41654558Sbp	u_char *cp;
41754558Sbp	short type;
41854558Sbp
41954558Sbp	if (ifp->if_type != IFT_XETHER)
42059681Sbp		return ENETDOWN;
42154558Sbp	switch (ifp->if_unit) {
42254558Sbp	    case ETHER_FT_EII:
42354558Sbp#ifdef IPX
42454558Sbp		type = htons(ETHERTYPE_IPX);
42554558Sbp#else
42659681Sbp		return EPFNOSUPPORT;
42754558Sbp#endif
42854558Sbp		break;
42954558Sbp	    case ETHER_FT_8023:
43054558Sbp		type = htons(m->m_pkthdr.len);
43154558Sbp		break;
43254558Sbp	    case ETHER_FT_8022:
433111119Simp		M_PREPEND(m, ETHER_HDR_LEN + 3, M_TRYWAIT);
43459681Sbp		if (m == NULL) {
43559681Sbp			*mp = NULL;
43659681Sbp			return ENOBUFS;
43759681Sbp		}
43859681Sbp		/*
43959681Sbp		 * Ensure that ethernet header and next three bytes
44059681Sbp		 * will fit into single mbuf
44159681Sbp		 */
44259681Sbp		m = m_pullup(m, ETHER_HDR_LEN + 3);
44359681Sbp		if (m == NULL) {
44459681Sbp			*mp = NULL;
44559681Sbp			return ENOBUFS;
44659681Sbp		}
44759681Sbp		m_adj(m, ETHER_HDR_LEN);
44854558Sbp		type = htons(m->m_pkthdr.len);
44954558Sbp		cp = mtod(m, u_char *);
45054558Sbp		*cp++ = 0xE0;
45154558Sbp		*cp++ = 0xE0;
45254558Sbp		*cp++ = 0x03;
45366479Sbp		*hlen += 3;
45454558Sbp		break;
45554558Sbp	    case ETHER_FT_SNAP:
456111119Simp		M_PREPEND(m, 8, M_TRYWAIT);
45759681Sbp		if (m == NULL) {
45859681Sbp			*mp = NULL;
45959681Sbp			return ENOBUFS;
46059681Sbp		}
46154558Sbp		type = htons(m->m_pkthdr.len);
46254558Sbp		cp = mtod(m, u_char *);
46354558Sbp		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
46466479Sbp		*hlen += 8;
46554558Sbp		break;
46654558Sbp	    default:
46759681Sbp		return EPFNOSUPPORT;
46854558Sbp	}
46959681Sbp	*mp = m;
47054558Sbp	*tp = type;
47154558Sbp	return 0;
47254558Sbp}
47354558Sbp
47454558Sbp/*
47554558Sbp * Create clone from the given interface
47654558Sbp */
47754558Sbpstatic int
47854558Sbpef_clone(struct ef_link *efl, int ft)
47954558Sbp{
48054558Sbp	struct efnet *efp;
48154558Sbp	struct ifnet *eifp;
48254558Sbp	struct ifnet *ifp = efl->el_ifp;
48354558Sbp	char cbuf[IFNAMSIZ], *ifname;
48454558Sbp	int ifnlen;
48554558Sbp
48669781Sdwmalone	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
487111119Simp	    M_WAITOK | M_ZERO);
48854558Sbp	if (efp == NULL)
48954558Sbp		return ENOMEM;
49054558Sbp	efp->ef_ifp = ifp;
49154558Sbp	eifp = &efp->ef_ac.ac_if;
49254558Sbp	ifnlen = 1 + snprintf(cbuf, sizeof(cbuf), "%s%df", ifp->if_name,
49354558Sbp	    ifp->if_unit);
494111119Simp	ifname = (char*)malloc(ifnlen, M_IFADDR, M_WAITOK);
49554558Sbp	eifp->if_name = strcpy(ifname, cbuf);
49654558Sbp	eifp->if_unit = ft;
49754558Sbp	eifp->if_softc = efp;
49854558Sbp	if (ifp->if_ioctl)
49954558Sbp		eifp->if_ioctl = ef_ioctl;
50054558Sbp	efl->el_units[ft] = efp;
50154558Sbp	return 0;
50254558Sbp}
50354558Sbp
50454558Sbpstatic int
50554558Sbpef_load(void)
50654558Sbp{
50754558Sbp	struct ifnet *ifp;
50854558Sbp	struct efnet *efp;
50954558Sbp	struct ef_link *efl = NULL;
51054558Sbp	int error = 0, d;
51154558Sbp
512108172Shsu	IFNET_RLOCK();
51371999Sphk	TAILQ_FOREACH(ifp, &ifnet, if_link) {
51454558Sbp		if (ifp->if_type != IFT_ETHER) continue;
51554558Sbp		EFDEBUG("Found interface %s%d\n", ifp->if_name, ifp->if_unit);
51654558Sbp		efl = (struct ef_link*)malloc(sizeof(struct ef_link),
517111119Simp		    M_IFADDR, M_WAITOK | M_ZERO);
51854558Sbp		if (efl == NULL) {
51954558Sbp			error = ENOMEM;
52054558Sbp			break;
52154558Sbp		}
52254558Sbp
52354558Sbp		efl->el_ifp = ifp;
52454558Sbp#ifdef ETHER_II
52554558Sbp		error = ef_clone(efl, ETHER_FT_EII);
52654558Sbp		if (error) break;
52754558Sbp#endif
52854558Sbp#ifdef ETHER_8023
52954558Sbp		error = ef_clone(efl, ETHER_FT_8023);
53054558Sbp		if (error) break;
53154558Sbp#endif
53254558Sbp#ifdef ETHER_8022
53354558Sbp		error = ef_clone(efl, ETHER_FT_8022);
53454558Sbp		if (error) break;
53554558Sbp#endif
53654558Sbp#ifdef ETHER_SNAP
53754558Sbp		error = ef_clone(efl, ETHER_FT_SNAP);
53854558Sbp		if (error) break;
53954558Sbp#endif
54054558Sbp		efcount++;
54154558Sbp		SLIST_INSERT_HEAD(&efdev, efl, el_next);
54254558Sbp	}
543108172Shsu	IFNET_RUNLOCK();
54454558Sbp	if (error) {
54554558Sbp		if (efl)
54654558Sbp			SLIST_INSERT_HEAD(&efdev, efl, el_next);
54754558Sbp		SLIST_FOREACH(efl, &efdev, el_next) {
54854558Sbp			for (d = 0; d < EF_NFT; d++)
54954558Sbp				if (efl->el_units[d])
55054558Sbp					free(efl->el_units[d], M_IFADDR);
55154558Sbp			free(efl, M_IFADDR);
55254558Sbp		}
55354558Sbp		return error;
55454558Sbp	}
55554558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
55654558Sbp		for (d = 0; d < EF_NFT; d++) {
55754558Sbp			efp = efl->el_units[d];
55854558Sbp			if (efp)
55954558Sbp				ef_attach(efp);
56054558Sbp		}
56154558Sbp	}
56254558Sbp	ef_inputp = ef_input;
56354558Sbp	ef_outputp = ef_output;
56454558Sbp	EFDEBUG("Loaded\n");
56554558Sbp	return 0;
56654558Sbp}
56754558Sbp
56854558Sbpstatic int
56954558Sbpef_unload(void)
57054558Sbp{
57154558Sbp	struct efnet *efp;
57254558Sbp	struct ef_link *efl;
57354558Sbp	int d;
57454558Sbp
57554558Sbp	ef_inputp = NULL;
57654558Sbp	ef_outputp = NULL;
57754558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
57854558Sbp		for (d = 0; d < EF_NFT; d++) {
57954558Sbp			efp = efl->el_units[d];
58054558Sbp			if (efp) {
58154558Sbp				ef_detach(efp);
58254558Sbp			}
58354558Sbp		}
58454558Sbp	}
58554558Sbp	EFDEBUG("Unloaded\n");
58654558Sbp	return 0;
58754558Sbp}
58854558Sbp
58954558Sbpstatic int
59054558Sbpif_ef_modevent(module_t mod, int type, void *data)
59154558Sbp{
59254558Sbp	switch ((modeventtype_t)type) {
59354558Sbp	    case MOD_LOAD:
59454558Sbp		return ef_load();
59554558Sbp	    case MOD_UNLOAD:
59654558Sbp		return ef_unload();
59754558Sbp	    default:
59854558Sbp		break;
59954558Sbp	}
60054558Sbp	return 0;
60154558Sbp}
60254558Sbp
60354558Sbpstatic moduledata_t if_ef_mod = {
60454558Sbp	"if_ef", if_ef_modevent, NULL
60554558Sbp};
60654558Sbp
60754558SbpDECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
608