xref: /freebsd/sys/net/dummymbuf.c (revision aa72c5bacb5f7ab359a3b7ae07b7c7b8705b60a8)
18aaffd78SIgor Ostapenko /*-
28aaffd78SIgor Ostapenko  * SPDX-License-Identifier: BSD-2-Clause
38aaffd78SIgor Ostapenko  *
48aaffd78SIgor Ostapenko  * Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
58aaffd78SIgor Ostapenko  *
68aaffd78SIgor Ostapenko  * Redistribution and use in source and binary forms, with or without
78aaffd78SIgor Ostapenko  * modification, are permitted provided that the following conditions
88aaffd78SIgor Ostapenko  * are met:
98aaffd78SIgor Ostapenko  * 1. Redistributions of source code must retain the above copyright
108aaffd78SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer.
118aaffd78SIgor Ostapenko  * 2. Redistributions in binary form must reproduce the above copyright
128aaffd78SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer in the
138aaffd78SIgor Ostapenko  *    documentation and/or other materials provided with the distribution.
148aaffd78SIgor Ostapenko  *
158aaffd78SIgor Ostapenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
168aaffd78SIgor Ostapenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
178aaffd78SIgor Ostapenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
188aaffd78SIgor Ostapenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
198aaffd78SIgor Ostapenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
208aaffd78SIgor Ostapenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
218aaffd78SIgor Ostapenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228aaffd78SIgor Ostapenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
238aaffd78SIgor Ostapenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
248aaffd78SIgor Ostapenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
258aaffd78SIgor Ostapenko  * SUCH DAMAGE.
268aaffd78SIgor Ostapenko  */
278aaffd78SIgor Ostapenko 
288aaffd78SIgor Ostapenko #include "opt_inet.h"
298aaffd78SIgor Ostapenko #include "opt_inet6.h"
308aaffd78SIgor Ostapenko 
318aaffd78SIgor Ostapenko #include <sys/param.h>
328aaffd78SIgor Ostapenko #include <sys/kernel.h>
338aaffd78SIgor Ostapenko #include <sys/mbuf.h>
348aaffd78SIgor Ostapenko #include <sys/module.h>
358aaffd78SIgor Ostapenko #include <sys/socket.h>
368aaffd78SIgor Ostapenko #include <sys/sysctl.h>
378aaffd78SIgor Ostapenko 
388aaffd78SIgor Ostapenko #include <net/if.h>
398aaffd78SIgor Ostapenko #include <net/if_var.h>
408aaffd78SIgor Ostapenko #include <net/vnet.h>
418aaffd78SIgor Ostapenko #include <net/pfil.h>
428aaffd78SIgor Ostapenko 
438aaffd78SIgor Ostapenko /*
448aaffd78SIgor Ostapenko  * Separate sysctl sub-tree
458aaffd78SIgor Ostapenko  */
468aaffd78SIgor Ostapenko 
478aaffd78SIgor Ostapenko SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL,
488aaffd78SIgor Ostapenko     "Dummy mbuf sysctl");
498aaffd78SIgor Ostapenko 
508aaffd78SIgor Ostapenko /*
518aaffd78SIgor Ostapenko  * Rules
528aaffd78SIgor Ostapenko  */
538aaffd78SIgor Ostapenko 
548aaffd78SIgor Ostapenko static MALLOC_DEFINE(M_DUMMYMBUF_RULES, "dummymbuf_rules",
558aaffd78SIgor Ostapenko     "dummymbuf rules string buffer");
568aaffd78SIgor Ostapenko 
578aaffd78SIgor Ostapenko #define RULES_MAXLEN		1024
588aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(char *,	dmb_rules) = NULL;
598aaffd78SIgor Ostapenko #define V_dmb_rules		VNET(dmb_rules)
608aaffd78SIgor Ostapenko 
618aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(struct sx,	dmb_rules_lock);
628aaffd78SIgor Ostapenko #define V_dmb_rules_lock	VNET(dmb_rules_lock)
638aaffd78SIgor Ostapenko 
648aaffd78SIgor Ostapenko #define DMB_RULES_SLOCK()	sx_slock(&V_dmb_rules_lock)
658aaffd78SIgor Ostapenko #define DMB_RULES_SUNLOCK()	sx_sunlock(&V_dmb_rules_lock)
668aaffd78SIgor Ostapenko #define DMB_RULES_XLOCK()	sx_xlock(&V_dmb_rules_lock)
678aaffd78SIgor Ostapenko #define DMB_RULES_XUNLOCK()	sx_xunlock(&V_dmb_rules_lock)
688aaffd78SIgor Ostapenko 
698aaffd78SIgor Ostapenko static int
708aaffd78SIgor Ostapenko dmb_sysctl_handle_rules(SYSCTL_HANDLER_ARGS)
718aaffd78SIgor Ostapenko {
728aaffd78SIgor Ostapenko 	int error = 0;
738aaffd78SIgor Ostapenko 	char empty = '\0';
748aaffd78SIgor Ostapenko 	char **rulesp = (char **)arg1;
758aaffd78SIgor Ostapenko 
768aaffd78SIgor Ostapenko 	if (req->newptr == NULL) {
778aaffd78SIgor Ostapenko 		// read only
788aaffd78SIgor Ostapenko 		DMB_RULES_SLOCK();
798aaffd78SIgor Ostapenko 		arg1 = *rulesp;
808aaffd78SIgor Ostapenko 		if (arg1 == NULL) {
818aaffd78SIgor Ostapenko 			arg1 = &empty;
828aaffd78SIgor Ostapenko 			arg2 = 0;
838aaffd78SIgor Ostapenko 		}
848aaffd78SIgor Ostapenko 		error = sysctl_handle_string(oidp, arg1, arg2, req);
858aaffd78SIgor Ostapenko 		DMB_RULES_SUNLOCK();
868aaffd78SIgor Ostapenko 	} else {
878aaffd78SIgor Ostapenko 		// read and write
888aaffd78SIgor Ostapenko 		DMB_RULES_XLOCK();
898aaffd78SIgor Ostapenko 		if (*rulesp == NULL)
908aaffd78SIgor Ostapenko 			*rulesp = malloc(arg2, M_DUMMYMBUF_RULES, M_WAITOK);
918aaffd78SIgor Ostapenko 		arg1 = *rulesp;
928aaffd78SIgor Ostapenko 		error = sysctl_handle_string(oidp, arg1, arg2, req);
938aaffd78SIgor Ostapenko 		DMB_RULES_XUNLOCK();
948aaffd78SIgor Ostapenko 	}
958aaffd78SIgor Ostapenko 
968aaffd78SIgor Ostapenko 	return (error);
978aaffd78SIgor Ostapenko }
988aaffd78SIgor Ostapenko 
998aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, rules,
1008aaffd78SIgor Ostapenko     CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_VNET,
1018aaffd78SIgor Ostapenko     &VNET_NAME(dmb_rules), RULES_MAXLEN, dmb_sysctl_handle_rules, "A",
1028aaffd78SIgor Ostapenko     "{inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];"
1038aaffd78SIgor Ostapenko     " ...;");
1048aaffd78SIgor Ostapenko 
1058aaffd78SIgor Ostapenko /*
1068aaffd78SIgor Ostapenko  * Statistics
1078aaffd78SIgor Ostapenko  */
1088aaffd78SIgor Ostapenko 
1098aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(counter_u64_t,	dmb_hits);
1108aaffd78SIgor Ostapenko #define V_dmb_hits			VNET(dmb_hits)
1118aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits,
1128aaffd78SIgor Ostapenko     CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET,
1138aaffd78SIgor Ostapenko     &VNET_NAME(dmb_hits), 0, sysctl_handle_counter_u64,
1148aaffd78SIgor Ostapenko     "QU", "Number of times a rule has been applied");
1158aaffd78SIgor Ostapenko 
1168aaffd78SIgor Ostapenko /*
1178aaffd78SIgor Ostapenko  * pfil(9) context
1188aaffd78SIgor Ostapenko  */
1198aaffd78SIgor Ostapenko 
120*aa72c5baSGleb Smirnoff #ifdef INET
1218aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_inet_hook);
1228aaffd78SIgor Ostapenko #define V_dmb_pfil_inet_hook		VNET(dmb_pfil_inet_hook)
123*aa72c5baSGleb Smirnoff #endif
1248aaffd78SIgor Ostapenko 
125*aa72c5baSGleb Smirnoff #ifdef INET6
1268aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_inet6_hook);
1278aaffd78SIgor Ostapenko #define V_dmb_pfil_inet6_hook		VNET(dmb_pfil_inet6_hook)
128*aa72c5baSGleb Smirnoff #endif
1298aaffd78SIgor Ostapenko 
1308aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_ethernet_hook);
1318aaffd78SIgor Ostapenko #define V_dmb_pfil_ethernet_hook	VNET(dmb_pfil_ethernet_hook)
1328aaffd78SIgor Ostapenko 
1338aaffd78SIgor Ostapenko /*
1348aaffd78SIgor Ostapenko  * Logging
1358aaffd78SIgor Ostapenko  */
1368aaffd78SIgor Ostapenko 
1378aaffd78SIgor Ostapenko #define FEEDBACK(pfil_type, pfil_flags, ifp, rule, msg)			\
1388aaffd78SIgor Ostapenko 	printf("dummymbuf: %s %b %s: %s: %.*s\n",			\
1398aaffd78SIgor Ostapenko 	    (pfil_type == PFIL_TYPE_IP4 ?	"PFIL_TYPE_IP4" :	\
1408aaffd78SIgor Ostapenko 	     pfil_type == PFIL_TYPE_IP6 ?	"PFIL_TYPE_IP6" :	\
1418aaffd78SIgor Ostapenko 	     pfil_type == PFIL_TYPE_ETHERNET ?	"PFIL_TYPE_ETHERNET" :	\
1428aaffd78SIgor Ostapenko 						"PFIL_TYPE_UNKNOWN"),	\
1438aaffd78SIgor Ostapenko 	    (pfil_flags), "\20\21PFIL_IN\22PFIL_OUT",			\
1448aaffd78SIgor Ostapenko 	    (ifp)->if_xname,						\
1458aaffd78SIgor Ostapenko 	    (msg),							\
1468aaffd78SIgor Ostapenko 	    (rule).syntax_len, (rule).syntax_begin			\
1478aaffd78SIgor Ostapenko 	)
1488aaffd78SIgor Ostapenko 
1498aaffd78SIgor Ostapenko /*
1508aaffd78SIgor Ostapenko  * Internals
1518aaffd78SIgor Ostapenko  */
1528aaffd78SIgor Ostapenko 
1538aaffd78SIgor Ostapenko struct rule;
1548aaffd78SIgor Ostapenko typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *);
1558aaffd78SIgor Ostapenko struct rule {
1568aaffd78SIgor Ostapenko 	const char	*syntax_begin;
1578aaffd78SIgor Ostapenko 	int		 syntax_len;
1588aaffd78SIgor Ostapenko 	int		 pfil_type;
1598aaffd78SIgor Ostapenko 	int		 pfil_dir;
1608aaffd78SIgor Ostapenko 	char		 ifname[IFNAMSIZ];
1618aaffd78SIgor Ostapenko 	op_t		 op;
1628aaffd78SIgor Ostapenko 	const char	*opargs;
1638aaffd78SIgor Ostapenko };
1648aaffd78SIgor Ostapenko 
1658aaffd78SIgor Ostapenko static struct mbuf *
1668aaffd78SIgor Ostapenko dmb_m_pull_head(struct mbuf *m, struct rule *rule)
1678aaffd78SIgor Ostapenko {
1688aaffd78SIgor Ostapenko 	struct mbuf *n;
1698aaffd78SIgor Ostapenko 	int count;
1708aaffd78SIgor Ostapenko 
1718aaffd78SIgor Ostapenko 	count = (int)strtol(rule->opargs, NULL, 10);
1728aaffd78SIgor Ostapenko 	if (count < 0 || count > MCLBYTES)
1738aaffd78SIgor Ostapenko 		goto bad;
1748aaffd78SIgor Ostapenko 
1758aaffd78SIgor Ostapenko 	if (!(m->m_flags & M_PKTHDR))
1768aaffd78SIgor Ostapenko 		goto bad;
1778aaffd78SIgor Ostapenko 	if (m->m_pkthdr.len <= 0)
1788aaffd78SIgor Ostapenko 		return (m);
1798aaffd78SIgor Ostapenko 	if (count > m->m_pkthdr.len)
1808aaffd78SIgor Ostapenko 		count = m->m_pkthdr.len;
1818aaffd78SIgor Ostapenko 
1828aaffd78SIgor Ostapenko 	if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL)
1838aaffd78SIgor Ostapenko 		goto bad;
1848aaffd78SIgor Ostapenko 
1858aaffd78SIgor Ostapenko 	m_move_pkthdr(n, m);
1868aaffd78SIgor Ostapenko 	m_copydata(m, 0, count, n->m_ext.ext_buf);
1878aaffd78SIgor Ostapenko 	n->m_len = count;
1888aaffd78SIgor Ostapenko 
1898aaffd78SIgor Ostapenko 	m_adj(m, count);
1908aaffd78SIgor Ostapenko 	n->m_next = m;
1918aaffd78SIgor Ostapenko 
1928aaffd78SIgor Ostapenko 	return (n);
1938aaffd78SIgor Ostapenko 
1948aaffd78SIgor Ostapenko bad:
1958aaffd78SIgor Ostapenko 	m_freem(m);
1968aaffd78SIgor Ostapenko 	return (NULL);
1978aaffd78SIgor Ostapenko }
1988aaffd78SIgor Ostapenko 
1998aaffd78SIgor Ostapenko static bool
2008aaffd78SIgor Ostapenko read_rule(const char **cur, struct rule *rule)
2018aaffd78SIgor Ostapenko {
2028aaffd78SIgor Ostapenko 	// {inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];
2038aaffd78SIgor Ostapenko 
2048aaffd78SIgor Ostapenko 	rule->syntax_begin = NULL;
2058aaffd78SIgor Ostapenko 	rule->syntax_len = 0;
2068aaffd78SIgor Ostapenko 
2078aaffd78SIgor Ostapenko 	if (*cur == NULL)
2088aaffd78SIgor Ostapenko 		return (false);
2098aaffd78SIgor Ostapenko 
2108aaffd78SIgor Ostapenko 	// syntax_begin
2118aaffd78SIgor Ostapenko 	while (**cur == ' ')
2128aaffd78SIgor Ostapenko 		(*cur)++;
2138aaffd78SIgor Ostapenko 	rule->syntax_begin = *cur;
2148aaffd78SIgor Ostapenko 
2158aaffd78SIgor Ostapenko 	// syntax_len
2168aaffd78SIgor Ostapenko 	char *delim = strchr(*cur, ';');
2178aaffd78SIgor Ostapenko 	if (delim == NULL)
2188aaffd78SIgor Ostapenko 		return (false);
2198aaffd78SIgor Ostapenko 	rule->syntax_len = (int)(delim - *cur + 1);
2208aaffd78SIgor Ostapenko 
2218aaffd78SIgor Ostapenko 	// pfil_type
2228aaffd78SIgor Ostapenko 	if (strstr(*cur, "inet6") == *cur) {
2238aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_IP6;
2248aaffd78SIgor Ostapenko 		*cur += strlen("inet6");
2258aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "inet") == *cur) {
2268aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_IP4;
2278aaffd78SIgor Ostapenko 		*cur += strlen("inet");
2288aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "ethernet")) {
2298aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_ETHERNET;
2308aaffd78SIgor Ostapenko 		*cur += strlen("ethernet");
2318aaffd78SIgor Ostapenko 	} else {
2328aaffd78SIgor Ostapenko 		return (false);
2338aaffd78SIgor Ostapenko 	}
2348aaffd78SIgor Ostapenko 	while (**cur == ' ')
2358aaffd78SIgor Ostapenko 		(*cur)++;
2368aaffd78SIgor Ostapenko 
2378aaffd78SIgor Ostapenko 	// pfil_dir
2388aaffd78SIgor Ostapenko 	if (strstr(*cur, "in") == *cur) {
2398aaffd78SIgor Ostapenko 		rule->pfil_dir = PFIL_IN;
2408aaffd78SIgor Ostapenko 		*cur += strlen("in");
2418aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "out") == *cur) {
2428aaffd78SIgor Ostapenko 		rule->pfil_dir = PFIL_OUT;
2438aaffd78SIgor Ostapenko 		*cur += strlen("out");
2448aaffd78SIgor Ostapenko 	} else {
2458aaffd78SIgor Ostapenko 		return (false);
2468aaffd78SIgor Ostapenko 	}
2478aaffd78SIgor Ostapenko 	while (**cur == ' ')
2488aaffd78SIgor Ostapenko 		(*cur)++;
2498aaffd78SIgor Ostapenko 
2508aaffd78SIgor Ostapenko 	// ifname
2518aaffd78SIgor Ostapenko 	char *sp = strchr(*cur, ' ');
2528aaffd78SIgor Ostapenko 	if (sp == NULL || sp > delim)
2538aaffd78SIgor Ostapenko 		return (false);
2548aaffd78SIgor Ostapenko 	size_t len = sp - *cur;
2558aaffd78SIgor Ostapenko 	if (len >= sizeof(rule->ifname))
2568aaffd78SIgor Ostapenko 		return (false);
2578aaffd78SIgor Ostapenko 	strncpy(rule->ifname, *cur, len);
2588aaffd78SIgor Ostapenko 	rule->ifname[len] = 0;
2598aaffd78SIgor Ostapenko 	*cur = sp;
2608aaffd78SIgor Ostapenko 	while (**cur == ' ')
2618aaffd78SIgor Ostapenko 		(*cur)++;
2628aaffd78SIgor Ostapenko 
2638aaffd78SIgor Ostapenko 	// opname
2648aaffd78SIgor Ostapenko 	if (strstr(*cur, "pull-head") == *cur) {
2658aaffd78SIgor Ostapenko 		rule->op = dmb_m_pull_head;
2668aaffd78SIgor Ostapenko 		*cur += strlen("pull-head");
2678aaffd78SIgor Ostapenko 	} else {
2688aaffd78SIgor Ostapenko 		return (false);
2698aaffd78SIgor Ostapenko 	}
2708aaffd78SIgor Ostapenko 	while (**cur == ' ')
2718aaffd78SIgor Ostapenko 		(*cur)++;
2728aaffd78SIgor Ostapenko 
2738aaffd78SIgor Ostapenko 	// opargs
2748aaffd78SIgor Ostapenko 	if (*cur > delim)
2758aaffd78SIgor Ostapenko 		return (false);
2768aaffd78SIgor Ostapenko 	rule->opargs = *cur;
2778aaffd78SIgor Ostapenko 
2788aaffd78SIgor Ostapenko 	*cur = delim + 1;
2798aaffd78SIgor Ostapenko 
2808aaffd78SIgor Ostapenko 	return (true);
2818aaffd78SIgor Ostapenko }
2828aaffd78SIgor Ostapenko 
2838aaffd78SIgor Ostapenko static pfil_return_t
2848aaffd78SIgor Ostapenko dmb_pfil_mbuf_chk(int pfil_type, struct mbuf **mp, struct ifnet *ifp,
2858aaffd78SIgor Ostapenko     int flags, void *ruleset, void *unused)
2868aaffd78SIgor Ostapenko {
2878aaffd78SIgor Ostapenko 	struct mbuf *m = *mp;
2888aaffd78SIgor Ostapenko 	const char *cursor;
2898aaffd78SIgor Ostapenko 	bool parsed;
2908aaffd78SIgor Ostapenko 	struct rule rule;
2918aaffd78SIgor Ostapenko 
2928aaffd78SIgor Ostapenko 	DMB_RULES_SLOCK();
2938aaffd78SIgor Ostapenko 	cursor = V_dmb_rules;
2948aaffd78SIgor Ostapenko 	while ((parsed = read_rule(&cursor, &rule))) {
2958aaffd78SIgor Ostapenko 		if (rule.pfil_type == pfil_type &&
2968aaffd78SIgor Ostapenko 		    rule.pfil_dir == (flags & rule.pfil_dir)  &&
2978aaffd78SIgor Ostapenko 		    strcmp(rule.ifname, ifp->if_xname) == 0) {
2988aaffd78SIgor Ostapenko 			m = rule.op(m, &rule);
2998aaffd78SIgor Ostapenko 			if (m == NULL) {
3008aaffd78SIgor Ostapenko 				FEEDBACK(pfil_type, flags, ifp, rule,
3018aaffd78SIgor Ostapenko 				    "mbuf operation failed");
3028aaffd78SIgor Ostapenko 				break;
3038aaffd78SIgor Ostapenko 			}
3048aaffd78SIgor Ostapenko 			counter_u64_add(V_dmb_hits, 1);
3058aaffd78SIgor Ostapenko 		}
3068aaffd78SIgor Ostapenko 		if (strlen(cursor) == 0)
3078aaffd78SIgor Ostapenko 			break;
3088aaffd78SIgor Ostapenko 	}
3098aaffd78SIgor Ostapenko 	if (!parsed) {
3108aaffd78SIgor Ostapenko 		FEEDBACK(pfil_type, flags, ifp, rule, "rule parsing failed");
3118aaffd78SIgor Ostapenko 		m_freem(m);
3128aaffd78SIgor Ostapenko 		m = NULL;
3138aaffd78SIgor Ostapenko 	}
3148aaffd78SIgor Ostapenko 	DMB_RULES_SUNLOCK();
3158aaffd78SIgor Ostapenko 
3168aaffd78SIgor Ostapenko 	if (m == NULL) {
3178aaffd78SIgor Ostapenko 		*mp = NULL;
3188aaffd78SIgor Ostapenko 		return (PFIL_DROPPED);
3198aaffd78SIgor Ostapenko 	}
3208aaffd78SIgor Ostapenko 	if (m != *mp) {
3218aaffd78SIgor Ostapenko 		*mp = m;
3228aaffd78SIgor Ostapenko 		return (PFIL_REALLOCED);
3238aaffd78SIgor Ostapenko 	}
3248aaffd78SIgor Ostapenko 
3258aaffd78SIgor Ostapenko 	return (PFIL_PASS);
3268aaffd78SIgor Ostapenko }
3278aaffd78SIgor Ostapenko 
328*aa72c5baSGleb Smirnoff #ifdef INET
3298aaffd78SIgor Ostapenko static pfil_return_t
3308aaffd78SIgor Ostapenko dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
3318aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
3328aaffd78SIgor Ostapenko {
3338aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP4, mp, ifp, flags,
3348aaffd78SIgor Ostapenko 	    ruleset, inp));
3358aaffd78SIgor Ostapenko }
336*aa72c5baSGleb Smirnoff #endif
3378aaffd78SIgor Ostapenko 
338*aa72c5baSGleb Smirnoff #ifdef INET6
3398aaffd78SIgor Ostapenko static pfil_return_t
3408aaffd78SIgor Ostapenko dmb_pfil_inet6_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
3418aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
3428aaffd78SIgor Ostapenko {
3438aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP6, mp, ifp, flags,
3448aaffd78SIgor Ostapenko 	    ruleset, inp));
3458aaffd78SIgor Ostapenko }
346*aa72c5baSGleb Smirnoff #endif
3478aaffd78SIgor Ostapenko 
3488aaffd78SIgor Ostapenko static pfil_return_t
3498aaffd78SIgor Ostapenko dmb_pfil_ethernet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
3508aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
3518aaffd78SIgor Ostapenko {
3528aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_ETHERNET, mp, ifp, flags,
3538aaffd78SIgor Ostapenko 	    ruleset, inp));
3548aaffd78SIgor Ostapenko }
3558aaffd78SIgor Ostapenko 
3568aaffd78SIgor Ostapenko static void
3578aaffd78SIgor Ostapenko dmb_pfil_init(void)
3588aaffd78SIgor Ostapenko {
3598aaffd78SIgor Ostapenko 	struct pfil_hook_args pha = {
3608aaffd78SIgor Ostapenko 		.pa_version = PFIL_VERSION,
3618aaffd78SIgor Ostapenko 		.pa_modname = "dummymbuf",
3628aaffd78SIgor Ostapenko 		.pa_flags = PFIL_IN | PFIL_OUT,
3638aaffd78SIgor Ostapenko 	};
3648aaffd78SIgor Ostapenko 
3658aaffd78SIgor Ostapenko #ifdef INET
3668aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_IP4;
3678aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_inet_mbuf_chk;
3688aaffd78SIgor Ostapenko 	pha.pa_rulname = "inet";
3698aaffd78SIgor Ostapenko 	V_dmb_pfil_inet_hook = pfil_add_hook(&pha);
3708aaffd78SIgor Ostapenko #endif
3718aaffd78SIgor Ostapenko 
3728aaffd78SIgor Ostapenko #ifdef INET6
3738aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_IP6;
3748aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_inet6_mbuf_chk;
3758aaffd78SIgor Ostapenko 	pha.pa_rulname = "inet6";
3768aaffd78SIgor Ostapenko 	V_dmb_pfil_inet6_hook = pfil_add_hook(&pha);
3778aaffd78SIgor Ostapenko #endif
3788aaffd78SIgor Ostapenko 
3798aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_ETHERNET;
3808aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_ethernet_mbuf_chk;
3818aaffd78SIgor Ostapenko 	pha.pa_rulname = "ethernet";
3828aaffd78SIgor Ostapenko 	V_dmb_pfil_ethernet_hook = pfil_add_hook(&pha);
3838aaffd78SIgor Ostapenko }
3848aaffd78SIgor Ostapenko 
3858aaffd78SIgor Ostapenko static void
3868aaffd78SIgor Ostapenko dmb_pfil_uninit(void)
3878aaffd78SIgor Ostapenko {
3888aaffd78SIgor Ostapenko #ifdef INET
3898aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_inet_hook);
3908aaffd78SIgor Ostapenko #endif
3918aaffd78SIgor Ostapenko 
3928aaffd78SIgor Ostapenko #ifdef INET6
3938aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_inet6_hook);
3948aaffd78SIgor Ostapenko #endif
3958aaffd78SIgor Ostapenko 
3968aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_ethernet_hook);
3978aaffd78SIgor Ostapenko }
3988aaffd78SIgor Ostapenko 
3998aaffd78SIgor Ostapenko static void
4008aaffd78SIgor Ostapenko vnet_dmb_init(void *unused __unused)
4018aaffd78SIgor Ostapenko {
4028aaffd78SIgor Ostapenko 	sx_init(&V_dmb_rules_lock, "dummymbuf rules");
4038aaffd78SIgor Ostapenko 	V_dmb_hits = counter_u64_alloc(M_WAITOK);
4048aaffd78SIgor Ostapenko 	dmb_pfil_init();
4058aaffd78SIgor Ostapenko }
4068aaffd78SIgor Ostapenko VNET_SYSINIT(vnet_dmb_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
4078aaffd78SIgor Ostapenko     vnet_dmb_init, NULL);
4088aaffd78SIgor Ostapenko 
4098aaffd78SIgor Ostapenko static void
4108aaffd78SIgor Ostapenko vnet_dmb_uninit(void *unused __unused)
4118aaffd78SIgor Ostapenko {
4128aaffd78SIgor Ostapenko 	dmb_pfil_uninit();
4138aaffd78SIgor Ostapenko 	counter_u64_free(V_dmb_hits);
4148aaffd78SIgor Ostapenko 	sx_destroy(&V_dmb_rules_lock);
4158aaffd78SIgor Ostapenko 	free(V_dmb_rules, M_DUMMYMBUF_RULES);
4168aaffd78SIgor Ostapenko }
4178aaffd78SIgor Ostapenko VNET_SYSUNINIT(vnet_dmb_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
4188aaffd78SIgor Ostapenko     vnet_dmb_uninit, NULL);
4198aaffd78SIgor Ostapenko 
4208aaffd78SIgor Ostapenko static int
4218aaffd78SIgor Ostapenko dmb_modevent(module_t mod __unused, int event, void *arg __unused)
4228aaffd78SIgor Ostapenko {
4238aaffd78SIgor Ostapenko 	int error = 0;
4248aaffd78SIgor Ostapenko 
4258aaffd78SIgor Ostapenko 	switch (event) {
4268aaffd78SIgor Ostapenko 	case MOD_LOAD:
4278aaffd78SIgor Ostapenko 	case MOD_UNLOAD:
4288aaffd78SIgor Ostapenko 		break;
4298aaffd78SIgor Ostapenko 	default:
4308aaffd78SIgor Ostapenko 		error = EOPNOTSUPP;
4318aaffd78SIgor Ostapenko 		break;
4328aaffd78SIgor Ostapenko 	}
4338aaffd78SIgor Ostapenko 
4348aaffd78SIgor Ostapenko 	return (error);
4358aaffd78SIgor Ostapenko }
4368aaffd78SIgor Ostapenko 
4378aaffd78SIgor Ostapenko static moduledata_t dmb_mod = {
4388aaffd78SIgor Ostapenko 	"dummymbuf",
4398aaffd78SIgor Ostapenko 	dmb_modevent,
4408aaffd78SIgor Ostapenko 	NULL
4418aaffd78SIgor Ostapenko };
4428aaffd78SIgor Ostapenko 
4438aaffd78SIgor Ostapenko DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY);
4448aaffd78SIgor Ostapenko MODULE_VERSION(dummymbuf, 1);
445