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/mpls.h> 10 #include <linux/netdevice.h> 11 #include <linux/skbuff.h> 12 #include <linux/slab.h> 13 #include <net/icmp.h> 14 #include <net/ip.h> 15 #include <net/protocol.h> 16 #include <net/xfrm.h> 17 18 static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 19 static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 20 static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly; 21 static DEFINE_MUTEX(tunnel4_mutex); 22 23 static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 24 { 25 return (family == AF_INET) ? &tunnel4_handlers : 26 (family == AF_INET6) ? &tunnel64_handlers : 27 &tunnelmpls4_handlers; 28 } 29 30 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 31 { 32 struct xfrm_tunnel __rcu **pprev; 33 struct xfrm_tunnel *t; 34 35 int ret = -EEXIST; 36 int priority = handler->priority; 37 38 mutex_lock(&tunnel4_mutex); 39 40 for (pprev = fam_handlers(family); 41 (t = rcu_dereference_protected(*pprev, 42 lockdep_is_held(&tunnel4_mutex))) != NULL; 43 pprev = &t->next) { 44 if (t->priority > priority) 45 break; 46 if (t->priority == priority) 47 goto err; 48 } 49 50 handler->next = *pprev; 51 rcu_assign_pointer(*pprev, handler); 52 53 ret = 0; 54 55 err: 56 mutex_unlock(&tunnel4_mutex); 57 58 return ret; 59 } 60 EXPORT_SYMBOL(xfrm4_tunnel_register); 61 62 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 63 { 64 struct xfrm_tunnel __rcu **pprev; 65 struct xfrm_tunnel *t; 66 int ret = -ENOENT; 67 68 mutex_lock(&tunnel4_mutex); 69 70 for (pprev = fam_handlers(family); 71 (t = rcu_dereference_protected(*pprev, 72 lockdep_is_held(&tunnel4_mutex))) != NULL; 73 pprev = &t->next) { 74 if (t == handler) { 75 *pprev = handler->next; 76 ret = 0; 77 break; 78 } 79 } 80 81 mutex_unlock(&tunnel4_mutex); 82 83 synchronize_net(); 84 85 return ret; 86 } 87 EXPORT_SYMBOL(xfrm4_tunnel_deregister); 88 89 #define for_each_tunnel_rcu(head, handler) \ 90 for (handler = rcu_dereference(head); \ 91 handler != NULL; \ 92 handler = rcu_dereference(handler->next)) \ 93 94 static int tunnel4_rcv(struct sk_buff *skb) 95 { 96 struct xfrm_tunnel *handler; 97 98 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 99 goto drop; 100 101 for_each_tunnel_rcu(tunnel4_handlers, handler) 102 if (!handler->handler(skb)) 103 return 0; 104 105 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 106 107 drop: 108 kfree_skb(skb); 109 return 0; 110 } 111 112 #if IS_ENABLED(CONFIG_IPV6) 113 static int tunnel64_rcv(struct sk_buff *skb) 114 { 115 struct xfrm_tunnel *handler; 116 117 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 118 goto drop; 119 120 for_each_tunnel_rcu(tunnel64_handlers, handler) 121 if (!handler->handler(skb)) 122 return 0; 123 124 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 125 126 drop: 127 kfree_skb(skb); 128 return 0; 129 } 130 #endif 131 132 #if IS_ENABLED(CONFIG_MPLS) 133 static int tunnelmpls4_rcv(struct sk_buff *skb) 134 { 135 struct xfrm_tunnel *handler; 136 137 if (!pskb_may_pull(skb, sizeof(struct mpls_label))) 138 goto drop; 139 140 for_each_tunnel_rcu(tunnelmpls4_handlers, handler) 141 if (!handler->handler(skb)) 142 return 0; 143 144 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 145 146 drop: 147 kfree_skb(skb); 148 return 0; 149 } 150 #endif 151 152 static void tunnel4_err(struct sk_buff *skb, u32 info) 153 { 154 struct xfrm_tunnel *handler; 155 156 for_each_tunnel_rcu(tunnel4_handlers, handler) 157 if (!handler->err_handler(skb, info)) 158 break; 159 } 160 161 #if IS_ENABLED(CONFIG_IPV6) 162 static void tunnel64_err(struct sk_buff *skb, u32 info) 163 { 164 struct xfrm_tunnel *handler; 165 166 for_each_tunnel_rcu(tunnel64_handlers, handler) 167 if (!handler->err_handler(skb, info)) 168 break; 169 } 170 #endif 171 172 #if IS_ENABLED(CONFIG_MPLS) 173 static void tunnelmpls4_err(struct sk_buff *skb, u32 info) 174 { 175 struct xfrm_tunnel *handler; 176 177 for_each_tunnel_rcu(tunnelmpls4_handlers, handler) 178 if (!handler->err_handler(skb, info)) 179 break; 180 } 181 #endif 182 183 static const struct net_protocol tunnel4_protocol = { 184 .handler = tunnel4_rcv, 185 .err_handler = tunnel4_err, 186 .no_policy = 1, 187 .netns_ok = 1, 188 }; 189 190 #if IS_ENABLED(CONFIG_IPV6) 191 static const struct net_protocol tunnel64_protocol = { 192 .handler = tunnel64_rcv, 193 .err_handler = tunnel64_err, 194 .no_policy = 1, 195 .netns_ok = 1, 196 }; 197 #endif 198 199 #if IS_ENABLED(CONFIG_MPLS) 200 static const struct net_protocol tunnelmpls4_protocol = { 201 .handler = tunnelmpls4_rcv, 202 .err_handler = tunnelmpls4_err, 203 .no_policy = 1, 204 .netns_ok = 1, 205 }; 206 #endif 207 208 static int __init tunnel4_init(void) 209 { 210 if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 211 goto err; 212 #if IS_ENABLED(CONFIG_IPV6) 213 if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 214 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 215 goto err; 216 } 217 #endif 218 #if IS_ENABLED(CONFIG_MPLS) 219 if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) { 220 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 221 #if IS_ENABLED(CONFIG_IPV6) 222 inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6); 223 #endif 224 goto err; 225 } 226 #endif 227 return 0; 228 229 err: 230 pr_err("%s: can't add protocol\n", __func__); 231 return -EAGAIN; 232 } 233 234 static void __exit tunnel4_fini(void) 235 { 236 #if IS_ENABLED(CONFIG_MPLS) 237 if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) 238 pr_err("tunnelmpls4 close: can't remove protocol\n"); 239 #endif 240 #if IS_ENABLED(CONFIG_IPV6) 241 if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 242 pr_err("tunnel64 close: can't remove protocol\n"); 243 #endif 244 if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 245 pr_err("tunnel4 close: can't remove protocol\n"); 246 } 247 248 module_init(tunnel4_init); 249 module_exit(tunnel4_fini); 250 MODULE_LICENSE("GPL"); 251