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> 11*5a0e3ad6STejun Heo #include <linux/slab.h> 1250fba2aaSHerbert Xu #include <net/icmp.h> 1350fba2aaSHerbert Xu #include <net/ip.h> 14d2acc347SHerbert Xu #include <net/protocol.h> 15d2acc347SHerbert Xu #include <net/xfrm.h> 16d2acc347SHerbert Xu 17d2acc347SHerbert Xu static struct xfrm_tunnel *tunnel4_handlers; 18c0d56408SKazunori MIYAZAWA static struct xfrm_tunnel *tunnel64_handlers; 19d2acc347SHerbert Xu static DEFINE_MUTEX(tunnel4_mutex); 20d2acc347SHerbert Xu 21358352b8SPavel Emelyanov static inline struct xfrm_tunnel **fam_handlers(unsigned short family) 22358352b8SPavel Emelyanov { 23358352b8SPavel Emelyanov return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 24358352b8SPavel Emelyanov } 25358352b8SPavel Emelyanov 26c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 27d2acc347SHerbert Xu { 28d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 29d2acc347SHerbert Xu int ret = -EEXIST; 30d2acc347SHerbert Xu int priority = handler->priority; 31d2acc347SHerbert Xu 32d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 33d2acc347SHerbert Xu 34358352b8SPavel Emelyanov for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 35d2acc347SHerbert Xu if ((*pprev)->priority > priority) 36d2acc347SHerbert Xu break; 37d2acc347SHerbert Xu if ((*pprev)->priority == priority) 38d2acc347SHerbert Xu goto err; 39d2acc347SHerbert Xu } 40d2acc347SHerbert Xu 41d2acc347SHerbert Xu handler->next = *pprev; 42d2acc347SHerbert Xu *pprev = handler; 43d2acc347SHerbert Xu 44d2acc347SHerbert Xu ret = 0; 45d2acc347SHerbert Xu 46d2acc347SHerbert Xu err: 47d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 48d2acc347SHerbert Xu 49d2acc347SHerbert Xu return ret; 50d2acc347SHerbert Xu } 51d2acc347SHerbert Xu 52d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_register); 53d2acc347SHerbert Xu 54c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 55d2acc347SHerbert Xu { 56d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 57d2acc347SHerbert Xu int ret = -ENOENT; 58d2acc347SHerbert Xu 59d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 60d2acc347SHerbert Xu 61358352b8SPavel Emelyanov for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) { 62d2acc347SHerbert Xu if (*pprev == handler) { 63d2acc347SHerbert Xu *pprev = handler->next; 64d2acc347SHerbert Xu ret = 0; 65d2acc347SHerbert Xu break; 66d2acc347SHerbert Xu } 67d2acc347SHerbert Xu } 68d2acc347SHerbert Xu 69d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 70d2acc347SHerbert Xu 71d2acc347SHerbert Xu synchronize_net(); 72d2acc347SHerbert Xu 73d2acc347SHerbert Xu return ret; 74d2acc347SHerbert Xu } 75d2acc347SHerbert Xu 76d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_deregister); 77d2acc347SHerbert Xu 78d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 79d2acc347SHerbert Xu { 80d2acc347SHerbert Xu struct xfrm_tunnel *handler; 81d2acc347SHerbert Xu 8250fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 8350fba2aaSHerbert Xu goto drop; 8450fba2aaSHerbert Xu 85d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 86d2acc347SHerbert Xu if (!handler->handler(skb)) 87d2acc347SHerbert Xu return 0; 88d2acc347SHerbert Xu 8950fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 9050fba2aaSHerbert Xu 9150fba2aaSHerbert Xu drop: 92d2acc347SHerbert Xu kfree_skb(skb); 93d2acc347SHerbert Xu return 0; 94d2acc347SHerbert Xu } 95d2acc347SHerbert Xu 96c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 97c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 98c0d56408SKazunori MIYAZAWA { 99c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 100c0d56408SKazunori MIYAZAWA 101baa2bfb8SYOSHIFUJI Hideaki if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 102c0d56408SKazunori MIYAZAWA goto drop; 103c0d56408SKazunori MIYAZAWA 104c0d56408SKazunori MIYAZAWA for (handler = tunnel64_handlers; handler; handler = handler->next) 105c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 106c0d56408SKazunori MIYAZAWA return 0; 107c0d56408SKazunori MIYAZAWA 108c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 109c0d56408SKazunori MIYAZAWA 110c0d56408SKazunori MIYAZAWA drop: 111c0d56408SKazunori MIYAZAWA kfree_skb(skb); 112c0d56408SKazunori MIYAZAWA return 0; 113c0d56408SKazunori MIYAZAWA } 114c0d56408SKazunori MIYAZAWA #endif 115c0d56408SKazunori MIYAZAWA 116d2acc347SHerbert Xu static void tunnel4_err(struct sk_buff *skb, u32 info) 117d2acc347SHerbert Xu { 118d2acc347SHerbert Xu struct xfrm_tunnel *handler; 119d2acc347SHerbert Xu 120d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 121d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 122d2acc347SHerbert Xu break; 123d2acc347SHerbert Xu } 124d2acc347SHerbert Xu 12599f93326SPavel Emelyanov #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 12699f93326SPavel Emelyanov static void tunnel64_err(struct sk_buff *skb, u32 info) 12799f93326SPavel Emelyanov { 12899f93326SPavel Emelyanov struct xfrm_tunnel *handler; 12999f93326SPavel Emelyanov 13099f93326SPavel Emelyanov for (handler = tunnel64_handlers; handler; handler = handler->next) 13199f93326SPavel Emelyanov if (!handler->err_handler(skb, info)) 13299f93326SPavel Emelyanov break; 13399f93326SPavel Emelyanov } 13499f93326SPavel Emelyanov #endif 13599f93326SPavel Emelyanov 13632613090SAlexey Dobriyan static const struct net_protocol tunnel4_protocol = { 137d2acc347SHerbert Xu .handler = tunnel4_rcv, 138d2acc347SHerbert Xu .err_handler = tunnel4_err, 139d2acc347SHerbert Xu .no_policy = 1, 1404597a0ceSPavel Emelyanov .netns_ok = 1, 141d2acc347SHerbert Xu }; 142d2acc347SHerbert Xu 143c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 14432613090SAlexey Dobriyan static const struct net_protocol tunnel64_protocol = { 145c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 14699f93326SPavel Emelyanov .err_handler = tunnel64_err, 147c0d56408SKazunori MIYAZAWA .no_policy = 1, 148b0970c42SPavel Emelyanov .netns_ok = 1, 149c0d56408SKazunori MIYAZAWA }; 150c0d56408SKazunori MIYAZAWA #endif 151c0d56408SKazunori MIYAZAWA 152d2acc347SHerbert Xu static int __init tunnel4_init(void) 153d2acc347SHerbert Xu { 154d2acc347SHerbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 155d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 156d2acc347SHerbert Xu return -EAGAIN; 157d2acc347SHerbert Xu } 158c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 159c0d56408SKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 160c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 161c0d56408SKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 162c0d56408SKazunori MIYAZAWA return -EAGAIN; 163c0d56408SKazunori MIYAZAWA } 164c0d56408SKazunori MIYAZAWA #endif 165d2acc347SHerbert Xu return 0; 166d2acc347SHerbert Xu } 167d2acc347SHerbert Xu 168d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 169d2acc347SHerbert Xu { 170c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 171c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 172c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 173c0d56408SKazunori MIYAZAWA #endif 174d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 175d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 176d2acc347SHerbert Xu } 177d2acc347SHerbert Xu 178d2acc347SHerbert Xu module_init(tunnel4_init); 179d2acc347SHerbert Xu module_exit(tunnel4_fini); 180d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 181