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 *tunnel4_handlers; 18static struct xfrm_tunnel *tunnel64_handlers; 19static DEFINE_MUTEX(tunnel4_mutex); 20 21static inline struct xfrm_tunnel **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 **pprev; 29 int ret = -EEXIST; 30 int priority = handler->priority; 31 32 mutex_lock(&tunnel4_mutex); 33 34 for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 35 if ((*pprev)->priority > priority) 36 break; 37 if ((*pprev)->priority == priority) 38 goto err; 39 } 40 41 handler->next = *pprev; 42 *pprev = handler; 43 44 ret = 0; 45 46err: 47 mutex_unlock(&tunnel4_mutex); 48 49 return ret; 50} 51EXPORT_SYMBOL(xfrm4_tunnel_register); 52 53int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 54{ 55 struct xfrm_tunnel **pprev; 56 int ret = -ENOENT; 57 58 mutex_lock(&tunnel4_mutex); 59 60 for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 61 if (*pprev == handler) { 62 *pprev = handler->next; 63 ret = 0; 64 break; 65 } 66 } 67 68 mutex_unlock(&tunnel4_mutex); 69 70 synchronize_net(); 71 72 return ret; 73} 74EXPORT_SYMBOL(xfrm4_tunnel_deregister); 75 76static int tunnel4_rcv(struct sk_buff *skb) 77{ 78 struct xfrm_tunnel *handler; 79 80 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 81 goto drop; 82 83 for (handler = tunnel4_handlers; handler; handler = handler->next) 84 if (!handler->handler(skb)) 85 return 0; 86 87 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 88 89drop: 90 kfree_skb(skb); 91 return 0; 92} 93 94#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 95static int tunnel64_rcv(struct sk_buff *skb) 96{ 97 struct xfrm_tunnel *handler; 98 99 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 100 goto drop; 101 102 for (handler = tunnel64_handlers; handler; handler = handler->next) 103 if (!handler->handler(skb)) 104 return 0; 105 106 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 107 108drop: 109 kfree_skb(skb); 110 return 0; 111} 112#endif 113 114static void tunnel4_err(struct sk_buff *skb, u32 info) 115{ 116 struct xfrm_tunnel *handler; 117 118 for (handler = tunnel4_handlers; handler; handler = handler->next) 119 if (!handler->err_handler(skb, info)) 120 break; 121} 122 123#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 124static void tunnel64_err(struct sk_buff *skb, u32 info) 125{ 126 struct xfrm_tunnel *handler; 127 128 for (handler = tunnel64_handlers; handler; handler = handler->next) 129 if (!handler->err_handler(skb, info)) 130 break; 131} 132#endif 133 134static const struct net_protocol tunnel4_protocol = { 135 .handler = tunnel4_rcv, 136 .err_handler = tunnel4_err, 137 .no_policy = 1, 138 .netns_ok = 1, 139}; 140 141#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 142static const struct net_protocol tunnel64_protocol = { 143 .handler = tunnel64_rcv, 144 .err_handler = tunnel64_err, 145 .no_policy = 1, 146 .netns_ok = 1, 147}; 148#endif 149 150static int __init tunnel4_init(void) 151{ 152 if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 153 printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 154 return -EAGAIN; 155 } 156#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 157 if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 158 printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 159 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 160 return -EAGAIN; 161 } 162#endif 163 return 0; 164} 165 166static void __exit tunnel4_fini(void) 167{ 168#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 169 if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 170 printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 171#endif 172 if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 173 printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 174} 175 176module_init(tunnel4_init); 177module_exit(tunnel4_fini); 178MODULE_LICENSE("GPL"); 179