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