1/*-
2 * Copyright (c) 1999, 2000 Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29#include "opt_inet.h"
30#include "opt_ipx.h"
31#include "opt_ef.h"
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/sockio.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/socket.h>
39#include <sys/syslog.h>
40#include <sys/kernel.h>
41#include <sys/module.h>
42
43#include <net/ethernet.h>
44#include <net/if_llc.h>
45#include <net/if.h>
46#include <net/if_arp.h>
47#include <net/if_dl.h>
48#include <net/if_types.h>
49#include <net/netisr.h>
50#include <net/bpf.h>
51#include <net/vnet.h>
52
53#ifdef INET
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/if_ether.h>
57#endif
58
59#ifdef IPX
60#include <netipx/ipx.h>
61#include <netipx/ipx_if.h>
62#endif
63
64/* If none of the supported layers is enabled explicitly enable them all */
65#if !defined(ETHER_II) && !defined(ETHER_8023) && !defined(ETHER_8022) && \
66    !defined(ETHER_SNAP)
67#define	ETHER_II	1
68#define	ETHER_8023	1
69#define	ETHER_8022	1
70#define	ETHER_SNAP	1
71#endif
72
73/* internal frame types */
74#define ETHER_FT_EII		0	/* Ethernet_II - default */
75#define	ETHER_FT_8023		1	/* 802.3 (Novell) */
76#define	ETHER_FT_8022		2	/* 802.2 */
77#define	ETHER_FT_SNAP		3	/* SNAP */
78#define	EF_NFT			4	/* total number of frame types */
79
80#ifdef EF_DEBUG
81#define EFDEBUG(format, args...) printf("%s: "format, __func__ ,## args)
82#else
83#define EFDEBUG(format, args...)
84#endif
85
86#define EFERROR(format, args...) printf("%s: "format, __func__ ,## args)
87
88struct efnet {
89	struct ifnet	*ef_ifp;
90	struct ifnet	*ef_pifp;
91	int		ef_frametype;
92};
93
94struct ef_link {
95	SLIST_ENTRY(ef_link) el_next;
96	struct ifnet	*el_ifp;		/* raw device for this clones */
97	struct efnet	*el_units[EF_NFT];	/* our clones */
98};
99
100static SLIST_HEAD(ef_link_head, ef_link) efdev = {NULL};
101static int efcount;
102
103extern int (*ef_inputp)(struct ifnet*, struct ether_header *eh, struct mbuf *m);
104extern int (*ef_outputp)(struct ifnet *ifp, struct mbuf **mp,
105		const struct sockaddr *dst, short *tp, int *hlen);
106
107/*
108static void ef_reset (struct ifnet *);
109*/
110static int ef_attach(struct efnet *sc);
111static int ef_detach(struct efnet *sc);
112static void ef_init(void *);
113static int ef_ioctl(struct ifnet *, u_long, caddr_t);
114static void ef_start(struct ifnet *);
115static int ef_input(struct ifnet*, struct ether_header *, struct mbuf *);
116static int ef_output(struct ifnet *ifp, struct mbuf **mp,
117		const struct sockaddr *dst, short *tp, int *hlen);
118
119static int ef_load(void);
120static int ef_unload(void);
121
122/*
123 * Install the interface, most of structure initialization done in ef_clone()
124 */
125static int
126ef_attach(struct efnet *sc)
127{
128	struct ifnet *ifp = sc->ef_ifp;
129
130	ifp->if_start = ef_start;
131	ifp->if_init = ef_init;
132	ifp->if_snd.ifq_maxlen = ifqmaxlen;
133	ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
134	/*
135	 * Attach the interface
136	 */
137	ether_ifattach(ifp, IF_LLADDR(sc->ef_pifp));
138
139	ifp->if_resolvemulti = 0;
140	ifp->if_type = IFT_XETHER;
141	ifp->if_drv_flags |= IFF_DRV_RUNNING;
142
143	EFDEBUG("%s: attached\n", ifp->if_xname);
144	return 1;
145}
146
147/*
148 * This is for _testing_only_, just removes interface from interfaces list
149 */
150static int
151ef_detach(struct efnet *sc)
152{
153	struct ifnet *ifp = sc->ef_ifp;
154
155	ether_ifdetach(ifp);
156	if_free(ifp);
157
158	return 0;
159}
160
161static void
162ef_init(void *foo) {
163	return;
164}
165
166static int
167ef_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
168{
169	struct efnet *sc = ifp->if_softc;
170	struct ifaddr *ifa = (struct ifaddr*)data;
171	int error;
172
173	EFDEBUG("IOCTL %ld for %s\n", cmd, ifp->if_xname);
174	error = 0;
175	switch (cmd) {
176	    case SIOCSIFFLAGS:
177		error = 0;
178		break;
179	    case SIOCSIFADDR:
180		if (sc->ef_frametype == ETHER_FT_8023 &&
181		    ifa->ifa_addr->sa_family != AF_IPX) {
182			error = EAFNOSUPPORT;
183			break;
184		}
185		ifp->if_flags |= IFF_UP;
186		/* FALL THROUGH */
187	    default:
188		error = ether_ioctl(ifp, cmd, data);
189		break;
190	}
191	return error;
192}
193
194/*
195 * Currently packet prepared in the ether_output(), but this can be a better
196 * place.
197 */
198static void
199ef_start(struct ifnet *ifp)
200{
201	struct efnet *sc = (struct efnet*)ifp->if_softc;
202	struct ifnet *p;
203	struct mbuf *m;
204	int error;
205
206	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
207	p = sc->ef_pifp;
208
209	EFDEBUG("\n");
210	for (;;) {
211		IF_DEQUEUE(&ifp->if_snd, m);
212		if (m == 0)
213			break;
214		BPF_MTAP(ifp, m);
215		error = p->if_transmit(p, m);
216		if (error) {
217			ifp->if_oerrors++;
218			continue;
219		}
220		ifp->if_opackets++;
221	}
222	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
223	return;
224}
225
226/*
227 * Inline functions do not put additional overhead to procedure call or
228 * parameter passing but simplify the code
229 */
230static int __inline
231ef_inputEII(struct mbuf *m, struct ether_header *eh, u_short ether_type)
232{
233	int isr;
234
235	switch(ether_type) {
236#ifdef IPX
237	case ETHERTYPE_IPX:
238		isr = NETISR_IPX;
239		break;
240#endif
241#ifdef INET
242	case ETHERTYPE_IP:
243		if ((m = ip_fastforward(m)) == NULL)
244			return (0);
245		isr = NETISR_IP;
246		break;
247
248	case ETHERTYPE_ARP:
249		isr = NETISR_ARP;
250		break;
251#endif
252	default:
253		return (EPROTONOSUPPORT);
254	}
255	netisr_dispatch(isr, m);
256	return (0);
257}
258
259static int __inline
260ef_inputSNAP(struct mbuf *m, struct ether_header *eh, struct llc* l,
261	u_short ether_type)
262{
263	int isr;
264
265	switch(ether_type) {
266#ifdef IPX
267	case ETHERTYPE_IPX:
268		m_adj(m, 8);
269		isr = NETISR_IPX;
270		break;
271#endif
272	default:
273		return (EPROTONOSUPPORT);
274	}
275	netisr_dispatch(isr, m);
276	return (0);
277}
278
279static int __inline
280ef_input8022(struct mbuf *m, struct ether_header *eh, struct llc* l,
281	u_short ether_type)
282{
283	int isr;
284
285	switch(ether_type) {
286#ifdef IPX
287	case 0xe0:
288		m_adj(m, 3);
289		isr = NETISR_IPX;
290		break;
291#endif
292	default:
293		return (EPROTONOSUPPORT);
294	}
295	netisr_dispatch(isr, m);
296	return (0);
297}
298
299/*
300 * Called from ether_input()
301 */
302static int
303ef_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
304{
305	u_short ether_type;
306	int ft = -1;
307	struct efnet *efp;
308	struct ifnet *eifp;
309	struct llc *l;
310	struct ef_link *efl;
311	int isr;
312
313	ether_type = ntohs(eh->ether_type);
314	l = NULL;
315	if (ether_type < ETHERMTU) {
316		l = mtod(m, struct llc*);
317		if (l->llc_dsap == 0xff && l->llc_ssap == 0xff) {
318			/*
319			 * Novell's "802.3" frame
320			 */
321			ft = ETHER_FT_8023;
322		} else if (l->llc_dsap == 0xaa && l->llc_ssap == 0xaa) {
323			/*
324			 * 802.2/SNAP
325			 */
326			ft = ETHER_FT_SNAP;
327			ether_type = ntohs(l->llc_un.type_snap.ether_type);
328		} else if (l->llc_dsap == l->llc_ssap) {
329			/*
330			 * 802.3/802.2
331			 */
332			ft = ETHER_FT_8022;
333			ether_type = l->llc_ssap;
334		}
335	} else
336		ft = ETHER_FT_EII;
337
338	if (ft == -1) {
339		EFDEBUG("Unrecognised ether_type %x\n", ether_type);
340		return EPROTONOSUPPORT;
341	}
342
343	/*
344	 * Check if interface configured for the given frame
345	 */
346	efp = NULL;
347	SLIST_FOREACH(efl, &efdev, el_next) {
348		if (efl->el_ifp == ifp) {
349			efp = efl->el_units[ft];
350			break;
351		}
352	}
353	if (efp == NULL) {
354		EFDEBUG("Can't find if for %d\n", ft);
355		return EPROTONOSUPPORT;
356	}
357	eifp = efp->ef_ifp;
358	if ((eifp->if_flags & IFF_UP) == 0)
359		return EPROTONOSUPPORT;
360	eifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
361	m->m_pkthdr.rcvif = eifp;
362
363	BPF_MTAP2(eifp, eh, ETHER_HDR_LEN, m);
364	/*
365	 * Now we ready to adjust mbufs and pass them to protocol intr's
366	 */
367	switch(ft) {
368	case ETHER_FT_EII:
369		return (ef_inputEII(m, eh, ether_type));
370#ifdef IPX
371	case ETHER_FT_8023:		/* only IPX can be here */
372		isr = NETISR_IPX;
373		break;
374#endif
375	case ETHER_FT_SNAP:
376		return (ef_inputSNAP(m, eh, l, ether_type));
377	case ETHER_FT_8022:
378		return (ef_input8022(m, eh, l, ether_type));
379	default:
380		EFDEBUG("No support for frame %d and proto %04x\n",
381			ft, ether_type);
382		return (EPROTONOSUPPORT);
383	}
384	netisr_dispatch(isr, m);
385	return (0);
386}
387
388static int
389ef_output(struct ifnet *ifp, struct mbuf **mp, const struct sockaddr *dst,
390	short *tp, int *hlen)
391{
392	struct efnet *sc = (struct efnet*)ifp->if_softc;
393	struct mbuf *m = *mp;
394	u_char *cp;
395	short type;
396
397	if (ifp->if_type != IFT_XETHER)
398		return ENETDOWN;
399	switch (sc->ef_frametype) {
400	    case ETHER_FT_EII:
401#ifdef IPX
402		type = htons(ETHERTYPE_IPX);
403#else
404		return EPFNOSUPPORT;
405#endif
406		break;
407	    case ETHER_FT_8023:
408		type = htons(m->m_pkthdr.len);
409		break;
410	    case ETHER_FT_8022:
411		M_PREPEND(m, ETHER_HDR_LEN + 3, M_WAITOK);
412		/*
413		 * Ensure that ethernet header and next three bytes
414		 * will fit into single mbuf
415		 */
416		m = m_pullup(m, ETHER_HDR_LEN + 3);
417		if (m == NULL) {
418			*mp = NULL;
419			return ENOBUFS;
420		}
421		m_adj(m, ETHER_HDR_LEN);
422		type = htons(m->m_pkthdr.len);
423		cp = mtod(m, u_char *);
424		*cp++ = 0xE0;
425		*cp++ = 0xE0;
426		*cp++ = 0x03;
427		*hlen += 3;
428		break;
429	    case ETHER_FT_SNAP:
430		M_PREPEND(m, 8, M_WAITOK);
431		type = htons(m->m_pkthdr.len);
432		cp = mtod(m, u_char *);
433		bcopy("\xAA\xAA\x03\x00\x00\x00\x81\x37", cp, 8);
434		*hlen += 8;
435		break;
436	    default:
437		return EPFNOSUPPORT;
438	}
439	*mp = m;
440	*tp = type;
441	return 0;
442}
443
444/*
445 * Create clone from the given interface
446 */
447static int
448ef_clone(struct ef_link *efl, int ft)
449{
450	struct efnet *efp;
451	struct ifnet *eifp;
452	struct ifnet *ifp = efl->el_ifp;
453
454	efp = (struct efnet*)malloc(sizeof(struct efnet), M_IFADDR,
455	    M_WAITOK | M_ZERO);
456	if (efp == NULL)
457		return ENOMEM;
458	efp->ef_pifp = ifp;
459	efp->ef_frametype = ft;
460	eifp = efp->ef_ifp = if_alloc(IFT_ETHER);
461	if (eifp == NULL) {
462		free(efp, M_IFADDR);
463		return (ENOSPC);
464	}
465	snprintf(eifp->if_xname, IFNAMSIZ,
466	    "%sf%d", ifp->if_xname, efp->ef_frametype);
467	eifp->if_dname = "ef";
468	eifp->if_dunit = IF_DUNIT_NONE;
469	eifp->if_softc = efp;
470	if (ifp->if_ioctl)
471		eifp->if_ioctl = ef_ioctl;
472	efl->el_units[ft] = efp;
473	return 0;
474}
475
476static int
477ef_load(void)
478{
479	VNET_ITERATOR_DECL(vnet_iter);
480	struct ifnet *ifp;
481	struct efnet *efp;
482	struct ef_link *efl = NULL, *efl_temp;
483	int error = 0, d;
484
485	VNET_LIST_RLOCK();
486	VNET_FOREACH(vnet_iter) {
487		CURVNET_SET(vnet_iter);
488
489		/*
490		 * XXXRW: The following loop walks the ifnet list while
491		 * modifying it, something not well-supported by ifnet
492		 * locking.  To avoid lock upgrade/recursion issues, manually
493		 * acquire a write lock of ifnet_sxlock here, rather than a
494		 * read lock, so that when if_alloc() recurses the lock, we
495		 * don't panic.  This structure, in which if_ef automatically
496		 * attaches to all ethernet interfaces, should be replaced
497		 * with a model like that found in if_vlan, in which
498		 * interfaces are explicitly configured, which would avoid
499		 * this (and other) problems.
500		 */
501		sx_xlock(&ifnet_sxlock);
502		TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
503			if (ifp->if_type != IFT_ETHER) continue;
504			EFDEBUG("Found interface %s\n", ifp->if_xname);
505			efl = (struct ef_link*)malloc(sizeof(struct ef_link),
506			    M_IFADDR, M_WAITOK | M_ZERO);
507			if (efl == NULL) {
508				error = ENOMEM;
509				break;
510			}
511
512			efl->el_ifp = ifp;
513#ifdef ETHER_II
514			error = ef_clone(efl, ETHER_FT_EII);
515			if (error) break;
516#endif
517#ifdef ETHER_8023
518			error = ef_clone(efl, ETHER_FT_8023);
519			if (error) break;
520#endif
521#ifdef ETHER_8022
522			error = ef_clone(efl, ETHER_FT_8022);
523			if (error) break;
524#endif
525#ifdef ETHER_SNAP
526			error = ef_clone(efl, ETHER_FT_SNAP);
527			if (error) break;
528#endif
529			efcount++;
530			SLIST_INSERT_HEAD(&efdev, efl, el_next);
531		}
532		sx_xunlock(&ifnet_sxlock);
533		CURVNET_RESTORE();
534	}
535	VNET_LIST_RUNLOCK();
536	if (error) {
537		if (efl)
538			SLIST_INSERT_HEAD(&efdev, efl, el_next);
539		SLIST_FOREACH_SAFE(efl, &efdev, el_next, efl_temp) {
540			for (d = 0; d < EF_NFT; d++)
541				if (efl->el_units[d]) {
542					if (efl->el_units[d]->ef_pifp != NULL)
543						if_free(efl->el_units[d]->ef_pifp);
544					free(efl->el_units[d], M_IFADDR);
545				}
546			free(efl, M_IFADDR);
547		}
548		return error;
549	}
550	SLIST_FOREACH(efl, &efdev, el_next) {
551		for (d = 0; d < EF_NFT; d++) {
552			efp = efl->el_units[d];
553			if (efp)
554				ef_attach(efp);
555		}
556	}
557	ef_inputp = ef_input;
558	ef_outputp = ef_output;
559	EFDEBUG("Loaded\n");
560	return 0;
561}
562
563static int
564ef_unload(void)
565{
566	struct efnet *efp;
567	struct ef_link *efl;
568	int d;
569
570	ef_inputp = NULL;
571	ef_outputp = NULL;
572	SLIST_FOREACH(efl, &efdev, el_next) {
573		for (d = 0; d < EF_NFT; d++) {
574			efp = efl->el_units[d];
575			if (efp) {
576				ef_detach(efp);
577			}
578		}
579	}
580	EFDEBUG("Unloaded\n");
581	return 0;
582}
583
584static int
585if_ef_modevent(module_t mod, int type, void *data)
586{
587	switch ((modeventtype_t)type) {
588	    case MOD_LOAD:
589		return ef_load();
590	    case MOD_UNLOAD:
591		return ef_unload();
592	    default:
593		return EOPNOTSUPP;
594	}
595	return 0;
596}
597
598static moduledata_t if_ef_mod = {
599	"if_ef", if_ef_modevent, NULL
600};
601
602DECLARE_MODULE(if_ef, if_ef_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
603