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 439f146a81SIgor Ostapenko static int validate_rules(const char *); 449f146a81SIgor Ostapenko 458aaffd78SIgor Ostapenko /* 468aaffd78SIgor Ostapenko * Separate sysctl sub-tree 478aaffd78SIgor Ostapenko */ 488aaffd78SIgor Ostapenko 498aaffd78SIgor Ostapenko SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL, 508aaffd78SIgor Ostapenko "Dummy mbuf sysctl"); 518aaffd78SIgor Ostapenko 528aaffd78SIgor Ostapenko /* 538aaffd78SIgor Ostapenko * Rules 548aaffd78SIgor Ostapenko */ 558aaffd78SIgor Ostapenko 568aaffd78SIgor Ostapenko static MALLOC_DEFINE(M_DUMMYMBUF_RULES, "dummymbuf_rules", 578aaffd78SIgor Ostapenko "dummymbuf rules string buffer"); 588aaffd78SIgor Ostapenko 598aaffd78SIgor Ostapenko #define RULES_MAXLEN 1024 608aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(char *, dmb_rules) = NULL; 618aaffd78SIgor Ostapenko #define V_dmb_rules VNET(dmb_rules) 628aaffd78SIgor Ostapenko 638aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(struct sx, dmb_rules_lock); 648aaffd78SIgor Ostapenko #define V_dmb_rules_lock VNET(dmb_rules_lock) 658aaffd78SIgor Ostapenko 668aaffd78SIgor Ostapenko #define DMB_RULES_SLOCK() sx_slock(&V_dmb_rules_lock) 678aaffd78SIgor Ostapenko #define DMB_RULES_SUNLOCK() sx_sunlock(&V_dmb_rules_lock) 688aaffd78SIgor Ostapenko #define DMB_RULES_XLOCK() sx_xlock(&V_dmb_rules_lock) 698aaffd78SIgor Ostapenko #define DMB_RULES_XUNLOCK() sx_xunlock(&V_dmb_rules_lock) 709f146a81SIgor Ostapenko #define DMB_RULES_LOCK_ASSERT() sx_assert(&V_dmb_rules_lock, SA_LOCKED) 718aaffd78SIgor Ostapenko 728aaffd78SIgor Ostapenko static int 738aaffd78SIgor Ostapenko dmb_sysctl_handle_rules(SYSCTL_HANDLER_ARGS) 748aaffd78SIgor Ostapenko { 758aaffd78SIgor Ostapenko int error = 0; 768aaffd78SIgor Ostapenko char empty = '\0'; 778aaffd78SIgor Ostapenko char **rulesp = (char **)arg1; 788aaffd78SIgor Ostapenko 798aaffd78SIgor Ostapenko if (req->newptr == NULL) { 8061295e09SMark Johnston /* read only */ 818aaffd78SIgor Ostapenko DMB_RULES_SLOCK(); 828aaffd78SIgor Ostapenko arg1 = *rulesp; 838aaffd78SIgor Ostapenko if (arg1 == NULL) { 848aaffd78SIgor Ostapenko arg1 = ∅ 858aaffd78SIgor Ostapenko arg2 = 0; 868aaffd78SIgor Ostapenko } 878aaffd78SIgor Ostapenko error = sysctl_handle_string(oidp, arg1, arg2, req); 888aaffd78SIgor Ostapenko DMB_RULES_SUNLOCK(); 898aaffd78SIgor Ostapenko } else { 9061295e09SMark Johnston /* read and write */ 918aaffd78SIgor Ostapenko DMB_RULES_XLOCK(); 929f146a81SIgor Ostapenko arg1 = malloc(arg2, M_DUMMYMBUF_RULES, M_WAITOK | M_ZERO); 938aaffd78SIgor Ostapenko error = sysctl_handle_string(oidp, arg1, arg2, req); 949f146a81SIgor Ostapenko if (error == 0 && (error = validate_rules(arg1)) == 0) { 959f146a81SIgor Ostapenko free(*rulesp, M_DUMMYMBUF_RULES); 969f146a81SIgor Ostapenko *rulesp = arg1; 979f146a81SIgor Ostapenko arg1 = NULL; 989f146a81SIgor Ostapenko } 999f146a81SIgor Ostapenko free(arg1, M_DUMMYMBUF_RULES); 1008aaffd78SIgor Ostapenko DMB_RULES_XUNLOCK(); 1018aaffd78SIgor Ostapenko } 1028aaffd78SIgor Ostapenko 1038aaffd78SIgor Ostapenko return (error); 1048aaffd78SIgor Ostapenko } 1058aaffd78SIgor Ostapenko 1068aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, rules, 1078aaffd78SIgor Ostapenko CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW | CTLFLAG_VNET, 1088aaffd78SIgor Ostapenko &VNET_NAME(dmb_rules), RULES_MAXLEN, dmb_sysctl_handle_rules, "A", 10961295e09SMark Johnston "{inet|inet6|ethernet} {in|out} <ifname> <opname>[ <opargs>]; ...;"); 1108aaffd78SIgor Ostapenko 1118aaffd78SIgor Ostapenko /* 1128aaffd78SIgor Ostapenko * Statistics 1138aaffd78SIgor Ostapenko */ 1148aaffd78SIgor Ostapenko 1158aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(counter_u64_t, dmb_hits); 1168aaffd78SIgor Ostapenko #define V_dmb_hits VNET(dmb_hits) 1178aaffd78SIgor Ostapenko SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits, 1188aaffd78SIgor Ostapenko CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET, 1198aaffd78SIgor Ostapenko &VNET_NAME(dmb_hits), 0, sysctl_handle_counter_u64, 1208aaffd78SIgor Ostapenko "QU", "Number of times a rule has been applied"); 1218aaffd78SIgor Ostapenko 1228aaffd78SIgor Ostapenko /* 1238aaffd78SIgor Ostapenko * pfil(9) context 1248aaffd78SIgor Ostapenko */ 1258aaffd78SIgor Ostapenko 126aa72c5baSGleb Smirnoff #ifdef INET 1278aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet_hook); 1288aaffd78SIgor Ostapenko #define V_dmb_pfil_inet_hook VNET(dmb_pfil_inet_hook) 129aa72c5baSGleb Smirnoff #endif 1308aaffd78SIgor Ostapenko 131aa72c5baSGleb Smirnoff #ifdef INET6 1328aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet6_hook); 1338aaffd78SIgor Ostapenko #define V_dmb_pfil_inet6_hook VNET(dmb_pfil_inet6_hook) 134aa72c5baSGleb Smirnoff #endif 1358aaffd78SIgor Ostapenko 1368aaffd78SIgor Ostapenko VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_ethernet_hook); 1378aaffd78SIgor Ostapenko #define V_dmb_pfil_ethernet_hook VNET(dmb_pfil_ethernet_hook) 1388aaffd78SIgor Ostapenko 1398aaffd78SIgor Ostapenko /* 1408aaffd78SIgor Ostapenko * Logging 1418aaffd78SIgor Ostapenko */ 1428aaffd78SIgor Ostapenko 1439f146a81SIgor Ostapenko #define FEEDBACK_RULE(rule, msg) \ 1449f146a81SIgor Ostapenko printf("dummymbuf: %s: %.*s\n", \ 1459f146a81SIgor Ostapenko (msg), \ 1469f146a81SIgor Ostapenko (rule).syntax_len, (rule).syntax_begin \ 1479f146a81SIgor Ostapenko ) 1489f146a81SIgor Ostapenko 1499f146a81SIgor Ostapenko #define FEEDBACK_PFIL(pfil_type, pfil_flags, ifp, rule, msg) \ 1508aaffd78SIgor Ostapenko printf("dummymbuf: %s %b %s: %s: %.*s\n", \ 151*6bd8d855SIgor Ostapenko ((pfil_type) == PFIL_TYPE_IP4 ? "PFIL_TYPE_IP4" : \ 152*6bd8d855SIgor Ostapenko (pfil_type) == PFIL_TYPE_IP6 ? "PFIL_TYPE_IP6" : \ 153*6bd8d855SIgor Ostapenko (pfil_type) == PFIL_TYPE_ETHERNET ? "PFIL_TYPE_ETHERNET" : \ 1548aaffd78SIgor Ostapenko "PFIL_TYPE_UNKNOWN"), \ 1558aaffd78SIgor Ostapenko (pfil_flags), "\20\21PFIL_IN\22PFIL_OUT", \ 1568aaffd78SIgor Ostapenko (ifp)->if_xname, \ 1578aaffd78SIgor Ostapenko (msg), \ 1588aaffd78SIgor Ostapenko (rule).syntax_len, (rule).syntax_begin \ 1598aaffd78SIgor Ostapenko ) 1608aaffd78SIgor Ostapenko 1618aaffd78SIgor Ostapenko /* 1628aaffd78SIgor Ostapenko * Internals 1638aaffd78SIgor Ostapenko */ 1648aaffd78SIgor Ostapenko 1658aaffd78SIgor Ostapenko struct rule; 1668aaffd78SIgor Ostapenko typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *); 1678aaffd78SIgor Ostapenko struct rule { 1688aaffd78SIgor Ostapenko const char *syntax_begin; 1698aaffd78SIgor Ostapenko int syntax_len; 1708aaffd78SIgor Ostapenko int pfil_type; 1718aaffd78SIgor Ostapenko int pfil_dir; 1728aaffd78SIgor Ostapenko char ifname[IFNAMSIZ]; 1738aaffd78SIgor Ostapenko op_t op; 1748aaffd78SIgor Ostapenko const char *opargs; 1758aaffd78SIgor Ostapenko }; 1768aaffd78SIgor Ostapenko 1778aaffd78SIgor Ostapenko static struct mbuf * 1788aaffd78SIgor Ostapenko dmb_m_pull_head(struct mbuf *m, struct rule *rule) 1798aaffd78SIgor Ostapenko { 1808aaffd78SIgor Ostapenko struct mbuf *n; 1818aaffd78SIgor Ostapenko int count; 1828aaffd78SIgor Ostapenko 1838aaffd78SIgor Ostapenko count = (int)strtol(rule->opargs, NULL, 10); 1848aaffd78SIgor Ostapenko if (count < 0 || count > MCLBYTES) 1858aaffd78SIgor Ostapenko goto bad; 1868aaffd78SIgor Ostapenko 1878aaffd78SIgor Ostapenko if (!(m->m_flags & M_PKTHDR)) 1888aaffd78SIgor Ostapenko goto bad; 1898aaffd78SIgor Ostapenko if (m->m_pkthdr.len <= 0) 1908aaffd78SIgor Ostapenko return (m); 1918aaffd78SIgor Ostapenko if (count > m->m_pkthdr.len) 1928aaffd78SIgor Ostapenko count = m->m_pkthdr.len; 1938aaffd78SIgor Ostapenko 1948aaffd78SIgor Ostapenko if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL) 1958aaffd78SIgor Ostapenko goto bad; 1968aaffd78SIgor Ostapenko 1978aaffd78SIgor Ostapenko m_move_pkthdr(n, m); 1988aaffd78SIgor Ostapenko m_copydata(m, 0, count, n->m_ext.ext_buf); 1998aaffd78SIgor Ostapenko n->m_len = count; 2008aaffd78SIgor Ostapenko 2018aaffd78SIgor Ostapenko m_adj(m, count); 2028aaffd78SIgor Ostapenko n->m_next = m; 2038aaffd78SIgor Ostapenko 2048aaffd78SIgor Ostapenko return (n); 2058aaffd78SIgor Ostapenko 2068aaffd78SIgor Ostapenko bad: 2078aaffd78SIgor Ostapenko m_freem(m); 2088aaffd78SIgor Ostapenko return (NULL); 2098aaffd78SIgor Ostapenko } 2108aaffd78SIgor Ostapenko 2118aaffd78SIgor Ostapenko static bool 2129f146a81SIgor Ostapenko read_rule(const char **cur, struct rule *rule, bool *eof) 2138aaffd78SIgor Ostapenko { 214*6bd8d855SIgor Ostapenko /* {inet|inet6|ethernet} {in|out} <ifname> <opname>[ <opargs>]; */ 2158aaffd78SIgor Ostapenko 2168aaffd78SIgor Ostapenko rule->syntax_begin = NULL; 2178aaffd78SIgor Ostapenko rule->syntax_len = 0; 2188aaffd78SIgor Ostapenko 2198aaffd78SIgor Ostapenko if (*cur == NULL) 2208aaffd78SIgor Ostapenko return (false); 2218aaffd78SIgor Ostapenko 222*6bd8d855SIgor Ostapenko /* syntax_begin */ 2238aaffd78SIgor Ostapenko while (**cur == ' ') 2248aaffd78SIgor Ostapenko (*cur)++; 2258aaffd78SIgor Ostapenko rule->syntax_begin = *cur; 2268aaffd78SIgor Ostapenko 227*6bd8d855SIgor Ostapenko /* syntax_len */ 2288aaffd78SIgor Ostapenko char *delim = strchr(*cur, ';'); 2298aaffd78SIgor Ostapenko if (delim == NULL) 2308aaffd78SIgor Ostapenko return (false); 2318aaffd78SIgor Ostapenko rule->syntax_len = (int)(delim - *cur + 1); 2328aaffd78SIgor Ostapenko 233*6bd8d855SIgor Ostapenko /* pfil_type */ 2348aaffd78SIgor Ostapenko if (strstr(*cur, "inet6") == *cur) { 2358aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_IP6; 2368aaffd78SIgor Ostapenko *cur += strlen("inet6"); 2378aaffd78SIgor Ostapenko } else if (strstr(*cur, "inet") == *cur) { 2388aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_IP4; 2398aaffd78SIgor Ostapenko *cur += strlen("inet"); 2408aaffd78SIgor Ostapenko } else if (strstr(*cur, "ethernet")) { 2418aaffd78SIgor Ostapenko rule->pfil_type = PFIL_TYPE_ETHERNET; 2428aaffd78SIgor Ostapenko *cur += strlen("ethernet"); 2438aaffd78SIgor Ostapenko } else { 2448aaffd78SIgor Ostapenko return (false); 2458aaffd78SIgor Ostapenko } 2468aaffd78SIgor Ostapenko while (**cur == ' ') 2478aaffd78SIgor Ostapenko (*cur)++; 2488aaffd78SIgor Ostapenko 249*6bd8d855SIgor Ostapenko /* pfil_dir */ 2508aaffd78SIgor Ostapenko if (strstr(*cur, "in") == *cur) { 2518aaffd78SIgor Ostapenko rule->pfil_dir = PFIL_IN; 2528aaffd78SIgor Ostapenko *cur += strlen("in"); 2538aaffd78SIgor Ostapenko } else if (strstr(*cur, "out") == *cur) { 2548aaffd78SIgor Ostapenko rule->pfil_dir = PFIL_OUT; 2558aaffd78SIgor Ostapenko *cur += strlen("out"); 2568aaffd78SIgor Ostapenko } else { 2578aaffd78SIgor Ostapenko return (false); 2588aaffd78SIgor Ostapenko } 2598aaffd78SIgor Ostapenko while (**cur == ' ') 2608aaffd78SIgor Ostapenko (*cur)++; 2618aaffd78SIgor Ostapenko 262*6bd8d855SIgor Ostapenko /* ifname */ 2638aaffd78SIgor Ostapenko char *sp = strchr(*cur, ' '); 2648aaffd78SIgor Ostapenko if (sp == NULL || sp > delim) 2658aaffd78SIgor Ostapenko return (false); 2668aaffd78SIgor Ostapenko size_t len = sp - *cur; 2678aaffd78SIgor Ostapenko if (len >= sizeof(rule->ifname)) 2688aaffd78SIgor Ostapenko return (false); 2698aaffd78SIgor Ostapenko strncpy(rule->ifname, *cur, len); 2708aaffd78SIgor Ostapenko rule->ifname[len] = 0; 2718aaffd78SIgor Ostapenko *cur = sp; 2728aaffd78SIgor Ostapenko while (**cur == ' ') 2738aaffd78SIgor Ostapenko (*cur)++; 2748aaffd78SIgor Ostapenko 275*6bd8d855SIgor Ostapenko /* opname */ 2768aaffd78SIgor Ostapenko if (strstr(*cur, "pull-head") == *cur) { 2778aaffd78SIgor Ostapenko rule->op = dmb_m_pull_head; 2788aaffd78SIgor Ostapenko *cur += strlen("pull-head"); 2798aaffd78SIgor Ostapenko } else { 2808aaffd78SIgor Ostapenko return (false); 2818aaffd78SIgor Ostapenko } 2828aaffd78SIgor Ostapenko while (**cur == ' ') 2838aaffd78SIgor Ostapenko (*cur)++; 2848aaffd78SIgor Ostapenko 285*6bd8d855SIgor Ostapenko /* opargs */ 2868aaffd78SIgor Ostapenko if (*cur > delim) 2878aaffd78SIgor Ostapenko return (false); 2888aaffd78SIgor Ostapenko rule->opargs = *cur; 2898aaffd78SIgor Ostapenko 290*6bd8d855SIgor Ostapenko /* the next rule & eof */ 2918aaffd78SIgor Ostapenko *cur = delim + 1; 2929f146a81SIgor Ostapenko while (**cur == ' ') 2939f146a81SIgor Ostapenko (*cur)++; 2949f146a81SIgor Ostapenko *eof = strlen(*cur) == 0; 2958aaffd78SIgor Ostapenko 2968aaffd78SIgor Ostapenko return (true); 2978aaffd78SIgor Ostapenko } 2988aaffd78SIgor Ostapenko 2999f146a81SIgor Ostapenko static int 3009f146a81SIgor Ostapenko validate_rules(const char *rules) 3019f146a81SIgor Ostapenko { 3029f146a81SIgor Ostapenko const char *cursor = rules; 3039f146a81SIgor Ostapenko bool parsed; 3049f146a81SIgor Ostapenko struct rule rule; 3059f146a81SIgor Ostapenko bool eof = false; 3069f146a81SIgor Ostapenko 3079f146a81SIgor Ostapenko DMB_RULES_LOCK_ASSERT(); 3089f146a81SIgor Ostapenko 3099f146a81SIgor Ostapenko while (!eof && (parsed = read_rule(&cursor, &rule, &eof))) { 3109f146a81SIgor Ostapenko /* noop */ 3119f146a81SIgor Ostapenko } 3129f146a81SIgor Ostapenko 3139f146a81SIgor Ostapenko if (!parsed) { 3149f146a81SIgor Ostapenko FEEDBACK_RULE(rule, "rule parsing failed"); 3159f146a81SIgor Ostapenko return (EINVAL); 3169f146a81SIgor Ostapenko } 3179f146a81SIgor Ostapenko 3189f146a81SIgor Ostapenko return (0); 3199f146a81SIgor Ostapenko } 3209f146a81SIgor Ostapenko 3218aaffd78SIgor Ostapenko static pfil_return_t 3228aaffd78SIgor Ostapenko dmb_pfil_mbuf_chk(int pfil_type, struct mbuf **mp, struct ifnet *ifp, 3238aaffd78SIgor Ostapenko int flags, void *ruleset, void *unused) 3248aaffd78SIgor Ostapenko { 3258aaffd78SIgor Ostapenko struct mbuf *m = *mp; 3268aaffd78SIgor Ostapenko const char *cursor; 3278aaffd78SIgor Ostapenko bool parsed; 3288aaffd78SIgor Ostapenko struct rule rule; 3299f146a81SIgor Ostapenko bool eof = false; 3308aaffd78SIgor Ostapenko 3318aaffd78SIgor Ostapenko DMB_RULES_SLOCK(); 3328aaffd78SIgor Ostapenko cursor = V_dmb_rules; 3339f146a81SIgor Ostapenko while (!eof && (parsed = read_rule(&cursor, &rule, &eof))) { 3348aaffd78SIgor Ostapenko if (rule.pfil_type == pfil_type && 3358aaffd78SIgor Ostapenko rule.pfil_dir == (flags & rule.pfil_dir) && 3368aaffd78SIgor Ostapenko strcmp(rule.ifname, ifp->if_xname) == 0) { 3378aaffd78SIgor Ostapenko m = rule.op(m, &rule); 3388aaffd78SIgor Ostapenko if (m == NULL) { 3399f146a81SIgor Ostapenko FEEDBACK_PFIL(pfil_type, flags, ifp, rule, 3408aaffd78SIgor Ostapenko "mbuf operation failed"); 3418aaffd78SIgor Ostapenko break; 3428aaffd78SIgor Ostapenko } 3438aaffd78SIgor Ostapenko counter_u64_add(V_dmb_hits, 1); 3448aaffd78SIgor Ostapenko } 3458aaffd78SIgor Ostapenko } 3468aaffd78SIgor Ostapenko if (!parsed) { 3479f146a81SIgor Ostapenko FEEDBACK_PFIL(pfil_type, flags, ifp, rule, 3489f146a81SIgor Ostapenko "rule parsing failed"); 3498aaffd78SIgor Ostapenko m_freem(m); 3508aaffd78SIgor Ostapenko m = NULL; 3518aaffd78SIgor Ostapenko } 3528aaffd78SIgor Ostapenko DMB_RULES_SUNLOCK(); 3538aaffd78SIgor Ostapenko 3548aaffd78SIgor Ostapenko if (m == NULL) { 3558aaffd78SIgor Ostapenko *mp = NULL; 3568aaffd78SIgor Ostapenko return (PFIL_DROPPED); 3578aaffd78SIgor Ostapenko } 3588aaffd78SIgor Ostapenko if (m != *mp) { 3598aaffd78SIgor Ostapenko *mp = m; 3608aaffd78SIgor Ostapenko return (PFIL_REALLOCED); 3618aaffd78SIgor Ostapenko } 3628aaffd78SIgor Ostapenko 3638aaffd78SIgor Ostapenko return (PFIL_PASS); 3648aaffd78SIgor Ostapenko } 3658aaffd78SIgor Ostapenko 366aa72c5baSGleb Smirnoff #ifdef INET 3678aaffd78SIgor Ostapenko static pfil_return_t 3688aaffd78SIgor Ostapenko dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 3698aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 3708aaffd78SIgor Ostapenko { 3718aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP4, mp, ifp, flags, 3728aaffd78SIgor Ostapenko ruleset, inp)); 3738aaffd78SIgor Ostapenko } 374aa72c5baSGleb Smirnoff #endif 3758aaffd78SIgor Ostapenko 376aa72c5baSGleb Smirnoff #ifdef INET6 3778aaffd78SIgor Ostapenko static pfil_return_t 3788aaffd78SIgor Ostapenko dmb_pfil_inet6_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 3798aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 3808aaffd78SIgor Ostapenko { 3818aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_IP6, mp, ifp, flags, 3828aaffd78SIgor Ostapenko ruleset, inp)); 3838aaffd78SIgor Ostapenko } 384aa72c5baSGleb Smirnoff #endif 3858aaffd78SIgor Ostapenko 3868aaffd78SIgor Ostapenko static pfil_return_t 3878aaffd78SIgor Ostapenko dmb_pfil_ethernet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags, 3888aaffd78SIgor Ostapenko void *ruleset, struct inpcb *inp) 3898aaffd78SIgor Ostapenko { 3908aaffd78SIgor Ostapenko return (dmb_pfil_mbuf_chk(PFIL_TYPE_ETHERNET, mp, ifp, flags, 3918aaffd78SIgor Ostapenko ruleset, inp)); 3928aaffd78SIgor Ostapenko } 3938aaffd78SIgor Ostapenko 3948aaffd78SIgor Ostapenko static void 3958aaffd78SIgor Ostapenko dmb_pfil_init(void) 3968aaffd78SIgor Ostapenko { 3978aaffd78SIgor Ostapenko struct pfil_hook_args pha = { 3988aaffd78SIgor Ostapenko .pa_version = PFIL_VERSION, 3998aaffd78SIgor Ostapenko .pa_modname = "dummymbuf", 4008aaffd78SIgor Ostapenko .pa_flags = PFIL_IN | PFIL_OUT, 4018aaffd78SIgor Ostapenko }; 4028aaffd78SIgor Ostapenko 4038aaffd78SIgor Ostapenko #ifdef INET 4048aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_IP4; 4058aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_inet_mbuf_chk; 4068aaffd78SIgor Ostapenko pha.pa_rulname = "inet"; 4078aaffd78SIgor Ostapenko V_dmb_pfil_inet_hook = pfil_add_hook(&pha); 4088aaffd78SIgor Ostapenko #endif 4098aaffd78SIgor Ostapenko 4108aaffd78SIgor Ostapenko #ifdef INET6 4118aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_IP6; 4128aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_inet6_mbuf_chk; 4138aaffd78SIgor Ostapenko pha.pa_rulname = "inet6"; 4148aaffd78SIgor Ostapenko V_dmb_pfil_inet6_hook = pfil_add_hook(&pha); 4158aaffd78SIgor Ostapenko #endif 4168aaffd78SIgor Ostapenko 4178aaffd78SIgor Ostapenko pha.pa_type = PFIL_TYPE_ETHERNET; 4188aaffd78SIgor Ostapenko pha.pa_mbuf_chk = dmb_pfil_ethernet_mbuf_chk; 4198aaffd78SIgor Ostapenko pha.pa_rulname = "ethernet"; 4208aaffd78SIgor Ostapenko V_dmb_pfil_ethernet_hook = pfil_add_hook(&pha); 4218aaffd78SIgor Ostapenko } 4228aaffd78SIgor Ostapenko 4238aaffd78SIgor Ostapenko static void 4248aaffd78SIgor Ostapenko dmb_pfil_uninit(void) 4258aaffd78SIgor Ostapenko { 4268aaffd78SIgor Ostapenko #ifdef INET 4278aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_inet_hook); 4288aaffd78SIgor Ostapenko #endif 4298aaffd78SIgor Ostapenko 4308aaffd78SIgor Ostapenko #ifdef INET6 4318aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_inet6_hook); 4328aaffd78SIgor Ostapenko #endif 4338aaffd78SIgor Ostapenko 4348aaffd78SIgor Ostapenko pfil_remove_hook(V_dmb_pfil_ethernet_hook); 4358aaffd78SIgor Ostapenko } 4368aaffd78SIgor Ostapenko 4378aaffd78SIgor Ostapenko static void 4388aaffd78SIgor Ostapenko vnet_dmb_init(void *unused __unused) 4398aaffd78SIgor Ostapenko { 4408aaffd78SIgor Ostapenko sx_init(&V_dmb_rules_lock, "dummymbuf rules"); 4418aaffd78SIgor Ostapenko V_dmb_hits = counter_u64_alloc(M_WAITOK); 4428aaffd78SIgor Ostapenko dmb_pfil_init(); 4438aaffd78SIgor Ostapenko } 4448aaffd78SIgor Ostapenko VNET_SYSINIT(vnet_dmb_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY, 4458aaffd78SIgor Ostapenko vnet_dmb_init, NULL); 4468aaffd78SIgor Ostapenko 4478aaffd78SIgor Ostapenko static void 4488aaffd78SIgor Ostapenko vnet_dmb_uninit(void *unused __unused) 4498aaffd78SIgor Ostapenko { 4508aaffd78SIgor Ostapenko dmb_pfil_uninit(); 4518aaffd78SIgor Ostapenko counter_u64_free(V_dmb_hits); 4528aaffd78SIgor Ostapenko sx_destroy(&V_dmb_rules_lock); 4538aaffd78SIgor Ostapenko free(V_dmb_rules, M_DUMMYMBUF_RULES); 4548aaffd78SIgor Ostapenko } 4558aaffd78SIgor Ostapenko VNET_SYSUNINIT(vnet_dmb_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY, 4568aaffd78SIgor Ostapenko vnet_dmb_uninit, NULL); 4578aaffd78SIgor Ostapenko 4588aaffd78SIgor Ostapenko static int 4598aaffd78SIgor Ostapenko dmb_modevent(module_t mod __unused, int event, void *arg __unused) 4608aaffd78SIgor Ostapenko { 4618aaffd78SIgor Ostapenko int error = 0; 4628aaffd78SIgor Ostapenko 4638aaffd78SIgor Ostapenko switch (event) { 4648aaffd78SIgor Ostapenko case MOD_LOAD: 4658aaffd78SIgor Ostapenko case MOD_UNLOAD: 4668aaffd78SIgor Ostapenko break; 4678aaffd78SIgor Ostapenko default: 4688aaffd78SIgor Ostapenko error = EOPNOTSUPP; 4698aaffd78SIgor Ostapenko break; 4708aaffd78SIgor Ostapenko } 4718aaffd78SIgor Ostapenko 4728aaffd78SIgor Ostapenko return (error); 4738aaffd78SIgor Ostapenko } 4748aaffd78SIgor Ostapenko 4758aaffd78SIgor Ostapenko static moduledata_t dmb_mod = { 4768aaffd78SIgor Ostapenko "dummymbuf", 4778aaffd78SIgor Ostapenko dmb_modevent, 4788aaffd78SIgor Ostapenko NULL 4798aaffd78SIgor Ostapenko }; 4808aaffd78SIgor Ostapenko 4818aaffd78SIgor Ostapenko DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY); 4828aaffd78SIgor Ostapenko MODULE_VERSION(dummymbuf, 1); 483