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 17b33eab08SEric Dumazet static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 18b33eab08SEric Dumazet static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 19d2acc347SHerbert Xu static DEFINE_MUTEX(tunnel4_mutex); 20d2acc347SHerbert Xu 21b33eab08SEric Dumazet static inline struct xfrm_tunnel __rcu **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 { 28b33eab08SEric Dumazet struct xfrm_tunnel __rcu **pprev; 29b33eab08SEric Dumazet struct xfrm_tunnel *t; 30b33eab08SEric Dumazet 31d2acc347SHerbert Xu int ret = -EEXIST; 32d2acc347SHerbert Xu int priority = handler->priority; 33d2acc347SHerbert Xu 34d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 35d2acc347SHerbert Xu 36b33eab08SEric Dumazet for (pprev = fam_handlers(family); 37b33eab08SEric Dumazet (t = rcu_dereference_protected(*pprev, 38b33eab08SEric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 39b33eab08SEric Dumazet pprev = &t->next) { 40b33eab08SEric Dumazet if (t->priority > priority) 41d2acc347SHerbert Xu break; 42b33eab08SEric Dumazet if (t->priority == priority) 43d2acc347SHerbert Xu goto err; 44d2acc347SHerbert Xu } 45d2acc347SHerbert Xu 46d2acc347SHerbert Xu handler->next = *pprev; 4749d61e23SEric Dumazet rcu_assign_pointer(*pprev, handler); 48d2acc347SHerbert Xu 49d2acc347SHerbert Xu ret = 0; 50d2acc347SHerbert Xu 51d2acc347SHerbert Xu err: 52d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 53d2acc347SHerbert Xu 54d2acc347SHerbert Xu return ret; 55d2acc347SHerbert Xu } 56d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_register); 57d2acc347SHerbert Xu 58c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 59d2acc347SHerbert Xu { 60b33eab08SEric Dumazet struct xfrm_tunnel __rcu **pprev; 61b33eab08SEric Dumazet struct xfrm_tunnel *t; 62d2acc347SHerbert Xu int ret = -ENOENT; 63d2acc347SHerbert Xu 64d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 65d2acc347SHerbert Xu 66b33eab08SEric Dumazet for (pprev = fam_handlers(family); 67b33eab08SEric Dumazet (t = rcu_dereference_protected(*pprev, 68b33eab08SEric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 69b33eab08SEric Dumazet pprev = &t->next) { 70b33eab08SEric Dumazet if (t == handler) { 71d2acc347SHerbert Xu *pprev = handler->next; 72d2acc347SHerbert Xu ret = 0; 73d2acc347SHerbert Xu break; 74d2acc347SHerbert Xu } 75d2acc347SHerbert Xu } 76d2acc347SHerbert Xu 77d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 78d2acc347SHerbert Xu 79d2acc347SHerbert Xu synchronize_net(); 80d2acc347SHerbert Xu 81d2acc347SHerbert Xu return ret; 82d2acc347SHerbert Xu } 83d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_deregister); 84d2acc347SHerbert Xu 85875168a9SEric Dumazet #define for_each_tunnel_rcu(head, handler) \ 86875168a9SEric Dumazet for (handler = rcu_dereference(head); \ 87875168a9SEric Dumazet handler != NULL; \ 88875168a9SEric Dumazet handler = rcu_dereference(handler->next)) \ 89875168a9SEric Dumazet 90d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 91d2acc347SHerbert Xu { 92d2acc347SHerbert Xu struct xfrm_tunnel *handler; 93d2acc347SHerbert Xu 9450fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 9550fba2aaSHerbert Xu goto drop; 9650fba2aaSHerbert Xu 97875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 98d2acc347SHerbert Xu if (!handler->handler(skb)) 99d2acc347SHerbert Xu return 0; 100d2acc347SHerbert Xu 10150fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 10250fba2aaSHerbert Xu 10350fba2aaSHerbert Xu drop: 104d2acc347SHerbert Xu kfree_skb(skb); 105d2acc347SHerbert Xu return 0; 106d2acc347SHerbert Xu } 107d2acc347SHerbert Xu 108*dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 109c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 110c0d56408SKazunori MIYAZAWA { 111c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 112c0d56408SKazunori MIYAZAWA 113baa2bfb8SYOSHIFUJI Hideaki if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 114c0d56408SKazunori MIYAZAWA goto drop; 115c0d56408SKazunori MIYAZAWA 116875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 117c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 118c0d56408SKazunori MIYAZAWA return 0; 119c0d56408SKazunori MIYAZAWA 120c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 121c0d56408SKazunori MIYAZAWA 122c0d56408SKazunori MIYAZAWA drop: 123c0d56408SKazunori MIYAZAWA kfree_skb(skb); 124c0d56408SKazunori MIYAZAWA return 0; 125c0d56408SKazunori MIYAZAWA } 126c0d56408SKazunori MIYAZAWA #endif 127c0d56408SKazunori MIYAZAWA 128d2acc347SHerbert Xu static void tunnel4_err(struct sk_buff *skb, u32 info) 129d2acc347SHerbert Xu { 130d2acc347SHerbert Xu struct xfrm_tunnel *handler; 131d2acc347SHerbert Xu 132875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 133d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 134d2acc347SHerbert Xu break; 135d2acc347SHerbert Xu } 136d2acc347SHerbert Xu 137*dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 13899f93326SPavel Emelyanov static void tunnel64_err(struct sk_buff *skb, u32 info) 13999f93326SPavel Emelyanov { 14099f93326SPavel Emelyanov struct xfrm_tunnel *handler; 14199f93326SPavel Emelyanov 142875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 14399f93326SPavel Emelyanov if (!handler->err_handler(skb, info)) 14499f93326SPavel Emelyanov break; 14599f93326SPavel Emelyanov } 14699f93326SPavel Emelyanov #endif 14799f93326SPavel Emelyanov 14832613090SAlexey Dobriyan static const struct net_protocol tunnel4_protocol = { 149d2acc347SHerbert Xu .handler = tunnel4_rcv, 150d2acc347SHerbert Xu .err_handler = tunnel4_err, 151d2acc347SHerbert Xu .no_policy = 1, 1524597a0ceSPavel Emelyanov .netns_ok = 1, 153d2acc347SHerbert Xu }; 154d2acc347SHerbert Xu 155*dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 15632613090SAlexey Dobriyan static const struct net_protocol tunnel64_protocol = { 157c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 15899f93326SPavel Emelyanov .err_handler = tunnel64_err, 159c0d56408SKazunori MIYAZAWA .no_policy = 1, 160b0970c42SPavel Emelyanov .netns_ok = 1, 161c0d56408SKazunori MIYAZAWA }; 162c0d56408SKazunori MIYAZAWA #endif 163c0d56408SKazunori MIYAZAWA 164d2acc347SHerbert Xu static int __init tunnel4_init(void) 165d2acc347SHerbert Xu { 166d2acc347SHerbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 167d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 168d2acc347SHerbert Xu return -EAGAIN; 169d2acc347SHerbert Xu } 170*dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 171c0d56408SKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 172c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 173c0d56408SKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 174c0d56408SKazunori MIYAZAWA return -EAGAIN; 175c0d56408SKazunori MIYAZAWA } 176c0d56408SKazunori MIYAZAWA #endif 177d2acc347SHerbert Xu return 0; 178d2acc347SHerbert Xu } 179d2acc347SHerbert Xu 180d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 181d2acc347SHerbert Xu { 182*dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 183c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 184c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 185c0d56408SKazunori MIYAZAWA #endif 186d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 187d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 188d2acc347SHerbert Xu } 189d2acc347SHerbert Xu 190d2acc347SHerbert Xu module_init(tunnel4_init); 191d2acc347SHerbert Xu module_exit(tunnel4_fini); 192d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 193