linux/net/ipv6/tunnel6.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C)2003,2004 USAGI/WIDE Project
   4 *
   5 * Authors      Mitsuru KANDA  <mk@linux-ipv6.org>
   6 *              YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
   7 */
   8
   9#define pr_fmt(fmt) "IPv6: " fmt
  10
  11#include <linux/icmpv6.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/mutex.h>
  15#include <linux/netdevice.h>
  16#include <linux/skbuff.h>
  17#include <linux/slab.h>
  18#include <net/ipv6.h>
  19#include <net/protocol.h>
  20#include <net/xfrm.h>
  21
  22static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly;
  23static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly;
  24static struct xfrm6_tunnel __rcu *tunnelmpls6_handlers __read_mostly;
  25static DEFINE_MUTEX(tunnel6_mutex);
  26
  27static inline int xfrm6_tunnel_mpls_supported(void)
  28{
  29        return IS_ENABLED(CONFIG_MPLS);
  30}
  31
  32int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
  33{
  34        struct xfrm6_tunnel __rcu **pprev;
  35        struct xfrm6_tunnel *t;
  36        int ret = -EEXIST;
  37        int priority = handler->priority;
  38
  39        mutex_lock(&tunnel6_mutex);
  40
  41        switch (family) {
  42        case AF_INET6:
  43                pprev = &tunnel6_handlers;
  44                break;
  45        case AF_INET:
  46                pprev = &tunnel46_handlers;
  47                break;
  48        case AF_MPLS:
  49                pprev = &tunnelmpls6_handlers;
  50                break;
  51        default:
  52                goto err;
  53        }
  54
  55        for (; (t = rcu_dereference_protected(*pprev,
  56                        lockdep_is_held(&tunnel6_mutex))) != NULL;
  57             pprev = &t->next) {
  58                if (t->priority > priority)
  59                        break;
  60                if (t->priority == priority)
  61                        goto err;
  62        }
  63
  64        handler->next = *pprev;
  65        rcu_assign_pointer(*pprev, handler);
  66
  67        ret = 0;
  68
  69err:
  70        mutex_unlock(&tunnel6_mutex);
  71
  72        return ret;
  73}
  74EXPORT_SYMBOL(xfrm6_tunnel_register);
  75
  76int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
  77{
  78        struct xfrm6_tunnel __rcu **pprev;
  79        struct xfrm6_tunnel *t;
  80        int ret = -ENOENT;
  81
  82        mutex_lock(&tunnel6_mutex);
  83
  84        switch (family) {
  85        case AF_INET6:
  86                pprev = &tunnel6_handlers;
  87                break;
  88        case AF_INET:
  89                pprev = &tunnel46_handlers;
  90                break;
  91        case AF_MPLS:
  92                pprev = &tunnelmpls6_handlers;
  93                break;
  94        default:
  95                goto err;
  96        }
  97
  98        for (; (t = rcu_dereference_protected(*pprev,
  99                        lockdep_is_held(&tunnel6_mutex))) != NULL;
 100             pprev = &t->next) {
 101                if (t == handler) {
 102                        *pprev = handler->next;
 103                        ret = 0;
 104                        break;
 105                }
 106        }
 107
 108err:
 109        mutex_unlock(&tunnel6_mutex);
 110
 111        synchronize_net();
 112
 113        return ret;
 114}
 115EXPORT_SYMBOL(xfrm6_tunnel_deregister);
 116
 117#define for_each_tunnel_rcu(head, handler)              \
 118        for (handler = rcu_dereference(head);           \
 119             handler != NULL;                           \
 120             handler = rcu_dereference(handler->next))  \
 121
 122static int tunnelmpls6_rcv(struct sk_buff *skb)
 123{
 124        struct xfrm6_tunnel *handler;
 125
 126        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 127                goto drop;
 128
 129        for_each_tunnel_rcu(tunnelmpls6_handlers, handler)
 130                if (!handler->handler(skb))
 131                        return 0;
 132
 133        icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 134
 135drop:
 136        kfree_skb(skb);
 137        return 0;
 138}
 139
 140static int tunnel6_rcv(struct sk_buff *skb)
 141{
 142        struct xfrm6_tunnel *handler;
 143
 144        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 145                goto drop;
 146
 147        for_each_tunnel_rcu(tunnel6_handlers, handler)
 148                if (!handler->handler(skb))
 149                        return 0;
 150
 151        icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 152
 153drop:
 154        kfree_skb(skb);
 155        return 0;
 156}
 157
 158#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
 159static int tunnel6_rcv_cb(struct sk_buff *skb, u8 proto, int err)
 160{
 161        struct xfrm6_tunnel __rcu *head;
 162        struct xfrm6_tunnel *handler;
 163        int ret;
 164
 165        head = (proto == IPPROTO_IPV6) ? tunnel6_handlers : tunnel46_handlers;
 166
 167        for_each_tunnel_rcu(head, handler) {
 168                if (handler->cb_handler) {
 169                        ret = handler->cb_handler(skb, err);
 170                        if (ret <= 0)
 171                                return ret;
 172                }
 173        }
 174
 175        return 0;
 176}
 177
 178static const struct xfrm_input_afinfo tunnel6_input_afinfo = {
 179        .family         =       AF_INET6,
 180        .is_ipip        =       true,
 181        .callback       =       tunnel6_rcv_cb,
 182};
 183#endif
 184
 185static int tunnel46_rcv(struct sk_buff *skb)
 186{
 187        struct xfrm6_tunnel *handler;
 188
 189        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 190                goto drop;
 191
 192        for_each_tunnel_rcu(tunnel46_handlers, handler)
 193                if (!handler->handler(skb))
 194                        return 0;
 195
 196        icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
 197
 198drop:
 199        kfree_skb(skb);
 200        return 0;
 201}
 202
 203static int tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 204                        u8 type, u8 code, int offset, __be32 info)
 205{
 206        struct xfrm6_tunnel *handler;
 207
 208        for_each_tunnel_rcu(tunnel6_handlers, handler)
 209                if (!handler->err_handler(skb, opt, type, code, offset, info))
 210                        return 0;
 211
 212        return -ENOENT;
 213}
 214
 215static int tunnel46_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 216                         u8 type, u8 code, int offset, __be32 info)
 217{
 218        struct xfrm6_tunnel *handler;
 219
 220        for_each_tunnel_rcu(tunnel46_handlers, handler)
 221                if (!handler->err_handler(skb, opt, type, code, offset, info))
 222                        return 0;
 223
 224        return -ENOENT;
 225}
 226
 227static int tunnelmpls6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 228                           u8 type, u8 code, int offset, __be32 info)
 229{
 230        struct xfrm6_tunnel *handler;
 231
 232        for_each_tunnel_rcu(tunnelmpls6_handlers, handler)
 233                if (!handler->err_handler(skb, opt, type, code, offset, info))
 234                        return 0;
 235
 236        return -ENOENT;
 237}
 238
 239static const struct inet6_protocol tunnel6_protocol = {
 240        .handler        = tunnel6_rcv,
 241        .err_handler    = tunnel6_err,
 242        .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 243};
 244
 245static const struct inet6_protocol tunnel46_protocol = {
 246        .handler        = tunnel46_rcv,
 247        .err_handler    = tunnel46_err,
 248        .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 249};
 250
 251static const struct inet6_protocol tunnelmpls6_protocol = {
 252        .handler        = tunnelmpls6_rcv,
 253        .err_handler    = tunnelmpls6_err,
 254        .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 255};
 256
 257static int __init tunnel6_init(void)
 258{
 259        if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) {
 260                pr_err("%s: can't add protocol\n", __func__);
 261                return -EAGAIN;
 262        }
 263        if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) {
 264                pr_err("%s: can't add protocol\n", __func__);
 265                inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
 266                return -EAGAIN;
 267        }
 268        if (xfrm6_tunnel_mpls_supported() &&
 269            inet6_add_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS)) {
 270                pr_err("%s: can't add protocol\n", __func__);
 271                inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
 272                inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP);
 273                return -EAGAIN;
 274        }
 275#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
 276        if (xfrm_input_register_afinfo(&tunnel6_input_afinfo)) {
 277                pr_err("%s: can't add input afinfo\n", __func__);
 278                inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
 279                inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP);
 280                if (xfrm6_tunnel_mpls_supported())
 281                        inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS);
 282                return -EAGAIN;
 283        }
 284#endif
 285        return 0;
 286}
 287
 288static void __exit tunnel6_fini(void)
 289{
 290#if IS_ENABLED(CONFIG_INET6_XFRM_TUNNEL)
 291        if (xfrm_input_unregister_afinfo(&tunnel6_input_afinfo))
 292                pr_err("%s: can't remove input afinfo\n", __func__);
 293#endif
 294        if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP))
 295                pr_err("%s: can't remove protocol\n", __func__);
 296        if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6))
 297                pr_err("%s: can't remove protocol\n", __func__);
 298        if (xfrm6_tunnel_mpls_supported() &&
 299            inet6_del_protocol(&tunnelmpls6_protocol, IPPROTO_MPLS))
 300                pr_err("%s: can't remove protocol\n", __func__);
 301}
 302
 303module_init(tunnel6_init);
 304module_exit(tunnel6_fini);
 305MODULE_LICENSE("GPL");
 306