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  *
34*879652a3SSepherosa Ziehau  * $DragonFly: src/sys/net/dummynet/ip_dummynet_glue.c,v 1.4 2007/11/18 13:00:28 sephe Exp $
3584a3e25aSSepherosa Ziehau  */
3684a3e25aSSepherosa Ziehau 
3784a3e25aSSepherosa Ziehau #include <sys/param.h>
38329bf5d1SSepherosa Ziehau #include <sys/kernel.h>
3984a3e25aSSepherosa Ziehau #include <sys/mbuf.h>
4084a3e25aSSepherosa Ziehau #include <sys/msgport.h>
41*879652a3SSepherosa Ziehau #include <sys/socketvar.h>
42329bf5d1SSepherosa Ziehau #include <sys/sysctl.h>
4384a3e25aSSepherosa Ziehau 
4484a3e25aSSepherosa Ziehau #include <net/if.h>
4584a3e25aSSepherosa Ziehau #include <net/if_var.h>
4684a3e25aSSepherosa Ziehau #include <net/route.h>
4784a3e25aSSepherosa Ziehau #include <net/ethernet.h>
4884a3e25aSSepherosa Ziehau #include <net/netisr.h>
4984a3e25aSSepherosa Ziehau #include <net/netmsg2.h>
5084a3e25aSSepherosa Ziehau 
5184a3e25aSSepherosa Ziehau #include <netinet/in.h>
5284a3e25aSSepherosa Ziehau #include <netinet/in_var.h>
5384a3e25aSSepherosa Ziehau #include <netinet/ip.h>
5484a3e25aSSepherosa Ziehau #include <netinet/ip_var.h>
5584a3e25aSSepherosa Ziehau 
5684a3e25aSSepherosa Ziehau #include <net/dummynet/ip_dummynet.h>
5784a3e25aSSepherosa Ziehau 
5884a3e25aSSepherosa Ziehau static void	ip_dn_ether_output(struct netmsg *);
5984a3e25aSSepherosa Ziehau static void	ip_dn_ether_demux(struct netmsg *);
6084a3e25aSSepherosa Ziehau static void	ip_dn_ip_input(struct netmsg *);
6184a3e25aSSepherosa Ziehau static void	ip_dn_ip_output(struct netmsg *);
6284a3e25aSSepherosa Ziehau 
63*879652a3SSepherosa Ziehau static void	ip_dn_sockopt_dispatch(struct netmsg *);
6484a3e25aSSepherosa Ziehau static void	ip_dn_freepkt_dispatch(struct netmsg *);
6584a3e25aSSepherosa Ziehau static void	ip_dn_dispatch(struct netmsg *);
6684a3e25aSSepherosa Ziehau 
6784a3e25aSSepherosa Ziehau static void	ip_dn_freepkt(struct dn_pkt *);
6884a3e25aSSepherosa Ziehau 
69*879652a3SSepherosa Ziehau static int	ip_dn_sockopt_flush(struct sockopt *);
70*879652a3SSepherosa Ziehau static int	ip_dn_sockopt_get(struct sockopt *);
71*879652a3SSepherosa Ziehau static int	ip_dn_sockopt_config(struct sockopt *);
72*879652a3SSepherosa Ziehau 
7384a3e25aSSepherosa Ziehau ip_dn_io_t	*ip_dn_io_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
8384a3e25aSSepherosa Ziehau ip_dn_queue(struct mbuf *m)
8484a3e25aSSepherosa Ziehau {
8584a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
8684a3e25aSSepherosa Ziehau 	lwkt_port_t port;
8784a3e25aSSepherosa Ziehau 
8884a3e25aSSepherosa Ziehau 	KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
89840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
90840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
91840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
9284a3e25aSSepherosa Ziehau 
9384a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
9484a3e25aSSepherosa Ziehau 	netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
9584a3e25aSSepherosa Ziehau 		    ip_dn_dispatch);
9684a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
9784a3e25aSSepherosa Ziehau 
9884a3e25aSSepherosa Ziehau 	port = cpu_portfn(ip_dn_cpu);
9984a3e25aSSepherosa Ziehau 	lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
10084a3e25aSSepherosa Ziehau }
10184a3e25aSSepherosa Ziehau 
10284a3e25aSSepherosa Ziehau void
10384a3e25aSSepherosa Ziehau ip_dn_packet_free(struct dn_pkt *pkt)
10484a3e25aSSepherosa Ziehau {
10584a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
10684a3e25aSSepherosa Ziehau 	lwkt_port_t port;
10784a3e25aSSepherosa Ziehau 	struct mbuf *m = pkt->dn_m;
10884a3e25aSSepherosa Ziehau 
10984a3e25aSSepherosa Ziehau 	KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
110840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
111840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
112840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
11384a3e25aSSepherosa Ziehau 
11484a3e25aSSepherosa Ziehau 	if (pkt->cpuid == mycpuid) {
11584a3e25aSSepherosa Ziehau 		ip_dn_freepkt(pkt);
11684a3e25aSSepherosa Ziehau 		return;
11784a3e25aSSepherosa Ziehau 	}
11884a3e25aSSepherosa Ziehau 
11984a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
12084a3e25aSSepherosa Ziehau 	netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0,
12184a3e25aSSepherosa Ziehau 		    ip_dn_freepkt_dispatch);
12284a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
12384a3e25aSSepherosa Ziehau 
12484a3e25aSSepherosa Ziehau 	port = cpu_portfn(pkt->cpuid);
12584a3e25aSSepherosa Ziehau 	lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
12684a3e25aSSepherosa Ziehau }
12784a3e25aSSepherosa Ziehau 
12884a3e25aSSepherosa Ziehau void
12984a3e25aSSepherosa Ziehau ip_dn_packet_redispatch(struct dn_pkt *pkt)
13084a3e25aSSepherosa Ziehau {
13184a3e25aSSepherosa Ziehau 	static const netisr_fn_t dispatches[DN_TO_MAX] = {
13284a3e25aSSepherosa Ziehau 	[DN_TO_IP_OUT]		= ip_dn_ip_output,
13384a3e25aSSepherosa Ziehau 	[DN_TO_IP_IN]		= ip_dn_ip_input,
13484a3e25aSSepherosa Ziehau 	[DN_TO_ETH_DEMUX]	= ip_dn_ether_demux,
13584a3e25aSSepherosa Ziehau 	[DN_TO_ETH_OUT]		= ip_dn_ether_output
13684a3e25aSSepherosa Ziehau 	};
13784a3e25aSSepherosa Ziehau 
13884a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
13984a3e25aSSepherosa Ziehau 	struct mbuf *m;
14084a3e25aSSepherosa Ziehau 	netisr_fn_t dispatch;
14184a3e25aSSepherosa Ziehau 	lwkt_port_t port;
14284a3e25aSSepherosa Ziehau 	int dir;
14384a3e25aSSepherosa Ziehau 
14484a3e25aSSepherosa Ziehau 	dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
14584a3e25aSSepherosa Ziehau 	KASSERT(dir < DN_TO_MAX,
14684a3e25aSSepherosa Ziehau 		("unknown dummynet redispatch dir %d\n", dir));
14784a3e25aSSepherosa Ziehau 
14884a3e25aSSepherosa Ziehau 	dispatch = dispatches[dir];
14984a3e25aSSepherosa Ziehau 	KASSERT(dispatch != NULL,
15084a3e25aSSepherosa Ziehau 		("unsupported dummynet redispatch dir %d\n", dir));
15184a3e25aSSepherosa Ziehau 
15284a3e25aSSepherosa Ziehau 	m = pkt->dn_m;
15384a3e25aSSepherosa Ziehau 	KASSERT(m->m_type != MT_TAG, ("mbuf contains old style tag!\n"));
154840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
155840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
156840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
15784a3e25aSSepherosa Ziehau 
15884a3e25aSSepherosa Ziehau 	nmp = &m->m_hdr.mh_netmsg;
15984a3e25aSSepherosa Ziehau 	netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0, dispatch);
16084a3e25aSSepherosa Ziehau 	nmp->nm_packet = m;
16184a3e25aSSepherosa Ziehau 
16284a3e25aSSepherosa Ziehau 	port = cpu_portfn(pkt->cpuid);
16384a3e25aSSepherosa Ziehau 	lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
16484a3e25aSSepherosa Ziehau }
16584a3e25aSSepherosa Ziehau 
166*879652a3SSepherosa Ziehau int
167*879652a3SSepherosa Ziehau ip_dn_sockopt(struct sockopt *sopt)
168*879652a3SSepherosa Ziehau {
169*879652a3SSepherosa Ziehau 	int error = 0;
170*879652a3SSepherosa Ziehau 
171*879652a3SSepherosa Ziehau 	/* Disallow sets in really-really secure mode. */
172*879652a3SSepherosa Ziehau 	if (sopt->sopt_dir == SOPT_SET) {
173*879652a3SSepherosa Ziehau 		if (securelevel >= 3)
174*879652a3SSepherosa Ziehau 			return EPERM;
175*879652a3SSepherosa Ziehau 	}
176*879652a3SSepherosa Ziehau 
177*879652a3SSepherosa Ziehau 	switch (sopt->sopt_name) {
178*879652a3SSepherosa Ziehau 	case IP_DUMMYNET_GET:
179*879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_get(sopt);
180*879652a3SSepherosa Ziehau 		break;
181*879652a3SSepherosa Ziehau 
182*879652a3SSepherosa Ziehau 	case IP_DUMMYNET_FLUSH:
183*879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_flush(sopt);
184*879652a3SSepherosa Ziehau 		break;
185*879652a3SSepherosa Ziehau 
186*879652a3SSepherosa Ziehau 	case IP_DUMMYNET_DEL:
187*879652a3SSepherosa Ziehau 	case IP_DUMMYNET_CONFIGURE:
188*879652a3SSepherosa Ziehau 		error = ip_dn_sockopt_config(sopt);
189*879652a3SSepherosa Ziehau 		break;
190*879652a3SSepherosa Ziehau 
191*879652a3SSepherosa Ziehau 	default:
192*879652a3SSepherosa Ziehau 		kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
193*879652a3SSepherosa Ziehau 		error = EINVAL;
194*879652a3SSepherosa Ziehau 		break;
195*879652a3SSepherosa Ziehau 	}
196*879652a3SSepherosa Ziehau 	return error;
197*879652a3SSepherosa Ziehau }
198*879652a3SSepherosa Ziehau 
19984a3e25aSSepherosa Ziehau static void
20084a3e25aSSepherosa Ziehau ip_dn_freepkt(struct dn_pkt *pkt)
20184a3e25aSSepherosa Ziehau {
20284a3e25aSSepherosa Ziehau 	struct rtentry *rt = pkt->ro.ro_rt;
20384a3e25aSSepherosa Ziehau 
20484a3e25aSSepherosa Ziehau 	/* Unreference route entry */
20584a3e25aSSepherosa Ziehau 	if (rt != NULL) {
20684a3e25aSSepherosa Ziehau 		if (rt->rt_refcnt <= 0) {	/* XXX assert? */
20784a3e25aSSepherosa Ziehau 			kprintf("-- warning, refcnt now %ld, decreasing\n",
20884a3e25aSSepherosa Ziehau 				rt->rt_refcnt);
20984a3e25aSSepherosa Ziehau 		}
21084a3e25aSSepherosa Ziehau 		RTFREE(rt);
21184a3e25aSSepherosa Ziehau 	}
21284a3e25aSSepherosa Ziehau 
21384a3e25aSSepherosa Ziehau 	/* Unreference packet private data */
21484a3e25aSSepherosa Ziehau 	if (pkt->dn_unref_priv)
21584a3e25aSSepherosa Ziehau 		pkt->dn_unref_priv(pkt->dn_priv);
21684a3e25aSSepherosa Ziehau 
21784a3e25aSSepherosa Ziehau 	/* Free the parent mbuf, this will free 'pkt' as well */
21884a3e25aSSepherosa Ziehau 	m_freem(pkt->dn_m);
21984a3e25aSSepherosa Ziehau }
22084a3e25aSSepherosa Ziehau 
22184a3e25aSSepherosa Ziehau static void
22284a3e25aSSepherosa Ziehau ip_dn_freepkt_dispatch(struct netmsg *nmsg)
22384a3e25aSSepherosa Ziehau {
22484a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
22584a3e25aSSepherosa Ziehau 	struct mbuf *m;
22684a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
22784a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
22884a3e25aSSepherosa Ziehau 
22984a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
23084a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
231840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
232840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
233840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
23484a3e25aSSepherosa Ziehau 
23584a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
236840665f6SSepherosa Ziehau 	KKASSERT(mtag != NULL);
23784a3e25aSSepherosa Ziehau 
238840665f6SSepherosa Ziehau 	pkt = m_tag_data(mtag);
23984a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
24084a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
24184a3e25aSSepherosa Ziehau 		 "target cpuid %d, mycpuid %d\n", __func__,
24284a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
24384a3e25aSSepherosa Ziehau 
24484a3e25aSSepherosa Ziehau 	ip_dn_freepkt(pkt);
24584a3e25aSSepherosa Ziehau }
24684a3e25aSSepherosa Ziehau 
24784a3e25aSSepherosa Ziehau static void
24884a3e25aSSepherosa Ziehau ip_dn_dispatch(struct netmsg *nmsg)
24984a3e25aSSepherosa Ziehau {
25084a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
25184a3e25aSSepherosa Ziehau 	struct mbuf *m;
25284a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
25384a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
25484a3e25aSSepherosa Ziehau 
25584a3e25aSSepherosa Ziehau 	KASSERT(ip_dn_cpu == mycpuid,
25684a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
25784a3e25aSSepherosa Ziehau 		 "dummynet cpuid %d, mycpuid %d\n", __func__,
25884a3e25aSSepherosa Ziehau 		 ip_dn_cpu, mycpuid));
25984a3e25aSSepherosa Ziehau 
26084a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
26184a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
262840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
263840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
264840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
26584a3e25aSSepherosa Ziehau 
26684a3e25aSSepherosa Ziehau 	if (DUMMYNET_LOADED) {
26784a3e25aSSepherosa Ziehau 		if (ip_dn_io_ptr(m) == 0)
26884a3e25aSSepherosa Ziehau 			return;
26984a3e25aSSepherosa Ziehau 	}
27084a3e25aSSepherosa Ziehau 
27184a3e25aSSepherosa Ziehau 	/*
27284a3e25aSSepherosa Ziehau 	 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
27384a3e25aSSepherosa Ziehau 	 */
27484a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
275840665f6SSepherosa Ziehau 	KKASSERT(mtag != NULL);
276840665f6SSepherosa Ziehau 
27784a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
27884a3e25aSSepherosa Ziehau 	ip_dn_packet_free(pkt);
27984a3e25aSSepherosa Ziehau }
28084a3e25aSSepherosa Ziehau 
28184a3e25aSSepherosa Ziehau static void
28284a3e25aSSepherosa Ziehau ip_dn_ip_output(struct netmsg *nmsg)
28384a3e25aSSepherosa Ziehau {
28484a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
28584a3e25aSSepherosa Ziehau 	struct mbuf *m;
28684a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
28784a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
28884a3e25aSSepherosa Ziehau 	struct rtentry *rt;
28984a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
29084a3e25aSSepherosa Ziehau 	void *priv;
29184a3e25aSSepherosa Ziehau 
29284a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
29384a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
294840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
295840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
296840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
29784a3e25aSSepherosa Ziehau 
29884a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
29984a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
30084a3e25aSSepherosa Ziehau 
30184a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
30284a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
30384a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
30484a3e25aSSepherosa Ziehau 		 "target cpuid %d, mycpuid %d\n", __func__,
30584a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
30684a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
30784a3e25aSSepherosa Ziehau 		("wrong direction %d, should be %d\n",
30884a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
30984a3e25aSSepherosa Ziehau 
31084a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
31184a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
31284a3e25aSSepherosa Ziehau 	rt = pkt->ro.ro_rt;
31384a3e25aSSepherosa Ziehau 
31484a3e25aSSepherosa Ziehau 	if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
31584a3e25aSSepherosa Ziehau 		/*
31684a3e25aSSepherosa Ziehau 		 * Recorded rtentry is gone, when the packet
31784a3e25aSSepherosa Ziehau 		 * was on delay line.
31884a3e25aSSepherosa Ziehau 		 */
31984a3e25aSSepherosa Ziehau 		ip_dn_freepkt(pkt);
32084a3e25aSSepherosa Ziehau 		return;
32184a3e25aSSepherosa Ziehau 	}
32284a3e25aSSepherosa Ziehau 
32384a3e25aSSepherosa Ziehau 	ip_output(pkt->dn_m, NULL, NULL, 0, NULL, NULL);
32484a3e25aSSepherosa Ziehau 
32584a3e25aSSepherosa Ziehau 	if (rt != NULL) {
32684a3e25aSSepherosa Ziehau 		if (rt->rt_refcnt <= 0) {	/* XXX assert? */
32784a3e25aSSepherosa Ziehau 			kprintf("-- warning, refcnt now %ld, decreasing\n",
32884a3e25aSSepherosa Ziehau 				rt->rt_refcnt);
32984a3e25aSSepherosa Ziehau 		}
33084a3e25aSSepherosa Ziehau 		RTFREE(rt);
33184a3e25aSSepherosa Ziehau 	}
33284a3e25aSSepherosa Ziehau 	if (unref_priv)
33384a3e25aSSepherosa Ziehau 		unref_priv(priv);
33484a3e25aSSepherosa Ziehau }
33584a3e25aSSepherosa Ziehau 
33684a3e25aSSepherosa Ziehau static void
33784a3e25aSSepherosa Ziehau ip_dn_ip_input(struct netmsg *nmsg)
33884a3e25aSSepherosa Ziehau {
33984a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
34084a3e25aSSepherosa Ziehau 	struct mbuf *m;
34184a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
34284a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
34384a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
34484a3e25aSSepherosa Ziehau 	void *priv;
34584a3e25aSSepherosa Ziehau 
34684a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
34784a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
348840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
349840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
350840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
35184a3e25aSSepherosa Ziehau 
35284a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
35384a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
35484a3e25aSSepherosa Ziehau 
35584a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
35684a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
35784a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
35884a3e25aSSepherosa Ziehau 		 "target cpuid %d, mycpuid %d\n", __func__,
35984a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
36084a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
36184a3e25aSSepherosa Ziehau 		("route entry is not NULL for ip_input\n"));
36284a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
36384a3e25aSSepherosa Ziehau 		("wrong direction %d, should be %d\n",
36484a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
36584a3e25aSSepherosa Ziehau 
36684a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
36784a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
36884a3e25aSSepherosa Ziehau 
36984a3e25aSSepherosa Ziehau 	ip_input(m);
37084a3e25aSSepherosa Ziehau 
37184a3e25aSSepherosa Ziehau 	if (unref_priv)
37284a3e25aSSepherosa Ziehau 		unref_priv(priv);
37384a3e25aSSepherosa Ziehau }
37484a3e25aSSepherosa Ziehau 
37584a3e25aSSepherosa Ziehau static void
37684a3e25aSSepherosa Ziehau ip_dn_ether_demux(struct netmsg *nmsg)
37784a3e25aSSepherosa Ziehau {
37884a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
37984a3e25aSSepherosa Ziehau 	struct mbuf *m;
38084a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
38184a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
38284a3e25aSSepherosa Ziehau 	struct ether_header *eh;
38384a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
38484a3e25aSSepherosa Ziehau 	void *priv;
38584a3e25aSSepherosa Ziehau 
38684a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
38784a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
388840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
389840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
390840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
39184a3e25aSSepherosa Ziehau 
39284a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
39384a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
39484a3e25aSSepherosa Ziehau 
39584a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
39684a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
39784a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
39884a3e25aSSepherosa Ziehau 		 "target cpuid %d, mycpuid %d\n", __func__,
39984a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
40084a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
40184a3e25aSSepherosa Ziehau 		("route entry is not NULL for ether_demux\n"));
40284a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
40384a3e25aSSepherosa Ziehau 		("wrong direction %d, should be %d\n",
40484a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
40584a3e25aSSepherosa Ziehau 
40684a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
40784a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
40884a3e25aSSepherosa Ziehau 
40984a3e25aSSepherosa Ziehau 	if (m->m_len < ETHER_HDR_LEN &&
41084a3e25aSSepherosa Ziehau 	    (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
41184a3e25aSSepherosa Ziehau 		kprintf("%s: pullup fail, dropping pkt\n", __func__);
41284a3e25aSSepherosa Ziehau 		goto back;
41384a3e25aSSepherosa Ziehau 	}
41484a3e25aSSepherosa Ziehau 
41584a3e25aSSepherosa Ziehau 	/*
41684a3e25aSSepherosa Ziehau 	 * Same as ether_input, make eh be a pointer into the mbuf
41784a3e25aSSepherosa Ziehau 	 */
41884a3e25aSSepherosa Ziehau 	eh = mtod(m, struct ether_header *);
41984a3e25aSSepherosa Ziehau 	m_adj(m, ETHER_HDR_LEN);
42084a3e25aSSepherosa Ziehau 	ether_demux(NULL, eh, m);
42184a3e25aSSepherosa Ziehau back:
42284a3e25aSSepherosa Ziehau 	if (unref_priv)
42384a3e25aSSepherosa Ziehau 		unref_priv(priv);
42484a3e25aSSepherosa Ziehau }
42584a3e25aSSepherosa Ziehau 
42684a3e25aSSepherosa Ziehau static void
42784a3e25aSSepherosa Ziehau ip_dn_ether_output(struct netmsg *nmsg)
42884a3e25aSSepherosa Ziehau {
42984a3e25aSSepherosa Ziehau 	struct netmsg_packet *nmp;
43084a3e25aSSepherosa Ziehau 	struct mbuf *m;
43184a3e25aSSepherosa Ziehau 	struct m_tag *mtag;
43284a3e25aSSepherosa Ziehau 	struct dn_pkt *pkt;
43384a3e25aSSepherosa Ziehau 	ip_dn_unref_priv_t unref_priv;
43484a3e25aSSepherosa Ziehau 	void *priv;
43584a3e25aSSepherosa Ziehau 
43684a3e25aSSepherosa Ziehau 	nmp = (struct netmsg_packet *)nmsg;
43784a3e25aSSepherosa Ziehau 	m = nmp->nm_packet;
438840665f6SSepherosa Ziehau 	M_ASSERTPKTHDR(m);
439840665f6SSepherosa Ziehau 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
440840665f6SSepherosa Ziehau 		("mbuf is not tagged for dummynet!\n"));
44184a3e25aSSepherosa Ziehau 
44284a3e25aSSepherosa Ziehau 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
44384a3e25aSSepherosa Ziehau 	KKASSERT(mtag != NULL);
44484a3e25aSSepherosa Ziehau 
44584a3e25aSSepherosa Ziehau 	pkt = m_tag_data(mtag);
44684a3e25aSSepherosa Ziehau 	KASSERT(pkt->cpuid == mycpuid,
44784a3e25aSSepherosa Ziehau 		("%s: dummynet packet was delivered to wrong cpu! "
44884a3e25aSSepherosa Ziehau 		 "target cpuid %d, mycpuid %d\n", __func__,
44984a3e25aSSepherosa Ziehau 		 pkt->cpuid, mycpuid));
45084a3e25aSSepherosa Ziehau 	KASSERT(pkt->ro.ro_rt == NULL,
45184a3e25aSSepherosa Ziehau 		("route entry is not NULL for ether_output_frame\n"));
45284a3e25aSSepherosa Ziehau 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
45384a3e25aSSepherosa Ziehau 		("wrong direction %d, should be %d\n",
45484a3e25aSSepherosa Ziehau 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
45584a3e25aSSepherosa Ziehau 
45684a3e25aSSepherosa Ziehau 	priv = pkt->dn_priv;
45784a3e25aSSepherosa Ziehau 	unref_priv = pkt->dn_unref_priv;
45884a3e25aSSepherosa Ziehau 
45984a3e25aSSepherosa Ziehau 	ether_output_frame(pkt->ifp, m);
46084a3e25aSSepherosa Ziehau 
46184a3e25aSSepherosa Ziehau 	if (unref_priv)
46284a3e25aSSepherosa Ziehau 		unref_priv(priv);
46384a3e25aSSepherosa Ziehau }
464*879652a3SSepherosa Ziehau 
465*879652a3SSepherosa Ziehau static void
466*879652a3SSepherosa Ziehau ip_dn_sockopt_dispatch(struct netmsg *nmsg)
467*879652a3SSepherosa Ziehau {
468*879652a3SSepherosa Ziehau 	lwkt_msg *msg = &nmsg->nm_lmsg;
469*879652a3SSepherosa Ziehau 	struct dn_sopt *dn_sopt = msg->u.ms_resultp;
470*879652a3SSepherosa Ziehau 	int error;
471*879652a3SSepherosa Ziehau 
472*879652a3SSepherosa Ziehau 	KASSERT(ip_dn_cpu == mycpuid,
473*879652a3SSepherosa Ziehau 		("%s: dummynet sockopt is done on wrong cpu! "
474*879652a3SSepherosa Ziehau 		 "dummynet cpuid %d, mycpuid %d\n", __func__,
475*879652a3SSepherosa Ziehau 		 ip_dn_cpu, mycpuid));
476*879652a3SSepherosa Ziehau 
477*879652a3SSepherosa Ziehau 	if (DUMMYNET_LOADED)
478*879652a3SSepherosa Ziehau 		error = ip_dn_ctl_ptr(dn_sopt);
479*879652a3SSepherosa Ziehau 	else
480*879652a3SSepherosa Ziehau 		error = ENOPROTOOPT;
481*879652a3SSepherosa Ziehau 	lwkt_replymsg(msg, error);
482*879652a3SSepherosa Ziehau }
483*879652a3SSepherosa Ziehau 
484*879652a3SSepherosa Ziehau static int
485*879652a3SSepherosa Ziehau ip_dn_sockopt_flush(struct sockopt *sopt)
486*879652a3SSepherosa Ziehau {
487*879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
488*879652a3SSepherosa Ziehau 	struct netmsg smsg;
489*879652a3SSepherosa Ziehau 
490*879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
491*879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
492*879652a3SSepherosa Ziehau 
493*879652a3SSepherosa Ziehau 	netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
494*879652a3SSepherosa Ziehau 	smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
495*879652a3SSepherosa Ziehau 	lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
496*879652a3SSepherosa Ziehau 
497*879652a3SSepherosa Ziehau 	return smsg.nm_lmsg.ms_error;
498*879652a3SSepherosa Ziehau }
499*879652a3SSepherosa Ziehau 
500*879652a3SSepherosa Ziehau static int
501*879652a3SSepherosa Ziehau ip_dn_sockopt_get(struct sockopt *sopt)
502*879652a3SSepherosa Ziehau {
503*879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
504*879652a3SSepherosa Ziehau 	struct netmsg smsg;
505*879652a3SSepherosa Ziehau 	int error;
506*879652a3SSepherosa Ziehau 
507*879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
508*879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
509*879652a3SSepherosa Ziehau 
510*879652a3SSepherosa Ziehau 	netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
511*879652a3SSepherosa Ziehau 	smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
512*879652a3SSepherosa Ziehau 	lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
513*879652a3SSepherosa Ziehau 
514*879652a3SSepherosa Ziehau 	error = smsg.nm_lmsg.ms_error;
515*879652a3SSepherosa Ziehau 	if (error) {
516*879652a3SSepherosa Ziehau 		KKASSERT(dn_sopt.dn_sopt_arg == NULL);
517*879652a3SSepherosa Ziehau 		KKASSERT(dn_sopt.dn_sopt_arglen == 0);
518*879652a3SSepherosa Ziehau 		return error;
519*879652a3SSepherosa Ziehau 	}
520*879652a3SSepherosa Ziehau 
521*879652a3SSepherosa Ziehau 	error = sooptcopyout(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
522*879652a3SSepherosa Ziehau 	kfree(dn_sopt.dn_sopt_arg, M_TEMP);
523*879652a3SSepherosa Ziehau 	return error;
524*879652a3SSepherosa Ziehau }
525*879652a3SSepherosa Ziehau 
526*879652a3SSepherosa Ziehau static int
527*879652a3SSepherosa Ziehau ip_dn_sockopt_config(struct sockopt *sopt)
528*879652a3SSepherosa Ziehau {
529*879652a3SSepherosa Ziehau 	struct dn_ioc_pipe tmp_ioc_pipe;
530*879652a3SSepherosa Ziehau 	struct dn_sopt dn_sopt;
531*879652a3SSepherosa Ziehau 	struct netmsg smsg;
532*879652a3SSepherosa Ziehau 	int error;
533*879652a3SSepherosa Ziehau 
534*879652a3SSepherosa Ziehau 	error = sooptcopyin(sopt, &tmp_ioc_pipe, sizeof(tmp_ioc_pipe),
535*879652a3SSepherosa Ziehau 			    sizeof(tmp_ioc_pipe));
536*879652a3SSepherosa Ziehau 	if (error)
537*879652a3SSepherosa Ziehau 		return error;
538*879652a3SSepherosa Ziehau 
539*879652a3SSepherosa Ziehau 	bzero(&dn_sopt, sizeof(dn_sopt));
540*879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_name = sopt->sopt_name;
541*879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
542*879652a3SSepherosa Ziehau 	dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
543*879652a3SSepherosa Ziehau 
544*879652a3SSepherosa Ziehau 	netmsg_init(&smsg, &curthread->td_msgport, 0, ip_dn_sockopt_dispatch);
545*879652a3SSepherosa Ziehau 	smsg.nm_lmsg.u.ms_resultp = &dn_sopt;
546*879652a3SSepherosa Ziehau 	lwkt_domsg(cpu_portfn(ip_dn_cpu), &smsg.nm_lmsg, 0);
547*879652a3SSepherosa Ziehau 
548*879652a3SSepherosa Ziehau 	return smsg.nm_lmsg.ms_error;
549*879652a3SSepherosa Ziehau }
550