Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/export.h>
0003 #include <linux/icmpv6.h>
0004 #include <linux/mutex.h>
0005 #include <linux/netdevice.h>
0006 #include <linux/spinlock.h>
0007 
0008 #include <net/ipv6.h>
0009 
0010 #if IS_ENABLED(CONFIG_IPV6)
0011 
0012 #if !IS_BUILTIN(CONFIG_IPV6)
0013 
0014 static ip6_icmp_send_t __rcu *ip6_icmp_send;
0015 
0016 int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
0017 {
0018     return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
0019         0 : -EBUSY;
0020 }
0021 EXPORT_SYMBOL(inet6_register_icmp_sender);
0022 
0023 int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn)
0024 {
0025     int ret;
0026 
0027     ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ?
0028           0 : -EINVAL;
0029 
0030     synchronize_net();
0031 
0032     return ret;
0033 }
0034 EXPORT_SYMBOL(inet6_unregister_icmp_sender);
0035 
0036 void __icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
0037            const struct inet6_skb_parm *parm)
0038 {
0039     ip6_icmp_send_t *send;
0040 
0041     rcu_read_lock();
0042     send = rcu_dereference(ip6_icmp_send);
0043     if (send)
0044         send(skb, type, code, info, NULL, parm);
0045     rcu_read_unlock();
0046 }
0047 EXPORT_SYMBOL(__icmpv6_send);
0048 #endif
0049 
0050 #if IS_ENABLED(CONFIG_NF_NAT)
0051 #include <net/netfilter/nf_conntrack.h>
0052 void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
0053 {
0054     struct inet6_skb_parm parm = { 0 };
0055     struct sk_buff *cloned_skb = NULL;
0056     enum ip_conntrack_info ctinfo;
0057     struct in6_addr orig_ip;
0058     struct nf_conn *ct;
0059 
0060     ct = nf_ct_get(skb_in, &ctinfo);
0061     if (!ct || !(ct->status & IPS_SRC_NAT)) {
0062         __icmpv6_send(skb_in, type, code, info, &parm);
0063         return;
0064     }
0065 
0066     if (skb_shared(skb_in))
0067         skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
0068 
0069     if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
0070         (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) >
0071         skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
0072         skb_network_offset(skb_in) + sizeof(struct ipv6hdr))))
0073         goto out;
0074 
0075     orig_ip = ipv6_hdr(skb_in)->saddr;
0076     ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
0077     __icmpv6_send(skb_in, type, code, info, &parm);
0078     ipv6_hdr(skb_in)->saddr = orig_ip;
0079 out:
0080     consume_skb(cloned_skb);
0081 }
0082 EXPORT_SYMBOL(icmpv6_ndo_send);
0083 #endif
0084 #endif