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 skb_clear_tstamp(skb); 23 dev_queue_xmit(skb); 24 } 25 26 void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif) 27 { 28 struct net_device *dev; 29 30 dev = dev_get_by_index_rcu(nft_net(pkt), oif); 31 if (!dev) { 32 kfree_skb(pkt->skb); 33 return; 34 } 35 36 nf_do_netdev_egress(pkt->skb, dev); 37 } 38 EXPORT_SYMBOL_GPL(nf_fwd_netdev_egress); 39 40 void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif) 41 { 42 struct net_device *dev; 43 struct sk_buff *skb; 44 45 dev = dev_get_by_index_rcu(nft_net(pkt), oif); 46 if (dev == NULL) 47 return; 48 49 skb = skb_clone(pkt->skb, GFP_ATOMIC); 50 if (skb) 51 nf_do_netdev_egress(skb, dev); 52 } 53 EXPORT_SYMBOL_GPL(nf_dup_netdev_egress); 54 55 int nft_fwd_dup_netdev_offload(struct nft_offload_ctx *ctx, 56 struct nft_flow_rule *flow, 57 enum flow_action_id id, int oif) 58 { 59 struct flow_action_entry *entry; 60 struct net_device *dev; 61 62 /* nft_flow_rule_destroy() releases the reference on this device. */ 63 dev = dev_get_by_index(ctx->net, oif); 64 if (!dev) 65 return -EOPNOTSUPP; 66 67 entry = &flow->rule->action.entries[ctx->num_actions++]; 68 entry->id = id; 69 entry->dev = dev; 70 71 return 0; 72 } 73 EXPORT_SYMBOL_GPL(nft_fwd_dup_netdev_offload); 74 75 MODULE_LICENSE("GPL"); 76 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 77 MODULE_DESCRIPTION("Netfilter packet duplication support"); 78