[IPSEC]: changing API of xfrm6_tunnel_register
authorKazunori MIYAZAWA <miyazawa@linux-ipv6.org>
Tue, 13 Feb 2007 20:55:55 +0000 (12:55 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 13 Feb 2007 20:55:55 +0000 (12:55 -0800)
This patch changes xfrm6_tunnel register and deregister
interface to prepare for solving the conflict of device
tunnels with inter address family IPsec tunnel.
There is no device which conflicts with IPv4 over IPv6
IPsec tunnel.

Signed-off-by: Kazunori MIYAZAWA <miyazawa@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/xfrm.h
net/ipv6/ip6_tunnel.c
net/ipv6/tunnel6.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_tunnel.c

index 20be8beb9a111dd0ca174784e0561cea90d189c7..92a1fc46ea593c6cfb2f0529568c4aa2e83a7c48 100644 (file)
@@ -952,8 +952,8 @@ extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi);
 extern int xfrm6_rcv(struct sk_buff **pskb);
 extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
                            xfrm_address_t *saddr, u8 proto);
-extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
-extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
+extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
+extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
 extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
 extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
 extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
index 367b7483298610460e8449904200a1e5c3e0faee..662edb826899e5c78ba6f219699a8c4ac9199f4e 100644 (file)
@@ -1128,7 +1128,7 @@ static int __init ip6_tunnel_init(void)
 {
        int  err;
 
-       if (xfrm6_tunnel_register(&ip6ip6_handler)) {
+       if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
                printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
                return -EAGAIN;
        }
@@ -1147,7 +1147,7 @@ static int __init ip6_tunnel_init(void)
        }
        return 0;
 fail:
-       xfrm6_tunnel_deregister(&ip6ip6_handler);
+       xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
        return err;
 }
 
@@ -1171,7 +1171,7 @@ static void __exit ip6ip6_destroy_tunnels(void)
 
 static void __exit ip6_tunnel_cleanup(void)
 {
-       if (xfrm6_tunnel_deregister(&ip6ip6_handler))
+       if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
                printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
 
        rtnl_lock();
index 918d07dd12197f7da36820cd8010e0192a1cb4a4..23e2809878ae87a82e527415b399d80b493103d8 100644 (file)
 #include <net/xfrm.h>
 
 static struct xfrm6_tunnel *tunnel6_handlers;
+static struct xfrm6_tunnel *tunnel46_handlers;
 static DEFINE_MUTEX(tunnel6_mutex);
 
-int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
+int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family)
 {
        struct xfrm6_tunnel **pprev;
        int ret = -EEXIST;
@@ -40,7 +41,8 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
 
        mutex_lock(&tunnel6_mutex);
 
-       for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) {
+       for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
+            *pprev; pprev = &(*pprev)->next) {
                if ((*pprev)->priority > priority)
                        break;
                if ((*pprev)->priority == priority)
@@ -60,14 +62,15 @@ err:
 
 EXPORT_SYMBOL(xfrm6_tunnel_register);
 
-int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
+int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
 {
        struct xfrm6_tunnel **pprev;
        int ret = -ENOENT;
 
        mutex_lock(&tunnel6_mutex);
 
-       for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) {
+       for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers;
+            *pprev; pprev = &(*pprev)->next) {
                if (*pprev == handler) {
                        *pprev = handler->next;
                        ret = 0;
@@ -103,6 +106,25 @@ drop:
        return 0;
 }
 
+static int tunnel46_rcv(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct xfrm6_tunnel *handler;
+
+       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+               goto drop;
+
+       for (handler = tunnel46_handlers; handler; handler = handler->next)
+               if (!handler->handler(skb))
+                       return 0;
+
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev);
+
+drop:
+       kfree_skb(skb);
+       return 0;
+}
+
 static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        int type, int code, int offset, __be32 info)
 {
@@ -119,17 +141,30 @@ static struct inet6_protocol tunnel6_protocol = {
        .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
+static struct inet6_protocol tunnel46_protocol = {
+       .handler        = tunnel46_rcv,
+       .err_handler    = tunnel6_err,
+       .flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+};
+
 static int __init tunnel6_init(void)
 {
        if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) {
                printk(KERN_ERR "tunnel6 init(): can't add protocol\n");
                return -EAGAIN;
        }
+       if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) {
+               printk(KERN_ERR "tunnel6 init(): can't add protocol\n");
+               inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6);
+               return -EAGAIN;
+       }
        return 0;
 }
 
 static void __exit tunnel6_fini(void)
 {
+       if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP))
+               printk(KERN_ERR "tunnel6 close: can't remove protocol\n");
        if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6))
                printk(KERN_ERR "tunnel6 close: can't remove protocol\n");
 }
index 25250147bdc3514c21a92332a07e0f100383f8cd..31f651f950967018be3c43d0b173dd80dc0449c0 100644 (file)
@@ -40,7 +40,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
                if (xfrm_nr == XFRM_MAX_DEPTH)
                        goto drop;
 
-               x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6);
+               x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
+                               nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6);
                if (x == NULL)
                        goto drop;
                spin_lock(&x->lock);
index fb0228772f0194b7aad847c0e38093d561821213..ee4b84a33ff41a63a22fd7cb628e5e2e382e737c 100644 (file)
@@ -339,17 +339,29 @@ static struct xfrm6_tunnel xfrm6_tunnel_handler = {
        .priority       = 2,
 };
 
+static struct xfrm6_tunnel xfrm46_tunnel_handler = {
+       .handler        = xfrm6_tunnel_rcv,
+       .err_handler    = xfrm6_tunnel_err,
+       .priority       = 2,
+};
+
 static int __init xfrm6_tunnel_init(void)
 {
        if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0)
                return -EAGAIN;
 
-       if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) {
+       if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) {
+               xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
+               return -EAGAIN;
+       }
+       if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) {
+               xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
                xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
                return -EAGAIN;
        }
        if (xfrm6_tunnel_spi_init() < 0) {
-               xfrm6_tunnel_deregister(&xfrm6_tunnel_handler);
+               xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
+               xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
                xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
                return -EAGAIN;
        }
@@ -359,7 +371,8 @@ static int __init xfrm6_tunnel_init(void)
 static void __exit xfrm6_tunnel_fini(void)
 {
        xfrm6_tunnel_spi_fini();
-       xfrm6_tunnel_deregister(&xfrm6_tunnel_handler);
+       xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
+       xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
        xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
 }