xref: /freebsd/sys/net/if_epair.c (revision 98c230c8)
198c230c8SBjoern A. Zeeb /*-
298c230c8SBjoern A. Zeeb  * Copyright (c) 2008 The FreeBSD Foundation
398c230c8SBjoern A. Zeeb  * All rights reserved.
498c230c8SBjoern A. Zeeb  *
598c230c8SBjoern A. Zeeb  * This software was developed by CK Software GmbH under sponsorship
698c230c8SBjoern A. Zeeb  * from the FreeBSD Foundation.
798c230c8SBjoern A. Zeeb  *
898c230c8SBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
998c230c8SBjoern A. Zeeb  * modification, are permitted provided that the following conditions
1098c230c8SBjoern A. Zeeb  * are met:
1198c230c8SBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
1298c230c8SBjoern A. Zeeb  * notice, this list of conditions and the following disclaimer.
1398c230c8SBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
1498c230c8SBjoern A. Zeeb  * notice, this list of conditions and the following disclaimer in the
1598c230c8SBjoern A. Zeeb  * documentation and/or other materials provided with the distribution.
1698c230c8SBjoern A. Zeeb  *
1798c230c8SBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1898c230c8SBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1998c230c8SBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2098c230c8SBjoern A. Zeeb  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2198c230c8SBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2298c230c8SBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2398c230c8SBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2498c230c8SBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2598c230c8SBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2698c230c8SBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2798c230c8SBjoern A. Zeeb  * SUCH DAMAGE.
2898c230c8SBjoern A. Zeeb  */
2998c230c8SBjoern A. Zeeb 
3098c230c8SBjoern A. Zeeb /*
3198c230c8SBjoern A. Zeeb  * A pair of virtual ethernet interfaces directly connected with
3298c230c8SBjoern A. Zeeb  * a virtual cross-over cable.
3398c230c8SBjoern A. Zeeb  * This is mostly intended to be used to provide connectivity between
3498c230c8SBjoern A. Zeeb  * different virtual network stack instances.
3598c230c8SBjoern A. Zeeb  */
3698c230c8SBjoern A. Zeeb /*
3798c230c8SBjoern A. Zeeb  * Things to re-think once we have more experience:
3898c230c8SBjoern A. Zeeb  * - ifp->if_reassign function once we can test with vimage.
3998c230c8SBjoern A. Zeeb  * - Real random etheraddrs that are checked to be uniquish;
4098c230c8SBjoern A. Zeeb  *   in case we bridge we may need this or let the user handle that case?
4198c230c8SBjoern A. Zeeb  * - netisr and callback logic.
4298c230c8SBjoern A. Zeeb  * - netisr queue lengths.
4398c230c8SBjoern A. Zeeb  */
4498c230c8SBjoern A. Zeeb 
4598c230c8SBjoern A. Zeeb #include <sys/cdefs.h>
4698c230c8SBjoern A. Zeeb __FBSDID("$FreeBSD$");
4798c230c8SBjoern A. Zeeb 
4898c230c8SBjoern A. Zeeb #include <sys/param.h>
4998c230c8SBjoern A. Zeeb #include <sys/kernel.h>
5098c230c8SBjoern A. Zeeb #include <sys/mbuf.h>
5198c230c8SBjoern A. Zeeb #include <sys/module.h>
5298c230c8SBjoern A. Zeeb #include <sys/refcount.h>
5398c230c8SBjoern A. Zeeb #include <sys/queue.h>
5498c230c8SBjoern A. Zeeb #include <sys/socket.h>
5598c230c8SBjoern A. Zeeb #include <sys/sockio.h>
5698c230c8SBjoern A. Zeeb #include <sys/sysctl.h>
5798c230c8SBjoern A. Zeeb #include <sys/types.h>
5898c230c8SBjoern A. Zeeb #include <sys/vimage.h>
5998c230c8SBjoern A. Zeeb 
6098c230c8SBjoern A. Zeeb #include <net/bpf.h>
6198c230c8SBjoern A. Zeeb #include <net/ethernet.h>
6298c230c8SBjoern A. Zeeb #include <net/if.h>
6398c230c8SBjoern A. Zeeb #include <net/if_clone.h>
6498c230c8SBjoern A. Zeeb #include <net/if_var.h>
6598c230c8SBjoern A. Zeeb #include <net/if_types.h>
6698c230c8SBjoern A. Zeeb #include <net/netisr.h>
6798c230c8SBjoern A. Zeeb 
6898c230c8SBjoern A. Zeeb #define	EPAIRNAME	"epair"
6998c230c8SBjoern A. Zeeb 
7098c230c8SBjoern A. Zeeb #ifdef DEBUG_EPAIR
7198c230c8SBjoern A. Zeeb static int epair_debug = 0;
7298c230c8SBjoern A. Zeeb SYSCTL_DECL(_net_link);
7398c230c8SBjoern A. Zeeb SYSCTL_NODE(_net_link, OID_AUTO, epair, CTLFLAG_RW, 0, "epair sysctl");
7498c230c8SBjoern A. Zeeb SYSCTL_XINT(_net_link_epair, OID_AUTO, epair_debug, CTLFLAG_RW,
7598c230c8SBjoern A. Zeeb     &epair_debug, 0, "if_epair(4) debugging.");
7698c230c8SBjoern A. Zeeb #define	DPRINTF(fmt, arg...)	if (epair_debug) \
7798c230c8SBjoern A. Zeeb     printf("[%s:%d] " fmt, __func__, __LINE__, ##arg)
7898c230c8SBjoern A. Zeeb #else
7998c230c8SBjoern A. Zeeb #define	DPRINTF(fmt, arg...)
8098c230c8SBjoern A. Zeeb #endif
8198c230c8SBjoern A. Zeeb 
8298c230c8SBjoern A. Zeeb struct epair_softc {
8398c230c8SBjoern A. Zeeb 	struct ifnet	*ifp;
8498c230c8SBjoern A. Zeeb 	struct ifnet	*oifp;
8598c230c8SBjoern A. Zeeb 	u_int		refcount;
8698c230c8SBjoern A. Zeeb 	void		(*if_qflush)(struct ifnet *);
8798c230c8SBjoern A. Zeeb };
8898c230c8SBjoern A. Zeeb 
8998c230c8SBjoern A. Zeeb struct epair_ifp_drain {
9098c230c8SBjoern A. Zeeb 	STAILQ_ENTRY(epair_ifp_drain)	ifp_next;
9198c230c8SBjoern A. Zeeb 	struct ifnet			*ifp;
9298c230c8SBjoern A. Zeeb };
9398c230c8SBjoern A. Zeeb 
9498c230c8SBjoern A. Zeeb static STAILQ_HEAD(, epair_ifp_drain) epair_ifp_drain_list =
9598c230c8SBjoern A. Zeeb     STAILQ_HEAD_INITIALIZER(epair_ifp_drain_list);
9698c230c8SBjoern A. Zeeb 
9798c230c8SBjoern A. Zeeb #define ADD_IFQ_FOR_DRAINING(ifp)					\
9898c230c8SBjoern A. Zeeb 	do {								\
9998c230c8SBjoern A. Zeeb 		struct epair_ifp_drain *elm = NULL;			\
10098c230c8SBjoern A. Zeeb 									\
10198c230c8SBjoern A. Zeeb 		STAILQ_FOREACH(elm, &epair_ifp_drain_list, ifp_next) {	\
10298c230c8SBjoern A. Zeeb 			if (elm->ifp == (ifp))				\
10398c230c8SBjoern A. Zeeb 				break;					\
10498c230c8SBjoern A. Zeeb 		}							\
10598c230c8SBjoern A. Zeeb 		if (elm == NULL) {					\
10698c230c8SBjoern A. Zeeb 			elm = malloc(sizeof(struct epair_ifp_drain),	\
10798c230c8SBjoern A. Zeeb 			    M_EPAIR, M_ZERO);				\
10898c230c8SBjoern A. Zeeb 			if (elm != NULL) {				\
10998c230c8SBjoern A. Zeeb 				elm->ifp = (ifp);			\
11098c230c8SBjoern A. Zeeb 				STAILQ_INSERT_TAIL(			\
11198c230c8SBjoern A. Zeeb 				    &epair_ifp_drain_list,		\
11298c230c8SBjoern A. Zeeb 			    	    elm, ifp_next);			\
11398c230c8SBjoern A. Zeeb 			}						\
11498c230c8SBjoern A. Zeeb 		}							\
11598c230c8SBjoern A. Zeeb 	} while(0)
11698c230c8SBjoern A. Zeeb 
11798c230c8SBjoern A. Zeeb /* Our "hw" tx queue. */
11898c230c8SBjoern A. Zeeb static struct ifqueue epairinq;
11998c230c8SBjoern A. Zeeb static int epair_drv_flags;
12098c230c8SBjoern A. Zeeb 
12198c230c8SBjoern A. Zeeb static struct mtx if_epair_mtx;
12298c230c8SBjoern A. Zeeb #define	EPAIR_LOCK_INIT()	mtx_init(&if_epair_mtx, "if_epair", \
12398c230c8SBjoern A. Zeeb 				    NULL, MTX_DEF)
12498c230c8SBjoern A. Zeeb #define	EPAIR_LOCK_DESTROY()	mtx_destroy(&if_epair_mtx)
12598c230c8SBjoern A. Zeeb #define	EPAIR_LOCK_ASSERT()	mtx_assert(&if_epair_mtx, MA_OWNED)
12698c230c8SBjoern A. Zeeb #define	EPAIR_LOCK()		mtx_lock(&if_epair_mtx)
12798c230c8SBjoern A. Zeeb #define	EPAIR_UNLOCK()		mtx_unlock(&if_epair_mtx)
12898c230c8SBjoern A. Zeeb 
12998c230c8SBjoern A. Zeeb static MALLOC_DEFINE(M_EPAIR, EPAIRNAME,
13098c230c8SBjoern A. Zeeb     "Pair of virtual cross-over connected Ethernet-like interfaces");
13198c230c8SBjoern A. Zeeb 
13298c230c8SBjoern A. Zeeb static int epair_clone_match(struct if_clone *, const char *);
13398c230c8SBjoern A. Zeeb static int epair_clone_create(struct if_clone *, char *, size_t, caddr_t);
13498c230c8SBjoern A. Zeeb static int epair_clone_destroy(struct if_clone *, struct ifnet *);
13598c230c8SBjoern A. Zeeb 
13698c230c8SBjoern A. Zeeb static void epair_start_locked(struct ifnet *);
13798c230c8SBjoern A. Zeeb 
13898c230c8SBjoern A. Zeeb static struct if_clone epair_cloner = IFC_CLONE_INITIALIZER(
13998c230c8SBjoern A. Zeeb     EPAIRNAME, NULL, IF_MAXUNIT,
14098c230c8SBjoern A. Zeeb     NULL, epair_clone_match, epair_clone_create, epair_clone_destroy);
14198c230c8SBjoern A. Zeeb 
14298c230c8SBjoern A. Zeeb 
14398c230c8SBjoern A. Zeeb /*
14498c230c8SBjoern A. Zeeb  * Netisr handler functions.
14598c230c8SBjoern A. Zeeb  */
14698c230c8SBjoern A. Zeeb static void
14798c230c8SBjoern A. Zeeb epair_sintr(struct mbuf *m)
14898c230c8SBjoern A. Zeeb {
14998c230c8SBjoern A. Zeeb 	struct ifnet *ifp;
15098c230c8SBjoern A. Zeeb 	struct epair_softc *sc;
15198c230c8SBjoern A. Zeeb 
15298c230c8SBjoern A. Zeeb 	ifp = m->m_pkthdr.rcvif;
15398c230c8SBjoern A. Zeeb 	(*ifp->if_input)(ifp, m);
15498c230c8SBjoern A. Zeeb 	sc = ifp->if_softc;
15598c230c8SBjoern A. Zeeb 	refcount_release(&sc->refcount);
15698c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p refcount=%u\n", ifp, sc->refcount);
15798c230c8SBjoern A. Zeeb }
15898c230c8SBjoern A. Zeeb 
15998c230c8SBjoern A. Zeeb static void
16098c230c8SBjoern A. Zeeb epair_sintr_drained(void)
16198c230c8SBjoern A. Zeeb {
16298c230c8SBjoern A. Zeeb 	struct epair_ifp_drain *elm, *tvar;
16398c230c8SBjoern A. Zeeb 	struct ifnet *ifp;
16498c230c8SBjoern A. Zeeb 
16598c230c8SBjoern A. Zeeb 	EPAIR_LOCK();
16698c230c8SBjoern A. Zeeb 	/*
16798c230c8SBjoern A. Zeeb 	 * Assume our "hw" queue and possibly ifq will be emptied
16898c230c8SBjoern A. Zeeb 	 * again. In case we will overflow the "hw" queue while
16998c230c8SBjoern A. Zeeb 	 * draining, epair_start_locked will set IFF_DRV_OACTIVE
17098c230c8SBjoern A. Zeeb 	 * again and we will stop and return.
17198c230c8SBjoern A. Zeeb 	 */
17298c230c8SBjoern A. Zeeb 	STAILQ_FOREACH_SAFE(elm, &epair_ifp_drain_list, ifp_next, tvar) {
17398c230c8SBjoern A. Zeeb 		ifp = elm->ifp;
17498c230c8SBjoern A. Zeeb 		epair_drv_flags &= ~IFF_DRV_OACTIVE;
17598c230c8SBjoern A. Zeeb 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
17698c230c8SBjoern A. Zeeb 		epair_start_locked(ifp);
17798c230c8SBjoern A. Zeeb 
17898c230c8SBjoern A. Zeeb 		IFQ_LOCK(&ifp->if_snd);
17998c230c8SBjoern A. Zeeb 		if (IFQ_IS_EMPTY(&ifp->if_snd)) {
18098c230c8SBjoern A. Zeeb 			STAILQ_REMOVE(&epair_ifp_drain_list, elm,
18198c230c8SBjoern A. Zeeb 			    epair_ifp_drain, ifp_next);
18298c230c8SBjoern A. Zeeb 			free(elm, M_EPAIR);
18398c230c8SBjoern A. Zeeb 		}
18498c230c8SBjoern A. Zeeb 		IFQ_UNLOCK(&ifp->if_snd);
18598c230c8SBjoern A. Zeeb 
18698c230c8SBjoern A. Zeeb 		if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) {
18798c230c8SBjoern A. Zeeb 			/* Our "hw"q overflew again. */
18898c230c8SBjoern A. Zeeb 			epair_drv_flags |= IFF_DRV_OACTIVE
18998c230c8SBjoern A. Zeeb 			DPRINTF("hw queue length overflow at %u\n",
19098c230c8SBjoern A. Zeeb 			    epairinq.ifq_maxlen);
19198c230c8SBjoern A. Zeeb #if 0
19298c230c8SBjoern A. Zeeb 			/* ``Auto-tuning.'' */
19398c230c8SBjoern A. Zeeb 			epairinq.ifq_maxlen += ifqmaxlen;
19498c230c8SBjoern A. Zeeb #endif
19598c230c8SBjoern A. Zeeb 			break;
19698c230c8SBjoern A. Zeeb 		}
19798c230c8SBjoern A. Zeeb 	}
19898c230c8SBjoern A. Zeeb 	EPAIR_UNLOCK();
19998c230c8SBjoern A. Zeeb }
20098c230c8SBjoern A. Zeeb 
20198c230c8SBjoern A. Zeeb /*
20298c230c8SBjoern A. Zeeb  * Network interface (`if') related functions.
20398c230c8SBjoern A. Zeeb  */
20498c230c8SBjoern A. Zeeb static void
20598c230c8SBjoern A. Zeeb epair_start_locked(struct ifnet *ifp)
20698c230c8SBjoern A. Zeeb {
20798c230c8SBjoern A. Zeeb 	struct mbuf *m;
20898c230c8SBjoern A. Zeeb 	struct epair_softc *sc;
20998c230c8SBjoern A. Zeeb 	struct ifnet *oifp;
21098c230c8SBjoern A. Zeeb 	int error;
21198c230c8SBjoern A. Zeeb 
21298c230c8SBjoern A. Zeeb 	EPAIR_LOCK_ASSERT();
21398c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p\n", ifp);
21498c230c8SBjoern A. Zeeb 
21598c230c8SBjoern A. Zeeb 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
21698c230c8SBjoern A. Zeeb 		return;
21798c230c8SBjoern A. Zeeb 	if ((ifp->if_flags & IFF_UP) == 0)
21898c230c8SBjoern A. Zeeb 		return;
21998c230c8SBjoern A. Zeeb 
22098c230c8SBjoern A. Zeeb 	/*
22198c230c8SBjoern A. Zeeb 	 * We get patckets here from ether_output via if_handoff()
22298c230c8SBjoern A. Zeeb 	 * and ned to put them into the input queue of the oifp
22398c230c8SBjoern A. Zeeb 	 * and call oifp->if_input() via netisr/epair_sintr().
22498c230c8SBjoern A. Zeeb 	 */
22598c230c8SBjoern A. Zeeb 	sc = ifp->if_softc;
22698c230c8SBjoern A. Zeeb 	oifp = sc->oifp;
22798c230c8SBjoern A. Zeeb 	sc = oifp->if_softc;
22898c230c8SBjoern A. Zeeb 	for (;;) {
22998c230c8SBjoern A. Zeeb 		IFQ_DEQUEUE(&ifp->if_snd, m);
23098c230c8SBjoern A. Zeeb 		if (m == NULL)
23198c230c8SBjoern A. Zeeb 			break;
23298c230c8SBjoern A. Zeeb 		BPF_MTAP(ifp, m);
23398c230c8SBjoern A. Zeeb 
23498c230c8SBjoern A. Zeeb 		/*
23598c230c8SBjoern A. Zeeb 		 * In case the outgoing interface is not usable,
23698c230c8SBjoern A. Zeeb 		 * drop the packet.
23798c230c8SBjoern A. Zeeb 		 */
23898c230c8SBjoern A. Zeeb 		if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
23998c230c8SBjoern A. Zeeb 		    (oifp->if_flags & IFF_UP) ==0) {
24098c230c8SBjoern A. Zeeb 			ifp->if_oerrors++;
24198c230c8SBjoern A. Zeeb 			m_freem(m);
24298c230c8SBjoern A. Zeeb 			continue;
24398c230c8SBjoern A. Zeeb 		}
24498c230c8SBjoern A. Zeeb 		DPRINTF("packet %s -> %s\n", ifp->if_xname, oifp->if_xname);
24598c230c8SBjoern A. Zeeb 
24698c230c8SBjoern A. Zeeb 		/*
24798c230c8SBjoern A. Zeeb 		 * Add a reference so the interface cannot go while the
24898c230c8SBjoern A. Zeeb 		 * packet is in transit as we rely on rcvif to stay valid.
24998c230c8SBjoern A. Zeeb 		 */
25098c230c8SBjoern A. Zeeb 		refcount_acquire(&sc->refcount);
25198c230c8SBjoern A. Zeeb 		m->m_pkthdr.rcvif = oifp;
25298c230c8SBjoern A. Zeeb 		CURVNET_SET_QUIET(oifp->if_vnet);
25398c230c8SBjoern A. Zeeb 		error = netisr_queue(NETISR_EPAIR, m);
25498c230c8SBjoern A. Zeeb 		CURVNET_RESTORE();
25598c230c8SBjoern A. Zeeb 		if (!error) {
25698c230c8SBjoern A. Zeeb 			ifp->if_opackets++;
25798c230c8SBjoern A. Zeeb 			/* Someone else received the packet. */
25898c230c8SBjoern A. Zeeb 			oifp->if_ipackets++;
25998c230c8SBjoern A. Zeeb 		} else {
26098c230c8SBjoern A. Zeeb 			epair_drv_flags |= IFF_DRV_OACTIVE;
26198c230c8SBjoern A. Zeeb 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
26298c230c8SBjoern A. Zeeb 			ADD_IFQ_FOR_DRAINING(ifp);
26398c230c8SBjoern A. Zeeb 			refcount_release(&sc->refcount);
26498c230c8SBjoern A. Zeeb 		}
26598c230c8SBjoern A. Zeeb 	}
26698c230c8SBjoern A. Zeeb }
26798c230c8SBjoern A. Zeeb 
26898c230c8SBjoern A. Zeeb static void
26998c230c8SBjoern A. Zeeb epair_start(struct ifnet *ifp)
27098c230c8SBjoern A. Zeeb {
27198c230c8SBjoern A. Zeeb 
27298c230c8SBjoern A. Zeeb 	EPAIR_LOCK();
27398c230c8SBjoern A. Zeeb 	epair_start_locked(ifp);
27498c230c8SBjoern A. Zeeb 	EPAIR_UNLOCK();
27598c230c8SBjoern A. Zeeb }
27698c230c8SBjoern A. Zeeb 
27798c230c8SBjoern A. Zeeb static int
27898c230c8SBjoern A. Zeeb epair_transmit_locked(struct ifnet *ifp, struct mbuf *m)
27998c230c8SBjoern A. Zeeb {
28098c230c8SBjoern A. Zeeb 	struct epair_softc *sc;
28198c230c8SBjoern A. Zeeb 	struct ifnet *oifp;
28298c230c8SBjoern A. Zeeb 	int error, len;
28398c230c8SBjoern A. Zeeb 	short mflags;
28498c230c8SBjoern A. Zeeb 
28598c230c8SBjoern A. Zeeb 	EPAIR_LOCK_ASSERT();
28698c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p m=%p\n", ifp, m);
28798c230c8SBjoern A. Zeeb 
28898c230c8SBjoern A. Zeeb 	if (m == NULL)
28998c230c8SBjoern A. Zeeb 		return (0);
29098c230c8SBjoern A. Zeeb 
29198c230c8SBjoern A. Zeeb 	/*
29298c230c8SBjoern A. Zeeb 	 * We are not going to use the interface en/dequeue mechanism
29398c230c8SBjoern A. Zeeb 	 * on the TX side. We are called from ether_output_frame()
29498c230c8SBjoern A. Zeeb 	 * and will put the packet into the incoming queue of the
29598c230c8SBjoern A. Zeeb 	 * other interface of our pair via the netsir.
29698c230c8SBjoern A. Zeeb 	 */
29798c230c8SBjoern A. Zeeb 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
29898c230c8SBjoern A. Zeeb 		m_freem(m);
29998c230c8SBjoern A. Zeeb 		return (ENXIO);
30098c230c8SBjoern A. Zeeb 	}
30198c230c8SBjoern A. Zeeb 	if ((ifp->if_flags & IFF_UP) == 0) {
30298c230c8SBjoern A. Zeeb 		m_freem(m);
30398c230c8SBjoern A. Zeeb 		return (ENETDOWN);
30498c230c8SBjoern A. Zeeb 	}
30598c230c8SBjoern A. Zeeb 
30698c230c8SBjoern A. Zeeb 	BPF_MTAP(ifp, m);
30798c230c8SBjoern A. Zeeb 
30898c230c8SBjoern A. Zeeb 	/*
30998c230c8SBjoern A. Zeeb 	 * In case the outgoing interface is not usable,
31098c230c8SBjoern A. Zeeb 	 * drop the packet.
31198c230c8SBjoern A. Zeeb 	 */
31298c230c8SBjoern A. Zeeb 	sc = ifp->if_softc;
31398c230c8SBjoern A. Zeeb 	oifp = sc->oifp;
31498c230c8SBjoern A. Zeeb 	if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
31598c230c8SBjoern A. Zeeb 	    (oifp->if_flags & IFF_UP) ==0) {
31698c230c8SBjoern A. Zeeb 		ifp->if_oerrors++;
31798c230c8SBjoern A. Zeeb 		m_freem(m);
31898c230c8SBjoern A. Zeeb 		return (0);
31998c230c8SBjoern A. Zeeb 	}
32098c230c8SBjoern A. Zeeb 	len = m->m_pkthdr.len;
32198c230c8SBjoern A. Zeeb 	mflags = m->m_flags;
32298c230c8SBjoern A. Zeeb 	DPRINTF("packet %s -> %s\n", ifp->if_xname, oifp->if_xname);
32398c230c8SBjoern A. Zeeb 
32498c230c8SBjoern A. Zeeb #ifdef ALTQ
32598c230c8SBjoern A. Zeeb 	/* Support ALTQ via the clasic if_start() path. */
32698c230c8SBjoern A. Zeeb 	IF_LOCK(&ifp->if_snd);
32798c230c8SBjoern A. Zeeb 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
32898c230c8SBjoern A. Zeeb 		ALTQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
32998c230c8SBjoern A. Zeeb 		if (error)
33098c230c8SBjoern A. Zeeb 			ifp->if_snd.ifq_drops++;
33198c230c8SBjoern A. Zeeb 		IF_UNLOCK(&ifp->if_snd);
33298c230c8SBjoern A. Zeeb 		if (!error) {
33398c230c8SBjoern A. Zeeb 			ifp->if_obytes += len;
33498c230c8SBjoern A. Zeeb 			if (mflags & (M_BCAST|M_MCAST))
33598c230c8SBjoern A. Zeeb 				ifp->if_omcasts++;
33698c230c8SBjoern A. Zeeb 
33798c230c8SBjoern A. Zeeb 			if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0)
33898c230c8SBjoern A. Zeeb 				epair_start_locked(ifp);
33998c230c8SBjoern A. Zeeb 			else
34098c230c8SBjoern A. Zeeb 				ADD_IFQ_FOR_DRAINING(ifp);
34198c230c8SBjoern A. Zeeb 		}
34298c230c8SBjoern A. Zeeb 		return (error);
34398c230c8SBjoern A. Zeeb 	}
34498c230c8SBjoern A. Zeeb 	IF_UNLOCK(&ifp->if_snd);
34598c230c8SBjoern A. Zeeb #endif
34698c230c8SBjoern A. Zeeb 
34798c230c8SBjoern A. Zeeb 	if ((epair_drv_flags & IFF_DRV_OACTIVE) != 0) {
34898c230c8SBjoern A. Zeeb 		/*
34998c230c8SBjoern A. Zeeb 		 * Our hardware queue is full, try to fall back
35098c230c8SBjoern A. Zeeb 		 * queuing to the ifq but do not call ifp->if_start.
35198c230c8SBjoern A. Zeeb 		 * Either we are lucky or the packet is gone.
35298c230c8SBjoern A. Zeeb 		 */
35398c230c8SBjoern A. Zeeb 		IFQ_ENQUEUE(&ifp->if_snd, m, error);
35498c230c8SBjoern A. Zeeb 		if (!error)
35598c230c8SBjoern A. Zeeb 			ADD_IFQ_FOR_DRAINING(ifp);
35698c230c8SBjoern A. Zeeb 		return (error);
35798c230c8SBjoern A. Zeeb 	}
35898c230c8SBjoern A. Zeeb 	sc = oifp->if_softc;
35998c230c8SBjoern A. Zeeb 	/*
36098c230c8SBjoern A. Zeeb 	 * Add a reference so the interface cannot go while the
36198c230c8SBjoern A. Zeeb 	 * packet is in transit as we rely on rcvif to stay valid.
36298c230c8SBjoern A. Zeeb 	 */
36398c230c8SBjoern A. Zeeb 	refcount_acquire(&sc->refcount);
36498c230c8SBjoern A. Zeeb 	m->m_pkthdr.rcvif = oifp;
36598c230c8SBjoern A. Zeeb 	CURVNET_SET_QUIET(oifp->if_vnet);
36698c230c8SBjoern A. Zeeb 	error = netisr_queue(NETISR_EPAIR, m);
36798c230c8SBjoern A. Zeeb 	CURVNET_RESTORE();
36898c230c8SBjoern A. Zeeb 	if (!error) {
36998c230c8SBjoern A. Zeeb 		ifp->if_opackets++;
37098c230c8SBjoern A. Zeeb 		/*
37198c230c8SBjoern A. Zeeb 		 * IFQ_HANDOFF_ADJ/ip_handoff() update statistics,
37298c230c8SBjoern A. Zeeb 		 * but as we bypass all this we have to duplicate
37398c230c8SBjoern A. Zeeb 		 * the logic another time.
37498c230c8SBjoern A. Zeeb 		 */
37598c230c8SBjoern A. Zeeb 		ifp->if_obytes += len;
37698c230c8SBjoern A. Zeeb 		if (mflags & (M_BCAST|M_MCAST))
37798c230c8SBjoern A. Zeeb 			ifp->if_omcasts++;
37898c230c8SBjoern A. Zeeb 		/* Someone else received the packet. */
37998c230c8SBjoern A. Zeeb 		oifp->if_ipackets++;
38098c230c8SBjoern A. Zeeb 	} else {
38198c230c8SBjoern A. Zeeb 		/* The packet was freed already. */
38298c230c8SBjoern A. Zeeb 		refcount_release(&sc->refcount);
38398c230c8SBjoern A. Zeeb 		epair_drv_flags |= IFF_DRV_OACTIVE;
38498c230c8SBjoern A. Zeeb 		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
38598c230c8SBjoern A. Zeeb 	}
38698c230c8SBjoern A. Zeeb 
38798c230c8SBjoern A. Zeeb 	return (error);
38898c230c8SBjoern A. Zeeb }
38998c230c8SBjoern A. Zeeb 
39098c230c8SBjoern A. Zeeb static int
39198c230c8SBjoern A. Zeeb epair_transmit(struct ifnet *ifp, struct mbuf *m)
39298c230c8SBjoern A. Zeeb {
39398c230c8SBjoern A. Zeeb 	int error;
39498c230c8SBjoern A. Zeeb 
39598c230c8SBjoern A. Zeeb 	EPAIR_LOCK();
39698c230c8SBjoern A. Zeeb 	error = epair_transmit_locked(ifp, m);
39798c230c8SBjoern A. Zeeb 	EPAIR_UNLOCK();
39898c230c8SBjoern A. Zeeb 	return (error);
39998c230c8SBjoern A. Zeeb }
40098c230c8SBjoern A. Zeeb 
40198c230c8SBjoern A. Zeeb static void
40298c230c8SBjoern A. Zeeb epair_qflush(struct ifnet *ifp)
40398c230c8SBjoern A. Zeeb {
40498c230c8SBjoern A. Zeeb 	struct epair_softc *sc;
40598c230c8SBjoern A. Zeeb 	struct ifaltq *ifq;
40698c230c8SBjoern A. Zeeb 
40798c230c8SBjoern A. Zeeb 	EPAIR_LOCK();
40898c230c8SBjoern A. Zeeb 	sc = ifp->if_softc;
40998c230c8SBjoern A. Zeeb 	ifq = &ifp->if_snd;
41098c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p sc refcnt=%u ifq_len=%u\n",
41198c230c8SBjoern A. Zeeb 	    ifp, sc->refcount, ifq->ifq_len);
41298c230c8SBjoern A. Zeeb 	/*
41398c230c8SBjoern A. Zeeb 	 * Instead of calling refcount_release(&sc->refcount);
41498c230c8SBjoern A. Zeeb 	 * n times, just subtract for the cleanup.
41598c230c8SBjoern A. Zeeb 	 */
41698c230c8SBjoern A. Zeeb 	sc->refcount -= ifq->ifq_len;
41798c230c8SBjoern A. Zeeb 	EPAIR_UNLOCK();
41898c230c8SBjoern A. Zeeb 	if (sc->if_qflush)
41998c230c8SBjoern A. Zeeb 		sc->if_qflush(ifp);
42098c230c8SBjoern A. Zeeb }
42198c230c8SBjoern A. Zeeb 
42298c230c8SBjoern A. Zeeb static int
42398c230c8SBjoern A. Zeeb epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
42498c230c8SBjoern A. Zeeb {
42598c230c8SBjoern A. Zeeb 	struct ifreq *ifr;
42698c230c8SBjoern A. Zeeb 	int error;
42798c230c8SBjoern A. Zeeb 
42898c230c8SBjoern A. Zeeb 	ifr = (struct ifreq *)data;
42998c230c8SBjoern A. Zeeb 	switch (cmd) {
43098c230c8SBjoern A. Zeeb 	case SIOCSIFFLAGS:
43198c230c8SBjoern A. Zeeb 	case SIOCADDMULTI:
43298c230c8SBjoern A. Zeeb 	case SIOCDELMULTI:
43398c230c8SBjoern A. Zeeb 		error = 0;
43498c230c8SBjoern A. Zeeb 		break;
43598c230c8SBjoern A. Zeeb 
43698c230c8SBjoern A. Zeeb 	default:
43798c230c8SBjoern A. Zeeb 		/* Let the common ethernet handler process this. */
43898c230c8SBjoern A. Zeeb 		error = ether_ioctl(ifp, cmd, data);
43998c230c8SBjoern A. Zeeb 		break;
44098c230c8SBjoern A. Zeeb 	}
44198c230c8SBjoern A. Zeeb 
44298c230c8SBjoern A. Zeeb 	return (error);
44398c230c8SBjoern A. Zeeb }
44498c230c8SBjoern A. Zeeb 
44598c230c8SBjoern A. Zeeb static void
44698c230c8SBjoern A. Zeeb epair_init(void *dummy __unused)
44798c230c8SBjoern A. Zeeb {
44898c230c8SBjoern A. Zeeb }
44998c230c8SBjoern A. Zeeb 
45098c230c8SBjoern A. Zeeb 
45198c230c8SBjoern A. Zeeb /*
45298c230c8SBjoern A. Zeeb  * Interface cloning functions.
45398c230c8SBjoern A. Zeeb  * We use our private ones so that we can create/destroy our secondary
45498c230c8SBjoern A. Zeeb  * device along with the primary one.
45598c230c8SBjoern A. Zeeb  */
45698c230c8SBjoern A. Zeeb static int
45798c230c8SBjoern A. Zeeb epair_clone_match(struct if_clone *ifc, const char *name)
45898c230c8SBjoern A. Zeeb {
45998c230c8SBjoern A. Zeeb 	const char *cp;
46098c230c8SBjoern A. Zeeb 
46198c230c8SBjoern A. Zeeb 	DPRINTF("name='%s'\n", name);
46298c230c8SBjoern A. Zeeb 
46398c230c8SBjoern A. Zeeb 	/*
46498c230c8SBjoern A. Zeeb 	 * Our base name is epair.
46598c230c8SBjoern A. Zeeb 	 * Our interfaces will be named epair<n>[ab].
46698c230c8SBjoern A. Zeeb 	 * So accept anything of the following list:
46798c230c8SBjoern A. Zeeb 	 * - epair
46898c230c8SBjoern A. Zeeb 	 * - epair<n>
46998c230c8SBjoern A. Zeeb 	 * but not the epair<n>[ab] versions.
47098c230c8SBjoern A. Zeeb 	 */
47198c230c8SBjoern A. Zeeb 	if (strncmp(EPAIRNAME, name, sizeof(EPAIRNAME)-1) != 0)
47298c230c8SBjoern A. Zeeb 		return (0);
47398c230c8SBjoern A. Zeeb 
47498c230c8SBjoern A. Zeeb 	for (cp = name + sizeof(EPAIRNAME) - 1; *cp != '\0'; cp++) {
47598c230c8SBjoern A. Zeeb 		if (*cp < '0' || *cp > '9')
47698c230c8SBjoern A. Zeeb 			return (0);
47798c230c8SBjoern A. Zeeb 	}
47898c230c8SBjoern A. Zeeb 
47998c230c8SBjoern A. Zeeb 	return (1);
48098c230c8SBjoern A. Zeeb }
48198c230c8SBjoern A. Zeeb 
48298c230c8SBjoern A. Zeeb static int
48398c230c8SBjoern A. Zeeb epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
48498c230c8SBjoern A. Zeeb {
48598c230c8SBjoern A. Zeeb 	struct epair_softc *sca, *scb;
48698c230c8SBjoern A. Zeeb 	struct ifnet *ifp;
48798c230c8SBjoern A. Zeeb 	char *dp;
48898c230c8SBjoern A. Zeeb 	int error, unit, wildcard;
48998c230c8SBjoern A. Zeeb 	uint8_t eaddr[ETHER_ADDR_LEN];	/* 00:00:00:00:00:00 */
49098c230c8SBjoern A. Zeeb 
49198c230c8SBjoern A. Zeeb 	/*
49298c230c8SBjoern A. Zeeb 	 * We are abusing params to create our second interface.
49398c230c8SBjoern A. Zeeb 	 * Actually we already created it and called if_clone_createif()
49498c230c8SBjoern A. Zeeb 	 * for it to do the official insertion procedure the moment we knew
49598c230c8SBjoern A. Zeeb 	 * it cannot fail anymore. So just do attach it here.
49698c230c8SBjoern A. Zeeb 	 */
49798c230c8SBjoern A. Zeeb 	if (params) {
49898c230c8SBjoern A. Zeeb 		scb = (struct epair_softc *)params;
49998c230c8SBjoern A. Zeeb 		ifp = scb->ifp;
50098c230c8SBjoern A. Zeeb 		/* Assign a hopefully unique, locally administered etheraddr. */
50198c230c8SBjoern A. Zeeb 		eaddr[0] = 0x02;
50298c230c8SBjoern A. Zeeb 		eaddr[3] = (ifp->if_index >> 8) & 0xff;
50398c230c8SBjoern A. Zeeb 		eaddr[4] = ifp->if_index & 0xff;
50498c230c8SBjoern A. Zeeb 		eaddr[5] = 0x0b;
50598c230c8SBjoern A. Zeeb 		ether_ifattach(ifp, eaddr);
50698c230c8SBjoern A. Zeeb 		/* Correctly set the name for the cloner list. */
50798c230c8SBjoern A. Zeeb 		strlcpy(name, scb->ifp->if_xname, len);
50898c230c8SBjoern A. Zeeb 		return (0);
50998c230c8SBjoern A. Zeeb 	}
51098c230c8SBjoern A. Zeeb 
51198c230c8SBjoern A. Zeeb 	/* Try to see if a special unit was requested. */
51298c230c8SBjoern A. Zeeb 	error = ifc_name2unit(name, &unit);
51398c230c8SBjoern A. Zeeb 	if (error != 0)
51498c230c8SBjoern A. Zeeb 		return (error);
51598c230c8SBjoern A. Zeeb 	wildcard = (unit < 0);
51698c230c8SBjoern A. Zeeb 
51798c230c8SBjoern A. Zeeb 	error = ifc_alloc_unit(ifc, &unit);
51898c230c8SBjoern A. Zeeb 	if (error != 0)
51998c230c8SBjoern A. Zeeb 		return (error);
52098c230c8SBjoern A. Zeeb 
52198c230c8SBjoern A. Zeeb 	/*
52298c230c8SBjoern A. Zeeb 	 * If no unit had been given, we need to adjust the ifName.
52398c230c8SBjoern A. Zeeb 	 * Also make sure there is space for our extra [ab] suffix.
52498c230c8SBjoern A. Zeeb 	 */
52598c230c8SBjoern A. Zeeb 	for (dp = name; *dp != '\0'; dp++);
52698c230c8SBjoern A. Zeeb 	if (wildcard) {
52798c230c8SBjoern A. Zeeb 		error = snprintf(dp, len - (dp - name), "%d", unit);
52898c230c8SBjoern A. Zeeb 		if (error > len - (dp - name) - 1) {
52998c230c8SBjoern A. Zeeb 			/* ifName too long. */
53098c230c8SBjoern A. Zeeb 			ifc_free_unit(ifc, unit);
53198c230c8SBjoern A. Zeeb 			return (ENOSPC);
53298c230c8SBjoern A. Zeeb 		}
53398c230c8SBjoern A. Zeeb 		dp += error;
53498c230c8SBjoern A. Zeeb 	}
53598c230c8SBjoern A. Zeeb 	if (len - (dp - name) - 1 < 1) {
53698c230c8SBjoern A. Zeeb 		/* No space left for our [ab] suffix. */
53798c230c8SBjoern A. Zeeb 		ifc_free_unit(ifc, unit);
53898c230c8SBjoern A. Zeeb 		return (ENOSPC);
53998c230c8SBjoern A. Zeeb 	}
54098c230c8SBjoern A. Zeeb 	*dp = 'a';
54198c230c8SBjoern A. Zeeb 	/* Must not change dp so we can replace 'a' by 'b' later. */
54298c230c8SBjoern A. Zeeb 	*(dp+1) = '\0';
54398c230c8SBjoern A. Zeeb 
54498c230c8SBjoern A. Zeeb 	/* Allocate memory for both [ab] interfaces */
54598c230c8SBjoern A. Zeeb 	sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
54698c230c8SBjoern A. Zeeb 	refcount_init(&sca->refcount, 1);
54798c230c8SBjoern A. Zeeb 	sca->ifp = if_alloc(IFT_ETHER);
54898c230c8SBjoern A. Zeeb 	if (sca->ifp == NULL) {
54998c230c8SBjoern A. Zeeb 		free(sca, M_EPAIR);
55098c230c8SBjoern A. Zeeb 		ifc_free_unit(ifc, unit);
55198c230c8SBjoern A. Zeeb 		return (ENOSPC);
55298c230c8SBjoern A. Zeeb 	}
55398c230c8SBjoern A. Zeeb 
55498c230c8SBjoern A. Zeeb 	scb = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
55598c230c8SBjoern A. Zeeb 	refcount_init(&scb->refcount, 1);
55698c230c8SBjoern A. Zeeb 	scb->ifp = if_alloc(IFT_ETHER);
55798c230c8SBjoern A. Zeeb 	if (scb->ifp == NULL) {
55898c230c8SBjoern A. Zeeb 		free(scb, M_EPAIR);
55998c230c8SBjoern A. Zeeb 		if_free(sca->ifp);
56098c230c8SBjoern A. Zeeb 		free(sca, M_EPAIR);
56198c230c8SBjoern A. Zeeb 		ifc_free_unit(ifc, unit);
56298c230c8SBjoern A. Zeeb 		return (ENOSPC);
56398c230c8SBjoern A. Zeeb 	}
56498c230c8SBjoern A. Zeeb 
56598c230c8SBjoern A. Zeeb 	/*
56698c230c8SBjoern A. Zeeb 	 * Cross-reference the interfaces so we will be able to free both.
56798c230c8SBjoern A. Zeeb 	 */
56898c230c8SBjoern A. Zeeb 	sca->oifp = scb->ifp;
56998c230c8SBjoern A. Zeeb 	scb->oifp = sca->ifp;
57098c230c8SBjoern A. Zeeb 
57198c230c8SBjoern A. Zeeb 	/* Finish initialization of interface <n>a. */
57298c230c8SBjoern A. Zeeb 	ifp = sca->ifp;
57398c230c8SBjoern A. Zeeb 	ifp->if_softc = sca;
57498c230c8SBjoern A. Zeeb 	strlcpy(ifp->if_xname, name, IFNAMSIZ);
57598c230c8SBjoern A. Zeeb 	ifp->if_dname = ifc->ifc_name;
57698c230c8SBjoern A. Zeeb 	ifp->if_dunit = unit;
57798c230c8SBjoern A. Zeeb 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
57898c230c8SBjoern A. Zeeb 	ifp->if_start = epair_start;
57998c230c8SBjoern A. Zeeb 	ifp->if_ioctl = epair_ioctl;
58098c230c8SBjoern A. Zeeb 	ifp->if_init  = epair_init;
58198c230c8SBjoern A. Zeeb 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
58298c230c8SBjoern A. Zeeb 	/* Assign a hopefully unique, locally administered etheraddr. */
58398c230c8SBjoern A. Zeeb 	eaddr[0] = 0x02;
58498c230c8SBjoern A. Zeeb 	eaddr[3] = (ifp->if_index >> 8) & 0xff;
58598c230c8SBjoern A. Zeeb 	eaddr[4] = ifp->if_index & 0xff;
58698c230c8SBjoern A. Zeeb 	eaddr[5] = 0x0a;
58798c230c8SBjoern A. Zeeb 	ether_ifattach(ifp, eaddr);
58898c230c8SBjoern A. Zeeb 	sca->if_qflush = ifp->if_qflush;
58998c230c8SBjoern A. Zeeb 	ifp->if_qflush = epair_qflush;
59098c230c8SBjoern A. Zeeb 	ifp->if_transmit = epair_transmit;
59198c230c8SBjoern A. Zeeb 	ifp->if_baudrate = IF_Gbps(10UL);	/* arbitrary maximum */
59298c230c8SBjoern A. Zeeb 
59398c230c8SBjoern A. Zeeb 	/* Swap the name and finish initialization of interface <n>b. */
59498c230c8SBjoern A. Zeeb 	*dp = 'b';
59598c230c8SBjoern A. Zeeb 
59698c230c8SBjoern A. Zeeb 	ifp = scb->ifp;
59798c230c8SBjoern A. Zeeb 	ifp->if_softc = scb;
59898c230c8SBjoern A. Zeeb 	strlcpy(ifp->if_xname, name, IFNAMSIZ);
59998c230c8SBjoern A. Zeeb 	ifp->if_dname = ifc->ifc_name;
60098c230c8SBjoern A. Zeeb 	ifp->if_dunit = unit;
60198c230c8SBjoern A. Zeeb 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
60298c230c8SBjoern A. Zeeb 	ifp->if_start = epair_start;
60398c230c8SBjoern A. Zeeb 	ifp->if_ioctl = epair_ioctl;
60498c230c8SBjoern A. Zeeb 	ifp->if_init  = epair_init;
60598c230c8SBjoern A. Zeeb 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
60698c230c8SBjoern A. Zeeb 	/* We need to play some tricks here for the second interface. */
60798c230c8SBjoern A. Zeeb 	strlcpy(name, EPAIRNAME, len);
60898c230c8SBjoern A. Zeeb 	error = if_clone_create(name, len, (caddr_t)scb);
60998c230c8SBjoern A. Zeeb 	if (error)
61098c230c8SBjoern A. Zeeb 		panic("%s: if_clone_createif() for our 2nd iface failed: %d",
61198c230c8SBjoern A. Zeeb 		    __func__, error);
61298c230c8SBjoern A. Zeeb 	scb->if_qflush = ifp->if_qflush;
61398c230c8SBjoern A. Zeeb 	ifp->if_qflush = epair_qflush;
61498c230c8SBjoern A. Zeeb 	ifp->if_transmit = epair_transmit;
61598c230c8SBjoern A. Zeeb 	ifp->if_baudrate = IF_Gbps(10UL);	/* arbitrary maximum */
61698c230c8SBjoern A. Zeeb 
61798c230c8SBjoern A. Zeeb 	/*
61898c230c8SBjoern A. Zeeb 	 * Restore name to <n>a as the ifp for this will go into the
61998c230c8SBjoern A. Zeeb 	 * cloner list for the initial call.
62098c230c8SBjoern A. Zeeb 	 */
62198c230c8SBjoern A. Zeeb 	strlcpy(name, sca->ifp->if_xname, len);
62298c230c8SBjoern A. Zeeb 	DPRINTF("name='%s/%db' created sca=%p scb=%p\n", name, unit, sca, scb);
62398c230c8SBjoern A. Zeeb 
62498c230c8SBjoern A. Zeeb 	/* Tell the world, that we are ready to rock. */
62598c230c8SBjoern A. Zeeb 	sca->ifp->if_drv_flags |= IFF_DRV_RUNNING;
62698c230c8SBjoern A. Zeeb 	scb->ifp->if_drv_flags |= IFF_DRV_RUNNING;
62798c230c8SBjoern A. Zeeb 
62898c230c8SBjoern A. Zeeb 	return (0);
62998c230c8SBjoern A. Zeeb }
63098c230c8SBjoern A. Zeeb 
63198c230c8SBjoern A. Zeeb static int
63298c230c8SBjoern A. Zeeb epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
63398c230c8SBjoern A. Zeeb {
63498c230c8SBjoern A. Zeeb 	struct ifnet *oifp;
63598c230c8SBjoern A. Zeeb 	struct epair_softc *sca, *scb;
63698c230c8SBjoern A. Zeeb 	int unit, error;
63798c230c8SBjoern A. Zeeb 
63898c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p\n", ifp);
63998c230c8SBjoern A. Zeeb 
64098c230c8SBjoern A. Zeeb 	/*
64198c230c8SBjoern A. Zeeb 	 * In case we called into if_clone_destroyif() ourselves
64298c230c8SBjoern A. Zeeb 	 * again to remove the second interface, the softc will be
64398c230c8SBjoern A. Zeeb 	 * NULL. In that case so not do anything but return success.
64498c230c8SBjoern A. Zeeb 	 */
64598c230c8SBjoern A. Zeeb 	if (ifp->if_softc == NULL)
64698c230c8SBjoern A. Zeeb 		return (0);
64798c230c8SBjoern A. Zeeb 
64898c230c8SBjoern A. Zeeb 	unit = ifp->if_dunit;
64998c230c8SBjoern A. Zeeb 	sca = ifp->if_softc;
65098c230c8SBjoern A. Zeeb 	oifp = sca->oifp;
65198c230c8SBjoern A. Zeeb 	scb = oifp->if_softc;
65298c230c8SBjoern A. Zeeb 
65398c230c8SBjoern A. Zeeb 	DPRINTF("ifp=%p oifp=%p\n", ifp, oifp);
65498c230c8SBjoern A. Zeeb 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
65598c230c8SBjoern A. Zeeb 	oifp->if_drv_flags &= ~IFF_DRV_RUNNING;
65698c230c8SBjoern A. Zeeb 	ether_ifdetach(oifp);
65798c230c8SBjoern A. Zeeb 	ether_ifdetach(ifp);
65898c230c8SBjoern A. Zeeb 	/*
65998c230c8SBjoern A. Zeeb 	 * Wait for all packets to be dispatched to if_input.
66098c230c8SBjoern A. Zeeb 	 * The numbers can only go down as the interfaces are
66198c230c8SBjoern A. Zeeb 	 * detached so there is no need to use atomics.
66298c230c8SBjoern A. Zeeb 	 */
66398c230c8SBjoern A. Zeeb 	DPRINTF("sca refcnt=%u scb refcnt=%u\n", sca->refcount, scb->refcount);
66498c230c8SBjoern A. Zeeb 	KASSERT(sca->refcount == 1 && scb->refcount == 1,
66598c230c8SBjoern A. Zeeb 	    ("%s: sca->refcount!=1: %d || scb->refcount!=1: %d",
66698c230c8SBjoern A. Zeeb 	    __func__, sca->refcount, scb->refcount));
66798c230c8SBjoern A. Zeeb 
66898c230c8SBjoern A. Zeeb 	/*
66998c230c8SBjoern A. Zeeb 	 * Get rid of our second half.
67098c230c8SBjoern A. Zeeb 	 */
67198c230c8SBjoern A. Zeeb 	oifp->if_softc = NULL;
67298c230c8SBjoern A. Zeeb 	error = if_clone_destroyif(ifc, oifp);
67398c230c8SBjoern A. Zeeb 	if (error)
67498c230c8SBjoern A. Zeeb 		panic("%s: if_clone_destroyif() for our 2nd iface failed: %d",
67598c230c8SBjoern A. Zeeb 		    __func__, error);
67698c230c8SBjoern A. Zeeb 
67798c230c8SBjoern A. Zeeb 	/* Finish cleaning up. Free them and release the unit. */
67898c230c8SBjoern A. Zeeb 	if_free_type(oifp, IFT_ETHER);
67998c230c8SBjoern A. Zeeb 	if_free_type(ifp, IFT_ETHER);
68098c230c8SBjoern A. Zeeb 	free(scb, M_EPAIR);
68198c230c8SBjoern A. Zeeb 	free(sca, M_EPAIR);
68298c230c8SBjoern A. Zeeb 	ifc_free_unit(ifc, unit);
68398c230c8SBjoern A. Zeeb 
68498c230c8SBjoern A. Zeeb 	return (0);
68598c230c8SBjoern A. Zeeb }
68698c230c8SBjoern A. Zeeb 
68798c230c8SBjoern A. Zeeb static int
68898c230c8SBjoern A. Zeeb epair_modevent(module_t mod, int type, void *data)
68998c230c8SBjoern A. Zeeb {
69098c230c8SBjoern A. Zeeb 	int tmp;
69198c230c8SBjoern A. Zeeb 
69298c230c8SBjoern A. Zeeb 	switch (type) {
69398c230c8SBjoern A. Zeeb 	case MOD_LOAD:
69498c230c8SBjoern A. Zeeb 		/* For now limit us to one global mutex and one inq. */
69598c230c8SBjoern A. Zeeb 		EPAIR_LOCK_INIT();
69698c230c8SBjoern A. Zeeb 		epair_drv_flags = 0;
69798c230c8SBjoern A. Zeeb 		epairinq.ifq_maxlen = 16 * ifqmaxlen; /* What is a good 16? */
69898c230c8SBjoern A. Zeeb 		if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &tmp))
69998c230c8SBjoern A. Zeeb 		    epairinq.ifq_maxlen = tmp;
70098c230c8SBjoern A. Zeeb 		mtx_init(&epairinq.ifq_mtx, "epair_inq", NULL, MTX_DEF);
70198c230c8SBjoern A. Zeeb 		netisr_register2(NETISR_EPAIR, (netisr_t *)epair_sintr,
70298c230c8SBjoern A. Zeeb 		    epair_sintr_drained, &epairinq, 0);
70398c230c8SBjoern A. Zeeb 		if_clone_attach(&epair_cloner);
70498c230c8SBjoern A. Zeeb 		if (bootverbose)
70598c230c8SBjoern A. Zeeb 			printf("%s initialized.\n", EPAIRNAME);
70698c230c8SBjoern A. Zeeb 		break;
70798c230c8SBjoern A. Zeeb 	case MOD_UNLOAD:
70898c230c8SBjoern A. Zeeb 		if_clone_detach(&epair_cloner);
70998c230c8SBjoern A. Zeeb 		netisr_unregister(NETISR_EPAIR);
71098c230c8SBjoern A. Zeeb 		mtx_destroy(&epairinq.ifq_mtx);
71198c230c8SBjoern A. Zeeb 		EPAIR_LOCK_DESTROY();
71298c230c8SBjoern A. Zeeb 		if (bootverbose)
71398c230c8SBjoern A. Zeeb 			printf("%s unloaded.\n", EPAIRNAME);
71498c230c8SBjoern A. Zeeb 		break;
71598c230c8SBjoern A. Zeeb 	default:
71698c230c8SBjoern A. Zeeb 		return (EOPNOTSUPP);
71798c230c8SBjoern A. Zeeb 	}
71898c230c8SBjoern A. Zeeb 	return (0);
71998c230c8SBjoern A. Zeeb }
72098c230c8SBjoern A. Zeeb 
72198c230c8SBjoern A. Zeeb static moduledata_t epair_mod = {
72298c230c8SBjoern A. Zeeb 	"if_epair",
72398c230c8SBjoern A. Zeeb 	epair_modevent,
72498c230c8SBjoern A. Zeeb 	0
72598c230c8SBjoern A. Zeeb };
72698c230c8SBjoern A. Zeeb 
72798c230c8SBjoern A. Zeeb DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
72898c230c8SBjoern A. Zeeb MODULE_VERSION(if_epair, 1);
729