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