xref: /freebsd/sys/net/dummymbuf.c (revision 8aaffd78c0f517985c12fd1e3cbceeb6c6b98ef5)
1*8aaffd78SIgor Ostapenko /*-
2*8aaffd78SIgor Ostapenko  * SPDX-License-Identifier: BSD-2-Clause
3*8aaffd78SIgor Ostapenko  *
4*8aaffd78SIgor Ostapenko  * Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
5*8aaffd78SIgor Ostapenko  *
6*8aaffd78SIgor Ostapenko  * Redistribution and use in source and binary forms, with or without
7*8aaffd78SIgor Ostapenko  * modification, are permitted provided that the following conditions
8*8aaffd78SIgor Ostapenko  * are met:
9*8aaffd78SIgor Ostapenko  * 1. Redistributions of source code must retain the above copyright
10*8aaffd78SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer.
11*8aaffd78SIgor Ostapenko  * 2. Redistributions in binary form must reproduce the above copyright
12*8aaffd78SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer in the
13*8aaffd78SIgor Ostapenko  *    documentation and/or other materials provided with the distribution.
14*8aaffd78SIgor Ostapenko  *
15*8aaffd78SIgor Ostapenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*8aaffd78SIgor Ostapenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*8aaffd78SIgor Ostapenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*8aaffd78SIgor Ostapenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*8aaffd78SIgor Ostapenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*8aaffd78SIgor Ostapenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*8aaffd78SIgor Ostapenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*8aaffd78SIgor Ostapenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*8aaffd78SIgor Ostapenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*8aaffd78SIgor Ostapenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*8aaffd78SIgor Ostapenko  * SUCH DAMAGE.
26*8aaffd78SIgor Ostapenko  */
27*8aaffd78SIgor Ostapenko 
28*8aaffd78SIgor Ostapenko #include "opt_inet.h"
29*8aaffd78SIgor Ostapenko #include "opt_inet6.h"
30*8aaffd78SIgor Ostapenko 
31*8aaffd78SIgor Ostapenko #include <sys/param.h>
32*8aaffd78SIgor Ostapenko #include <sys/kernel.h>
33*8aaffd78SIgor Ostapenko #include <sys/mbuf.h>
34*8aaffd78SIgor Ostapenko #include <sys/module.h>
35*8aaffd78SIgor Ostapenko #include <sys/socket.h>
36*8aaffd78SIgor Ostapenko #include <sys/sysctl.h>
37*8aaffd78SIgor Ostapenko 
38*8aaffd78SIgor Ostapenko #include <net/if.h>
39*8aaffd78SIgor Ostapenko #include <net/if_var.h>
40*8aaffd78SIgor Ostapenko #include <net/vnet.h>
41*8aaffd78SIgor Ostapenko #include <net/pfil.h>
42*8aaffd78SIgor Ostapenko 
43*8aaffd78SIgor Ostapenko /*
44*8aaffd78SIgor Ostapenko  * Separate sysctl sub-tree
45*8aaffd78SIgor Ostapenko  */
46*8aaffd78SIgor Ostapenko 
47*8aaffd78SIgor Ostapenko SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL,
48*8aaffd78SIgor Ostapenko     "Dummy mbuf sysctl");
49*8aaffd78SIgor Ostapenko 
50*8aaffd78SIgor Ostapenko /*
51*8aaffd78SIgor Ostapenko  * Rules
52*8aaffd78SIgor Ostapenko  */
53*8aaffd78SIgor Ostapenko 
54*8aaffd78SIgor Ostapenko static MALLOC_DEFINE(M_DUMMYMBUF_RULES, "dummymbuf_rules",
55*8aaffd78SIgor Ostapenko     "dummymbuf rules string buffer");
56*8aaffd78SIgor Ostapenko 
57*8aaffd78SIgor Ostapenko #define RULES_MAXLEN		1024
58*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(char *,	dmb_rules) = NULL;
59*8aaffd78SIgor Ostapenko #define V_dmb_rules		VNET(dmb_rules)
60*8aaffd78SIgor Ostapenko 
61*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(struct sx,	dmb_rules_lock);
62*8aaffd78SIgor Ostapenko #define V_dmb_rules_lock	VNET(dmb_rules_lock)
63*8aaffd78SIgor Ostapenko 
64*8aaffd78SIgor Ostapenko #define DMB_RULES_SLOCK()	sx_slock(&V_dmb_rules_lock)
65*8aaffd78SIgor Ostapenko #define DMB_RULES_SUNLOCK()	sx_sunlock(&V_dmb_rules_lock)
66*8aaffd78SIgor Ostapenko #define DMB_RULES_XLOCK()	sx_xlock(&V_dmb_rules_lock)
67*8aaffd78SIgor Ostapenko #define DMB_RULES_XUNLOCK()	sx_xunlock(&V_dmb_rules_lock)
68*8aaffd78SIgor Ostapenko 
69*8aaffd78SIgor Ostapenko static int
70*8aaffd78SIgor Ostapenko dmb_sysctl_handle_rules(SYSCTL_HANDLER_ARGS)
71*8aaffd78SIgor Ostapenko {
72*8aaffd78SIgor Ostapenko 	int error = 0;
73*8aaffd78SIgor Ostapenko 	char empty = '\0';
74*8aaffd78SIgor Ostapenko 	char **rulesp = (char **)arg1;
75*8aaffd78SIgor Ostapenko 
76*8aaffd78SIgor Ostapenko 	if (req->newptr == NULL) {
77*8aaffd78SIgor Ostapenko 		// read only
78*8aaffd78SIgor Ostapenko 		DMB_RULES_SLOCK();
79*8aaffd78SIgor Ostapenko 		arg1 = *rulesp;
80*8aaffd78SIgor Ostapenko 		if (arg1 == NULL) {
81*8aaffd78SIgor Ostapenko 			arg1 = &empty;
82*8aaffd78SIgor Ostapenko 			arg2 = 0;
83*8aaffd78SIgor Ostapenko 		}
84*8aaffd78SIgor Ostapenko 		error = sysctl_handle_string(oidp, arg1, arg2, req);
85*8aaffd78SIgor Ostapenko 		DMB_RULES_SUNLOCK();
86*8aaffd78SIgor Ostapenko 	} else {
87*8aaffd78SIgor Ostapenko 		// read and write
88*8aaffd78SIgor Ostapenko 		DMB_RULES_XLOCK();
89*8aaffd78SIgor Ostapenko 		if (*rulesp == NULL)
90*8aaffd78SIgor Ostapenko 			*rulesp = malloc(arg2, M_DUMMYMBUF_RULES, M_WAITOK);
91*8aaffd78SIgor Ostapenko 		arg1 = *rulesp;
92*8aaffd78SIgor Ostapenko 		error = sysctl_handle_string(oidp, arg1, arg2, req);
93*8aaffd78SIgor Ostapenko 		DMB_RULES_XUNLOCK();
94*8aaffd78SIgor Ostapenko 	}
95*8aaffd78SIgor Ostapenko 
96*8aaffd78SIgor Ostapenko 	return (error);
97*8aaffd78SIgor Ostapenko }
98*8aaffd78SIgor Ostapenko 
99*8aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, rules,
100*8aaffd78SIgor Ostapenko     CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_VNET,
101*8aaffd78SIgor Ostapenko     &VNET_NAME(dmb_rules), RULES_MAXLEN, dmb_sysctl_handle_rules, "A",
102*8aaffd78SIgor Ostapenko     "{inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];"
103*8aaffd78SIgor Ostapenko     " ...;");
104*8aaffd78SIgor Ostapenko 
105*8aaffd78SIgor Ostapenko /*
106*8aaffd78SIgor Ostapenko  * Statistics
107*8aaffd78SIgor Ostapenko  */
108*8aaffd78SIgor Ostapenko 
109*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(counter_u64_t,	dmb_hits);
110*8aaffd78SIgor Ostapenko #define V_dmb_hits			VNET(dmb_hits)
111*8aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits,
112*8aaffd78SIgor Ostapenko     CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET,
113*8aaffd78SIgor Ostapenko     &VNET_NAME(dmb_hits), 0, sysctl_handle_counter_u64,
114*8aaffd78SIgor Ostapenko     "QU", "Number of times a rule has been applied");
115*8aaffd78SIgor Ostapenko 
116*8aaffd78SIgor Ostapenko /*
117*8aaffd78SIgor Ostapenko  * pfil(9) context
118*8aaffd78SIgor Ostapenko  */
119*8aaffd78SIgor Ostapenko 
120*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_inet_hook);
121*8aaffd78SIgor Ostapenko #define V_dmb_pfil_inet_hook		VNET(dmb_pfil_inet_hook)
122*8aaffd78SIgor Ostapenko 
123*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_inet6_hook);
124*8aaffd78SIgor Ostapenko #define V_dmb_pfil_inet6_hook		VNET(dmb_pfil_inet6_hook)
125*8aaffd78SIgor Ostapenko 
126*8aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t,		dmb_pfil_ethernet_hook);
127*8aaffd78SIgor Ostapenko #define V_dmb_pfil_ethernet_hook	VNET(dmb_pfil_ethernet_hook)
128*8aaffd78SIgor Ostapenko 
129*8aaffd78SIgor Ostapenko /*
130*8aaffd78SIgor Ostapenko  * Logging
131*8aaffd78SIgor Ostapenko  */
132*8aaffd78SIgor Ostapenko 
133*8aaffd78SIgor Ostapenko #define FEEDBACK(pfil_type, pfil_flags, ifp, rule, msg)			\
134*8aaffd78SIgor Ostapenko 	printf("dummymbuf: %s %b %s: %s: %.*s\n",			\
135*8aaffd78SIgor Ostapenko 	    (pfil_type == PFIL_TYPE_IP4 ?	"PFIL_TYPE_IP4" :	\
136*8aaffd78SIgor Ostapenko 	     pfil_type == PFIL_TYPE_IP6 ?	"PFIL_TYPE_IP6" :	\
137*8aaffd78SIgor Ostapenko 	     pfil_type == PFIL_TYPE_ETHERNET ?	"PFIL_TYPE_ETHERNET" :	\
138*8aaffd78SIgor Ostapenko 						"PFIL_TYPE_UNKNOWN"),	\
139*8aaffd78SIgor Ostapenko 	    (pfil_flags), "\20\21PFIL_IN\22PFIL_OUT",			\
140*8aaffd78SIgor Ostapenko 	    (ifp)->if_xname,						\
141*8aaffd78SIgor Ostapenko 	    (msg),							\
142*8aaffd78SIgor Ostapenko 	    (rule).syntax_len, (rule).syntax_begin			\
143*8aaffd78SIgor Ostapenko 	)
144*8aaffd78SIgor Ostapenko 
145*8aaffd78SIgor Ostapenko /*
146*8aaffd78SIgor Ostapenko  * Internals
147*8aaffd78SIgor Ostapenko  */
148*8aaffd78SIgor Ostapenko 
149*8aaffd78SIgor Ostapenko struct rule;
150*8aaffd78SIgor Ostapenko typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *);
151*8aaffd78SIgor Ostapenko struct rule {
152*8aaffd78SIgor Ostapenko 	const char	*syntax_begin;
153*8aaffd78SIgor Ostapenko 	int		 syntax_len;
154*8aaffd78SIgor Ostapenko 	int		 pfil_type;
155*8aaffd78SIgor Ostapenko 	int		 pfil_dir;
156*8aaffd78SIgor Ostapenko 	char		 ifname[IFNAMSIZ];
157*8aaffd78SIgor Ostapenko 	op_t		 op;
158*8aaffd78SIgor Ostapenko 	const char	*opargs;
159*8aaffd78SIgor Ostapenko };
160*8aaffd78SIgor Ostapenko 
161*8aaffd78SIgor Ostapenko static struct mbuf *
162*8aaffd78SIgor Ostapenko dmb_m_pull_head(struct mbuf *m, struct rule *rule)
163*8aaffd78SIgor Ostapenko {
164*8aaffd78SIgor Ostapenko 	struct mbuf *n;
165*8aaffd78SIgor Ostapenko 	int count;
166*8aaffd78SIgor Ostapenko 
167*8aaffd78SIgor Ostapenko 	count = (int)strtol(rule->opargs, NULL, 10);
168*8aaffd78SIgor Ostapenko 	if (count < 0 || count > MCLBYTES)
169*8aaffd78SIgor Ostapenko 		goto bad;
170*8aaffd78SIgor Ostapenko 
171*8aaffd78SIgor Ostapenko 	if (!(m->m_flags & M_PKTHDR))
172*8aaffd78SIgor Ostapenko 		goto bad;
173*8aaffd78SIgor Ostapenko 	if (m->m_pkthdr.len <= 0)
174*8aaffd78SIgor Ostapenko 		return (m);
175*8aaffd78SIgor Ostapenko 	if (count > m->m_pkthdr.len)
176*8aaffd78SIgor Ostapenko 		count = m->m_pkthdr.len;
177*8aaffd78SIgor Ostapenko 
178*8aaffd78SIgor Ostapenko 	if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL)
179*8aaffd78SIgor Ostapenko 		goto bad;
180*8aaffd78SIgor Ostapenko 
181*8aaffd78SIgor Ostapenko 	m_move_pkthdr(n, m);
182*8aaffd78SIgor Ostapenko 	m_copydata(m, 0, count, n->m_ext.ext_buf);
183*8aaffd78SIgor Ostapenko 	n->m_len = count;
184*8aaffd78SIgor Ostapenko 
185*8aaffd78SIgor Ostapenko 	m_adj(m, count);
186*8aaffd78SIgor Ostapenko 	n->m_next = m;
187*8aaffd78SIgor Ostapenko 
188*8aaffd78SIgor Ostapenko 	return (n);
189*8aaffd78SIgor Ostapenko 
190*8aaffd78SIgor Ostapenko bad:
191*8aaffd78SIgor Ostapenko 	m_freem(m);
192*8aaffd78SIgor Ostapenko 	return (NULL);
193*8aaffd78SIgor Ostapenko }
194*8aaffd78SIgor Ostapenko 
195*8aaffd78SIgor Ostapenko static bool
196*8aaffd78SIgor Ostapenko read_rule(const char **cur, struct rule *rule)
197*8aaffd78SIgor Ostapenko {
198*8aaffd78SIgor Ostapenko 	// {inet | inet6 | ethernet} {in | out} <ifname> <opname>[ <opargs>];
199*8aaffd78SIgor Ostapenko 
200*8aaffd78SIgor Ostapenko 	rule->syntax_begin = NULL;
201*8aaffd78SIgor Ostapenko 	rule->syntax_len = 0;
202*8aaffd78SIgor Ostapenko 
203*8aaffd78SIgor Ostapenko 	if (*cur == NULL)
204*8aaffd78SIgor Ostapenko 		return (false);
205*8aaffd78SIgor Ostapenko 
206*8aaffd78SIgor Ostapenko 	// syntax_begin
207*8aaffd78SIgor Ostapenko 	while (**cur == ' ')
208*8aaffd78SIgor Ostapenko 		(*cur)++;
209*8aaffd78SIgor Ostapenko 	rule->syntax_begin = *cur;
210*8aaffd78SIgor Ostapenko 
211*8aaffd78SIgor Ostapenko 	// syntax_len
212*8aaffd78SIgor Ostapenko 	char *delim = strchr(*cur, ';');
213*8aaffd78SIgor Ostapenko 	if (delim == NULL)
214*8aaffd78SIgor Ostapenko 		return (false);
215*8aaffd78SIgor Ostapenko 	rule->syntax_len = (int)(delim - *cur + 1);
216*8aaffd78SIgor Ostapenko 
217*8aaffd78SIgor Ostapenko 	// pfil_type
218*8aaffd78SIgor Ostapenko 	if (strstr(*cur, "inet6") == *cur) {
219*8aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_IP6;
220*8aaffd78SIgor Ostapenko 		*cur += strlen("inet6");
221*8aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "inet") == *cur) {
222*8aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_IP4;
223*8aaffd78SIgor Ostapenko 		*cur += strlen("inet");
224*8aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "ethernet")) {
225*8aaffd78SIgor Ostapenko 		rule->pfil_type = PFIL_TYPE_ETHERNET;
226*8aaffd78SIgor Ostapenko 		*cur += strlen("ethernet");
227*8aaffd78SIgor Ostapenko 	} else {
228*8aaffd78SIgor Ostapenko 		return (false);
229*8aaffd78SIgor Ostapenko 	}
230*8aaffd78SIgor Ostapenko 	while (**cur == ' ')
231*8aaffd78SIgor Ostapenko 		(*cur)++;
232*8aaffd78SIgor Ostapenko 
233*8aaffd78SIgor Ostapenko 	// pfil_dir
234*8aaffd78SIgor Ostapenko 	if (strstr(*cur, "in") == *cur) {
235*8aaffd78SIgor Ostapenko 		rule->pfil_dir = PFIL_IN;
236*8aaffd78SIgor Ostapenko 		*cur += strlen("in");
237*8aaffd78SIgor Ostapenko 	} else if (strstr(*cur, "out") == *cur) {
238*8aaffd78SIgor Ostapenko 		rule->pfil_dir = PFIL_OUT;
239*8aaffd78SIgor Ostapenko 		*cur += strlen("out");
240*8aaffd78SIgor Ostapenko 	} else {
241*8aaffd78SIgor Ostapenko 		return (false);
242*8aaffd78SIgor Ostapenko 	}
243*8aaffd78SIgor Ostapenko 	while (**cur == ' ')
244*8aaffd78SIgor Ostapenko 		(*cur)++;
245*8aaffd78SIgor Ostapenko 
246*8aaffd78SIgor Ostapenko 	// ifname
247*8aaffd78SIgor Ostapenko 	char *sp = strchr(*cur, ' ');
248*8aaffd78SIgor Ostapenko 	if (sp == NULL || sp > delim)
249*8aaffd78SIgor Ostapenko 		return (false);
250*8aaffd78SIgor Ostapenko 	size_t len = sp - *cur;
251*8aaffd78SIgor Ostapenko 	if (len >= sizeof(rule->ifname))
252*8aaffd78SIgor Ostapenko 		return (false);
253*8aaffd78SIgor Ostapenko 	strncpy(rule->ifname, *cur, len);
254*8aaffd78SIgor Ostapenko 	rule->ifname[len] = 0;
255*8aaffd78SIgor Ostapenko 	*cur = sp;
256*8aaffd78SIgor Ostapenko 	while (**cur == ' ')
257*8aaffd78SIgor Ostapenko 		(*cur)++;
258*8aaffd78SIgor Ostapenko 
259*8aaffd78SIgor Ostapenko 	// opname
260*8aaffd78SIgor Ostapenko 	if (strstr(*cur, "pull-head") == *cur) {
261*8aaffd78SIgor Ostapenko 		rule->op = dmb_m_pull_head;
262*8aaffd78SIgor Ostapenko 		*cur += strlen("pull-head");
263*8aaffd78SIgor Ostapenko 	} else {
264*8aaffd78SIgor Ostapenko 		return (false);
265*8aaffd78SIgor Ostapenko 	}
266*8aaffd78SIgor Ostapenko 	while (**cur == ' ')
267*8aaffd78SIgor Ostapenko 		(*cur)++;
268*8aaffd78SIgor Ostapenko 
269*8aaffd78SIgor Ostapenko 	// opargs
270*8aaffd78SIgor Ostapenko 	if (*cur > delim)
271*8aaffd78SIgor Ostapenko 		return (false);
272*8aaffd78SIgor Ostapenko 	rule->opargs = *cur;
273*8aaffd78SIgor Ostapenko 
274*8aaffd78SIgor Ostapenko 	*cur = delim + 1;
275*8aaffd78SIgor Ostapenko 
276*8aaffd78SIgor Ostapenko 	return (true);
277*8aaffd78SIgor Ostapenko }
278*8aaffd78SIgor Ostapenko 
279*8aaffd78SIgor Ostapenko static pfil_return_t
280*8aaffd78SIgor Ostapenko dmb_pfil_mbuf_chk(int pfil_type, struct mbuf **mp, struct ifnet *ifp,
281*8aaffd78SIgor Ostapenko     int flags, void *ruleset, void *unused)
282*8aaffd78SIgor Ostapenko {
283*8aaffd78SIgor Ostapenko 	struct mbuf *m = *mp;
284*8aaffd78SIgor Ostapenko 	const char *cursor;
285*8aaffd78SIgor Ostapenko 	bool parsed;
286*8aaffd78SIgor Ostapenko 	struct rule rule;
287*8aaffd78SIgor Ostapenko 
288*8aaffd78SIgor Ostapenko 	DMB_RULES_SLOCK();
289*8aaffd78SIgor Ostapenko 	cursor = V_dmb_rules;
290*8aaffd78SIgor Ostapenko 	while ((parsed = read_rule(&cursor, &rule))) {
291*8aaffd78SIgor Ostapenko 		if (rule.pfil_type == pfil_type &&
292*8aaffd78SIgor Ostapenko 		    rule.pfil_dir == (flags & rule.pfil_dir)  &&
293*8aaffd78SIgor Ostapenko 		    strcmp(rule.ifname, ifp->if_xname) == 0) {
294*8aaffd78SIgor Ostapenko 			m = rule.op(m, &rule);
295*8aaffd78SIgor Ostapenko 			if (m == NULL) {
296*8aaffd78SIgor Ostapenko 				FEEDBACK(pfil_type, flags, ifp, rule,
297*8aaffd78SIgor Ostapenko 				    "mbuf operation failed");
298*8aaffd78SIgor Ostapenko 				break;
299*8aaffd78SIgor Ostapenko 			}
300*8aaffd78SIgor Ostapenko 			counter_u64_add(V_dmb_hits, 1);
301*8aaffd78SIgor Ostapenko 		}
302*8aaffd78SIgor Ostapenko 		if (strlen(cursor) == 0)
303*8aaffd78SIgor Ostapenko 			break;
304*8aaffd78SIgor Ostapenko 	}
305*8aaffd78SIgor Ostapenko 	if (!parsed) {
306*8aaffd78SIgor Ostapenko 		FEEDBACK(pfil_type, flags, ifp, rule, "rule parsing failed");
307*8aaffd78SIgor Ostapenko 		m_freem(m);
308*8aaffd78SIgor Ostapenko 		m = NULL;
309*8aaffd78SIgor Ostapenko 	}
310*8aaffd78SIgor Ostapenko 	DMB_RULES_SUNLOCK();
311*8aaffd78SIgor Ostapenko 
312*8aaffd78SIgor Ostapenko 	if (m == NULL) {
313*8aaffd78SIgor Ostapenko 		*mp = NULL;
314*8aaffd78SIgor Ostapenko 		return (PFIL_DROPPED);
315*8aaffd78SIgor Ostapenko 	}
316*8aaffd78SIgor Ostapenko 	if (m != *mp) {
317*8aaffd78SIgor Ostapenko 		*mp = m;
318*8aaffd78SIgor Ostapenko 		return (PFIL_REALLOCED);
319*8aaffd78SIgor Ostapenko 	}
320*8aaffd78SIgor Ostapenko 
321*8aaffd78SIgor Ostapenko 	return (PFIL_PASS);
322*8aaffd78SIgor Ostapenko }
323*8aaffd78SIgor Ostapenko 
324*8aaffd78SIgor Ostapenko static pfil_return_t
325*8aaffd78SIgor Ostapenko dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
326*8aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
327*8aaffd78SIgor Ostapenko {
328*8aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP4, mp, ifp, flags,
329*8aaffd78SIgor Ostapenko 	    ruleset, inp));
330*8aaffd78SIgor Ostapenko }
331*8aaffd78SIgor Ostapenko 
332*8aaffd78SIgor Ostapenko static pfil_return_t
333*8aaffd78SIgor Ostapenko dmb_pfil_inet6_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
334*8aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
335*8aaffd78SIgor Ostapenko {
336*8aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP6, mp, ifp, flags,
337*8aaffd78SIgor Ostapenko 	    ruleset, inp));
338*8aaffd78SIgor Ostapenko }
339*8aaffd78SIgor Ostapenko 
340*8aaffd78SIgor Ostapenko static pfil_return_t
341*8aaffd78SIgor Ostapenko dmb_pfil_ethernet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
342*8aaffd78SIgor Ostapenko     void *ruleset, struct inpcb *inp)
343*8aaffd78SIgor Ostapenko {
344*8aaffd78SIgor Ostapenko 	return (dmb_pfil_mbuf_chk(PFIL_TYPE_ETHERNET, mp, ifp, flags,
345*8aaffd78SIgor Ostapenko 	    ruleset, inp));
346*8aaffd78SIgor Ostapenko }
347*8aaffd78SIgor Ostapenko 
348*8aaffd78SIgor Ostapenko static void
349*8aaffd78SIgor Ostapenko dmb_pfil_init(void)
350*8aaffd78SIgor Ostapenko {
351*8aaffd78SIgor Ostapenko 	struct pfil_hook_args pha = {
352*8aaffd78SIgor Ostapenko 		.pa_version = PFIL_VERSION,
353*8aaffd78SIgor Ostapenko 		.pa_modname = "dummymbuf",
354*8aaffd78SIgor Ostapenko 		.pa_flags = PFIL_IN | PFIL_OUT,
355*8aaffd78SIgor Ostapenko 	};
356*8aaffd78SIgor Ostapenko 
357*8aaffd78SIgor Ostapenko #ifdef INET
358*8aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_IP4;
359*8aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_inet_mbuf_chk;
360*8aaffd78SIgor Ostapenko 	pha.pa_rulname = "inet";
361*8aaffd78SIgor Ostapenko 	V_dmb_pfil_inet_hook = pfil_add_hook(&pha);
362*8aaffd78SIgor Ostapenko #endif
363*8aaffd78SIgor Ostapenko 
364*8aaffd78SIgor Ostapenko #ifdef INET6
365*8aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_IP6;
366*8aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_inet6_mbuf_chk;
367*8aaffd78SIgor Ostapenko 	pha.pa_rulname = "inet6";
368*8aaffd78SIgor Ostapenko 	V_dmb_pfil_inet6_hook = pfil_add_hook(&pha);
369*8aaffd78SIgor Ostapenko #endif
370*8aaffd78SIgor Ostapenko 
371*8aaffd78SIgor Ostapenko 	pha.pa_type = PFIL_TYPE_ETHERNET;
372*8aaffd78SIgor Ostapenko 	pha.pa_mbuf_chk = dmb_pfil_ethernet_mbuf_chk;
373*8aaffd78SIgor Ostapenko 	pha.pa_rulname = "ethernet";
374*8aaffd78SIgor Ostapenko 	V_dmb_pfil_ethernet_hook = pfil_add_hook(&pha);
375*8aaffd78SIgor Ostapenko }
376*8aaffd78SIgor Ostapenko 
377*8aaffd78SIgor Ostapenko static void
378*8aaffd78SIgor Ostapenko dmb_pfil_uninit(void)
379*8aaffd78SIgor Ostapenko {
380*8aaffd78SIgor Ostapenko #ifdef INET
381*8aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_inet_hook);
382*8aaffd78SIgor Ostapenko #endif
383*8aaffd78SIgor Ostapenko 
384*8aaffd78SIgor Ostapenko #ifdef INET6
385*8aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_inet6_hook);
386*8aaffd78SIgor Ostapenko #endif
387*8aaffd78SIgor Ostapenko 
388*8aaffd78SIgor Ostapenko 	pfil_remove_hook(V_dmb_pfil_ethernet_hook);
389*8aaffd78SIgor Ostapenko }
390*8aaffd78SIgor Ostapenko 
391*8aaffd78SIgor Ostapenko static void
392*8aaffd78SIgor Ostapenko vnet_dmb_init(void *unused __unused)
393*8aaffd78SIgor Ostapenko {
394*8aaffd78SIgor Ostapenko 	sx_init(&V_dmb_rules_lock, "dummymbuf rules");
395*8aaffd78SIgor Ostapenko 	V_dmb_hits = counter_u64_alloc(M_WAITOK);
396*8aaffd78SIgor Ostapenko 	dmb_pfil_init();
397*8aaffd78SIgor Ostapenko }
398*8aaffd78SIgor Ostapenko VNET_SYSINIT(vnet_dmb_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
399*8aaffd78SIgor Ostapenko     vnet_dmb_init, NULL);
400*8aaffd78SIgor Ostapenko 
401*8aaffd78SIgor Ostapenko static void
402*8aaffd78SIgor Ostapenko vnet_dmb_uninit(void *unused __unused)
403*8aaffd78SIgor Ostapenko {
404*8aaffd78SIgor Ostapenko 	dmb_pfil_uninit();
405*8aaffd78SIgor Ostapenko 	counter_u64_free(V_dmb_hits);
406*8aaffd78SIgor Ostapenko 	sx_destroy(&V_dmb_rules_lock);
407*8aaffd78SIgor Ostapenko 	free(V_dmb_rules, M_DUMMYMBUF_RULES);
408*8aaffd78SIgor Ostapenko }
409*8aaffd78SIgor Ostapenko VNET_SYSUNINIT(vnet_dmb_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
410*8aaffd78SIgor Ostapenko     vnet_dmb_uninit, NULL);
411*8aaffd78SIgor Ostapenko 
412*8aaffd78SIgor Ostapenko static int
413*8aaffd78SIgor Ostapenko dmb_modevent(module_t mod __unused, int event, void *arg __unused)
414*8aaffd78SIgor Ostapenko {
415*8aaffd78SIgor Ostapenko 	int error = 0;
416*8aaffd78SIgor Ostapenko 
417*8aaffd78SIgor Ostapenko 	switch (event) {
418*8aaffd78SIgor Ostapenko 	case MOD_LOAD:
419*8aaffd78SIgor Ostapenko 	case MOD_UNLOAD:
420*8aaffd78SIgor Ostapenko 		break;
421*8aaffd78SIgor Ostapenko 	default:
422*8aaffd78SIgor Ostapenko 		error = EOPNOTSUPP;
423*8aaffd78SIgor Ostapenko 		break;
424*8aaffd78SIgor Ostapenko 	}
425*8aaffd78SIgor Ostapenko 
426*8aaffd78SIgor Ostapenko 	return (error);
427*8aaffd78SIgor Ostapenko }
428*8aaffd78SIgor Ostapenko 
429*8aaffd78SIgor Ostapenko static moduledata_t dmb_mod = {
430*8aaffd78SIgor Ostapenko 	"dummymbuf",
431*8aaffd78SIgor Ostapenko 	dmb_modevent,
432*8aaffd78SIgor Ostapenko 	NULL
433*8aaffd78SIgor Ostapenko };
434*8aaffd78SIgor Ostapenko 
435*8aaffd78SIgor Ostapenko DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY);
436*8aaffd78SIgor Ostapenko MODULE_VERSION(dummymbuf, 1);
437