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