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