1d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu/* tunnel4.c: Generic IP tunnel transformer. 2d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu * 3d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu */ 5d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 6d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <linux/init.h> 7d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <linux/module.h> 8d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <linux/mutex.h> 9d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <linux/netdevice.h> 10d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <linux/skbuff.h> 115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1250fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu#include <net/icmp.h> 1350fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu#include <net/ip.h> 14d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <net/protocol.h> 15d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu#include <net/xfrm.h> 16d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 17b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazetstatic struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 18b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazetstatic struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 19d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xustatic DEFINE_MUTEX(tunnel4_mutex); 20d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 21b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazetstatic inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 22358352b8b83c67ecf75f6d7bc3e2d64bf0cf506aPavel Emelyanov{ 23358352b8b83c67ecf75f6d7bc3e2d64bf0cf506aPavel Emelyanov return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 24358352b8b83c67ecf75f6d7bc3e2d64bf0cf506aPavel Emelyanov} 25358352b8b83c67ecf75f6d7bc3e2d64bf0cf506aPavel Emelyanov 26c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWAint xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 27d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 28b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet struct xfrm_tunnel __rcu **pprev; 29b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet struct xfrm_tunnel *t; 30b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet 31d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu int ret = -EEXIST; 32d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu int priority = handler->priority; 33d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 34d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu mutex_lock(&tunnel4_mutex); 35d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 36b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet for (pprev = fam_handlers(family); 37b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet (t = rcu_dereference_protected(*pprev, 38b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 39b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet pprev = &t->next) { 40b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet if (t->priority > priority) 41d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu break; 42b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet if (t->priority == priority) 43d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu goto err; 44d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu } 45d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 46d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu handler->next = *pprev; 4749d61e2390c92bd226fc395a6165eb5a65ae4de6Eric Dumazet rcu_assign_pointer(*pprev, handler); 48d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 49d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu ret = 0; 50d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 51d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xuerr: 52d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu mutex_unlock(&tunnel4_mutex); 53d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 54d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return ret; 55d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 56d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert XuEXPORT_SYMBOL(xfrm4_tunnel_register); 57d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 58c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWAint xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 59d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 60b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet struct xfrm_tunnel __rcu **pprev; 61b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet struct xfrm_tunnel *t; 62d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu int ret = -ENOENT; 63d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 64d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu mutex_lock(&tunnel4_mutex); 65d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 66b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet for (pprev = fam_handlers(family); 67b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet (t = rcu_dereference_protected(*pprev, 68b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 69b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet pprev = &t->next) { 70b33eab08445d86c3d0dec3111ce10df561328705Eric Dumazet if (t == handler) { 71d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu *pprev = handler->next; 72d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu ret = 0; 73d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu break; 74d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu } 75d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu } 76d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 77d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu mutex_unlock(&tunnel4_mutex); 78d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 79d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu synchronize_net(); 80d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 81d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return ret; 82d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 83d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert XuEXPORT_SYMBOL(xfrm4_tunnel_deregister); 84d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 85875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet#define for_each_tunnel_rcu(head, handler) \ 86875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet for (handler = rcu_dereference(head); \ 87875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet handler != NULL; \ 88875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet handler = rcu_dereference(handler->next)) \ 89875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet 90d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xustatic int tunnel4_rcv(struct sk_buff *skb) 91d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 92d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu struct xfrm_tunnel *handler; 93d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 9450fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 9550fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu goto drop; 9650fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu 97875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 98d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu if (!handler->handler(skb)) 99d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return 0; 100d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 10150fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 10250fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xu 10350fba2aa7cefa6b0e1768cb350c9e69042320c03Herbert Xudrop: 104d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu kfree_skb(skb); 105d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return 0; 106d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 107d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 108dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6) 109c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWAstatic int tunnel64_rcv(struct sk_buff *skb) 110c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA{ 111c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA struct xfrm_tunnel *handler; 112c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 113baa2bfb8aef24bb7fe1875b256918724b3884662YOSHIFUJI Hideaki if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 114c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA goto drop; 115c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 116875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 117c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA if (!handler->handler(skb)) 118c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA return 0; 119c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 120c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 121c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 122c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWAdrop: 123c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA kfree_skb(skb); 124c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA return 0; 125c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA} 126c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA#endif 127c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 128d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xustatic void tunnel4_err(struct sk_buff *skb, u32 info) 129d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 130d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu struct xfrm_tunnel *handler; 131d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 132875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 133d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu if (!handler->err_handler(skb, info)) 134d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu break; 135d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 136d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 137dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6) 13899f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanovstatic void tunnel64_err(struct sk_buff *skb, u32 info) 13999f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov{ 14099f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov struct xfrm_tunnel *handler; 14199f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov 142875168a9330d3aa6481ce62ce8fa77c7be0c75fbEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 14399f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov if (!handler->err_handler(skb, info)) 14499f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov break; 14599f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov} 14699f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov#endif 14799f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov 14832613090a96dba2ca2cc524c8d4749d3126fdde5Alexey Dobriyanstatic const struct net_protocol tunnel4_protocol = { 149d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu .handler = tunnel4_rcv, 150d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu .err_handler = tunnel4_err, 151d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu .no_policy = 1, 1524597a0ce0849eaa62fc9083c21943e0c434e4135Pavel Emelyanov .netns_ok = 1, 153d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu}; 154d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 155dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6) 15632613090a96dba2ca2cc524c8d4749d3126fdde5Alexey Dobriyanstatic const struct net_protocol tunnel64_protocol = { 157c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA .handler = tunnel64_rcv, 15899f933263ac30eafbb008d01ac1dd0adf40fc343Pavel Emelyanov .err_handler = tunnel64_err, 159c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA .no_policy = 1, 160b0970c428b33ee6e0aa576f58f87dde74262a441Pavel Emelyanov .netns_ok = 1, 161c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA}; 162c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA#endif 163c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA 164d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xustatic int __init tunnel4_init(void) 165d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 166d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 167058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches pr_err("%s: can't add protocol\n", __func__); 168d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return -EAGAIN; 169d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu } 170dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6) 171c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 172058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches pr_err("tunnel64 init: can't add protocol\n"); 173c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 174c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA return -EAGAIN; 175c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA } 176c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA#endif 177d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu return 0; 178d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 179d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 180d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xustatic void __exit tunnel4_fini(void) 181d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu{ 182dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6) 183c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 184058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches pr_err("tunnel64 close: can't remove protocol\n"); 185c0d56408e3ff52d635441e0f08d12164a63728cfKazunori MIYAZAWA#endif 186d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 187058bd4d2a4ff0aaa4a5381c67e776729d840c785Joe Perches pr_err("tunnel4 close: can't remove protocol\n"); 188d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu} 189d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xu 190d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xumodule_init(tunnel4_init); 191d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert Xumodule_exit(tunnel4_fini); 192d2acc3479cbccd5cfbca6c787be713ef1de12ec6Herbert XuMODULE_LICENSE("GPL"); 193