1#include <linux/export.h> 2#include <linux/icmpv6.h> 3#include <linux/mutex.h> 4#include <linux/netdevice.h> 5#include <linux/spinlock.h> 6 7#include <net/ipv6.h> 8 9#if IS_ENABLED(CONFIG_IPV6) 10 11static ip6_icmp_send_t __rcu *ip6_icmp_send; 12 13int inet6_register_icmp_sender(ip6_icmp_send_t *fn) 14{ 15 return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? 16 0 : -EBUSY; 17} 18EXPORT_SYMBOL(inet6_register_icmp_sender); 19 20int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn) 21{ 22 int ret; 23 24 ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ? 25 0 : -EINVAL; 26 27 synchronize_net(); 28 29 return ret; 30} 31EXPORT_SYMBOL(inet6_unregister_icmp_sender); 32 33void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) 34{ 35 ip6_icmp_send_t *send; 36 37 rcu_read_lock(); 38 send = rcu_dereference(ip6_icmp_send); 39 40 if (!send) 41 goto out; 42 send(skb, type, code, info); 43out: 44 rcu_read_unlock(); 45} 46EXPORT_SYMBOL(icmpv6_send); 47#endif 48