1d2acc347SHerbert Xu /* tunnel4.c: Generic IP tunnel transformer. 2d2acc347SHerbert Xu * 3d2acc347SHerbert Xu * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4d2acc347SHerbert Xu */ 5d2acc347SHerbert Xu 6d2acc347SHerbert Xu #include <linux/init.h> 7d2acc347SHerbert Xu #include <linux/module.h> 8d2acc347SHerbert Xu #include <linux/mutex.h> 9d2acc347SHerbert Xu #include <linux/netdevice.h> 10d2acc347SHerbert Xu #include <linux/skbuff.h> 1150fba2aaSHerbert Xu #include <net/icmp.h> 1250fba2aaSHerbert Xu #include <net/ip.h> 13d2acc347SHerbert Xu #include <net/protocol.h> 14d2acc347SHerbert Xu #include <net/xfrm.h> 15d2acc347SHerbert Xu 16d2acc347SHerbert Xu static struct xfrm_tunnel *tunnel4_handlers; 17c0d56408SKazunori MIYAZAWA static struct xfrm_tunnel *tunnel64_handlers; 18d2acc347SHerbert Xu static DEFINE_MUTEX(tunnel4_mutex); 19d2acc347SHerbert Xu 20358352b8SPavel Emelyanov static inline struct xfrm_tunnel **fam_handlers(unsigned short family) 21358352b8SPavel Emelyanov { 22358352b8SPavel Emelyanov return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 23358352b8SPavel Emelyanov } 24358352b8SPavel Emelyanov 25c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 26d2acc347SHerbert Xu { 27d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 28d2acc347SHerbert Xu int ret = -EEXIST; 29d2acc347SHerbert Xu int priority = handler->priority; 30d2acc347SHerbert Xu 31d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 32d2acc347SHerbert Xu 33358352b8SPavel Emelyanov for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 34d2acc347SHerbert Xu if ((*pprev)->priority > priority) 35d2acc347SHerbert Xu break; 36d2acc347SHerbert Xu if ((*pprev)->priority == priority) 37d2acc347SHerbert Xu goto err; 38d2acc347SHerbert Xu } 39d2acc347SHerbert Xu 40d2acc347SHerbert Xu handler->next = *pprev; 41d2acc347SHerbert Xu *pprev = handler; 42d2acc347SHerbert Xu 43d2acc347SHerbert Xu ret = 0; 44d2acc347SHerbert Xu 45d2acc347SHerbert Xu err: 46d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 47d2acc347SHerbert Xu 48d2acc347SHerbert Xu return ret; 49d2acc347SHerbert Xu } 50d2acc347SHerbert Xu 51d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_register); 52d2acc347SHerbert Xu 53c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 54d2acc347SHerbert Xu { 55d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 56d2acc347SHerbert Xu int ret = -ENOENT; 57d2acc347SHerbert Xu 58d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 59d2acc347SHerbert Xu 60358352b8SPavel Emelyanov for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 61d2acc347SHerbert Xu if (*pprev == handler) { 62d2acc347SHerbert Xu *pprev = handler->next; 63d2acc347SHerbert Xu ret = 0; 64d2acc347SHerbert Xu break; 65d2acc347SHerbert Xu } 66d2acc347SHerbert Xu } 67d2acc347SHerbert Xu 68d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 69d2acc347SHerbert Xu 70d2acc347SHerbert Xu synchronize_net(); 71d2acc347SHerbert Xu 72d2acc347SHerbert Xu return ret; 73d2acc347SHerbert Xu } 74d2acc347SHerbert Xu 75d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_deregister); 76d2acc347SHerbert Xu 77d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 78d2acc347SHerbert Xu { 79d2acc347SHerbert Xu struct xfrm_tunnel *handler; 80d2acc347SHerbert Xu 8150fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 8250fba2aaSHerbert Xu goto drop; 8350fba2aaSHerbert Xu 84d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 85d2acc347SHerbert Xu if (!handler->handler(skb)) 86d2acc347SHerbert Xu return 0; 87d2acc347SHerbert Xu 8850fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 8950fba2aaSHerbert Xu 9050fba2aaSHerbert Xu drop: 91d2acc347SHerbert Xu kfree_skb(skb); 92d2acc347SHerbert Xu return 0; 93d2acc347SHerbert Xu } 94d2acc347SHerbert Xu 95c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 96c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 97c0d56408SKazunori MIYAZAWA { 98c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 99c0d56408SKazunori MIYAZAWA 100c0d56408SKazunori MIYAZAWA if (!pskb_may_pull(skb, sizeof(struct iphdr))) 101c0d56408SKazunori MIYAZAWA goto drop; 102c0d56408SKazunori MIYAZAWA 103c0d56408SKazunori MIYAZAWA for (handler = tunnel64_handlers; handler; handler = handler->next) 104c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 105c0d56408SKazunori MIYAZAWA return 0; 106c0d56408SKazunori MIYAZAWA 107c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 108c0d56408SKazunori MIYAZAWA 109c0d56408SKazunori MIYAZAWA drop: 110c0d56408SKazunori MIYAZAWA kfree_skb(skb); 111c0d56408SKazunori MIYAZAWA return 0; 112c0d56408SKazunori MIYAZAWA } 113c0d56408SKazunori MIYAZAWA #endif 114c0d56408SKazunori MIYAZAWA 115d2acc347SHerbert Xu static void tunnel4_err(struct sk_buff *skb, u32 info) 116d2acc347SHerbert Xu { 117d2acc347SHerbert Xu struct xfrm_tunnel *handler; 118d2acc347SHerbert Xu 119d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 120d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 121d2acc347SHerbert Xu break; 122d2acc347SHerbert Xu } 123d2acc347SHerbert Xu 12499f93326SPavel Emelyanov #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 12599f93326SPavel Emelyanov static void tunnel64_err(struct sk_buff *skb, u32 info) 12699f93326SPavel Emelyanov { 12799f93326SPavel Emelyanov struct xfrm_tunnel *handler; 12899f93326SPavel Emelyanov 12999f93326SPavel Emelyanov for (handler = tunnel64_handlers; handler; handler = handler->next) 13099f93326SPavel Emelyanov if (!handler->err_handler(skb, info)) 13199f93326SPavel Emelyanov break; 13299f93326SPavel Emelyanov } 13399f93326SPavel Emelyanov #endif 13499f93326SPavel Emelyanov 135d2acc347SHerbert Xu static struct net_protocol tunnel4_protocol = { 136d2acc347SHerbert Xu .handler = tunnel4_rcv, 137d2acc347SHerbert Xu .err_handler = tunnel4_err, 138d2acc347SHerbert Xu .no_policy = 1, 1394597a0ceSPavel Emelyanov .netns_ok = 1, 140d2acc347SHerbert Xu }; 141d2acc347SHerbert Xu 142c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 143c0d56408SKazunori MIYAZAWA static struct net_protocol tunnel64_protocol = { 144c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 14599f93326SPavel Emelyanov .err_handler = tunnel64_err, 146c0d56408SKazunori MIYAZAWA .no_policy = 1, 147*b0970c42SPavel Emelyanov .netns_ok = 1, 148c0d56408SKazunori MIYAZAWA }; 149c0d56408SKazunori MIYAZAWA #endif 150c0d56408SKazunori MIYAZAWA 151d2acc347SHerbert Xu static int __init tunnel4_init(void) 152d2acc347SHerbert Xu { 153d2acc347SHerbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 154d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 155d2acc347SHerbert Xu return -EAGAIN; 156d2acc347SHerbert Xu } 157c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 158c0d56408SKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 159c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 160c0d56408SKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 161c0d56408SKazunori MIYAZAWA return -EAGAIN; 162c0d56408SKazunori MIYAZAWA } 163c0d56408SKazunori MIYAZAWA #endif 164d2acc347SHerbert Xu return 0; 165d2acc347SHerbert Xu } 166d2acc347SHerbert Xu 167d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 168d2acc347SHerbert Xu { 169c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 170c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 171c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 172c0d56408SKazunori MIYAZAWA #endif 173d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 174d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 175d2acc347SHerbert Xu } 176d2acc347SHerbert Xu 177d2acc347SHerbert Xu module_init(tunnel4_init); 178d2acc347SHerbert Xu module_exit(tunnel4_fini); 179d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 180