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 11 static ip6_icmp_send_t __rcu *ip6_icmp_send; 12 13 int 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 } 18 EXPORT_SYMBOL(inet6_register_icmp_sender); 19 20 int 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 } 31 EXPORT_SYMBOL(inet6_unregister_icmp_sender); 32 33 void 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, NULL); 43 out: 44 rcu_read_unlock(); 45 } 46 EXPORT_SYMBOL(icmpv6_send); 47 #endif 48