ip6_icmp.c (2086B)
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) 11 12#if !IS_BUILTIN(CONFIG_IPV6) 13 14static ip6_icmp_send_t __rcu *ip6_icmp_send; 15 16int inet6_register_icmp_sender(ip6_icmp_send_t *fn) 17{ 18 return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? 19 0 : -EBUSY; 20} 21EXPORT_SYMBOL(inet6_register_icmp_sender); 22 23int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn) 24{ 25 int ret; 26 27 ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ? 28 0 : -EINVAL; 29 30 synchronize_net(); 31 32 return ret; 33} 34EXPORT_SYMBOL(inet6_unregister_icmp_sender); 35 36void __icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, 37 const struct inet6_skb_parm *parm) 38{ 39 ip6_icmp_send_t *send; 40 41 rcu_read_lock(); 42 send = rcu_dereference(ip6_icmp_send); 43 if (send) 44 send(skb, type, code, info, NULL, parm); 45 rcu_read_unlock(); 46} 47EXPORT_SYMBOL(__icmpv6_send); 48#endif 49 50#if IS_ENABLED(CONFIG_NF_NAT) 51#include <net/netfilter/nf_conntrack.h> 52void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info) 53{ 54 struct inet6_skb_parm parm = { 0 }; 55 struct sk_buff *cloned_skb = NULL; 56 enum ip_conntrack_info ctinfo; 57 struct in6_addr orig_ip; 58 struct nf_conn *ct; 59 60 ct = nf_ct_get(skb_in, &ctinfo); 61 if (!ct || !(ct->status & IPS_SRC_NAT)) { 62 __icmpv6_send(skb_in, type, code, info, &parm); 63 return; 64 } 65 66 if (skb_shared(skb_in)) 67 skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC); 68 69 if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head || 70 (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) > 71 skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in, 72 skb_network_offset(skb_in) + sizeof(struct ipv6hdr)))) 73 goto out; 74 75 orig_ip = ipv6_hdr(skb_in)->saddr; 76 ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6; 77 __icmpv6_send(skb_in, type, code, info, &parm); 78 ipv6_hdr(skb_in)->saddr = orig_ip; 79out: 80 consume_skb(cloned_skb); 81} 82EXPORT_SYMBOL(icmpv6_ndo_send); 83#endif 84#endif