tunnel6.c (7216B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C)2003,2004 USAGI/WIDE Project 4 * 5 * Authors Mitsuru KANDA <mk@linux-ipv6.org> 6 * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> 7 */ 8 9#define pr_fmt(fmt) "IPv6: " fmt 10 11#include <linux/icmpv6.h> 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/mutex.h> 15#include <linux/netdevice.h> 16#include <linux/skbuff.h> 17#include <linux/slab.h> 18#include <net/ipv6.h> 19#include <net/protocol.h> 20#include <net/xfrm.h> 21 22static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly; 23static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly; 24static struct xfrm6_tunnel __rcu *tunnelmpls6_handlers __read_mostly; 25static DEFINE_MUTEX(tunnel6_mutex); 26 27static inline int xfrm6_tunnel_mpls_supported(void) 28{ 29 return IS_ENABLED(CONFIG_MPLS); 30} 31 32int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) 33{ 34 struct xfrm6_tunnel __rcu **pprev; 35 struct xfrm6_tunnel *t; 36 int ret = -EEXIST; 37 int priority = handler->priority; 38 39 mutex_lock(&tunnel6_mutex); 40 41 switch (family) { 42 case AF_INET6: 43 pprev = &tunnel6_handlers; 44 break; 45 case AF_INET: 46 pprev = &tunnel46_handlers; 47 break; 48 case AF_MPLS: 49 pprev = &tunnelmpls6_handlers; 50 break; 51 default: 52 goto err; 53 } 54 55 for (; (t = rcu_dereference_protected(*pprev, 56 lockdep_is_held(&tunnel6_mutex))) != NULL; 57 pprev = &t->next) { 58 if (t->priority > priority) 59 break; 60 if (t->priority == priority) 61 goto err; 62 } 63 64 handler->next = *pprev; 65 rcu_assign_pointer(*pprev, handler); 66 67 ret = 0; 68 69err: 70 mutex_unlock(&tunnel6_mutex); 71 72 return ret; 73} 74EXPORT_SYMBOL(xfrm6_tunnel_register); 75 76int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) 77{ 78 struct xfrm6_tunnel __rcu **pprev; 79 struct xfrm6_tunnel *t; 80 int ret = -ENOENT; 81 82 mutex_lock(&tunnel6_mutex); 83 84 switch (family) { 85 case AF_INET6: 86 pprev = &tunnel6_handlers; 87 break; 88 case AF_INET: 89 pprev = &tunnel46_handlers; 90 break; 91 case AF_MPLS: 92 pprev = &tunnelmpls6_handlers; 93 break; 94 default: 95 goto err; 96 } 97 98 for (; (t = rcu_dereference_protected(*pprev, 99 lockdep_is_held(&tunnel6_mutex))) != NULL; 100 pprev = &t->next) { 101 if (t == handler) { 102 *pprev = handler->next; 103 ret = 0; 104 break; 105 } 106 } 107 108err: 109 mutex_unlock(&tunnel6_mutex); 110 111 synchronize_net(); 112 113 return ret; 114} 115EXPORT_SYMBOL(xfrm6_tunnel_deregister); 116 117#define for_each_tunnel_rcu(head, handler) \ 118 for (handler = rcu_dereference(head); \ 119 handler != NULL; \ 120 handler = rcu_dereference(handler->next)) \ 121 122static int tunnelmpls6_rcv(struct sk_buff *skb) 123{ 124 struct xfrm6_tunnel *handler; 125 126 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 127 goto drop; 128 129 for_each_tunnel_rcu(tunnelmpls6_handlers, handler) 130 if (!handler->handler(skb)) 131 return 0; 132 133 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 134 135drop: 136 kfree_skb(skb); 137 return 0; 138} 139 140static int tunnel6_rcv(struct sk_buff *skb) 141{ 142 struct xfrm6_tunnel *handler; 143 144 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 145 goto drop; 146 147 for_each_tunnel_rcu(tunnel6_handlers, handler) 148 if (!handler->handler(skb)) 149 return 0; 150 151 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 152 153drop: 154 kfree_skb(skb); 155 return 0; 156} 157 158#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL) 159static int tunnel6_rcv_cb(struct sk_buff *skb, u8 proto, int err) 160{ 161 struct xfrm6_tunnel __rcu *head; 162 struct xfrm6_tunnel *handler; 163 int ret; 164 165 head = (proto == IPPROTO_IPV6) ? tunnel6_handlers : tunnel46_handlers; 166 167 for_each_tunnel_rcu(head, handler) { 168 if (handler->cb_handler) { 169 ret = handler->cb_handler(skb, err); 170 if (ret <= 0) 171 return ret; 172 } 173 } 174 175 return 0; 176} 177 178static const struct xfrm_input_afinfo tunnel6_input_afinfo = { 179 .family = AF_INET6, 180 .is_ipip = true, 181 .callback = tunnel6_rcv_cb, 182}; 183#endif 184 185static int tunnel46_rcv(struct sk_buff *skb) 186{ 187 struct xfrm6_tunnel *handler; 188 189 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 190 goto drop; 191 192 for_each_tunnel_rcu(tunnel46_handlers, handler) 193 if (!handler->handler(skb)) 194 return 0; 195 196 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 197 198drop: 199 kfree_skb(skb); 200 return 0; 201} 202 203static int tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 204 u8 type, u8 code, int offset, __be32 info) 205{ 206 struct xfrm6_tunnel *handler; 207 208 for_each_tunnel_rcu(tunnel6_handlers, handler) 209 if (!handler->err_handler(skb, opt, type, code, offset, info)) 210 return 0; 211 212 return -ENOENT; 213} 214 215static int tunnel46_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 216 u8 type, u8 code, int offset, __be32 info) 217{ 218 struct xfrm6_tunnel *handler; 219 220 for_each_tunnel_rcu(tunnel46_handlers, handler) 221 if (!handler->err_handler(skb, opt, type, code, offset, info)) 222 return 0; 223 224 return -ENOENT; 225} 226 227static int tunnelmpls6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 228 u8 type, u8 code, int offset, __be32 info) 229{ 230 struct xfrm6_tunnel *handler; 231 232 for_each_tunnel_rcu(tunnelmpls6_handlers, handler) 233 if (!handler->err_handler(skb, opt, type, code, offset, info)) 234 return 0; 235 236 return -ENOENT; 237} 238 239static const struct inet6_protocol tunnel6_protocol = { 240 .handler = tunnel6_rcv, 241 .err_handler = tunnel6_err, 242 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 243}; 244 245static const struct inet6_protocol tunnel46_protocol = { 246 .handler = tunnel46_rcv, 247 .err_handler = tunnel46_err, 248 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 249}; 250 251static const struct inet6_protocol tunnelmpls6_protocol = { 252 .handler = tunnelmpls6_rcv, 253 .err_handler = tunnelmpls6_err, 254 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 255}; 256 257static int __init tunnel6_init(void) 258{ 259 if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { 260 pr_err("%s: can't add protocol\n", __func__); 261 return -EAGAIN; 262 } 263 if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) { 264 pr_err("%s: can't add protocol\n", __func__); 265 inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); 266 return -EAGAIN; 267 } 268 if (xfrm6_tunnel_mpls_supported() && 269 inet6_add_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS)) { 270 pr_err("%s: can't add protocol\n", __func__); 271 inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); 272 inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP); 273 return -EAGAIN; 274 } 275#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL) 276 if (xfrm_input_register_afinfo(&tunnel6_input_afinfo)) { 277 pr_err("%s: can't add input afinfo\n", __func__); 278 inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); 279 inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP); 280 if (xfrm6_tunnel_mpls_supported()) 281 inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS); 282 return -EAGAIN; 283 } 284#endif 285 return 0; 286} 287 288static void __exit tunnel6_fini(void) 289{ 290#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL) 291 if (xfrm_input_unregister_afinfo(&tunnel6_input_afinfo)) 292 pr_err("%s: can't remove input afinfo\n", __func__); 293#endif 294 if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP)) 295 pr_err("%s: can't remove protocol\n", __func__); 296 if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) 297 pr_err("%s: can't remove protocol\n", __func__); 298 if (xfrm6_tunnel_mpls_supported() && 299 inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS)) 300 pr_err("%s: can't remove protocol\n", __func__); 301} 302 303module_init(tunnel6_init); 304module_exit(tunnel6_fini); 305MODULE_LICENSE("GPL");