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> 115a0e3ad6STejun 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 176dcd814bSEric Dumazet static struct xfrm_tunnel *tunnel4_handlers __read_mostly; 186dcd814bSEric Dumazet static struct xfrm_tunnel *tunnel64_handlers __read_mostly; 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 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 EXPORT_SYMBOL(xfrm4_tunnel_deregister); 75d2acc347SHerbert Xu 76*875168a9SEric Dumazet #define for_each_tunnel_rcu(head, handler) \ 77*875168a9SEric Dumazet for (handler = rcu_dereference(head); \ 78*875168a9SEric Dumazet handler != NULL; \ 79*875168a9SEric Dumazet handler = rcu_dereference(handler->next)) \ 80*875168a9SEric Dumazet 81d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 82d2acc347SHerbert Xu { 83d2acc347SHerbert Xu struct xfrm_tunnel *handler; 84d2acc347SHerbert Xu 8550fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 8650fba2aaSHerbert Xu goto drop; 8750fba2aaSHerbert Xu 88*875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 89d2acc347SHerbert Xu if (!handler->handler(skb)) 90d2acc347SHerbert Xu return 0; 91d2acc347SHerbert Xu 9250fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 9350fba2aaSHerbert Xu 9450fba2aaSHerbert Xu drop: 95d2acc347SHerbert Xu kfree_skb(skb); 96d2acc347SHerbert Xu return 0; 97d2acc347SHerbert Xu } 98d2acc347SHerbert Xu 99c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 100c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 101c0d56408SKazunori MIYAZAWA { 102c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 103c0d56408SKazunori MIYAZAWA 104baa2bfb8SYOSHIFUJI Hideaki if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 105c0d56408SKazunori MIYAZAWA goto drop; 106c0d56408SKazunori MIYAZAWA 107*875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 108c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 109c0d56408SKazunori MIYAZAWA return 0; 110c0d56408SKazunori MIYAZAWA 111c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 112c0d56408SKazunori MIYAZAWA 113c0d56408SKazunori MIYAZAWA drop: 114c0d56408SKazunori MIYAZAWA kfree_skb(skb); 115c0d56408SKazunori MIYAZAWA return 0; 116c0d56408SKazunori MIYAZAWA } 117c0d56408SKazunori MIYAZAWA #endif 118c0d56408SKazunori MIYAZAWA 119d2acc347SHerbert Xu static void tunnel4_err(struct sk_buff *skb, u32 info) 120d2acc347SHerbert Xu { 121d2acc347SHerbert Xu struct xfrm_tunnel *handler; 122d2acc347SHerbert Xu 123*875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 124d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 125d2acc347SHerbert Xu break; 126d2acc347SHerbert Xu } 127d2acc347SHerbert Xu 12899f93326SPavel Emelyanov #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 12999f93326SPavel Emelyanov static void tunnel64_err(struct sk_buff *skb, u32 info) 13099f93326SPavel Emelyanov { 13199f93326SPavel Emelyanov struct xfrm_tunnel *handler; 13299f93326SPavel Emelyanov 133*875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 13499f93326SPavel Emelyanov if (!handler->err_handler(skb, info)) 13599f93326SPavel Emelyanov break; 13699f93326SPavel Emelyanov } 13799f93326SPavel Emelyanov #endif 13899f93326SPavel Emelyanov 13932613090SAlexey Dobriyan static const struct net_protocol tunnel4_protocol = { 140d2acc347SHerbert Xu .handler = tunnel4_rcv, 141d2acc347SHerbert Xu .err_handler = tunnel4_err, 142d2acc347SHerbert Xu .no_policy = 1, 1434597a0ceSPavel Emelyanov .netns_ok = 1, 144d2acc347SHerbert Xu }; 145d2acc347SHerbert Xu 146c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 14732613090SAlexey Dobriyan static const struct net_protocol tunnel64_protocol = { 148c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 14999f93326SPavel Emelyanov .err_handler = tunnel64_err, 150c0d56408SKazunori MIYAZAWA .no_policy = 1, 151b0970c42SPavel Emelyanov .netns_ok = 1, 152c0d56408SKazunori MIYAZAWA }; 153c0d56408SKazunori MIYAZAWA #endif 154c0d56408SKazunori MIYAZAWA 155d2acc347SHerbert Xu static int __init tunnel4_init(void) 156d2acc347SHerbert Xu { 157d2acc347SHerbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 158d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 159d2acc347SHerbert Xu return -EAGAIN; 160d2acc347SHerbert Xu } 161c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 162c0d56408SKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 163c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 164c0d56408SKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 165c0d56408SKazunori MIYAZAWA return -EAGAIN; 166c0d56408SKazunori MIYAZAWA } 167c0d56408SKazunori MIYAZAWA #endif 168d2acc347SHerbert Xu return 0; 169d2acc347SHerbert Xu } 170d2acc347SHerbert Xu 171d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 172d2acc347SHerbert Xu { 173c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 174c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 175c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 176c0d56408SKazunori MIYAZAWA #endif 177d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 178d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 179d2acc347SHerbert Xu } 180d2acc347SHerbert Xu 181d2acc347SHerbert Xu module_init(tunnel4_init); 182d2acc347SHerbert Xu module_exit(tunnel4_fini); 183d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 184