109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d2acc347SHerbert Xu /* tunnel4.c: Generic IP tunnel transformer. 3d2acc347SHerbert Xu * 4d2acc347SHerbert Xu * Copyright (C) 2003 David S. Miller (davem@redhat.com) 5d2acc347SHerbert Xu */ 6d2acc347SHerbert Xu 7d2acc347SHerbert Xu #include <linux/init.h> 8d2acc347SHerbert Xu #include <linux/module.h> 9d2acc347SHerbert Xu #include <linux/mutex.h> 108afe97e5SSimon Horman #include <linux/mpls.h> 11d2acc347SHerbert Xu #include <linux/netdevice.h> 12d2acc347SHerbert Xu #include <linux/skbuff.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 1450fba2aaSHerbert Xu #include <net/icmp.h> 1550fba2aaSHerbert Xu #include <net/ip.h> 16d2acc347SHerbert Xu #include <net/protocol.h> 17d2acc347SHerbert Xu #include <net/xfrm.h> 18d2acc347SHerbert Xu 19b33eab08SEric Dumazet static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 20b33eab08SEric Dumazet static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 218afe97e5SSimon Horman static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly; 22d2acc347SHerbert Xu static DEFINE_MUTEX(tunnel4_mutex); 23d2acc347SHerbert Xu 24b33eab08SEric Dumazet static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 25358352b8SPavel Emelyanov { 268afe97e5SSimon Horman return (family == AF_INET) ? &tunnel4_handlers : 278afe97e5SSimon Horman (family == AF_INET6) ? &tunnel64_handlers : 288afe97e5SSimon Horman &tunnelmpls4_handlers; 29358352b8SPavel Emelyanov } 30358352b8SPavel Emelyanov 31c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 32d2acc347SHerbert Xu { 33b33eab08SEric Dumazet struct xfrm_tunnel __rcu **pprev; 34b33eab08SEric Dumazet struct xfrm_tunnel *t; 35b33eab08SEric Dumazet 36d2acc347SHerbert Xu int ret = -EEXIST; 37d2acc347SHerbert Xu int priority = handler->priority; 38d2acc347SHerbert Xu 39d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 40d2acc347SHerbert Xu 41b33eab08SEric Dumazet for (pprev = fam_handlers(family); 42b33eab08SEric Dumazet (t = rcu_dereference_protected(*pprev, 43b33eab08SEric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 44b33eab08SEric Dumazet pprev = &t->next) { 45b33eab08SEric Dumazet if (t->priority > priority) 46d2acc347SHerbert Xu break; 47b33eab08SEric Dumazet if (t->priority == priority) 48d2acc347SHerbert Xu goto err; 49d2acc347SHerbert Xu } 50d2acc347SHerbert Xu 51d2acc347SHerbert Xu handler->next = *pprev; 5249d61e23SEric Dumazet rcu_assign_pointer(*pprev, handler); 53d2acc347SHerbert Xu 54d2acc347SHerbert Xu ret = 0; 55d2acc347SHerbert Xu 56d2acc347SHerbert Xu err: 57d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 58d2acc347SHerbert Xu 59d2acc347SHerbert Xu return ret; 60d2acc347SHerbert Xu } 61d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_register); 62d2acc347SHerbert Xu 63c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 64d2acc347SHerbert Xu { 65b33eab08SEric Dumazet struct xfrm_tunnel __rcu **pprev; 66b33eab08SEric Dumazet struct xfrm_tunnel *t; 67d2acc347SHerbert Xu int ret = -ENOENT; 68d2acc347SHerbert Xu 69d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 70d2acc347SHerbert Xu 71b33eab08SEric Dumazet for (pprev = fam_handlers(family); 72b33eab08SEric Dumazet (t = rcu_dereference_protected(*pprev, 73b33eab08SEric Dumazet lockdep_is_held(&tunnel4_mutex))) != NULL; 74b33eab08SEric Dumazet pprev = &t->next) { 75b33eab08SEric Dumazet if (t == handler) { 76d2acc347SHerbert Xu *pprev = handler->next; 77d2acc347SHerbert Xu ret = 0; 78d2acc347SHerbert Xu break; 79d2acc347SHerbert Xu } 80d2acc347SHerbert Xu } 81d2acc347SHerbert Xu 82d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 83d2acc347SHerbert Xu 84d2acc347SHerbert Xu synchronize_net(); 85d2acc347SHerbert Xu 86d2acc347SHerbert Xu return ret; 87d2acc347SHerbert Xu } 88d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_deregister); 89d2acc347SHerbert Xu 90875168a9SEric Dumazet #define for_each_tunnel_rcu(head, handler) \ 91875168a9SEric Dumazet for (handler = rcu_dereference(head); \ 92875168a9SEric Dumazet handler != NULL; \ 93875168a9SEric Dumazet handler = rcu_dereference(handler->next)) \ 94875168a9SEric Dumazet 95d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 96d2acc347SHerbert Xu { 97d2acc347SHerbert Xu struct xfrm_tunnel *handler; 98d2acc347SHerbert Xu 9950fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 10050fba2aaSHerbert Xu goto drop; 10150fba2aaSHerbert Xu 102875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 103d2acc347SHerbert Xu if (!handler->handler(skb)) 104d2acc347SHerbert Xu return 0; 105d2acc347SHerbert Xu 10650fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 10750fba2aaSHerbert Xu 10850fba2aaSHerbert Xu drop: 109d2acc347SHerbert Xu kfree_skb(skb); 110d2acc347SHerbert Xu return 0; 111d2acc347SHerbert Xu } 112d2acc347SHerbert Xu 113*6df2db5dSXin Long #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) 114*6df2db5dSXin Long static int tunnel4_rcv_cb(struct sk_buff *skb, u8 proto, int err) 115*6df2db5dSXin Long { 116*6df2db5dSXin Long struct xfrm_tunnel __rcu *head; 117*6df2db5dSXin Long struct xfrm_tunnel *handler; 118*6df2db5dSXin Long int ret; 119*6df2db5dSXin Long 120*6df2db5dSXin Long head = (proto == IPPROTO_IPIP) ? tunnel4_handlers : tunnel64_handlers; 121*6df2db5dSXin Long 122*6df2db5dSXin Long for_each_tunnel_rcu(head, handler) { 123*6df2db5dSXin Long if (handler->cb_handler) { 124*6df2db5dSXin Long ret = handler->cb_handler(skb, err); 125*6df2db5dSXin Long if (ret <= 0) 126*6df2db5dSXin Long return ret; 127*6df2db5dSXin Long } 128*6df2db5dSXin Long } 129*6df2db5dSXin Long 130*6df2db5dSXin Long return 0; 131*6df2db5dSXin Long } 132*6df2db5dSXin Long 133*6df2db5dSXin Long static const struct xfrm_input_afinfo tunnel4_input_afinfo = { 134*6df2db5dSXin Long .family = AF_INET, 135*6df2db5dSXin Long .is_ipip = true, 136*6df2db5dSXin Long .callback = tunnel4_rcv_cb, 137*6df2db5dSXin Long }; 138*6df2db5dSXin Long #endif 139*6df2db5dSXin Long 140dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 141c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 142c0d56408SKazunori MIYAZAWA { 143c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 144c0d56408SKazunori MIYAZAWA 145baa2bfb8SYOSHIFUJI Hideaki if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 146c0d56408SKazunori MIYAZAWA goto drop; 147c0d56408SKazunori MIYAZAWA 148875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 149c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 150c0d56408SKazunori MIYAZAWA return 0; 151c0d56408SKazunori MIYAZAWA 152c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 153c0d56408SKazunori MIYAZAWA 154c0d56408SKazunori MIYAZAWA drop: 155c0d56408SKazunori MIYAZAWA kfree_skb(skb); 156c0d56408SKazunori MIYAZAWA return 0; 157c0d56408SKazunori MIYAZAWA } 158c0d56408SKazunori MIYAZAWA #endif 159c0d56408SKazunori MIYAZAWA 1608afe97e5SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 1618afe97e5SSimon Horman static int tunnelmpls4_rcv(struct sk_buff *skb) 1628afe97e5SSimon Horman { 1638afe97e5SSimon Horman struct xfrm_tunnel *handler; 1648afe97e5SSimon Horman 1658afe97e5SSimon Horman if (!pskb_may_pull(skb, sizeof(struct mpls_label))) 1668afe97e5SSimon Horman goto drop; 1678afe97e5SSimon Horman 1688afe97e5SSimon Horman for_each_tunnel_rcu(tunnelmpls4_handlers, handler) 1698afe97e5SSimon Horman if (!handler->handler(skb)) 1708afe97e5SSimon Horman return 0; 1718afe97e5SSimon Horman 1728afe97e5SSimon Horman icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 1738afe97e5SSimon Horman 1748afe97e5SSimon Horman drop: 1758afe97e5SSimon Horman kfree_skb(skb); 1768afe97e5SSimon Horman return 0; 1778afe97e5SSimon Horman } 1788afe97e5SSimon Horman #endif 1798afe97e5SSimon Horman 18032bbd879SStefano Brivio static int tunnel4_err(struct sk_buff *skb, u32 info) 181d2acc347SHerbert Xu { 182d2acc347SHerbert Xu struct xfrm_tunnel *handler; 183d2acc347SHerbert Xu 184875168a9SEric Dumazet for_each_tunnel_rcu(tunnel4_handlers, handler) 185d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 18632bbd879SStefano Brivio return 0; 18732bbd879SStefano Brivio 18832bbd879SStefano Brivio return -ENOENT; 189d2acc347SHerbert Xu } 190d2acc347SHerbert Xu 191dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 19232bbd879SStefano Brivio static int tunnel64_err(struct sk_buff *skb, u32 info) 19399f93326SPavel Emelyanov { 19499f93326SPavel Emelyanov struct xfrm_tunnel *handler; 19599f93326SPavel Emelyanov 196875168a9SEric Dumazet for_each_tunnel_rcu(tunnel64_handlers, handler) 19799f93326SPavel Emelyanov if (!handler->err_handler(skb, info)) 19832bbd879SStefano Brivio return 0; 19932bbd879SStefano Brivio 20032bbd879SStefano Brivio return -ENOENT; 20199f93326SPavel Emelyanov } 20299f93326SPavel Emelyanov #endif 20399f93326SPavel Emelyanov 2048afe97e5SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 20532bbd879SStefano Brivio static int tunnelmpls4_err(struct sk_buff *skb, u32 info) 2068afe97e5SSimon Horman { 2078afe97e5SSimon Horman struct xfrm_tunnel *handler; 2088afe97e5SSimon Horman 2098afe97e5SSimon Horman for_each_tunnel_rcu(tunnelmpls4_handlers, handler) 2108afe97e5SSimon Horman if (!handler->err_handler(skb, info)) 21132bbd879SStefano Brivio return 0; 21232bbd879SStefano Brivio 21332bbd879SStefano Brivio return -ENOENT; 2148afe97e5SSimon Horman } 2158afe97e5SSimon Horman #endif 2168afe97e5SSimon Horman 21732613090SAlexey Dobriyan static const struct net_protocol tunnel4_protocol = { 218d2acc347SHerbert Xu .handler = tunnel4_rcv, 219d2acc347SHerbert Xu .err_handler = tunnel4_err, 220d2acc347SHerbert Xu .no_policy = 1, 2214597a0ceSPavel Emelyanov .netns_ok = 1, 222d2acc347SHerbert Xu }; 223d2acc347SHerbert Xu 224dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 22532613090SAlexey Dobriyan static const struct net_protocol tunnel64_protocol = { 226c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 22799f93326SPavel Emelyanov .err_handler = tunnel64_err, 228c0d56408SKazunori MIYAZAWA .no_policy = 1, 229b0970c42SPavel Emelyanov .netns_ok = 1, 230c0d56408SKazunori MIYAZAWA }; 231c0d56408SKazunori MIYAZAWA #endif 232c0d56408SKazunori MIYAZAWA 2338afe97e5SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2348afe97e5SSimon Horman static const struct net_protocol tunnelmpls4_protocol = { 2358afe97e5SSimon Horman .handler = tunnelmpls4_rcv, 2368afe97e5SSimon Horman .err_handler = tunnelmpls4_err, 2378afe97e5SSimon Horman .no_policy = 1, 2388afe97e5SSimon Horman .netns_ok = 1, 2398afe97e5SSimon Horman }; 2408afe97e5SSimon Horman #endif 2418afe97e5SSimon Horman 242d2acc347SHerbert Xu static int __init tunnel4_init(void) 243d2acc347SHerbert Xu { 2448afe97e5SSimon Horman if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 245aa9667e7SSimon Horman goto err; 246dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 247aa9667e7SSimon Horman if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 248aa9667e7SSimon Horman inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 249aa9667e7SSimon Horman goto err; 250aa9667e7SSimon Horman } 2518afe97e5SSimon Horman #endif 2528afe97e5SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 253aa9667e7SSimon Horman if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) { 254aa9667e7SSimon Horman inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 255aa9667e7SSimon Horman #if IS_ENABLED(CONFIG_IPV6) 256aa9667e7SSimon Horman inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6); 257aa9667e7SSimon Horman #endif 258aa9667e7SSimon Horman goto err; 259aa9667e7SSimon Horman } 260c0d56408SKazunori MIYAZAWA #endif 261*6df2db5dSXin Long #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) 262*6df2db5dSXin Long if (xfrm_input_register_afinfo(&tunnel4_input_afinfo)) { 263*6df2db5dSXin Long inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 264*6df2db5dSXin Long #if IS_ENABLED(CONFIG_IPV6) 265*6df2db5dSXin Long inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6); 266*6df2db5dSXin Long #endif 267*6df2db5dSXin Long #if IS_ENABLED(CONFIG_MPLS) 268*6df2db5dSXin Long inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS); 269*6df2db5dSXin Long #endif 270*6df2db5dSXin Long goto err; 271*6df2db5dSXin Long } 272*6df2db5dSXin Long #endif 273d2acc347SHerbert Xu return 0; 2748afe97e5SSimon Horman 275aa9667e7SSimon Horman err: 2768afe97e5SSimon Horman pr_err("%s: can't add protocol\n", __func__); 2778afe97e5SSimon Horman return -EAGAIN; 278d2acc347SHerbert Xu } 279d2acc347SHerbert Xu 280d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 281d2acc347SHerbert Xu { 282*6df2db5dSXin Long #if IS_ENABLED(CONFIG_INET_XFRM_TUNNEL) 283*6df2db5dSXin Long if (xfrm_input_unregister_afinfo(&tunnel4_input_afinfo)) 284*6df2db5dSXin Long pr_err("tunnel4 close: can't remove input afinfo\n"); 285*6df2db5dSXin Long #endif 2868afe97e5SSimon Horman #if IS_ENABLED(CONFIG_MPLS) 2878afe97e5SSimon Horman if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) 2888afe97e5SSimon Horman pr_err("tunnelmpls4 close: can't remove protocol\n"); 2898afe97e5SSimon Horman #endif 290dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 291c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 292058bd4d2SJoe Perches pr_err("tunnel64 close: can't remove protocol\n"); 293c0d56408SKazunori MIYAZAWA #endif 294d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 295058bd4d2SJoe Perches pr_err("tunnel4 close: can't remove protocol\n"); 296d2acc347SHerbert Xu } 297d2acc347SHerbert Xu 298d2acc347SHerbert Xu module_init(tunnel4_init); 299d2acc347SHerbert Xu module_exit(tunnel4_fini); 300d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 301