1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org> 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/init.h> 8 #include <linux/module.h> 9 #include <linux/netlink.h> 10 #include <linux/netfilter.h> 11 #include <linux/netfilter/nf_tables.h> 12 #include <net/netfilter/nf_tables.h> 13 #include <net/netfilter/nf_tables_offload.h> 14 #include <net/netfilter/nf_dup_netdev.h> 15 16 static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev) 17 { 18 if (skb_mac_header_was_set(skb)) 19 skb_push(skb, skb->mac_len); 20 21 skb->dev = dev; 22 dev_queue_xmit(skb); 23 } 24 25 void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif) 26 { 27 struct net_device *dev; 28 29 dev = dev_get_by_index_rcu(nft_net(pkt), oif); 30 if (!dev) { 31 kfree_skb(pkt->skb); 32 return; 33 } 34 35 nf_do_netdev_egress(pkt->skb, dev); 36 } 37 EXPORT_SYMBOL_GPL(nf_fwd_netdev_egress); 38 39 void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif) 40 { 41 struct net_device *dev; 42 struct sk_buff *skb; 43 44 dev = dev_get_by_index_rcu(nft_net(pkt), oif); 45 if (dev == NULL) 46 return; 47 48 skb = skb_clone(pkt->skb, GFP_ATOMIC); 49 if (skb) 50 nf_do_netdev_egress(skb, dev); 51 } 52 EXPORT_SYMBOL_GPL(nf_dup_netdev_egress); 53 54 int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx, 55 struct nft_flow_rule *flow, 56 enum flow_action_id id, int oif) 57 { 58 struct flow_action_entry *entry; 59 struct net_device *dev; 60 61 /* nft_flow_rule_destroy() releases the reference on this device. */ 62 dev = dev_get_by_index(ctx->net, oif); 63 if (!dev) 64 return -EOPNOTSUPP; 65 66 entry = &flow->rule->action.entries[ctx->num_actions++]; 67 entry->id = id; 68 entry->dev = dev; 69 70 return 0; 71 } 72 EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload); 73 74 MODULE_LICENSE("GPL"); 75 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 76