Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc4 250 lines 5.5 kB view raw
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 18static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 19static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 20static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly; 21static DEFINE_MUTEX(tunnel4_mutex); 22 23static 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 30int 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 55err: 56 mutex_unlock(&tunnel4_mutex); 57 58 return ret; 59} 60EXPORT_SYMBOL(xfrm4_tunnel_register); 61 62int 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} 87EXPORT_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 94static 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 107drop: 108 kfree_skb(skb); 109 return 0; 110} 111 112#if IS_ENABLED(CONFIG_IPV6) 113static 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 126drop: 127 kfree_skb(skb); 128 return 0; 129} 130#endif 131 132#if IS_ENABLED(CONFIG_MPLS) 133static 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 146drop: 147 kfree_skb(skb); 148 return 0; 149} 150#endif 151 152static 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) 162static 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) 173static 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 183static 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) 191static 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) 200static 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 208static 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 229err: 230 pr_err("%s: can't add protocol\n", __func__); 231 return -EAGAIN; 232} 233 234static 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 248module_init(tunnel4_init); 249module_exit(tunnel4_fini); 250MODULE_LICENSE("GPL");