1/* tunnel4.c: Generic IP tunnel transformer. 2 * 3 * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4 */ 5 6#include <linux/init.h> 7#include <linux/module.h> 8#include <linux/mutex.h> 9#include <linux/netdevice.h> 10#include <linux/skbuff.h> 11#include <linux/slab.h> 12#include <net/icmp.h> 13#include <net/ip.h> 14#include <net/protocol.h> 15#include <net/xfrm.h> 16 17static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 18static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 19static DEFINE_MUTEX(tunnel4_mutex); 20 21static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 22{ 23 return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 24} 25 26int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 27{ 28 struct xfrm_tunnel __rcu **pprev; 29 struct xfrm_tunnel *t; 30 31 int ret = -EEXIST; 32 int priority = handler->priority; 33 34 mutex_lock(&tunnel4_mutex); 35 36 for (pprev = fam_handlers(family); 37 (t = rcu_dereference_protected(*pprev, 38 lockdep_is_held(&tunnel4_mutex))) != NULL; 39 pprev = &t->next) { 40 if (t->priority > priority) 41 break; 42 if (t->priority == priority) 43 goto err; 44 } 45 46 handler->next = *pprev; 47 rcu_assign_pointer(*pprev, handler); 48 49 ret = 0; 50 51err: 52 mutex_unlock(&tunnel4_mutex); 53 54 return ret; 55} 56EXPORT_SYMBOL(xfrm4_tunnel_register); 57 58int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 59{ 60 struct xfrm_tunnel __rcu **pprev; 61 struct xfrm_tunnel *t; 62 int ret = -ENOENT; 63 64 mutex_lock(&tunnel4_mutex); 65 66 for (pprev = fam_handlers(family); 67 (t = rcu_dereference_protected(*pprev, 68 lockdep_is_held(&tunnel4_mutex))) != NULL; 69 pprev = &t->next) { 70 if (t == handler) { 71 *pprev = handler->next; 72 ret = 0; 73 break; 74 } 75 } 76 77 mutex_unlock(&tunnel4_mutex); 78 79 synchronize_net(); 80 81 return ret; 82} 83EXPORT_SYMBOL(xfrm4_tunnel_deregister); 84 85#define for_each_tunnel_rcu(head, handler) \ 86 for (handler = rcu_dereference(head); \ 87 handler != NULL; \ 88 handler = rcu_dereference(handler->next)) \ 89 90static int tunnel4_rcv(struct sk_buff *skb) 91{ 92 struct xfrm_tunnel *handler; 93 94 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 95 goto drop; 96 97 for_each_tunnel_rcu(tunnel4_handlers, handler) 98 if (!handler->handler(skb)) 99 return 0; 100 101 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 102 103drop: 104 kfree_skb(skb); 105 return 0; 106} 107 108#if IS_ENABLED(CONFIG_IPV6) 109static int tunnel64_rcv(struct sk_buff *skb) 110{ 111 struct xfrm_tunnel *handler; 112 113 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 114 goto drop; 115 116 for_each_tunnel_rcu(tunnel64_handlers, handler) 117 if (!handler->handler(skb)) 118 return 0; 119 120 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 121 122drop: 123 kfree_skb(skb); 124 return 0; 125} 126#endif 127 128static void tunnel4_err(struct sk_buff *skb, u32 info) 129{ 130 struct xfrm_tunnel *handler; 131 132 for_each_tunnel_rcu(tunnel4_handlers, handler) 133 if (!handler->err_handler(skb, info)) 134 break; 135} 136 137#if IS_ENABLED(CONFIG_IPV6) 138static void tunnel64_err(struct sk_buff *skb, u32 info) 139{ 140 struct xfrm_tunnel *handler; 141 142 for_each_tunnel_rcu(tunnel64_handlers, handler) 143 if (!handler->err_handler(skb, info)) 144 break; 145} 146#endif 147 148static const struct net_protocol tunnel4_protocol = { 149 .handler = tunnel4_rcv, 150 .err_handler = tunnel4_err, 151 .no_policy = 1, 152 .netns_ok = 1, 153}; 154 155#if IS_ENABLED(CONFIG_IPV6) 156static const struct net_protocol tunnel64_protocol = { 157 .handler = tunnel64_rcv, 158 .err_handler = tunnel64_err, 159 .no_policy = 1, 160 .netns_ok = 1, 161}; 162#endif 163 164static int __init tunnel4_init(void) 165{ 166 if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 167 pr_err("%s: can't add protocol\n", __func__); 168 return -EAGAIN; 169 } 170#if IS_ENABLED(CONFIG_IPV6) 171 if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 172 pr_err("tunnel64 init: can't add protocol\n"); 173 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 174 return -EAGAIN; 175 } 176#endif 177 return 0; 178} 179 180static void __exit tunnel4_fini(void) 181{ 182#if IS_ENABLED(CONFIG_IPV6) 183 if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 184 pr_err("tunnel64 close: can't remove protocol\n"); 185#endif 186 if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 187 pr_err("tunnel4 close: can't remove protocol\n"); 188} 189 190module_init(tunnel4_init); 191module_exit(tunnel4_fini); 192MODULE_LICENSE("GPL"); 193