184a3e25aSSepherosa Ziehau /*
284a3e25aSSepherosa Ziehau  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
384a3e25aSSepherosa Ziehau  *
484a3e25aSSepherosa Ziehau  * This code is derived from software contributed to The DragonFly Project
584a3e25aSSepherosa Ziehau  * by Sepherosa Ziehau <sepherosa@gmail.com>
684a3e25aSSepherosa Ziehau  *
784a3e25aSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
884a3e25aSSepherosa Ziehau  * modification, are permitted provided that the following conditions
984a3e25aSSepherosa Ziehau  * are met:
1084a3e25aSSepherosa Ziehau  *
1184a3e25aSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
1284a3e25aSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
1384a3e25aSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1484a3e25aSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in
1584a3e25aSSepherosa Ziehau  *    the documentation and/or other materials provided with the
1684a3e25aSSepherosa Ziehau  *    distribution.
1784a3e25aSSepherosa Ziehau  * 3. Neither the name of The DragonFly Project nor the names of its
1884a3e25aSSepherosa Ziehau  *    contributors may be used to endorse or promote products derived
1984a3e25aSSepherosa Ziehau  *    from this software without specific, prior written permission.
2084a3e25aSSepherosa Ziehau  *
2184a3e25aSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2284a3e25aSSepherosa Ziehau  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2384a3e25aSSepherosa Ziehau  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2484a3e25aSSepherosa Ziehau  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2584a3e25aSSepherosa Ziehau  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2684a3e25aSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2784a3e25aSSepherosa Ziehau  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2884a3e25aSSepherosa Ziehau  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2984a3e25aSSepherosa Ziehau  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3084a3e25aSSepherosa Ziehau  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3184a3e25aSSepherosa Ziehau  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3284a3e25aSSepherosa Ziehau  * SUCH DAMAGE.
3384a3e25aSSepherosa Ziehau  */
3484a3e25aSSepherosa Ziehau 
3584a3e25aSSepherosa Ziehau #include <sys/param.h>
36329bf5d1SSepherosa Ziehau #include <sys/kernel.h>
37*805c8e8eSzrj #include <sys/malloc.h>
3884a3e25aSSepherosa Ziehau #include <sys/mbuf.h>
3984a3e25aSSepherosa Ziehau #include <sys/msgport.h>
40879652a3SSepherosa Ziehau #include <sys/socketvar.h>
41329bf5d1SSepherosa Ziehau #include <sys/sysctl.h>
4284a3e25aSSepherosa Ziehau 
4384a3e25aSSepherosa Ziehau #include <net/if.h>
4484a3e25aSSepherosa Ziehau #include <net/if_var.h>
4584a3e25aSSepherosa Ziehau #include <net/route.h>
4684a3e25aSSepherosa Ziehau #include <net/ethernet.h>
475337421cSSepherosa Ziehau #include <net/netisr2.h>
4884a3e25aSSepherosa Ziehau #include <net/netmsg2.h>
4984a3e25aSSepherosa Ziehau 
5084a3e25aSSepherosa Ziehau #include <netinet/in.h>
5184a3e25aSSepherosa Ziehau #include <netinet/in_var.h>
5284a3e25aSSepherosa Ziehau #include <netinet/ip.h>
5384a3e25aSSepherosa Ziehau #include <netinet/ip_var.h>
5484a3e25aSSepherosa Ziehau 
5584a3e25aSSepherosa Ziehau #include <net/dummynet/ip_dummynet.h>
5684a3e25aSSepherosa Ziehau 
57002c1265SMatthew Dillon static void	ip_dn_ether_output(netmsg_t);
58002c1265SMatthew Dillon static void	ip_dn_ether_demux(netmsg_t);
59002c1265SMatthew Dillon static void	ip_dn_ip_input(netmsg_t);
60002c1265SMatthew Dillon static void	ip_dn_ip_output(netmsg_t);
6184a3e25aSSepherosa Ziehau 
62002c1265SMatthew Dillon static void	ip_dn_sockopt_dispatch(netmsg_t);
63002c1265SMatthew Dillon static void	ip_dn_freepkt_dispatch(netmsg_t);
64002c1265SMatthew Dillon static void	ip_dn_dispatch(netmsg_t);
6584a3e25aSSepherosa Ziehau 
6684a3e25aSSepherosa Ziehau static void	ip_dn_freepkt(struct dn_pkt *);
6784a3e25aSSepherosa Ziehau 
68879652a3SSepherosa Ziehau static int	ip_dn_sockopt_flush(struct sockopt *);
69879652a3SSepherosa Ziehau static int	ip_dn_sockopt_get(struct sockopt *);
70879652a3SSepherosa Ziehau static int	ip_dn_sockopt_config(struct sockopt *);
71879652a3SSepherosa Ziehau 
7284a3e25aSSepherosa Ziehau ip_dn_io_t	*ip_dn_io_ptr;
7331ce7747SSepherosa Ziehau ip_dn_ctl_t	*ip_dn_ctl_ptr;
7484a3e25aSSepherosa Ziehau int		ip_dn_cpu = 0;
7584a3e25aSSepherosa Ziehau 
76329bf5d1SSepherosa Ziehau TUNABLE_INT("net.inet.ip.dummynet.cpu", &ip_dn_cpu);
77329bf5d1SSepherosa Ziehau 
78329bf5d1SSepherosa Ziehau SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
79329bf5d1SSepherosa Ziehau SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, cpu, CTLFLAG_RD,
80329bf5d1SSepherosa Ziehau 	   &ip_dn_cpu, 0, "CPU to run dummynet");
81329bf5d1SSepherosa Ziehau 
8284a3e25aSSepherosa Ziehau void
ip_dn_queue(struct mbuf * m)8384a3e25aSSepherosa Ziehau ip_dn_queue(struct mbuf *m)
8484a3e25aSSepherosa Ziehau {
8584a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
8684a3e25aSSepherosa Ziehau 	lwkt_port_t port;
8784a3e25aSSepherosa Ziehau 
88840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
89840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
90ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
9184a3e25aSSepherosa Ziehau 
9284a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
93002c1265SMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
9448e7b118SMatthew Dillon 		    0, ip_dn_dispatch);
9584a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
9684a3e25aSSepherosa Ziehau 
97ec7f7fc8SSepherosa Ziehau 	port = netisr_cpuport(ip_dn_cpu);
98002c1265SMatthew Dillon 	lwkt_sendmsg(port, &nmp->base.lmsg);
9984a3e25aSSepherosa Ziehau }
10084a3e25aSSepherosa Ziehau 
10184a3e25aSSepherosa Ziehau void
ip_dn_packet_free(struct dn_pkt * pkt)10284a3e25aSSepherosa Ziehau ip_dn_packet_free(struct dn_pkt *pkt)
10384a3e25aSSepherosa Ziehau {
10484a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
10584a3e25aSSepherosa Ziehau 	struct mbuf *m = pkt->dn_m;
10684a3e25aSSepherosa Ziehau 
107840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
108840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
109ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
11084a3e25aSSepherosa Ziehau 
11184a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
112002c1265SMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
11348e7b118SMatthew Dillon 		    0, ip_dn_freepkt_dispatch);
11484a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
11584a3e25aSSepherosa Ziehau 
116002c1265SMatthew Dillon 	lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
11784a3e25aSSepherosa Ziehau }
11884a3e25aSSepherosa Ziehau 
11984a3e25aSSepherosa Ziehau void
ip_dn_packet_redispatch(struct dn_pkt * pkt)12084a3e25aSSepherosa Ziehau ip_dn_packet_redispatch(struct dn_pkt *pkt)
12184a3e25aSSepherosa Ziehau {
12284a3e25aSSepherosa Ziehau 	static const netisr_fn_t dispatches[DN_TO_MAX] = {
12384a3e25aSSepherosa Ziehau 	[DN_TO_IP_OUT]		= ip_dn_ip_output,
12484a3e25aSSepherosa Ziehau 	[DN_TO_IP_IN]		= ip_dn_ip_input,
12584a3e25aSSepherosa Ziehau 	[DN_TO_ETH_DEMUX]	= ip_dn_ether_demux,
12684a3e25aSSepherosa Ziehau 	[DN_TO_ETH_OUT]		= ip_dn_ether_output
12784a3e25aSSepherosa Ziehau 	};
12884a3e25aSSepherosa Ziehau 
12984a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
13084a3e25aSSepherosa Ziehau 	struct mbuf *m;
13184a3e25aSSepherosa Ziehau 	netisr_fn_t dispatch;
13284a3e25aSSepherosa Ziehau 	int dir;
13384a3e25aSSepherosa Ziehau 
13484a3e25aSSepherosa Ziehau 	dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
13584a3e25aSSepherosa Ziehau 	KASSERT(dir < DN_TO_MAX,
136ed20d0e3SSascha Wildner 		("unknown dummynet redispatch dir %d", dir));
13784a3e25aSSepherosa Ziehau 
13884a3e25aSSepherosa Ziehau 	dispatch = dispatches[dir];
13984a3e25aSSepherosa Ziehau 	KASSERT(dispatch != NULL,
140ed20d0e3SSascha Wildner 		("unsupported dummynet redispatch dir %d", dir));
14184a3e25aSSepherosa Ziehau 
14284a3e25aSSepherosa Ziehau 	m = pkt->dn_m;
143840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
144840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
145ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
14684a3e25aSSepherosa Ziehau 
14784a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
148002c1265SMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport, 0, dispatch);
14984a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
15084a3e25aSSepherosa Ziehau 
151002c1265SMatthew Dillon 	lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
15284a3e25aSSepherosa Ziehau }
15384a3e25aSSepherosa Ziehau 
154879652a3SSepherosa Ziehau int
ip_dn_sockopt(struct sockopt * sopt)155879652a3SSepherosa Ziehau ip_dn_sockopt(struct sockopt *sopt)
156879652a3SSepherosa Ziehau {
157879652a3SSepherosa Ziehau 	int error = 0;
158879652a3SSepherosa Ziehau 
159879652a3SSepherosa Ziehau 	/* Disallow sets in really-really secure mode. */
160879652a3SSepherosa Ziehau 	if (sopt->sopt_dir == SOPT_SET) {
161879652a3SSepherosa Ziehau 		if (securelevel >= 3)
162879652a3SSepherosa Ziehau 			return EPERM;
163879652a3SSepherosa Ziehau 	}
164879652a3SSepherosa Ziehau 
165879652a3SSepherosa Ziehau 	switch (sopt->sopt_name) {
166879652a3SSepherosa Ziehau 	case IP_DUMMYNET_GET:
167879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_get(sopt);
168879652a3SSepherosa Ziehau 		break;
169879652a3SSepherosa Ziehau 
170879652a3SSepherosa Ziehau 	case IP_DUMMYNET_FLUSH:
171879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_flush(sopt);
172879652a3SSepherosa Ziehau 		break;
173879652a3SSepherosa Ziehau 
174879652a3SSepherosa Ziehau 	case IP_DUMMYNET_DEL:
175879652a3SSepherosa Ziehau 	case IP_DUMMYNET_CONFIGURE:
176879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_config(sopt);
177879652a3SSepherosa Ziehau 		break;
178879652a3SSepherosa Ziehau 
179879652a3SSepherosa Ziehau 	default:
180879652a3SSepherosa Ziehau 		kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
181879652a3SSepherosa Ziehau 		error = EINVAL;
182879652a3SSepherosa Ziehau 		break;
183879652a3SSepherosa Ziehau 	}
184879652a3SSepherosa Ziehau 	return error;
185879652a3SSepherosa Ziehau }
186879652a3SSepherosa Ziehau 
18784a3e25aSSepherosa Ziehau static void
ip_dn_freepkt(struct dn_pkt * pkt)18884a3e25aSSepherosa Ziehau ip_dn_freepkt(struct dn_pkt *pkt)
18984a3e25aSSepherosa Ziehau {
19084a3e25aSSepherosa Ziehau 	struct rtentry *rt = pkt->ro.ro_rt;
19184a3e25aSSepherosa Ziehau 
19284a3e25aSSepherosa Ziehau 	/* Unreference route entry */
19384a3e25aSSepherosa Ziehau 	if (rt != NULL) {
19484a3e25aSSepherosa Ziehau 		if (rt->rt_refcnt <= 0) {	/* XXX assert? */
19584a3e25aSSepherosa Ziehau 			kprintf("-- warning, refcnt now %ld, decreasing\n",
19684a3e25aSSepherosa Ziehau 				rt->rt_refcnt);
19784a3e25aSSepherosa Ziehau 		}
19884a3e25aSSepherosa Ziehau 		RTFREE(rt);
19984a3e25aSSepherosa Ziehau 	}
20084a3e25aSSepherosa Ziehau 
20184a3e25aSSepherosa Ziehau 	/* Unreference packet private data */
20284a3e25aSSepherosa Ziehau 	if (pkt->dn_unref_priv)
20384a3e25aSSepherosa Ziehau 		pkt->dn_unref_priv(pkt->dn_priv);
20484a3e25aSSepherosa Ziehau 
20584a3e25aSSepherosa Ziehau 	/* Free the parent mbuf, this will free 'pkt' as well */
20684a3e25aSSepherosa Ziehau 	m_freem(pkt->dn_m);
20784a3e25aSSepherosa Ziehau }
20884a3e25aSSepherosa Ziehau 
20984a3e25aSSepherosa Ziehau static void
ip_dn_freepkt_dispatch(netmsg_t nmsg)210002c1265SMatthew Dillon ip_dn_freepkt_dispatch(netmsg_t nmsg)
21184a3e25aSSepherosa Ziehau {
21284a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
21384a3e25aSSepherosa Ziehau 	struct mbuf *m;
21484a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
21584a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
21684a3e25aSSepherosa Ziehau 
217002c1265SMatthew Dillon 	nmp = &nmsg->packet;
21884a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
219840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
220840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
221ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
22284a3e25aSSepherosa Ziehau 
22384a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
224840665f6SSepherosa Ziehau 	KKASSERT(mtag != NULL);
22584a3e25aSSepherosa Ziehau 
226840665f6SSepherosa Ziehau 	pkt = m_tag_data(mtag);
22784a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
22884a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
229ed20d0e3SSascha Wildner 		 "target cpuid %d, mycpuid %d", __func__,
23084a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
23184a3e25aSSepherosa Ziehau 
23284a3e25aSSepherosa Ziehau 	ip_dn_freepkt(pkt);
23384a3e25aSSepherosa Ziehau }
23484a3e25aSSepherosa Ziehau 
23584a3e25aSSepherosa Ziehau static void
ip_dn_dispatch(netmsg_t nmsg)236002c1265SMatthew Dillon ip_dn_dispatch(netmsg_t nmsg)
23784a3e25aSSepherosa Ziehau {
23884a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
23984a3e25aSSepherosa Ziehau 	struct mbuf *m;
24084a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
24184a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
24284a3e25aSSepherosa Ziehau 
24384a3e25aSSepherosa Ziehau 	KASSERT(ip_dn_cpu == mycpuid,
24484a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
245ed20d0e3SSascha Wildner 		 "dummynet cpuid %d, mycpuid %d", __func__,
24684a3e25aSSepherosa Ziehau 		 ip_dn_cpu, mycpuid));
24784a3e25aSSepherosa Ziehau 
248002c1265SMatthew Dillon 	nmp = &nmsg->packet;
24984a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
250840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
251840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
252ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
25384a3e25aSSepherosa Ziehau 
25484a3e25aSSepherosa Ziehau 	if (DUMMYNET_LOADED) {
25584a3e25aSSepherosa Ziehau 		if (ip_dn_io_ptr(m) == 0)
25684a3e25aSSepherosa Ziehau 			return;
25784a3e25aSSepherosa Ziehau 	}
25884a3e25aSSepherosa Ziehau 
25984a3e25aSSepherosa Ziehau 	/*
26084a3e25aSSepherosa Ziehau 	 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
26184a3e25aSSepherosa Ziehau 	 */
26284a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
263840665f6SSepherosa Ziehau 	KKASSERT(mtag != NULL);
264840665f6SSepherosa Ziehau 
26584a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
26684a3e25aSSepherosa Ziehau 	ip_dn_packet_free(pkt);
26784a3e25aSSepherosa Ziehau }
26884a3e25aSSepherosa Ziehau 
26984a3e25aSSepherosa Ziehau static void
ip_dn_ip_output(netmsg_t nmsg)270002c1265SMatthew Dillon ip_dn_ip_output(netmsg_t nmsg)
27184a3e25aSSepherosa Ziehau {
27284a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
27384a3e25aSSepherosa Ziehau 	struct mbuf *m;
27484a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
27584a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
27684a3e25aSSepherosa Ziehau 	struct rtentry *rt;
27784a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
27884a3e25aSSepherosa Ziehau 	void *priv;
27984a3e25aSSepherosa Ziehau 
280002c1265SMatthew Dillon 	nmp = &nmsg->packet;
28184a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
282840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
283840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
284ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
28584a3e25aSSepherosa Ziehau 
28684a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
28784a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
28884a3e25aSSepherosa Ziehau 
28984a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
29084a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
29184a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
292ed20d0e3SSascha Wildner 		 "target cpuid %d, mycpuid %d", __func__,
29384a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
29484a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
295ed20d0e3SSascha Wildner 		("wrong direction %d, should be %d",
29684a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
29784a3e25aSSepherosa Ziehau 
29884a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
29984a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
30084a3e25aSSepherosa Ziehau 	rt = pkt->ro.ro_rt;
30184a3e25aSSepherosa Ziehau 
30284a3e25aSSepherosa Ziehau 	if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
30384a3e25aSSepherosa Ziehau 		/*
30484a3e25aSSepherosa Ziehau 		 * Recorded rtentry is gone, when the packet
30584a3e25aSSepherosa Ziehau 		 * was on delay line.
30684a3e25aSSepherosa Ziehau 		 */
30784a3e25aSSepherosa Ziehau 		ip_dn_freepkt(pkt);
30884a3e25aSSepherosa Ziehau 		return;
30984a3e25aSSepherosa Ziehau 	}
31084a3e25aSSepherosa Ziehau 
3114d935b66SSepherosa Ziehau 	ip_output(pkt->dn_m, NULL, NULL, pkt->flags, NULL, NULL);
3124d935b66SSepherosa Ziehau 	/* 'rt' will be freed in ip_output */
31384a3e25aSSepherosa Ziehau 
31484a3e25aSSepherosa Ziehau 	if (unref_priv)
31584a3e25aSSepherosa Ziehau 		unref_priv(priv);
31684a3e25aSSepherosa Ziehau }
31784a3e25aSSepherosa Ziehau 
31884a3e25aSSepherosa Ziehau static void
ip_dn_ip_input(netmsg_t nmsg)319002c1265SMatthew Dillon ip_dn_ip_input(netmsg_t nmsg)
32084a3e25aSSepherosa Ziehau {
32184a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
32284a3e25aSSepherosa Ziehau 	struct mbuf *m;
32384a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
32484a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
32584a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
32684a3e25aSSepherosa Ziehau 	void *priv;
3277376bec4SSepherosa Ziehau 	struct ip *ip;
32884a3e25aSSepherosa Ziehau 
329002c1265SMatthew Dillon 	nmp = &nmsg->packet;
33084a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
331840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
332840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
333ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
33484a3e25aSSepherosa Ziehau 
33584a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
33684a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
33784a3e25aSSepherosa Ziehau 
33884a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
33984a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
34084a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
341ed20d0e3SSascha Wildner 		 "target cpuid %d, mycpuid %d", __func__,
34284a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
34384a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
344ed20d0e3SSascha Wildner 		("route entry is not NULL for ip_input"));
34584a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
346ed20d0e3SSascha Wildner 		("wrong direction %d, should be %d",
34784a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
34884a3e25aSSepherosa Ziehau 
34984a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
35084a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
35184a3e25aSSepherosa Ziehau 
3527376bec4SSepherosa Ziehau 	KKASSERT(m->m_len >= sizeof(*ip));
3537376bec4SSepherosa Ziehau 
35484a3e25aSSepherosa Ziehau 	ip_input(m);
35584a3e25aSSepherosa Ziehau 
35684a3e25aSSepherosa Ziehau 	if (unref_priv)
35784a3e25aSSepherosa Ziehau 		unref_priv(priv);
35884a3e25aSSepherosa Ziehau }
35984a3e25aSSepherosa Ziehau 
36084a3e25aSSepherosa Ziehau static void
ip_dn_ether_demux(netmsg_t nmsg)361002c1265SMatthew Dillon ip_dn_ether_demux(netmsg_t nmsg)
36284a3e25aSSepherosa Ziehau {
36384a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
36484a3e25aSSepherosa Ziehau 	struct mbuf *m;
36584a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
36684a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
36784a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
36884a3e25aSSepherosa Ziehau 	void *priv;
36984a3e25aSSepherosa Ziehau 
370002c1265SMatthew Dillon 	nmp = &nmsg->packet;
37184a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
372840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
373840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
374ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
37584a3e25aSSepherosa Ziehau 
37684a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
37784a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
37884a3e25aSSepherosa Ziehau 
37984a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
38084a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
38184a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
382ed20d0e3SSascha Wildner 		 "target cpuid %d, mycpuid %d", __func__,
38384a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
38484a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
385ed20d0e3SSascha Wildner 		("route entry is not NULL for ether_demux"));
38684a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
387ed20d0e3SSascha Wildner 		("wrong direction %d, should be %d",
38884a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
38984a3e25aSSepherosa Ziehau 
39084a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
39184a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
39284a3e25aSSepherosa Ziehau 
393d781b904SSepherosa Ziehau 	/*
394d781b904SSepherosa Ziehau 	 * Make sure that ether header is contiguous
395d781b904SSepherosa Ziehau 	 */
39684a3e25aSSepherosa Ziehau 	if (m->m_len < ETHER_HDR_LEN &&
39784a3e25aSSepherosa Ziehau 	    (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
39884a3e25aSSepherosa Ziehau 		kprintf("%s: pullup fail, dropping pkt\n", __func__);
39984a3e25aSSepherosa Ziehau 		goto back;
40084a3e25aSSepherosa Ziehau 	}
4015bad48b5SSepherosa Ziehau 	ether_demux_oncpu(m->m_pkthdr.rcvif, m);
40284a3e25aSSepherosa Ziehau back:
40384a3e25aSSepherosa Ziehau 	if (unref_priv)
40484a3e25aSSepherosa Ziehau 		unref_priv(priv);
40584a3e25aSSepherosa Ziehau }
40684a3e25aSSepherosa Ziehau 
40784a3e25aSSepherosa Ziehau static void
ip_dn_ether_output(netmsg_t nmsg)408002c1265SMatthew Dillon ip_dn_ether_output(netmsg_t nmsg)
40984a3e25aSSepherosa Ziehau {
41084a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
41184a3e25aSSepherosa Ziehau 	struct mbuf *m;
41284a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
41384a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
41484a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
41584a3e25aSSepherosa Ziehau 	void *priv;
41684a3e25aSSepherosa Ziehau 
417002c1265SMatthew Dillon 	nmp = &nmsg->packet;
41884a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
419840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
420840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
421ed20d0e3SSascha Wildner 		("mbuf is not tagged for dummynet!"));
42284a3e25aSSepherosa Ziehau 
42384a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
42484a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
42584a3e25aSSepherosa Ziehau 
42684a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
42784a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
42884a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
429ed20d0e3SSascha Wildner 		 "target cpuid %d, mycpuid %d", __func__,
43084a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
43184a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
432ed20d0e3SSascha Wildner 		("route entry is not NULL for ether_output_frame"));
43384a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
434ed20d0e3SSascha Wildner 		("wrong direction %d, should be %d",
43584a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
43684a3e25aSSepherosa Ziehau 
43784a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
43884a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
43984a3e25aSSepherosa Ziehau 
44084a3e25aSSepherosa Ziehau 	ether_output_frame(pkt->ifp, m);
44184a3e25aSSepherosa Ziehau 
44284a3e25aSSepherosa Ziehau 	if (unref_priv)
44384a3e25aSSepherosa Ziehau 		unref_priv(priv);
44484a3e25aSSepherosa Ziehau }
445879652a3SSepherosa Ziehau 
446879652a3SSepherosa Ziehau static void
ip_dn_sockopt_dispatch(netmsg_t nmsg)447002c1265SMatthew Dillon ip_dn_sockopt_dispatch(netmsg_t nmsg)
448879652a3SSepherosa Ziehau {
449002c1265SMatthew Dillon 	lwkt_msg *msg = &nmsg->lmsg;
450879652a3SSepherosa Ziehau 	struct dn_sopt *dn_sopt = msg->u.ms_resultp;
451879652a3SSepherosa Ziehau 	int error;
452879652a3SSepherosa Ziehau 
453879652a3SSepherosa Ziehau 	KASSERT(ip_dn_cpu == mycpuid,
454879652a3SSepherosa Ziehau 		("%s: dummynet sockopt is done on wrong cpu! "
455ed20d0e3SSascha Wildner 		 "dummynet cpuid %d, mycpuid %d", __func__,
456879652a3SSepherosa Ziehau 		 ip_dn_cpu, mycpuid));
457879652a3SSepherosa Ziehau 
458879652a3SSepherosa Ziehau 	if (DUMMYNET_LOADED)
459879652a3SSepherosa Ziehau 		error = ip_dn_ctl_ptr(dn_sopt);
460879652a3SSepherosa Ziehau 	else
461879652a3SSepherosa Ziehau 		error = ENOPROTOOPT;
462879652a3SSepherosa Ziehau 	lwkt_replymsg(msg, error);
463879652a3SSepherosa Ziehau }
464879652a3SSepherosa Ziehau 
465879652a3SSepherosa Ziehau static int
ip_dn_sockopt_flush(struct sockopt * sopt)466879652a3SSepherosa Ziehau ip_dn_sockopt_flush(struct sockopt *sopt)
467879652a3SSepherosa Ziehau {
468879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
469002c1265SMatthew Dillon 	struct netmsg_base smsg;
470879652a3SSepherosa Ziehau 
471879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
472879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
473879652a3SSepherosa Ziehau 
47448e7b118SMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
47548e7b118SMatthew Dillon 		    0, ip_dn_sockopt_dispatch);
476002c1265SMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
477ec7f7fc8SSepherosa Ziehau 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
478879652a3SSepherosa Ziehau 
479002c1265SMatthew Dillon 	return smsg.lmsg.ms_error;
480879652a3SSepherosa Ziehau }
481879652a3SSepherosa Ziehau 
482879652a3SSepherosa Ziehau static int
ip_dn_sockopt_get(struct sockopt * sopt)483879652a3SSepherosa Ziehau ip_dn_sockopt_get(struct sockopt *sopt)
484879652a3SSepherosa Ziehau {
485879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
486002c1265SMatthew Dillon 	struct netmsg_base smsg;
487879652a3SSepherosa Ziehau 	int error;
488879652a3SSepherosa Ziehau 
489879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
490879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
491879652a3SSepherosa Ziehau 
49248e7b118SMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
49348e7b118SMatthew Dillon 		    0, ip_dn_sockopt_dispatch);
494002c1265SMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
495ec7f7fc8SSepherosa Ziehau 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
496879652a3SSepherosa Ziehau 
497002c1265SMatthew Dillon 	error = smsg.lmsg.ms_error;
498879652a3SSepherosa Ziehau 	if (error) {
499879652a3SSepherosa Ziehau 		KKASSERT(dn_sopt.dn_sopt_arg == NULL);
500879652a3SSepherosa Ziehau 		KKASSERT(dn_sopt.dn_sopt_arglen == 0);
501879652a3SSepherosa Ziehau 		return error;
502879652a3SSepherosa Ziehau 	}
503879652a3SSepherosa Ziehau 
504e71a125fSAggelos Economopoulos 	soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
505879652a3SSepherosa Ziehau 	kfree(dn_sopt.dn_sopt_arg, M_TEMP);
506e71a125fSAggelos Economopoulos 	return 0;
507879652a3SSepherosa Ziehau }
508879652a3SSepherosa Ziehau 
509879652a3SSepherosa Ziehau static int
ip_dn_sockopt_config(struct sockopt * sopt)510879652a3SSepherosa Ziehau ip_dn_sockopt_config(struct sockopt *sopt)
511879652a3SSepherosa Ziehau {
512879652a3SSepherosa Ziehau 	struct dn_ioc_pipe tmp_ioc_pipe;
513879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
514002c1265SMatthew Dillon 	struct netmsg_base smsg;
515879652a3SSepherosa Ziehau 	int error;
516879652a3SSepherosa Ziehau 
517e71a125fSAggelos Economopoulos 	error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
518e71a125fSAggelos Economopoulos 			      sizeof tmp_ioc_pipe);
519879652a3SSepherosa Ziehau 	if (error)
520879652a3SSepherosa Ziehau 		return error;
521879652a3SSepherosa Ziehau 
522879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
523879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
524879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
525879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
526879652a3SSepherosa Ziehau 
52748e7b118SMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
52848e7b118SMatthew Dillon 		    0, ip_dn_sockopt_dispatch);
529002c1265SMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
530ec7f7fc8SSepherosa Ziehau 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
531879652a3SSepherosa Ziehau 
532002c1265SMatthew Dillon 	return smsg.lmsg.ms_error;
533879652a3SSepherosa Ziehau }
534