123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- // SPDX-License-Identifier: GPL-2.0
- #include <linux/export.h>
- #include <linux/icmpv6.h>
- #include <linux/mutex.h>
- #include <linux/netdevice.h>
- #include <linux/spinlock.h>
- #include <net/ipv6.h>
- #if IS_ENABLED(CONFIG_IPV6)
- #if !IS_BUILTIN(CONFIG_IPV6)
- static ip6_icmp_send_t __rcu *ip6_icmp_send;
- int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
- {
- return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
- 0 : -EBUSY;
- }
- EXPORT_SYMBOL(inet6_register_icmp_sender);
- int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn)
- {
- int ret;
- ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ?
- 0 : -EINVAL;
- synchronize_net();
- return ret;
- }
- EXPORT_SYMBOL(inet6_unregister_icmp_sender);
- void __icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
- const struct inet6_skb_parm *parm)
- {
- ip6_icmp_send_t *send;
- rcu_read_lock();
- send = rcu_dereference(ip6_icmp_send);
- if (send)
- send(skb, type, code, info, NULL, parm);
- rcu_read_unlock();
- }
- EXPORT_SYMBOL(__icmpv6_send);
- #endif
- #if IS_ENABLED(CONFIG_NF_NAT)
- #include <net/netfilter/nf_conntrack.h>
- void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
- {
- struct inet6_skb_parm parm = { 0 };
- struct sk_buff *cloned_skb = NULL;
- enum ip_conntrack_info ctinfo;
- struct in6_addr orig_ip;
- struct nf_conn *ct;
- ct = nf_ct_get(skb_in, &ctinfo);
- if (!ct || !(ct->status & IPS_SRC_NAT)) {
- __icmpv6_send(skb_in, type, code, info, &parm);
- return;
- }
- if (skb_shared(skb_in))
- skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
- if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
- (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) >
- skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
- skb_network_offset(skb_in) + sizeof(struct ipv6hdr))))
- goto out;
- orig_ip = ipv6_hdr(skb_in)->saddr;
- ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
- __icmpv6_send(skb_in, type, code, info, &parm);
- ipv6_hdr(skb_in)->saddr = orig_ip;
- out:
- consume_skb(cloned_skb);
- }
- EXPORT_SYMBOL(icmpv6_ndo_send);
- #endif
- #endif
|