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/netdevice.h>
  10#include <linux/skbuff.h>
  11#include <net/icmp.h>
  12#include <net/ip.h>
  13#include <net/protocol.h>
  14#include <net/xfrm.h>
  15
  16static struct xfrm_tunnel *tunnel4_handlers;
  17static struct xfrm_tunnel *tunnel64_handlers;
  18static DEFINE_MUTEX(tunnel4_mutex);
  19
  20static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
  21{
  22        return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
  23}
  24
  25int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
  26{
  27        struct xfrm_tunnel **pprev;
  28        int ret = -EEXIST;
  29        int priority = handler->priority;
  30
  31        mutex_lock(&tunnel4_mutex);
  32
  33        for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
  34                if ((*pprev)->priority > priority)
  35                        break;
  36                if ((*pprev)->priority == priority)
  37                        goto err;
  38        }
  39
  40        handler->next = *pprev;
  41        *pprev = handler;
  42
  43        ret = 0;
  44
  45err:
  46        mutex_unlock(&tunnel4_mutex);
  47
  48        return ret;
  49}
  50
  51EXPORT_SYMBOL(xfrm4_tunnel_register);
  52
  53int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
  54{
  55        struct xfrm_tunnel **pprev;
  56        int ret = -ENOENT;
  57
  58        mutex_lock(&tunnel4_mutex);
  59
  60        for (pprev = fam_handlers(family); *pprev; pprev = &(*pprev)->next) {
  61                if (*pprev == handler) {
  62                        *pprev = handler->next;
  63                        ret = 0;
  64                        break;
  65                }
  66        }
  67
  68        mutex_unlock(&tunnel4_mutex);
  69
  70        synchronize_net();
  71
  72        return ret;
  73}
  74
  75EXPORT_SYMBOL(xfrm4_tunnel_deregister);
  76
  77static int tunnel4_rcv(struct sk_buff *skb)
  78{
  79        struct xfrm_tunnel *handler;
  80
  81        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  82                goto drop;
  83
  84        for (handler = tunnel4_handlers; handler; handler = handler->next)
  85                if (!handler->handler(skb))
  86                        return 0;
  87
  88        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  89
  90drop:
  91        kfree_skb(skb);
  92        return 0;
  93}
  94
  95#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  96static int tunnel64_rcv(struct sk_buff *skb)
  97{
  98        struct xfrm_tunnel *handler;
  99
 100        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 101                goto drop;
 102
 103        for (handler = tunnel64_handlers; handler; handler = handler->next)
 104                if (!handler->handler(skb))
 105                        return 0;
 106
 107        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 108
 109drop:
 110        kfree_skb(skb);
 111        return 0;
 112}
 113#endif
 114
 115static void tunnel4_err(struct sk_buff *skb, u32 info)
 116{
 117        struct xfrm_tunnel *handler;
 118
 119        for (handler = tunnel4_handlers; handler; handler = handler->next)
 120                if (!handler->err_handler(skb, info))
 121                        break;
 122}
 123
 124#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 125static void tunnel64_err(struct sk_buff *skb, u32 info)
 126{
 127        struct xfrm_tunnel *handler;
 128
 129        for (handler = tunnel64_handlers; handler; handler = handler->next)
 130                if (!handler->err_handler(skb, info))
 131                        break;
 132}
 133#endif
 134
 135static const struct net_protocol tunnel4_protocol = {
 136        .handler        =       tunnel4_rcv,
 137        .err_handler    =       tunnel4_err,
 138        .no_policy      =       1,
 139        .netns_ok       =       1,
 140};
 141
 142#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 143static const struct net_protocol tunnel64_protocol = {
 144        .handler        =       tunnel64_rcv,
 145        .err_handler    =       tunnel64_err,
 146        .no_policy      =       1,
 147        .netns_ok       =       1,
 148};
 149#endif
 150
 151static int __init tunnel4_init(void)
 152{
 153        if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
 154                printk(KERN_ERR "tunnel4 init: can't add protocol\n");
 155                return -EAGAIN;
 156        }
 157#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 158        if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
 159                printk(KERN_ERR "tunnel64 init: can't add protocol\n");
 160                inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
 161                return -EAGAIN;
 162        }
 163#endif
 164        return 0;
 165}
 166
 167static void __exit tunnel4_fini(void)
 168{
 169#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 170        if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
 171                printk(KERN_ERR "tunnel64 close: can't remove protocol\n");
 172#endif
 173        if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP))
 174                printk(KERN_ERR "tunnel4 close: can't remove protocol\n");
 175}
 176
 177module_init(tunnel4_init);
 178module_exit(tunnel4_fini);
 179MODULE_LICENSE("GPL");
 180