linux/net/ipv4/tunnel4.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* tunnel4.c: Generic IP tunnel transformer.
   3 *
   4 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
   5 */
   6
   7#include <linux/init.h>
   8#include <linux/module.h>
   9#include <linux/mutex.h>
  10#include <linux/mpls.h>
  11#include <linux/netdevice.h>
  12#include <linux/skbuff.h>
  13#include <linux/slab.h>
  14#include <net/icmp.h>
  15#include <net/ip.h>
  16#include <net/protocol.h>
  17#include <net/xfrm.h>
  18
  19static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
  20static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
  21static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly;
  22static DEFINE_MUTEX(tunnel4_mutex);
  23
  24static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
  25{
  26        return (family == AF_INET) ? &tunnel4_handlers :
  27                (family == AF_INET6) ? &tunnel64_handlers :
  28                &tunnelmpls4_handlers;
  29}
  30
  31int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
  32{
  33        struct xfrm_tunnel __rcu **pprev;
  34        struct xfrm_tunnel *t;
  35
  36        int ret = -EEXIST;
  37        int priority = handler->priority;
  38
  39        mutex_lock(&tunnel4_mutex);
  40
  41        for (pprev = fam_handlers(family);
  42             (t = rcu_dereference_protected(*pprev,
  43                        lockdep_is_held(&tunnel4_mutex))) != NULL;
  44             pprev = &t->next) {
  45                if (t->priority > priority)
  46                        break;
  47                if (t->priority == priority)
  48                        goto err;
  49        }
  50
  51        handler->next = *pprev;
  52        rcu_assign_pointer(*pprev, handler);
  53
  54        ret = 0;
  55
  56err:
  57        mutex_unlock(&tunnel4_mutex);
  58
  59        return ret;
  60}
  61EXPORT_SYMBOL(xfrm4_tunnel_register);
  62
  63int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
  64{
  65        struct xfrm_tunnel __rcu **pprev;
  66        struct xfrm_tunnel *t;
  67        int ret = -ENOENT;
  68
  69        mutex_lock(&tunnel4_mutex);
  70
  71        for (pprev = fam_handlers(family);
  72             (t = rcu_dereference_protected(*pprev,
  73                        lockdep_is_held(&tunnel4_mutex))) != NULL;
  74             pprev = &t->next) {
  75                if (t == handler) {
  76                        *pprev = handler->next;
  77                        ret = 0;
  78                        break;
  79                }
  80        }
  81
  82        mutex_unlock(&tunnel4_mutex);
  83
  84        synchronize_net();
  85
  86        return ret;
  87}
  88EXPORT_SYMBOL(xfrm4_tunnel_deregister);
  89
  90#define for_each_tunnel_rcu(head, handler)              \
  91        for (handler = rcu_dereference(head);           \
  92             handler != NULL;                           \
  93             handler = rcu_dereference(handler->next))  \
  94
  95static int tunnel4_rcv(struct sk_buff *skb)
  96{
  97        struct xfrm_tunnel *handler;
  98
  99        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 100                goto drop;
 101
 102        for_each_tunnel_rcu(tunnel4_handlers, handler)
 103                if (!handler->handler(skb))
 104                        return 0;
 105
 106        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 107
 108drop:
 109        kfree_skb(skb);
 110        return 0;
 111}
 112
 113#if IS_ENABLED(CONFIG_IPV6)
 114static int tunnel64_rcv(struct sk_buff *skb)
 115{
 116        struct xfrm_tunnel *handler;
 117
 118        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 119                goto drop;
 120
 121        for_each_tunnel_rcu(tunnel64_handlers, handler)
 122                if (!handler->handler(skb))
 123                        return 0;
 124
 125        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 126
 127drop:
 128        kfree_skb(skb);
 129        return 0;
 130}
 131#endif
 132
 133#if IS_ENABLED(CONFIG_MPLS)
 134static int tunnelmpls4_rcv(struct sk_buff *skb)
 135{
 136        struct xfrm_tunnel *handler;
 137
 138        if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
 139                goto drop;
 140
 141        for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
 142                if (!handler->handler(skb))
 143                        return 0;
 144
 145        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 146
 147drop:
 148        kfree_skb(skb);
 149        return 0;
 150}
 151#endif
 152
 153static int tunnel4_err(struct sk_buff *skb, u32 info)
 154{
 155        struct xfrm_tunnel *handler;
 156
 157        for_each_tunnel_rcu(tunnel4_handlers, handler)
 158                if (!handler->err_handler(skb, info))
 159                        return 0;
 160
 161        return -ENOENT;
 162}
 163
 164#if IS_ENABLED(CONFIG_IPV6)
 165static int tunnel64_err(struct sk_buff *skb, u32 info)
 166{
 167        struct xfrm_tunnel *handler;
 168
 169        for_each_tunnel_rcu(tunnel64_handlers, handler)
 170                if (!handler->err_handler(skb, info))
 171                        return 0;
 172
 173        return -ENOENT;
 174}
 175#endif
 176
 177#if IS_ENABLED(CONFIG_MPLS)
 178static int tunnelmpls4_err(struct sk_buff *skb, u32 info)
 179{
 180        struct xfrm_tunnel *handler;
 181
 182        for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
 183                if (!handler->err_handler(skb, info))
 184                        return 0;
 185
 186        return -ENOENT;
 187}
 188#endif
 189
 190static const struct net_protocol tunnel4_protocol = {
 191        .handler        =       tunnel4_rcv,
 192        .err_handler    =       tunnel4_err,
 193        .no_policy      =       1,
 194        .netns_ok       =       1,
 195};
 196
 197#if IS_ENABLED(CONFIG_IPV6)
 198static const struct net_protocol tunnel64_protocol = {
 199        .handler        =       tunnel64_rcv,
 200        .err_handler    =       tunnel64_err,
 201        .no_policy      =       1,
 202        .netns_ok       =       1,
 203};
 204#endif
 205
 206#if IS_ENABLED(CONFIG_MPLS)
 207static const struct net_protocol tunnelmpls4_protocol = {
 208        .handler        =       tunnelmpls4_rcv,
 209        .err_handler    =       tunnelmpls4_err,
 210        .no_policy      =       1,
 211        .netns_ok       =       1,
 212};
 213#endif
 214
 215static int __init tunnel4_init(void)
 216{
 217        if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
 218                goto err;
 219#if IS_ENABLED(CONFIG_IPV6)
 220        if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
 221                inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
 222                goto err;
 223        }
 224#endif
 225#if IS_ENABLED(CONFIG_MPLS)
 226        if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) {
 227                inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
 228#if IS_ENABLED(CONFIG_IPV6)
 229                inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6);
 230#endif
 231                goto err;
 232        }
 233#endif
 234        return 0;
 235
 236err:
 237        pr_err("%s: can't add protocol\n", __func__);
 238        return -EAGAIN;
 239}
 240
 241static void __exit tunnel4_fini(void)
 242{
 243#if IS_ENABLED(CONFIG_MPLS)
 244        if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
 245                pr_err("tunnelmpls4 close: can't remove protocol\n");
 246#endif
 247#if IS_ENABLED(CONFIG_IPV6)
 248        if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
 249                pr_err("tunnel64 close: can't remove protocol\n");
 250#endif
 251        if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
 252                pr_err("tunnel4 close: can't remove protocol\n");
 253}
 254
 255module_init(tunnel4_init);
 256module_exit(tunnel4_fini);
 257MODULE_LICENSE("GPL");
 258