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 = ∅ 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