if_ef.c revision 66479
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 66479 2000-09-30 14:33:53Z bp $
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
7254558Sbp#define EFDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
7354558Sbp#else
7454558Sbp#define EFDEBUG(format, args...)
7554558Sbp#endif
7654558Sbp
7754558Sbp#define EFERROR(format, args...) printf("%s: "format, __FUNCTION__ ,## 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;
11954558Sbp	struct ifaddr *ifa1, *ifa2;
12054558Sbp	struct sockaddr_dl *sdl1, *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	 */
13163090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
13254558Sbp
13354558Sbp	ifp->if_resolvemulti = 0;
13454558Sbp	ifp->if_type = IFT_XETHER;
13554558Sbp	ifp->if_flags |= IFF_RUNNING;
13654558Sbp
13754558Sbp	ifa1 = ifnet_addrs[ifp->if_index - 1];
13854558Sbp	ifa2 = ifnet_addrs[sc->ef_ifp->if_index - 1];
13954558Sbp	sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
14054558Sbp	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
14154558Sbp	sdl1->sdl_type = IFT_ETHER;
14254558Sbp	sdl1->sdl_alen = ETHER_ADDR_LEN;
14354558Sbp	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
14454558Sbp	bcopy(LLADDR(sdl2), sc->ef_ac.ac_enaddr, ETHER_ADDR_LEN);
14554558Sbp
14654558Sbp	EFDEBUG("%s%d: attached\n", ifp->if_name, ifp->if_unit);
14754558Sbp	return 1;
14854558Sbp}
14954558Sbp
15054558Sbp/*
15154558Sbp * This is for _testing_only_, just removes interface from interfaces list
15254558Sbp */
15354558Sbpstatic int
15454558Sbpef_detach(struct efnet *sc)
15554558Sbp{
15654558Sbp	struct ifnet *ifp = (struct ifnet*)&sc->ef_ac.ac_if;
15754558Sbp	int s;
15854558Sbp
15954558Sbp	s = splimp();
16054558Sbp
16154558Sbp	if (ifp->if_flags & IFF_UP) {
16254558Sbp		if_down(ifp);
16354558Sbp		if (ifp->if_flags & IFF_RUNNING) {
16454558Sbp		    /* find internet addresses and delete routes */
16554558Sbp		    register struct ifaddr *ifa;
16654558Sbp		    for (ifa = ifp->if_addrhead.tqh_first; ifa;
16754558Sbp			 ifa = ifa->ifa_link.tqe_next) {
16854558Sbp			    rtinit(ifa, (int)RTM_DELETE, 0);
16954558Sbp		    }
17054558Sbp		}
17154558Sbp	}
17254558Sbp
17354558Sbp	TAILQ_REMOVE(&ifnet, ifp, if_link);
17454558Sbp	splx(s);
17554558Sbp	return 0;
17654558Sbp}
17754558Sbp
17854558Sbpstatic void
17954558Sbpef_init(void *foo) {
18054558Sbp	return;
18154558Sbp}
18254558Sbp
18354558Sbpstatic int
18454558Sbpef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
18554558Sbp{
18654558Sbp/*	struct ef_link *sc = (struct ef_link*)ifp->if_softc;*/
18754558Sbp	struct ifaddr *ifa = (struct ifaddr*)data;
18854558Sbp	int s, error;
18954558Sbp
19054558Sbp	EFDEBUG("IOCTL %ld for %s%d\n", cmd, ifp->if_name, ifp->if_unit);
19154558Sbp	error = 0;
19254558Sbp	s = splimp();
19354558Sbp	switch (cmd) {
19454558Sbp	    case SIOCSIFADDR:
19554558Sbp		if (ifp->if_unit == ETHER_FT_8023 &&
19654558Sbp		    ifa->ifa_addr->sa_family != AF_IPX) {
19754558Sbp			error = EAFNOSUPPORT;
19854558Sbp			break;
19954558Sbp		}
20054558Sbp		ifp->if_flags |= IFF_UP;
20154558Sbp		/* FALL THROUGH */
20254558Sbp	    case SIOCGIFADDR:
20354558Sbp	    case SIOCSIFMTU:
20454558Sbp		error = ether_ioctl(ifp, cmd, data);
20554558Sbp		break;
20654558Sbp	    case SIOCSIFFLAGS:
20754558Sbp		error = 0;
20854558Sbp		break;
20954558Sbp	    default:
21054558Sbp		error = EINVAL;
21154558Sbp	}
21254558Sbp	splx(s);
21354558Sbp	return error;
21454558Sbp}
21554558Sbp
21654558Sbp/*
21754558Sbp * Currently packet prepared in the ether_output(), but this can be a better
21854558Sbp * place.
21954558Sbp */
22054558Sbpstatic void
22154558Sbpef_start(struct ifnet *ifp)
22254558Sbp{
22354558Sbp	struct efnet *sc = (struct efnet*)ifp->if_softc;
22454558Sbp	struct ifnet *p;
22554558Sbp	struct mbuf *m;
22654558Sbp
22754558Sbp	ifp->if_flags |= IFF_OACTIVE;
22854558Sbp	p = sc->ef_ifp;
22954558Sbp
23054558Sbp	EFDEBUG("\n");
23154558Sbp	for (;;) {
23254558Sbp		IF_DEQUEUE(&ifp->if_snd, m);
23354558Sbp		if (m == 0)
23454558Sbp			break;
23554558Sbp		if (ifp->if_bpf)
23654558Sbp			bpf_mtap(ifp, m);
23754558Sbp		if (IF_QFULL(&p->if_snd)) {
23854558Sbp			IF_DROP(&p->if_snd);
23959681Sbp			ifp->if_oerrors++;
24059681Sbp			m_freem(m);
24159681Sbp			continue;
24254558Sbp		}
24354558Sbp		IF_ENQUEUE(&p->if_snd, m);
24459681Sbp		if ((p->if_flags & IFF_OACTIVE) == 0) {
24554558Sbp			p->if_start(p);
24659681Sbp			ifp->if_opackets++;
24759681Sbp		}
24854558Sbp	}
24954558Sbp	ifp->if_flags &= ~IFF_OACTIVE;
25054558Sbp	return;
25154558Sbp}
25254558Sbp
25354558Sbp/*
25454558Sbp * Inline functions do not put additional overhead to procedure call or
25554558Sbp * parameter passing but simplify the code
25654558Sbp */
25754558Sbpstatic int __inline
25854558Sbpef_inputEII(struct mbuf *m, struct ether_header *eh, struct llc* l,
25954558Sbp	u_short ether_type, struct ifqueue **inq)
26054558Sbp{
26154558Sbp	switch(ether_type) {
26254558Sbp#ifdef IPX
26354558Sbp	    case ETHERTYPE_IPX:
26454558Sbp		schednetisr(NETISR_IPX);
26554558Sbp		*inq = &ipxintrq;
26654558Sbp		break;
26754558Sbp#endif
26854558Sbp#ifdef INET
26954558Sbp	    case ETHERTYPE_IP:
27054558Sbp		if (ipflow_fastforward(m))
27154558Sbp			return 1;
27254558Sbp		schednetisr(NETISR_IP);
27354558Sbp		*inq = &ipintrq;
27454558Sbp		break;
27554558Sbp
27654558Sbp	    case ETHERTYPE_ARP:
27754558Sbp		schednetisr(NETISR_ARP);
27854558Sbp		*inq = &arpintrq;
27954558Sbp		break;
28054558Sbp#endif
28159681Sbp	    default:
28259681Sbp		return EPROTONOSUPPORT;
28354558Sbp	}
28454558Sbp	return 0;
28554558Sbp}
28654558Sbp
28754558Sbpstatic int __inline
28854558Sbpef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
28954558Sbp	u_short ether_type, struct ifqueue **inq)
29054558Sbp{
29154558Sbp	switch(ether_type) {
29254558Sbp#ifdef IPX
29354558Sbp	    case ETHERTYPE_IPX:
29454558Sbp		m_adj(m, 8);
29554558Sbp		schednetisr(NETISR_IPX);
29654558Sbp		*inq = &ipxintrq;
29754558Sbp		break;
29854558Sbp#endif
29959681Sbp	    default:
30059681Sbp		return EPROTONOSUPPORT;
30154558Sbp	}
30254558Sbp	return 0;
30354558Sbp}
30454558Sbp
30554558Sbpstatic int __inline
30654558Sbpef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
30754558Sbp	u_short ether_type, struct ifqueue **inq)
30854558Sbp{
30954558Sbp	switch(ether_type) {
31054558Sbp#ifdef IPX
31154558Sbp	    case 0xe0:
31254558Sbp		m_adj(m, 3);
31354558Sbp		schednetisr(NETISR_IPX);
31454558Sbp		*inq = &ipxintrq;
31554558Sbp		break;
31654558Sbp#endif
31759681Sbp	    default:
31859681Sbp		return EPROTONOSUPPORT;
31954558Sbp	}
32054558Sbp	return 0;
32154558Sbp}
32254558Sbp/*
32354558Sbp * Called from ether_input()
32454558Sbp */
32554558Sbpstatic int
32654558Sbpef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
32754558Sbp{
32854558Sbp	u_short ether_type;
32954558Sbp	int s, ft = -1;
33054558Sbp	struct ifqueue *inq;
33154558Sbp	struct efnet *efp;
33254558Sbp	struct ifnet *eifp;
33354558Sbp	struct llc *l;
33454558Sbp	struct ef_link *efl;
33554558Sbp
33654558Sbp	ether_type = ntohs(eh->ether_type);
33754558Sbp	if (ether_type < ETHERMTU) {
33854558Sbp		l = mtod(m, struct llc*);
33954558Sbp		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
34054558Sbp			/*
34154558Sbp			 * Novell's "802.3" frame
34254558Sbp			 */
34354558Sbp			ft = ETHER_FT_8023;
34454558Sbp		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
34554558Sbp			/*
34654558Sbp			 * 802.2/SNAP
34754558Sbp			 */
34854558Sbp			ft = ETHER_FT_SNAP;
34954558Sbp			ether_type = ntohs(l->llc_un.type_snap.ether_type);
35054558Sbp		} else if (l->llc_dsap == l->llc_ssap) {
35154558Sbp			/*
35254558Sbp			 * 802.3/802.2
35354558Sbp			 */
35454558Sbp			ft = ETHER_FT_8022;
35554558Sbp			ether_type = l->llc_ssap;
35654558Sbp		}
35754558Sbp	} else
35854558Sbp		ft = ETHER_FT_EII;
35954558Sbp
36054558Sbp	if (ft == -1) {
36154558Sbp		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
36259681Sbp		return EPROTONOSUPPORT;
36354558Sbp	}
36454558Sbp
36554558Sbp	/*
36654558Sbp	 * Check if interface configured for the given frame
36754558Sbp	 */
36854558Sbp	efp = NULL;
36954558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
37054558Sbp		if (efl->el_ifp == ifp) {
37154558Sbp			efp = efl->el_units[ft];
37254558Sbp			break;
37354558Sbp		}
37454558Sbp	}
37554558Sbp	if (efp == NULL) {
37654558Sbp		EFDEBUG("Can't find if for %d\n", ft);
37759681Sbp		return EPROTONOSUPPORT;
37854558Sbp	}
37954558Sbp	eifp = &efp->ef_ac.ac_if;
38054558Sbp	if ((eifp->if_flags & IFF_UP) == 0)
38159681Sbp		return EPROTONOSUPPORT;
38254558Sbp	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
38354558Sbp	m->m_pkthdr.rcvif = eifp;
38454558Sbp
38554558Sbp	if (eifp->if_bpf) {
38654558Sbp		struct mbuf m0;
38754558Sbp		m0.m_next = m;
38854558Sbp		m0.m_len = sizeof(struct ether_header);
38954558Sbp		m0.m_data = (char *)eh;
39054558Sbp		bpf_mtap(eifp, &m0);
39154558Sbp	}
39254558Sbp	/*
39354558Sbp	 * Now we ready to adjust mbufs and pass them to protocol intr's
39454558Sbp	 */
39554558Sbp	inq = NULL;
39654558Sbp	switch(ft) {
39754558Sbp	    case ETHER_FT_EII:
39859681Sbp		if (ef_inputEII(m, eh, l, ether_type, &inq) != 0)
39959681Sbp			return EPROTONOSUPPORT;
40054558Sbp		break;
40154558Sbp#ifdef IPX
40254558Sbp	    case ETHER_FT_8023:		/* only IPX can be here */
40354558Sbp		schednetisr(NETISR_IPX);
40454558Sbp		inq = &ipxintrq;
40554558Sbp		break;
40654558Sbp#endif
40754558Sbp	    case ETHER_FT_SNAP:
40859681Sbp		if (ef_inputSNAP(m, eh, l, ether_type, &inq) != 0)
40959681Sbp			return EPROTONOSUPPORT;
41054558Sbp		break;
41154558Sbp	    case ETHER_FT_8022:
41259681Sbp		if (ef_input8022(m, eh, l, ether_type, &inq) != 0)
41359681Sbp			return EPROTONOSUPPORT;
41454558Sbp		break;
41554558Sbp	}
41654558Sbp
41754558Sbp	if (inq == NULL) {
41854558Sbp		EFDEBUG("No support for frame %d and proto %04x\n",
41954558Sbp			ft, ether_type);
42059681Sbp		return EPROTONOSUPPORT;
42154558Sbp	}
42254558Sbp	s = splimp();
42354558Sbp	if (IF_QFULL(inq)) {
42454558Sbp		IF_DROP(inq);
42554558Sbp		m_freem(m);
42654558Sbp	} else
42754558Sbp		IF_ENQUEUE(inq, m);
42854558Sbp	splx(s);
42954558Sbp	return 0;
43054558Sbp}
43154558Sbp
43254558Sbpstatic int
43366479Sbpef_output(struct ifnet *ifp, struct mbuf **mp, struct sockaddr *dst, short *tp,
43466479Sbp	int *hlen)
43554558Sbp{
43659681Sbp	struct mbuf *m = *mp;
43754558Sbp	u_char *cp;
43854558Sbp	short type;
43954558Sbp
44054558Sbp	if (ifp->if_type != IFT_XETHER)
44159681Sbp		return ENETDOWN;
44254558Sbp	switch (ifp->if_unit) {
44354558Sbp	    case ETHER_FT_EII:
44454558Sbp#ifdef IPX
44554558Sbp		type = htons(ETHERTYPE_IPX);
44654558Sbp#else
44759681Sbp		return EPFNOSUPPORT;
44854558Sbp#endif
44954558Sbp		break;
45054558Sbp	    case ETHER_FT_8023:
45154558Sbp		type = htons(m->m_pkthdr.len);
45254558Sbp		break;
45354558Sbp	    case ETHER_FT_8022:
45459681Sbp		M_PREPEND(m, ETHER_HDR_LEN + 3, M_WAIT);
45559681Sbp		if (m == NULL) {
45659681Sbp			*mp = NULL;
45759681Sbp			return ENOBUFS;
45859681Sbp		}
45959681Sbp		/*
46059681Sbp		 * Ensure that ethernet header and next three bytes
46159681Sbp		 * will fit into single mbuf
46259681Sbp		 */
46359681Sbp		m = m_pullup(m, ETHER_HDR_LEN + 3);
46459681Sbp		if (m == NULL) {
46559681Sbp			*mp = NULL;
46659681Sbp			return ENOBUFS;
46759681Sbp		}
46859681Sbp		m_adj(m, ETHER_HDR_LEN);
46954558Sbp		type = htons(m->m_pkthdr.len);
47054558Sbp		cp = mtod(m, u_char *);
47154558Sbp		*cp++ = 0xE0;
47254558Sbp		*cp++ = 0xE0;
47354558Sbp		*cp++ = 0x03;
47466479Sbp		*hlen += 3;
47554558Sbp		break;
47654558Sbp	    case ETHER_FT_SNAP:
47754558Sbp		M_PREPEND(m, 8, M_WAIT);
47859681Sbp		if (m == NULL) {
47959681Sbp			*mp = NULL;
48059681Sbp			return ENOBUFS;
48159681Sbp		}
48254558Sbp		type = htons(m->m_pkthdr.len);
48354558Sbp		cp = mtod(m, u_char *);
48454558Sbp		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
48566479Sbp		*hlen += 8;
48654558Sbp		break;
48754558Sbp	    default:
48859681Sbp		return EPFNOSUPPORT;
48954558Sbp	}
49059681Sbp	*mp = m;
49154558Sbp	*tp = type;
49254558Sbp	return 0;
49354558Sbp}
49454558Sbp
49554558Sbp/*
49654558Sbp * Create clone from the given interface
49754558Sbp */
49854558Sbpstatic int
49954558Sbpef_clone(struct ef_link *efl, int ft)
50054558Sbp{
50154558Sbp	struct efnet *efp;
50254558Sbp	struct ifnet *eifp;
50354558Sbp	struct ifnet *ifp = efl->el_ifp;
50454558Sbp	char cbuf[IFNAMSIZ], *ifname;
50554558Sbp	int ifnlen;
50654558Sbp
50754558Sbp	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR, M_WAITOK);
50854558Sbp	if (efp == NULL)
50954558Sbp		return ENOMEM;
51054558Sbp	bzero(efp, sizeof(*efp));
51154558Sbp	efp->ef_ifp = ifp;
51254558Sbp	eifp = &efp->ef_ac.ac_if;
51354558Sbp	ifnlen = 1 + snprintf(cbuf, sizeof(cbuf), "%s%df", ifp->if_name,
51454558Sbp	    ifp->if_unit);
51554558Sbp	ifname = (char*)malloc(ifnlen, M_IFADDR, M_WAITOK);
51654558Sbp	eifp->if_name = strcpy(ifname, cbuf);
51754558Sbp	eifp->if_unit = ft;
51854558Sbp	eifp->if_softc = efp;
51954558Sbp	if (ifp->if_ioctl)
52054558Sbp		eifp->if_ioctl = ef_ioctl;
52154558Sbp	efl->el_units[ft] = efp;
52254558Sbp	return 0;
52354558Sbp}
52454558Sbp
52554558Sbpstatic int
52654558Sbpef_load(void)
52754558Sbp{
52854558Sbp	struct ifnet *ifp;
52954558Sbp	struct efnet *efp;
53054558Sbp	struct ef_link *efl = NULL;
53154558Sbp	int error = 0, d;
53254558Sbp
53354558Sbp	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
53454558Sbp		if (ifp->if_type != IFT_ETHER) continue;
53554558Sbp		EFDEBUG("Found interface %s%d\n", ifp->if_name, ifp->if_unit);
53654558Sbp		efl = (struct ef_link*)malloc(sizeof(struct ef_link),
53754558Sbp		    M_IFADDR, M_WAITOK);
53854558Sbp		if (efl == NULL) {
53954558Sbp			error = ENOMEM;
54054558Sbp			break;
54154558Sbp		}
54254558Sbp		bzero(efl, sizeof(*efl));
54354558Sbp
54454558Sbp		efl->el_ifp = ifp;
54554558Sbp#ifdef ETHER_II
54654558Sbp		error = ef_clone(efl, ETHER_FT_EII);
54754558Sbp		if (error) break;
54854558Sbp#endif
54954558Sbp#ifdef ETHER_8023
55054558Sbp		error = ef_clone(efl, ETHER_FT_8023);
55154558Sbp		if (error) break;
55254558Sbp#endif
55354558Sbp#ifdef ETHER_8022
55454558Sbp		error = ef_clone(efl, ETHER_FT_8022);
55554558Sbp		if (error) break;
55654558Sbp#endif
55754558Sbp#ifdef ETHER_SNAP
55854558Sbp		error = ef_clone(efl, ETHER_FT_SNAP);
55954558Sbp		if (error) break;
56054558Sbp#endif
56154558Sbp		efcount++;
56254558Sbp		SLIST_INSERT_HEAD(&efdev, efl, el_next);
56354558Sbp	}
56454558Sbp	if (error) {
56554558Sbp		if (efl)
56654558Sbp			SLIST_INSERT_HEAD(&efdev, efl, el_next);
56754558Sbp		SLIST_FOREACH(efl, &efdev, el_next) {
56854558Sbp			for (d = 0; d < EF_NFT; d++)
56954558Sbp				if (efl->el_units[d])
57054558Sbp					free(efl->el_units[d], M_IFADDR);
57154558Sbp			free(efl, M_IFADDR);
57254558Sbp		}
57354558Sbp		return error;
57454558Sbp	}
57554558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
57654558Sbp		for (d = 0; d < EF_NFT; d++) {
57754558Sbp			efp = efl->el_units[d];
57854558Sbp			if (efp)
57954558Sbp				ef_attach(efp);
58054558Sbp		}
58154558Sbp	}
58254558Sbp	ef_inputp = ef_input;
58354558Sbp	ef_outputp = ef_output;
58454558Sbp	EFDEBUG("Loaded\n");
58554558Sbp	return 0;
58654558Sbp}
58754558Sbp
58854558Sbpstatic int
58954558Sbpef_unload(void)
59054558Sbp{
59154558Sbp	struct efnet *efp;
59254558Sbp	struct ef_link *efl;
59354558Sbp	int d;
59454558Sbp
59554558Sbp	ef_inputp = NULL;
59654558Sbp	ef_outputp = NULL;
59754558Sbp	SLIST_FOREACH(efl, &efdev, el_next) {
59854558Sbp		for (d = 0; d < EF_NFT; d++) {
59954558Sbp			efp = efl->el_units[d];
60054558Sbp			if (efp) {
60154558Sbp				ef_detach(efp);
60254558Sbp			}
60354558Sbp		}
60454558Sbp	}
60554558Sbp	EFDEBUG("Unloaded\n");
60654558Sbp	return 0;
60754558Sbp}
60854558Sbp
60954558Sbpstatic int
61054558Sbpif_ef_modevent(module_t mod, int type, void *data)
61154558Sbp{
61254558Sbp	switch ((modeventtype_t)type) {
61354558Sbp	    case MOD_LOAD:
61454558Sbp		return ef_load();
61554558Sbp	    case MOD_UNLOAD:
61654558Sbp		return ef_unload();
61754558Sbp	    default:
61854558Sbp		break;
61954558Sbp	}
62054558Sbp	return 0;
62154558Sbp}
62254558Sbp
62354558Sbpstatic moduledata_t if_ef_mod = {
62454558Sbp	"if_ef", if_ef_modevent, NULL
62554558Sbp};
62654558Sbp
62754558SbpDECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
628