xref: /dflybsd-src/sys/net/dummynet3/ip_dummynet3_glue.c (revision 8a93af2a9b3a6586d0d394bec8454562ee76044f)
16a03354eSMatthew Dillon /*
26a03354eSMatthew Dillon  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
36a03354eSMatthew Dillon  *
46a03354eSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
56a03354eSMatthew Dillon  * by Sepherosa Ziehau <sepherosa@gmail.com>
66a03354eSMatthew Dillon  *
76a03354eSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
86a03354eSMatthew Dillon  * modification, are permitted provided that the following conditions
96a03354eSMatthew Dillon  * are met:
106a03354eSMatthew Dillon  *
116a03354eSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
126a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
136a03354eSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
146a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
156a03354eSMatthew Dillon  *    the documentation and/or other materials provided with the
166a03354eSMatthew Dillon  *    distribution.
176a03354eSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
186a03354eSMatthew Dillon  *    contributors may be used to endorse or promote products derived
196a03354eSMatthew Dillon  *    from this software without specific, prior written permission.
206a03354eSMatthew Dillon  *
216a03354eSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226a03354eSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236a03354eSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246a03354eSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
256a03354eSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266a03354eSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276a03354eSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286a03354eSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296a03354eSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306a03354eSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316a03354eSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326a03354eSMatthew Dillon  * SUCH DAMAGE.
336a03354eSMatthew Dillon  */
346a03354eSMatthew Dillon 
356a03354eSMatthew Dillon 
366a03354eSMatthew Dillon #include <sys/param.h>
376a03354eSMatthew Dillon #include <sys/kernel.h>
386a03354eSMatthew Dillon #include <sys/mbuf.h>
396a03354eSMatthew Dillon #include <sys/msgport.h>
406a03354eSMatthew Dillon #include <sys/socketvar.h>
416a03354eSMatthew Dillon #include <sys/sysctl.h>
426a03354eSMatthew Dillon 
436a03354eSMatthew Dillon #include <net/if.h>
446a03354eSMatthew Dillon #include <net/if_var.h>
456a03354eSMatthew Dillon #include <net/route.h>
466a03354eSMatthew Dillon #include <net/ethernet.h>
476a03354eSMatthew Dillon #include <net/netisr2.h>
486a03354eSMatthew Dillon #include <net/netmsg2.h>
496a03354eSMatthew Dillon 
506a03354eSMatthew Dillon #include <netinet/in.h>
516a03354eSMatthew Dillon #include <netinet/in_var.h>
526a03354eSMatthew Dillon #include <netinet/ip.h>
536a03354eSMatthew Dillon #include <netinet/ip_var.h>
546a03354eSMatthew Dillon 
556a03354eSMatthew Dillon #include <net/ipfw3/ip_fw.h>
566a03354eSMatthew Dillon #include <net/dummynet3/ip_dummynet.h>
576a03354eSMatthew Dillon 
586a03354eSMatthew Dillon static void	ip_dn_ether_output(netmsg_t);
596a03354eSMatthew Dillon static void	ip_dn_ether_demux(netmsg_t);
606a03354eSMatthew Dillon static void	ip_dn_ip_input(netmsg_t);
616a03354eSMatthew Dillon static void	ip_dn_ip_output(netmsg_t);
626a03354eSMatthew Dillon 
636a03354eSMatthew Dillon static void	ip_dn_sockopt_dispatch(netmsg_t);
646a03354eSMatthew Dillon static void	ip_dn_freepkt_dispatch(netmsg_t);
656a03354eSMatthew Dillon static void	ip_dn_dispatch(netmsg_t);
666a03354eSMatthew Dillon 
676a03354eSMatthew Dillon static void	ip_dn_freepkt(struct dn_pkt *);
686a03354eSMatthew Dillon 
696a03354eSMatthew Dillon static int	ip_dn_sockopt_flush(struct sockopt *);
706a03354eSMatthew Dillon static int	ip_dn_sockopt_get(struct sockopt *);
716a03354eSMatthew Dillon static int	ip_dn_sockopt_config(struct sockopt *);
726a03354eSMatthew Dillon 
736a03354eSMatthew Dillon ip_dn_io_t	*ip_dn_io_ptr;
746a03354eSMatthew Dillon int		ip_dn_cpu = 0;
756a03354eSMatthew Dillon 
766a03354eSMatthew Dillon TUNABLE_INT("net.inet.ip.dummynet.cpu", &ip_dn_cpu);
776a03354eSMatthew Dillon 
786a03354eSMatthew Dillon SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet, CTLFLAG_RW, 0, "Dummynet");
796a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, cpu, CTLFLAG_RD,
806a03354eSMatthew Dillon 	   &ip_dn_cpu, 0, "CPU to run dummynet");
816a03354eSMatthew Dillon 
826a03354eSMatthew Dillon void
ip_dn_queue(struct mbuf * m)836a03354eSMatthew Dillon ip_dn_queue(struct mbuf *m)
846a03354eSMatthew Dillon {
856a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
866a03354eSMatthew Dillon 	lwkt_port_t port;
876a03354eSMatthew Dillon 
886a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
896a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
906a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
916a03354eSMatthew Dillon 
926a03354eSMatthew Dillon 	nmp = &m->m_hdr.mh_netmsg;
936a03354eSMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
946a03354eSMatthew Dillon 			0, ip_dn_dispatch);
956a03354eSMatthew Dillon 	nmp->nm_packet = m;
966a03354eSMatthew Dillon 
976a03354eSMatthew Dillon 	port = netisr_cpuport(ip_dn_cpu);
986a03354eSMatthew Dillon 	lwkt_sendmsg(port, &nmp->base.lmsg);
996a03354eSMatthew Dillon }
1006a03354eSMatthew Dillon 
1016a03354eSMatthew Dillon void
ip_dn_packet_free(struct dn_pkt * pkt)1026a03354eSMatthew Dillon ip_dn_packet_free(struct dn_pkt *pkt)
1036a03354eSMatthew Dillon {
1046a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
1056a03354eSMatthew Dillon 	struct mbuf *m = pkt->dn_m;
1066a03354eSMatthew Dillon 
1076a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
1086a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
1096a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
1106a03354eSMatthew Dillon 
1116a03354eSMatthew Dillon 	nmp = &m->m_hdr.mh_netmsg;
1126a03354eSMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport,
1136a03354eSMatthew Dillon 			0, ip_dn_freepkt_dispatch);
1146a03354eSMatthew Dillon 	nmp->nm_packet = m;
1156a03354eSMatthew Dillon 
1166a03354eSMatthew Dillon 	lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
1176a03354eSMatthew Dillon }
1186a03354eSMatthew Dillon 
1196a03354eSMatthew Dillon void
ip_dn_packet_redispatch(struct dn_pkt * pkt)1206a03354eSMatthew Dillon ip_dn_packet_redispatch(struct dn_pkt *pkt)
1216a03354eSMatthew Dillon {
1226a03354eSMatthew Dillon 	static const netisr_fn_t dispatches[DN_TO_MAX] = {
1236a03354eSMatthew Dillon 	[DN_TO_IP_OUT]		= ip_dn_ip_output,
1246a03354eSMatthew Dillon 	[DN_TO_IP_IN]		= ip_dn_ip_input,
1256a03354eSMatthew Dillon 	[DN_TO_ETH_DEMUX]	= ip_dn_ether_demux,
1266a03354eSMatthew Dillon 	[DN_TO_ETH_OUT]		= ip_dn_ether_output
1276a03354eSMatthew Dillon 	};
1286a03354eSMatthew Dillon 
1296a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
1306a03354eSMatthew Dillon 	struct mbuf *m;
1316a03354eSMatthew Dillon 	netisr_fn_t dispatch;
1326a03354eSMatthew Dillon 	int dir;
1336a03354eSMatthew Dillon 
1346a03354eSMatthew Dillon 	dir = (pkt->dn_flags & DN_FLAGS_DIR_MASK);
1356a03354eSMatthew Dillon 	KASSERT(dir < DN_TO_MAX,
1366a03354eSMatthew Dillon 		("unknown dummynet redispatch dir %d", dir));
1376a03354eSMatthew Dillon 
1386a03354eSMatthew Dillon 	dispatch = dispatches[dir];
1396a03354eSMatthew Dillon 	KASSERT(dispatch != NULL,
1406a03354eSMatthew Dillon 		("unsupported dummynet redispatch dir %d", dir));
1416a03354eSMatthew Dillon 
1426a03354eSMatthew Dillon 	m = pkt->dn_m;
1436a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
1446a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
1456a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
1466a03354eSMatthew Dillon 
1476a03354eSMatthew Dillon 	nmp = &m->m_hdr.mh_netmsg;
1486a03354eSMatthew Dillon 	netmsg_init(&nmp->base, NULL, &netisr_apanic_rport, 0, dispatch);
1496a03354eSMatthew Dillon 	nmp->nm_packet = m;
1506a03354eSMatthew Dillon 
1516a03354eSMatthew Dillon 	lwkt_sendmsg(pkt->msgport, &nmp->base.lmsg);
1526a03354eSMatthew Dillon }
1536a03354eSMatthew Dillon 
1546a03354eSMatthew Dillon int
ip_dn_sockopt(struct sockopt * sopt)1556a03354eSMatthew Dillon ip_dn_sockopt(struct sockopt *sopt)
1566a03354eSMatthew Dillon {
1576a03354eSMatthew Dillon 	int error = 0;
1586a03354eSMatthew Dillon 
1596a03354eSMatthew Dillon 	/* Disallow sets in really-really secure mode. */
1606a03354eSMatthew Dillon 	if (sopt->sopt_dir == SOPT_SET) {
1616a03354eSMatthew Dillon 		if (securelevel >= 3)
1626a03354eSMatthew Dillon 			return EPERM;
1636a03354eSMatthew Dillon 	}
1646a03354eSMatthew Dillon 
1656a03354eSMatthew Dillon 	switch (sopt->sopt_name) {
1666a03354eSMatthew Dillon 	case IP_DUMMYNET_GET:
1676a03354eSMatthew Dillon 		error = ip_dn_sockopt_get(sopt);
1686a03354eSMatthew Dillon 		break;
1696a03354eSMatthew Dillon 
1706a03354eSMatthew Dillon 	case IP_DUMMYNET_FLUSH:
1716a03354eSMatthew Dillon 		error = ip_dn_sockopt_flush(sopt);
1726a03354eSMatthew Dillon 		break;
1736a03354eSMatthew Dillon 
1746a03354eSMatthew Dillon 	case IP_DUMMYNET_DEL:
1756a03354eSMatthew Dillon 	case IP_DUMMYNET_CONFIGURE:
1766a03354eSMatthew Dillon 		error = ip_dn_sockopt_config(sopt);
1776a03354eSMatthew Dillon 		break;
1786a03354eSMatthew Dillon 
1796a03354eSMatthew Dillon 	default:
1806a03354eSMatthew Dillon 		kprintf("%s -- unknown option %d\n", __func__, sopt->sopt_name);
1816a03354eSMatthew Dillon 		error = EINVAL;
1826a03354eSMatthew Dillon 		break;
1836a03354eSMatthew Dillon 	}
1846a03354eSMatthew Dillon 	return error;
1856a03354eSMatthew Dillon }
1866a03354eSMatthew Dillon 
1876a03354eSMatthew Dillon static void
ip_dn_freepkt(struct dn_pkt * pkt)1886a03354eSMatthew Dillon ip_dn_freepkt(struct dn_pkt *pkt)
1896a03354eSMatthew Dillon {
1906a03354eSMatthew Dillon 	struct rtentry *rt = pkt->ro.ro_rt;
1916a03354eSMatthew Dillon 
1926a03354eSMatthew Dillon 	/* Unreference route entry */
1936a03354eSMatthew Dillon 	if (rt != NULL) {
1946a03354eSMatthew Dillon 		if (rt->rt_refcnt <= 0) {	/* XXX assert? */
1956a03354eSMatthew Dillon 			kprintf("-- warning, refcnt now %ld, decreasing\n",
1966a03354eSMatthew Dillon 				rt->rt_refcnt);
1976a03354eSMatthew Dillon 		}
1986a03354eSMatthew Dillon 		RTFREE(rt);
1996a03354eSMatthew Dillon 	}
2006a03354eSMatthew Dillon 
2016a03354eSMatthew Dillon 	/* Unreference packet private data */
2026a03354eSMatthew Dillon 	if (pkt->dn_unref_priv)
2036a03354eSMatthew Dillon 		pkt->dn_unref_priv(pkt->dn_priv);
2046a03354eSMatthew Dillon 
2056a03354eSMatthew Dillon 	/* Free the parent mbuf, this will free 'pkt' as well */
2066a03354eSMatthew Dillon 	m_freem(pkt->dn_m);
2076a03354eSMatthew Dillon }
2086a03354eSMatthew Dillon 
2096a03354eSMatthew Dillon static void
ip_dn_freepkt_dispatch(netmsg_t nmsg)2106a03354eSMatthew Dillon ip_dn_freepkt_dispatch(netmsg_t nmsg)
2116a03354eSMatthew Dillon {
2126a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
2136a03354eSMatthew Dillon 	struct mbuf *m;
2146a03354eSMatthew Dillon 	struct m_tag *mtag;
2156a03354eSMatthew Dillon 	struct dn_pkt *pkt;
2166a03354eSMatthew Dillon 
2176a03354eSMatthew Dillon 	nmp = &nmsg->packet;
2186a03354eSMatthew Dillon 	m = nmp->nm_packet;
2196a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
2206a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
2216a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
2226a03354eSMatthew Dillon 
2236a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
2246a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
2256a03354eSMatthew Dillon 
2266a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
2276a03354eSMatthew Dillon 	KASSERT(pkt->cpuid == mycpuid,
2286a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
2296a03354eSMatthew Dillon 		 "target cpuid %d, mycpuid %d", __func__,
2306a03354eSMatthew Dillon 		 pkt->cpuid, mycpuid));
2316a03354eSMatthew Dillon 
2326a03354eSMatthew Dillon 	ip_dn_freepkt(pkt);
2336a03354eSMatthew Dillon }
2346a03354eSMatthew Dillon 
2356a03354eSMatthew Dillon static void
ip_dn_dispatch(netmsg_t nmsg)2366a03354eSMatthew Dillon ip_dn_dispatch(netmsg_t nmsg)
2376a03354eSMatthew Dillon {
2386a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
2396a03354eSMatthew Dillon 	struct mbuf *m;
2406a03354eSMatthew Dillon 	struct m_tag *mtag;
2416a03354eSMatthew Dillon 	struct dn_pkt *pkt;
2426a03354eSMatthew Dillon 
2436a03354eSMatthew Dillon 	KASSERT(ip_dn_cpu == mycpuid,
2446a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
2456a03354eSMatthew Dillon 		 "dummynet cpuid %d, mycpuid %d", __func__,
2466a03354eSMatthew Dillon 		 ip_dn_cpu, mycpuid));
2476a03354eSMatthew Dillon 
2486a03354eSMatthew Dillon 	nmp = &nmsg->packet;
2496a03354eSMatthew Dillon 	m = nmp->nm_packet;
2506a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
2516a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
2526a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
2536a03354eSMatthew Dillon 
2546a03354eSMatthew Dillon 	if (DUMMYNET_LOADED) {
2556a03354eSMatthew Dillon 		if (ip_dn_io_ptr(m) == 0)
2566a03354eSMatthew Dillon 			return;
2576a03354eSMatthew Dillon 	}
2586a03354eSMatthew Dillon 
2596a03354eSMatthew Dillon 	/*
2606a03354eSMatthew Dillon 	 * ip_dn_io_ptr() failed or dummynet(4) is not loaded
2616a03354eSMatthew Dillon 	 */
2626a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
2636a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
2646a03354eSMatthew Dillon 
2656a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
2666a03354eSMatthew Dillon 	ip_dn_packet_free(pkt);
2676a03354eSMatthew Dillon }
2686a03354eSMatthew Dillon 
2696a03354eSMatthew Dillon static void
ip_dn_ip_output(netmsg_t nmsg)2706a03354eSMatthew Dillon ip_dn_ip_output(netmsg_t nmsg)
2716a03354eSMatthew Dillon {
2726a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
2736a03354eSMatthew Dillon 	struct mbuf *m;
2746a03354eSMatthew Dillon 	struct m_tag *mtag;
2756a03354eSMatthew Dillon 	struct dn_pkt *pkt;
2766a03354eSMatthew Dillon 	struct rtentry *rt;
2776a03354eSMatthew Dillon 	ip_dn_unref_priv_t unref_priv;
2786a03354eSMatthew Dillon 	void *priv;
2796a03354eSMatthew Dillon 
2806a03354eSMatthew Dillon 	nmp = &nmsg->packet;
2816a03354eSMatthew Dillon 	m = nmp->nm_packet;
2826a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
2836a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
2846a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
2856a03354eSMatthew Dillon 
2866a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
2876a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
2886a03354eSMatthew Dillon 
2896a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
2906a03354eSMatthew Dillon 	KASSERT(pkt->cpuid == mycpuid,
2916a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
2926a03354eSMatthew Dillon 		 "target cpuid %d, mycpuid %d", __func__,
2936a03354eSMatthew Dillon 		 pkt->cpuid, mycpuid));
2946a03354eSMatthew Dillon 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_OUT,
2956a03354eSMatthew Dillon 		("wrong direction %d, should be %d",
2966a03354eSMatthew Dillon 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_OUT));
2976a03354eSMatthew Dillon 
2986a03354eSMatthew Dillon 	priv = pkt->dn_priv;
2996a03354eSMatthew Dillon 	unref_priv = pkt->dn_unref_priv;
3006a03354eSMatthew Dillon 	rt = pkt->ro.ro_rt;
3016a03354eSMatthew Dillon 
3026a03354eSMatthew Dillon 	if (rt != NULL && !(rt->rt_flags & RTF_UP)) {
3036a03354eSMatthew Dillon 		/*
3046a03354eSMatthew Dillon 		 * Recorded rtentry is gone, when the packet
3056a03354eSMatthew Dillon 		 * was on delay line.
3066a03354eSMatthew Dillon 		 */
3076a03354eSMatthew Dillon 		ip_dn_freepkt(pkt);
3086a03354eSMatthew Dillon 		return;
3096a03354eSMatthew Dillon 	}
3106a03354eSMatthew Dillon 
3116a03354eSMatthew Dillon 	ip_output(pkt->dn_m, NULL, NULL, pkt->flags, NULL, NULL);
3126a03354eSMatthew Dillon 	/* 'rt' will be freed in ip_output */
3136a03354eSMatthew Dillon 
3146a03354eSMatthew Dillon 	if (unref_priv)
3156a03354eSMatthew Dillon 		unref_priv(priv);
3166a03354eSMatthew Dillon }
3176a03354eSMatthew Dillon 
3186a03354eSMatthew Dillon static void
ip_dn_ip_input(netmsg_t nmsg)3196a03354eSMatthew Dillon ip_dn_ip_input(netmsg_t nmsg)
3206a03354eSMatthew Dillon {
3216a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
3226a03354eSMatthew Dillon 	struct mbuf *m;
3236a03354eSMatthew Dillon 	struct m_tag *mtag;
3246a03354eSMatthew Dillon 	struct dn_pkt *pkt;
3256a03354eSMatthew Dillon 	ip_dn_unref_priv_t unref_priv;
3266a03354eSMatthew Dillon 	void *priv;
327*7376bec4SSepherosa Ziehau 	struct ip *ip;
3286a03354eSMatthew Dillon 
3296a03354eSMatthew Dillon 	nmp = &nmsg->packet;
3306a03354eSMatthew Dillon 	m = nmp->nm_packet;
3316a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
3326a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
3336a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
3346a03354eSMatthew Dillon 
3356a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
3366a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
3376a03354eSMatthew Dillon 
3386a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
3396a03354eSMatthew Dillon 	KASSERT(pkt->cpuid == mycpuid,
3406a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
3416a03354eSMatthew Dillon 		 "target cpuid %d, mycpuid %d", __func__,
3426a03354eSMatthew Dillon 		 pkt->cpuid, mycpuid));
3436a03354eSMatthew Dillon 	KASSERT(pkt->ro.ro_rt == NULL,
3446a03354eSMatthew Dillon 		("route entry is not NULL for ip_input"));
3456a03354eSMatthew Dillon 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_IP_IN,
3466a03354eSMatthew Dillon 		("wrong direction %d, should be %d",
3476a03354eSMatthew Dillon 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_IP_IN));
3486a03354eSMatthew Dillon 
3496a03354eSMatthew Dillon 	priv = pkt->dn_priv;
3506a03354eSMatthew Dillon 	unref_priv = pkt->dn_unref_priv;
3516a03354eSMatthew Dillon 
352*7376bec4SSepherosa Ziehau 	KKASSERT(m->m_len >= sizeof(*ip));
353*7376bec4SSepherosa Ziehau 
3546a03354eSMatthew Dillon 	ip_input(m);
3556a03354eSMatthew Dillon 
3566a03354eSMatthew Dillon 	if (unref_priv)
3576a03354eSMatthew Dillon 		unref_priv(priv);
3586a03354eSMatthew Dillon }
3596a03354eSMatthew Dillon 
3606a03354eSMatthew Dillon static void
ip_dn_ether_demux(netmsg_t nmsg)3616a03354eSMatthew Dillon ip_dn_ether_demux(netmsg_t nmsg)
3626a03354eSMatthew Dillon {
3636a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
3646a03354eSMatthew Dillon 	struct mbuf *m;
3656a03354eSMatthew Dillon 	struct m_tag *mtag;
3666a03354eSMatthew Dillon 	struct dn_pkt *pkt;
3676a03354eSMatthew Dillon 	ip_dn_unref_priv_t unref_priv;
3686a03354eSMatthew Dillon 	void *priv;
3696a03354eSMatthew Dillon 
3706a03354eSMatthew Dillon 	nmp = &nmsg->packet;
3716a03354eSMatthew Dillon 	m = nmp->nm_packet;
3726a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
3736a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
3746a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
3756a03354eSMatthew Dillon 
3766a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
3776a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
3786a03354eSMatthew Dillon 
3796a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
3806a03354eSMatthew Dillon 	KASSERT(pkt->cpuid == mycpuid,
3816a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
3826a03354eSMatthew Dillon 		 "target cpuid %d, mycpuid %d", __func__,
3836a03354eSMatthew Dillon 		 pkt->cpuid, mycpuid));
3846a03354eSMatthew Dillon 	KASSERT(pkt->ro.ro_rt == NULL,
3856a03354eSMatthew Dillon 		("route entry is not NULL for ether_demux"));
3866a03354eSMatthew Dillon 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_DEMUX,
3876a03354eSMatthew Dillon 		("wrong direction %d, should be %d",
3886a03354eSMatthew Dillon 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_DEMUX));
3896a03354eSMatthew Dillon 
3906a03354eSMatthew Dillon 	priv = pkt->dn_priv;
3916a03354eSMatthew Dillon 	unref_priv = pkt->dn_unref_priv;
3926a03354eSMatthew Dillon 
3936a03354eSMatthew Dillon 	/*
3946a03354eSMatthew Dillon 	 * Make sure that ether header is contiguous
3956a03354eSMatthew Dillon 	 */
3966a03354eSMatthew Dillon 	if (m->m_len < ETHER_HDR_LEN &&
3976a03354eSMatthew Dillon 		(m = m_pullup(m, ETHER_HDR_LEN)) == NULL) {
3986a03354eSMatthew Dillon 		kprintf("%s: pullup fail, dropping pkt\n", __func__);
3996a03354eSMatthew Dillon 		goto back;
4006a03354eSMatthew Dillon 	}
4016a03354eSMatthew Dillon 	ether_demux_oncpu(m->m_pkthdr.rcvif, m);
4026a03354eSMatthew Dillon back:
4036a03354eSMatthew Dillon 	if (unref_priv)
4046a03354eSMatthew Dillon 		unref_priv(priv);
4056a03354eSMatthew Dillon }
4066a03354eSMatthew Dillon 
4076a03354eSMatthew Dillon static void
ip_dn_ether_output(netmsg_t nmsg)4086a03354eSMatthew Dillon ip_dn_ether_output(netmsg_t nmsg)
4096a03354eSMatthew Dillon {
4106a03354eSMatthew Dillon 	struct netmsg_packet *nmp;
4116a03354eSMatthew Dillon 	struct mbuf *m;
4126a03354eSMatthew Dillon 	struct m_tag *mtag;
4136a03354eSMatthew Dillon 	struct dn_pkt *pkt;
4146a03354eSMatthew Dillon 	ip_dn_unref_priv_t unref_priv;
4156a03354eSMatthew Dillon 	void *priv;
4166a03354eSMatthew Dillon 
4176a03354eSMatthew Dillon 	nmp = &nmsg->packet;
4186a03354eSMatthew Dillon 	m = nmp->nm_packet;
4196a03354eSMatthew Dillon 	M_ASSERTPKTHDR(m);
4206a03354eSMatthew Dillon 	KASSERT(m->m_pkthdr.fw_flags & DUMMYNET_MBUF_TAGGED,
4216a03354eSMatthew Dillon 		("mbuf is not tagged for dummynet!"));
4226a03354eSMatthew Dillon 
4236a03354eSMatthew Dillon 	mtag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
4246a03354eSMatthew Dillon 	KKASSERT(mtag != NULL);
4256a03354eSMatthew Dillon 
4266a03354eSMatthew Dillon 	pkt = m_tag_data(mtag);
4276a03354eSMatthew Dillon 	KASSERT(pkt->cpuid == mycpuid,
4286a03354eSMatthew Dillon 		("%s: dummynet packet was delivered to wrong cpu! "
4296a03354eSMatthew Dillon 		 "target cpuid %d, mycpuid %d", __func__,
4306a03354eSMatthew Dillon 		 pkt->cpuid, mycpuid));
4316a03354eSMatthew Dillon 	KASSERT(pkt->ro.ro_rt == NULL,
4326a03354eSMatthew Dillon 		("route entry is not NULL for ether_output_frame"));
4336a03354eSMatthew Dillon 	KASSERT((pkt->dn_flags & DN_FLAGS_DIR_MASK) == DN_TO_ETH_OUT,
4346a03354eSMatthew Dillon 		("wrong direction %d, should be %d",
4356a03354eSMatthew Dillon 		 (pkt->dn_flags & DN_FLAGS_DIR_MASK), DN_TO_ETH_OUT));
4366a03354eSMatthew Dillon 
4376a03354eSMatthew Dillon 	priv = pkt->dn_priv;
4386a03354eSMatthew Dillon 	unref_priv = pkt->dn_unref_priv;
4396a03354eSMatthew Dillon 
4406a03354eSMatthew Dillon 	ether_output_frame(pkt->ifp, m);
4416a03354eSMatthew Dillon 
4426a03354eSMatthew Dillon 	if (unref_priv)
4436a03354eSMatthew Dillon 		unref_priv(priv);
4446a03354eSMatthew Dillon }
4456a03354eSMatthew Dillon 
4466a03354eSMatthew Dillon static void
ip_dn_sockopt_dispatch(netmsg_t nmsg)4476a03354eSMatthew Dillon ip_dn_sockopt_dispatch(netmsg_t nmsg)
4486a03354eSMatthew Dillon {
4496a03354eSMatthew Dillon 	lwkt_msg *msg = &nmsg->lmsg;
4506a03354eSMatthew Dillon 	struct dn_sopt *dn_sopt = msg->u.ms_resultp;
4516a03354eSMatthew Dillon 	int error;
4526a03354eSMatthew Dillon 
4536a03354eSMatthew Dillon 	KASSERT(ip_dn_cpu == mycpuid,
4546a03354eSMatthew Dillon 		("%s: dummynet sockopt is done on wrong cpu! "
4556a03354eSMatthew Dillon 		 "dummynet cpuid %d, mycpuid %d", __func__,
4566a03354eSMatthew Dillon 		 ip_dn_cpu, mycpuid));
4576a03354eSMatthew Dillon 
4586a03354eSMatthew Dillon 	if (DUMMYNET_LOADED)
4596a03354eSMatthew Dillon 		error = ip_dn_ctl_ptr(dn_sopt);
4606a03354eSMatthew Dillon 	else
4616a03354eSMatthew Dillon 		error = ENOPROTOOPT;
4626a03354eSMatthew Dillon 	lwkt_replymsg(msg, error);
4636a03354eSMatthew Dillon }
4646a03354eSMatthew Dillon 
4656a03354eSMatthew Dillon static int
ip_dn_sockopt_flush(struct sockopt * sopt)4666a03354eSMatthew Dillon ip_dn_sockopt_flush(struct sockopt *sopt)
4676a03354eSMatthew Dillon {
4686a03354eSMatthew Dillon 	struct dn_sopt dn_sopt;
4696a03354eSMatthew Dillon 	struct netmsg_base smsg;
4706a03354eSMatthew Dillon 
4716a03354eSMatthew Dillon 	bzero(&dn_sopt, sizeof(dn_sopt));
4726a03354eSMatthew Dillon 	dn_sopt.dn_sopt_name = sopt->sopt_name;
4736a03354eSMatthew Dillon 
4746a03354eSMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
4756a03354eSMatthew Dillon 			0, ip_dn_sockopt_dispatch);
4766a03354eSMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
4776a03354eSMatthew Dillon 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
4786a03354eSMatthew Dillon 
4796a03354eSMatthew Dillon 	return smsg.lmsg.ms_error;
4806a03354eSMatthew Dillon }
4816a03354eSMatthew Dillon 
4826a03354eSMatthew Dillon static int
ip_dn_sockopt_get(struct sockopt * sopt)4836a03354eSMatthew Dillon ip_dn_sockopt_get(struct sockopt *sopt)
4846a03354eSMatthew Dillon {
4856a03354eSMatthew Dillon 	struct dn_sopt dn_sopt;
4866a03354eSMatthew Dillon 	struct netmsg_base smsg;
4876a03354eSMatthew Dillon 	int error;
4886a03354eSMatthew Dillon 
4896a03354eSMatthew Dillon 	bzero(&dn_sopt, sizeof(dn_sopt));
4906a03354eSMatthew Dillon 	dn_sopt.dn_sopt_name = sopt->sopt_name;
4916a03354eSMatthew Dillon 
4926a03354eSMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
4936a03354eSMatthew Dillon 			0, ip_dn_sockopt_dispatch);
4946a03354eSMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
4956a03354eSMatthew Dillon 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
4966a03354eSMatthew Dillon 
4976a03354eSMatthew Dillon 	error = smsg.lmsg.ms_error;
4986a03354eSMatthew Dillon 	if (error) {
4996a03354eSMatthew Dillon 		KKASSERT(dn_sopt.dn_sopt_arg == NULL);
5006a03354eSMatthew Dillon 		KKASSERT(dn_sopt.dn_sopt_arglen == 0);
5016a03354eSMatthew Dillon 		return error;
5026a03354eSMatthew Dillon 	}
5036a03354eSMatthew Dillon 
5046a03354eSMatthew Dillon 	soopt_from_kbuf(sopt, dn_sopt.dn_sopt_arg, dn_sopt.dn_sopt_arglen);
5056a03354eSMatthew Dillon 	kfree(dn_sopt.dn_sopt_arg, M_TEMP);
5066a03354eSMatthew Dillon 	return 0;
5076a03354eSMatthew Dillon }
5086a03354eSMatthew Dillon 
5096a03354eSMatthew Dillon static int
ip_dn_sockopt_config(struct sockopt * sopt)5106a03354eSMatthew Dillon ip_dn_sockopt_config(struct sockopt *sopt)
5116a03354eSMatthew Dillon {
5126a03354eSMatthew Dillon 	struct dn_ioc_pipe tmp_ioc_pipe;
5136a03354eSMatthew Dillon 	struct dn_sopt dn_sopt;
5146a03354eSMatthew Dillon 	struct netmsg_base smsg;
5156a03354eSMatthew Dillon 	int error;
5166a03354eSMatthew Dillon 
5176a03354eSMatthew Dillon 	error = soopt_to_kbuf(sopt, &tmp_ioc_pipe, sizeof tmp_ioc_pipe,
5186a03354eSMatthew Dillon 				  sizeof tmp_ioc_pipe);
5196a03354eSMatthew Dillon 	if (error)
5206a03354eSMatthew Dillon 		return error;
5216a03354eSMatthew Dillon 
5226a03354eSMatthew Dillon 	bzero(&dn_sopt, sizeof(dn_sopt));
5236a03354eSMatthew Dillon 	dn_sopt.dn_sopt_name = sopt->sopt_name;
5246a03354eSMatthew Dillon 	dn_sopt.dn_sopt_arg = &tmp_ioc_pipe;
5256a03354eSMatthew Dillon 	dn_sopt.dn_sopt_arglen = sizeof(tmp_ioc_pipe);
5266a03354eSMatthew Dillon 
5276a03354eSMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
5286a03354eSMatthew Dillon 			0, ip_dn_sockopt_dispatch);
5296a03354eSMatthew Dillon 	smsg.lmsg.u.ms_resultp = &dn_sopt;
5306a03354eSMatthew Dillon 	lwkt_domsg(netisr_cpuport(ip_dn_cpu), &smsg.lmsg, 0);
5316a03354eSMatthew Dillon 
5326a03354eSMatthew Dillon 	return smsg.lmsg.ms_error;
5336a03354eSMatthew Dillon }
534