1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/export.h> 3 #include <linux/icmpv6.h> 4 #include <linux/mutex.h> 5 #include <linux/netdevice.h> 6 #include <linux/spinlock.h> 7 8 #include <net/ipv6.h> 9 10 #if IS_ENABLED(CONFIG_IPV6) && IS_ENABLED(CONFIG_NF_NAT) 11 12 #include <net/netfilter/nf_conntrack.h> 13 void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info) 14 { 15 struct inet6_skb_parm parm = { 0 }; 16 struct sk_buff *cloned_skb = NULL; 17 enum ip_conntrack_info ctinfo; 18 enum ip_conntrack_dir dir; 19 struct in6_addr orig_ip; 20 struct nf_conn *ct; 21 22 ct = nf_ct_get(skb_in, &ctinfo); 23 if (!ct || !(READ_ONCE(ct->status) & IPS_NAT_MASK)) { 24 icmp6_send(skb_in, type, code, info, NULL, &parm); 25 return; 26 } 27 28 if (skb_shared(skb_in)) 29 skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC); 30 31 if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head || 32 (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) > 33 skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in, 34 skb_network_offset(skb_in) + sizeof(struct ipv6hdr)))) 35 goto out; 36 37 orig_ip = ipv6_hdr(skb_in)->saddr; 38 dir = CTINFO2DIR(ctinfo); 39 ipv6_hdr(skb_in)->saddr = ct->tuplehash[dir].tuple.src.u3.in6; 40 icmp6_send(skb_in, type, code, info, NULL, &parm); 41 ipv6_hdr(skb_in)->saddr = orig_ip; 42 out: 43 consume_skb(cloned_skb); 44 } 45 EXPORT_SYMBOL(icmpv6_ndo_send); 46 #endif 47