18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/sched/act_ipt.c iptables target interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci *TODO: Add other tables. For now we only support the ipv4 table targets 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright: Jamal Hadi Salim (2002-13) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 158c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <net/netlink.h> 208c2ecf20Sopenharmony_ci#include <net/pkt_sched.h> 218c2ecf20Sopenharmony_ci#include <linux/tc_act/tc_ipt.h> 228c2ecf20Sopenharmony_ci#include <net/tc_act/tc_ipt.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4/ip_tables.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic unsigned int ipt_net_id; 288c2ecf20Sopenharmony_cistatic struct tc_action_ops act_ipt_ops; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic unsigned int xt_net_id; 318c2ecf20Sopenharmony_cistatic struct tc_action_ops act_xt_ops; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int ipt_init_target(struct net *net, struct xt_entry_target *t, 348c2ecf20Sopenharmony_ci char *table, unsigned int hook) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct xt_tgchk_param par; 378c2ecf20Sopenharmony_ci struct xt_target *target; 388c2ecf20Sopenharmony_ci struct ipt_entry e = {}; 398c2ecf20Sopenharmony_ci int ret = 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci target = xt_request_find_target(AF_INET, t->u.user.name, 428c2ecf20Sopenharmony_ci t->u.user.revision); 438c2ecf20Sopenharmony_ci if (IS_ERR(target)) 448c2ecf20Sopenharmony_ci return PTR_ERR(target); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci t->u.kernel.target = target; 478c2ecf20Sopenharmony_ci memset(&par, 0, sizeof(par)); 488c2ecf20Sopenharmony_ci par.net = net; 498c2ecf20Sopenharmony_ci par.table = table; 508c2ecf20Sopenharmony_ci par.entryinfo = &e; 518c2ecf20Sopenharmony_ci par.target = target; 528c2ecf20Sopenharmony_ci par.targinfo = t->data; 538c2ecf20Sopenharmony_ci par.hook_mask = hook; 548c2ecf20Sopenharmony_ci par.family = NFPROTO_IPV4; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false); 578c2ecf20Sopenharmony_ci if (ret < 0) { 588c2ecf20Sopenharmony_ci module_put(t->u.kernel.target->me); 598c2ecf20Sopenharmony_ci return ret; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void ipt_destroy_target(struct xt_entry_target *t, struct net *net) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct xt_tgdtor_param par = { 678c2ecf20Sopenharmony_ci .target = t->u.kernel.target, 688c2ecf20Sopenharmony_ci .targinfo = t->data, 698c2ecf20Sopenharmony_ci .family = NFPROTO_IPV4, 708c2ecf20Sopenharmony_ci .net = net, 718c2ecf20Sopenharmony_ci }; 728c2ecf20Sopenharmony_ci if (par.target->destroy != NULL) 738c2ecf20Sopenharmony_ci par.target->destroy(&par); 748c2ecf20Sopenharmony_ci module_put(par.target->me); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void tcf_ipt_release(struct tc_action *a) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct tcf_ipt *ipt = to_ipt(a); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (ipt->tcfi_t) { 828c2ecf20Sopenharmony_ci ipt_destroy_target(ipt->tcfi_t, a->idrinfo->net); 838c2ecf20Sopenharmony_ci kfree(ipt->tcfi_t); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci kfree(ipt->tcfi_tname); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { 898c2ecf20Sopenharmony_ci [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ }, 908c2ecf20Sopenharmony_ci [TCA_IPT_HOOK] = { .type = NLA_U32 }, 918c2ecf20Sopenharmony_ci [TCA_IPT_INDEX] = { .type = NLA_U32 }, 928c2ecf20Sopenharmony_ci [TCA_IPT_TARG] = { .len = sizeof(struct xt_entry_target) }, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, 968c2ecf20Sopenharmony_ci struct nlattr *est, struct tc_action **a, 978c2ecf20Sopenharmony_ci const struct tc_action_ops *ops, int ovr, int bind, 988c2ecf20Sopenharmony_ci struct tcf_proto *tp, u32 flags) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, id); 1018c2ecf20Sopenharmony_ci struct nlattr *tb[TCA_IPT_MAX + 1]; 1028c2ecf20Sopenharmony_ci struct tcf_ipt *ipt; 1038c2ecf20Sopenharmony_ci struct xt_entry_target *td, *t; 1048c2ecf20Sopenharmony_ci char *tname; 1058c2ecf20Sopenharmony_ci bool exists = false; 1068c2ecf20Sopenharmony_ci int ret = 0, err; 1078c2ecf20Sopenharmony_ci u32 hook = 0; 1088c2ecf20Sopenharmony_ci u32 index = 0; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (nla == NULL) 1118c2ecf20Sopenharmony_ci return -EINVAL; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(tb, TCA_IPT_MAX, nla, ipt_policy, 1148c2ecf20Sopenharmony_ci NULL); 1158c2ecf20Sopenharmony_ci if (err < 0) 1168c2ecf20Sopenharmony_ci return err; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (tb[TCA_IPT_INDEX] != NULL) 1198c2ecf20Sopenharmony_ci index = nla_get_u32(tb[TCA_IPT_INDEX]); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci err = tcf_idr_check_alloc(tn, &index, a, bind); 1228c2ecf20Sopenharmony_ci if (err < 0) 1238c2ecf20Sopenharmony_ci return err; 1248c2ecf20Sopenharmony_ci exists = err; 1258c2ecf20Sopenharmony_ci if (exists && bind) 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) { 1298c2ecf20Sopenharmony_ci if (exists) 1308c2ecf20Sopenharmony_ci tcf_idr_release(*a, bind); 1318c2ecf20Sopenharmony_ci else 1328c2ecf20Sopenharmony_ci tcf_idr_cleanup(tn, index); 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); 1378c2ecf20Sopenharmony_ci if (nla_len(tb[TCA_IPT_TARG]) != td->u.target_size) { 1388c2ecf20Sopenharmony_ci if (exists) 1398c2ecf20Sopenharmony_ci tcf_idr_release(*a, bind); 1408c2ecf20Sopenharmony_ci else 1418c2ecf20Sopenharmony_ci tcf_idr_cleanup(tn, index); 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!exists) { 1468c2ecf20Sopenharmony_ci ret = tcf_idr_create(tn, index, est, a, ops, bind, 1478c2ecf20Sopenharmony_ci false, flags); 1488c2ecf20Sopenharmony_ci if (ret) { 1498c2ecf20Sopenharmony_ci tcf_idr_cleanup(tn, index); 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci ret = ACT_P_CREATED; 1538c2ecf20Sopenharmony_ci } else { 1548c2ecf20Sopenharmony_ci if (bind)/* dont override defaults */ 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (!ovr) { 1588c2ecf20Sopenharmony_ci tcf_idr_release(*a, bind); 1598c2ecf20Sopenharmony_ci return -EEXIST; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci hook = nla_get_u32(tb[TCA_IPT_HOOK]); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci err = -ENOMEM; 1658c2ecf20Sopenharmony_ci tname = kmalloc(IFNAMSIZ, GFP_KERNEL); 1668c2ecf20Sopenharmony_ci if (unlikely(!tname)) 1678c2ecf20Sopenharmony_ci goto err1; 1688c2ecf20Sopenharmony_ci if (tb[TCA_IPT_TABLE] == NULL || 1698c2ecf20Sopenharmony_ci nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ) 1708c2ecf20Sopenharmony_ci strcpy(tname, "mangle"); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci t = kmemdup(td, td->u.target_size, GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (unlikely(!t)) 1748c2ecf20Sopenharmony_ci goto err2; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci err = ipt_init_target(net, t, tname, hook); 1778c2ecf20Sopenharmony_ci if (err < 0) 1788c2ecf20Sopenharmony_ci goto err3; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ipt = to_ipt(*a); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci spin_lock_bh(&ipt->tcf_lock); 1838c2ecf20Sopenharmony_ci if (ret != ACT_P_CREATED) { 1848c2ecf20Sopenharmony_ci ipt_destroy_target(ipt->tcfi_t, net); 1858c2ecf20Sopenharmony_ci kfree(ipt->tcfi_tname); 1868c2ecf20Sopenharmony_ci kfree(ipt->tcfi_t); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci ipt->tcfi_tname = tname; 1898c2ecf20Sopenharmony_ci ipt->tcfi_t = t; 1908c2ecf20Sopenharmony_ci ipt->tcfi_hook = hook; 1918c2ecf20Sopenharmony_ci spin_unlock_bh(&ipt->tcf_lock); 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cierr3: 1958c2ecf20Sopenharmony_ci kfree(t); 1968c2ecf20Sopenharmony_cierr2: 1978c2ecf20Sopenharmony_ci kfree(tname); 1988c2ecf20Sopenharmony_cierr1: 1998c2ecf20Sopenharmony_ci tcf_idr_release(*a, bind); 2008c2ecf20Sopenharmony_ci return err; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int tcf_ipt_init(struct net *net, struct nlattr *nla, 2048c2ecf20Sopenharmony_ci struct nlattr *est, struct tc_action **a, int ovr, 2058c2ecf20Sopenharmony_ci int bind, bool rtnl_held, struct tcf_proto *tp, 2068c2ecf20Sopenharmony_ci u32 flags, struct netlink_ext_ack *extack) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci return __tcf_ipt_init(net, ipt_net_id, nla, est, a, &act_ipt_ops, ovr, 2098c2ecf20Sopenharmony_ci bind, tp, flags); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int tcf_xt_init(struct net *net, struct nlattr *nla, 2138c2ecf20Sopenharmony_ci struct nlattr *est, struct tc_action **a, int ovr, 2148c2ecf20Sopenharmony_ci int bind, bool unlocked, struct tcf_proto *tp, 2158c2ecf20Sopenharmony_ci u32 flags, struct netlink_ext_ack *extack) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return __tcf_ipt_init(net, xt_net_id, nla, est, a, &act_xt_ops, ovr, 2188c2ecf20Sopenharmony_ci bind, tp, flags); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int tcf_ipt_act(struct sk_buff *skb, const struct tc_action *a, 2228c2ecf20Sopenharmony_ci struct tcf_result *res) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int ret = 0, result = 0; 2258c2ecf20Sopenharmony_ci struct tcf_ipt *ipt = to_ipt(a); 2268c2ecf20Sopenharmony_ci struct xt_action_param par; 2278c2ecf20Sopenharmony_ci struct nf_hook_state state = { 2288c2ecf20Sopenharmony_ci .net = dev_net(skb->dev), 2298c2ecf20Sopenharmony_ci .in = skb->dev, 2308c2ecf20Sopenharmony_ci .hook = ipt->tcfi_hook, 2318c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV4, 2328c2ecf20Sopenharmony_ci }; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (skb_unclone(skb, GFP_ATOMIC)) 2358c2ecf20Sopenharmony_ci return TC_ACT_UNSPEC; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci spin_lock(&ipt->tcf_lock); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci tcf_lastuse_update(&ipt->tcf_tm); 2408c2ecf20Sopenharmony_ci bstats_update(&ipt->tcf_bstats, skb); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* yes, we have to worry about both in and out dev 2438c2ecf20Sopenharmony_ci * worry later - danger - this API seems to have changed 2448c2ecf20Sopenharmony_ci * from earlier kernels 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci par.state = &state; 2478c2ecf20Sopenharmony_ci par.target = ipt->tcfi_t->u.kernel.target; 2488c2ecf20Sopenharmony_ci par.targinfo = ipt->tcfi_t->data; 2498c2ecf20Sopenharmony_ci ret = par.target->target(skb, &par); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci switch (ret) { 2528c2ecf20Sopenharmony_ci case NF_ACCEPT: 2538c2ecf20Sopenharmony_ci result = TC_ACT_OK; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci case NF_DROP: 2568c2ecf20Sopenharmony_ci result = TC_ACT_SHOT; 2578c2ecf20Sopenharmony_ci ipt->tcf_qstats.drops++; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case XT_CONTINUE: 2608c2ecf20Sopenharmony_ci result = TC_ACT_PIPE; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci default: 2638c2ecf20Sopenharmony_ci net_notice_ratelimited("tc filter: Bogus netfilter code %d assume ACCEPT\n", 2648c2ecf20Sopenharmony_ci ret); 2658c2ecf20Sopenharmony_ci result = TC_ACT_OK; 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci spin_unlock(&ipt->tcf_lock); 2698c2ecf20Sopenharmony_ci return result; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, 2748c2ecf20Sopenharmony_ci int ref) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci unsigned char *b = skb_tail_pointer(skb); 2778c2ecf20Sopenharmony_ci struct tcf_ipt *ipt = to_ipt(a); 2788c2ecf20Sopenharmony_ci struct xt_entry_target *t; 2798c2ecf20Sopenharmony_ci struct tcf_t tm; 2808c2ecf20Sopenharmony_ci struct tc_cnt c; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* for simple targets kernel size == user size 2838c2ecf20Sopenharmony_ci * user name = target name 2848c2ecf20Sopenharmony_ci * for foolproof you need to not assume this 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci spin_lock_bh(&ipt->tcf_lock); 2888c2ecf20Sopenharmony_ci t = kmemdup(ipt->tcfi_t, ipt->tcfi_t->u.user.target_size, GFP_ATOMIC); 2898c2ecf20Sopenharmony_ci if (unlikely(!t)) 2908c2ecf20Sopenharmony_ci goto nla_put_failure; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci c.bindcnt = atomic_read(&ipt->tcf_bindcnt) - bind; 2938c2ecf20Sopenharmony_ci c.refcnt = refcount_read(&ipt->tcf_refcnt) - ref; 2948c2ecf20Sopenharmony_ci strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (nla_put(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t) || 2978c2ecf20Sopenharmony_ci nla_put_u32(skb, TCA_IPT_INDEX, ipt->tcf_index) || 2988c2ecf20Sopenharmony_ci nla_put_u32(skb, TCA_IPT_HOOK, ipt->tcfi_hook) || 2998c2ecf20Sopenharmony_ci nla_put(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c) || 3008c2ecf20Sopenharmony_ci nla_put_string(skb, TCA_IPT_TABLE, ipt->tcfi_tname)) 3018c2ecf20Sopenharmony_ci goto nla_put_failure; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci tcf_tm_dump(&tm, &ipt->tcf_tm); 3048c2ecf20Sopenharmony_ci if (nla_put_64bit(skb, TCA_IPT_TM, sizeof(tm), &tm, TCA_IPT_PAD)) 3058c2ecf20Sopenharmony_ci goto nla_put_failure; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci spin_unlock_bh(&ipt->tcf_lock); 3088c2ecf20Sopenharmony_ci kfree(t); 3098c2ecf20Sopenharmony_ci return skb->len; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cinla_put_failure: 3128c2ecf20Sopenharmony_ci spin_unlock_bh(&ipt->tcf_lock); 3138c2ecf20Sopenharmony_ci nlmsg_trim(skb, b); 3148c2ecf20Sopenharmony_ci kfree(t); 3158c2ecf20Sopenharmony_ci return -1; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int tcf_ipt_walker(struct net *net, struct sk_buff *skb, 3198c2ecf20Sopenharmony_ci struct netlink_callback *cb, int type, 3208c2ecf20Sopenharmony_ci const struct tc_action_ops *ops, 3218c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, ipt_net_id); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return tcf_generic_walker(tn, skb, cb, type, ops, extack); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, ipt_net_id); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return tcf_idr_search(tn, a, index); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic struct tc_action_ops act_ipt_ops = { 3368c2ecf20Sopenharmony_ci .kind = "ipt", 3378c2ecf20Sopenharmony_ci .id = TCA_ID_IPT, 3388c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3398c2ecf20Sopenharmony_ci .act = tcf_ipt_act, 3408c2ecf20Sopenharmony_ci .dump = tcf_ipt_dump, 3418c2ecf20Sopenharmony_ci .cleanup = tcf_ipt_release, 3428c2ecf20Sopenharmony_ci .init = tcf_ipt_init, 3438c2ecf20Sopenharmony_ci .walk = tcf_ipt_walker, 3448c2ecf20Sopenharmony_ci .lookup = tcf_ipt_search, 3458c2ecf20Sopenharmony_ci .size = sizeof(struct tcf_ipt), 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic __net_init int ipt_init_net(struct net *net) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, ipt_net_id); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return tc_action_net_init(net, tn, &act_ipt_ops); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void __net_exit ipt_exit_net(struct list_head *net_list) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci tc_action_net_exit(net_list, ipt_net_id); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic struct pernet_operations ipt_net_ops = { 3618c2ecf20Sopenharmony_ci .init = ipt_init_net, 3628c2ecf20Sopenharmony_ci .exit_batch = ipt_exit_net, 3638c2ecf20Sopenharmony_ci .id = &ipt_net_id, 3648c2ecf20Sopenharmony_ci .size = sizeof(struct tc_action_net), 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int tcf_xt_walker(struct net *net, struct sk_buff *skb, 3688c2ecf20Sopenharmony_ci struct netlink_callback *cb, int type, 3698c2ecf20Sopenharmony_ci const struct tc_action_ops *ops, 3708c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, xt_net_id); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return tcf_generic_walker(tn, skb, cb, type, ops, extack); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int tcf_xt_search(struct net *net, struct tc_action **a, u32 index) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, xt_net_id); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return tcf_idr_search(tn, a, index); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic struct tc_action_ops act_xt_ops = { 3858c2ecf20Sopenharmony_ci .kind = "xt", 3868c2ecf20Sopenharmony_ci .id = TCA_ID_XT, 3878c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3888c2ecf20Sopenharmony_ci .act = tcf_ipt_act, 3898c2ecf20Sopenharmony_ci .dump = tcf_ipt_dump, 3908c2ecf20Sopenharmony_ci .cleanup = tcf_ipt_release, 3918c2ecf20Sopenharmony_ci .init = tcf_xt_init, 3928c2ecf20Sopenharmony_ci .walk = tcf_xt_walker, 3938c2ecf20Sopenharmony_ci .lookup = tcf_xt_search, 3948c2ecf20Sopenharmony_ci .size = sizeof(struct tcf_ipt), 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic __net_init int xt_init_net(struct net *net) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct tc_action_net *tn = net_generic(net, xt_net_id); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return tc_action_net_init(net, tn, &act_xt_ops); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void __net_exit xt_exit_net(struct list_head *net_list) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci tc_action_net_exit(net_list, xt_net_id); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct pernet_operations xt_net_ops = { 4108c2ecf20Sopenharmony_ci .init = xt_init_net, 4118c2ecf20Sopenharmony_ci .exit_batch = xt_exit_net, 4128c2ecf20Sopenharmony_ci .id = &xt_net_id, 4138c2ecf20Sopenharmony_ci .size = sizeof(struct tc_action_net), 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jamal Hadi Salim(2002-13)"); 4178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Iptables target actions"); 4188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4198c2ecf20Sopenharmony_ciMODULE_ALIAS("act_xt"); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int __init ipt_init_module(void) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci int ret1, ret2; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret1 = tcf_register_action(&act_xt_ops, &xt_net_ops); 4268c2ecf20Sopenharmony_ci if (ret1 < 0) 4278c2ecf20Sopenharmony_ci pr_err("Failed to load xt action\n"); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ret2 = tcf_register_action(&act_ipt_ops, &ipt_net_ops); 4308c2ecf20Sopenharmony_ci if (ret2 < 0) 4318c2ecf20Sopenharmony_ci pr_err("Failed to load ipt action\n"); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (ret1 < 0 && ret2 < 0) { 4348c2ecf20Sopenharmony_ci return ret1; 4358c2ecf20Sopenharmony_ci } else 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void __exit ipt_cleanup_module(void) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci tcf_unregister_action(&act_ipt_ops, &ipt_net_ops); 4428c2ecf20Sopenharmony_ci tcf_unregister_action(&act_xt_ops, &xt_net_ops); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cimodule_init(ipt_init_module); 4468c2ecf20Sopenharmony_cimodule_exit(ipt_cleanup_module); 447