netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] xfrm ip6ip6
@ 2003-05-31 15:20 Mitsuru KANDA / 神田 充
  2003-05-31 16:01 ` James Morris
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Mitsuru KANDA / 神田 充 @ 2003-05-31 15:20 UTC (permalink / raw)
  To: davem, jmorris, kuznet; +Cc: netdev, usagi


Hello,

Here is the xfrm style ip6ip6 patch,
which is against linux-2.5.70+CS1.1254.2.15.

I honestly have to say it is not tested well.
But I promise I'll test/fix after xfrm tunnel tool will be visible :-)
(Does anyone work on this?)

Anyway, I have one discussion point.
When we use 'setkey -D', xfrm ipip tunnels are displayed as unspec SAs.
Do we need to filter out these xfrm_states other than AH/ESP/IPcomp 
in case of PF_KEY based queries?

Regards,
-mk


Index: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/include/net/xfrm.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/xfrm.h,v
retrieving revision 1.1.1.23
retrieving revision 1.1.1.23.10.1
diff -u -r1.1.1.23 -r1.1.1.23.10.1
--- linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/include/net/xfrm.h	26 May 2003 08:04:25 -0000	1.1.1.23
+++ linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/include/net/xfrm.h	31 May 2003 08:52:20 -0000	1.1.1.23.10.1
@@ -493,8 +493,16 @@
 }
 
 /* placeholder until xfrm6_tunnel.c is written */
-static inline int xfrm6_tunnel_check_size(struct sk_buff *skb)
-{ return 0; }
+extern int xfrm6_tunnel_check_size(struct sk_buff *skb);
+#define XFRM_ADDR_HSIZE		1024
+static __inline__ /* same as __xfrm6_dst_hash */
+unsigned xfrm6_tunnel_addr_hash(xfrm_address_t *addr)
+{
+	unsigned h;
+	h = ntohl(addr->a6[2]^addr->a6[3]);
+	h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
+	return h;
+}
 
 /* A struct encoding bundle of transformations to apply to some set of flow.
  *
Index: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/Makefile
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Makefile,v
retrieving revision 1.1.1.12
retrieving revision 1.1.1.12.10.1
diff -u -r1.1.1.12 -r1.1.1.12.10.1
--- linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/Makefile	26 May 2003 08:04:11 -0000	1.1.1.12
+++ linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/Makefile	31 May 2003 08:56:24 -0000	1.1.1.12.10.1
@@ -9,7 +9,7 @@
 		protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
 		ip6_flowlabel.o ipv6_syms.o \
-		xfrm6_policy.o xfrm6_state.o xfrm6_input.o
+		xfrm6_policy.o xfrm6_state.o xfrm6_input.o xfrm6_tunnel.o
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
Index: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/ipcomp6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipcomp6.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.8.2
diff -u -r1.1.1.2 -r1.1.1.2.8.2
--- linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/ipcomp6.c	21 May 2003 13:15:20 -0000	1.1.1.2
+++ linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/ipcomp6.c	31 May 2003 14:19:54 -0000	1.1.1.2.8.2
@@ -254,6 +254,66 @@
 	xfrm_state_put(x);
 }
 
+static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
+{
+	struct xfrm_state *t = NULL;
+
+	t = xfrm_state_alloc();
+	if (!t)
+		goto out;
+
+	t->id.proto = IPPROTO_IPV6;
+	t->id.spi = xfrm6_tunnel_addr_hash((xfrm_address_t *)&x->props.saddr);
+	memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
+	memcpy(&t->sel, &x->sel, sizeof(t->sel));
+	t->props.family = AF_INET6;
+	t->props.mode = 1;
+	memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
+
+	t->type = xfrm_get_type(IPPROTO_IPV6, t->props.family);
+	if (t->type == NULL)
+		goto error;
+
+	if (t->type->init_state(t, NULL))
+		goto error;
+
+	t->km.state = XFRM_STATE_VALID;
+	atomic_set(&t->tunnel_users, 1);
+
+out:
+	return t;
+
+error:
+	xfrm_state_put(t);
+	goto out;
+}
+
+static int ipcomp6_tunnel_attach(struct xfrm_state *x)
+{
+	int err = 0;
+	struct xfrm_state *t;
+	u32 spi;
+
+	spi = xfrm6_tunnel_addr_hash((xfrm_address_t *)&x->props.saddr);
+	
+	t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr,
+				      spi, IPPROTO_IPV6, AF_INET6);
+	if (!t) {
+		t = ipcomp6_tunnel_create(x);
+		if (!t) {
+			err = -EINVAL;
+			goto out;
+		}
+		xfrm_state_insert(t);
+		xfrm_state_hold(t);
+	}
+	x->tunnel = t;
+	atomic_inc(&t->tunnel_users);
+
+out:
+	return err;
+}
+
 static void ipcomp6_free_data(struct ipcomp_data *ipcd)
 {
 	if (ipcd->tfm)
@@ -292,6 +352,12 @@
 	ipcd->tfm = crypto_alloc_tfm(x->calg->alg_name, 0);
 	if (!ipcd->tfm)
 		goto error;
+
+	if (x->props.mode) {
+		err = ipcomp6_tunnel_attach(x);
+		if (err)
+			goto error;
+	}
 
 	calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
 	BUG_ON(!calg_desc);
Index: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/xfrm6_tunnel.c
===================================================================
RCS file: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/xfrm6_tunnel.c
diff -N linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/xfrm6_tunnel.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/ipv6/xfrm6_tunnel.c	31 May 2003 14:03:12 -0000	1.1.4.2
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author	Mitsuru KANDA  <mk@linux-ipv6.org>
+ *
+ * Based on xfrm4_tunnel
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/icmp.h>
+#include <net/ipv6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+int xfrm6_tunnel_check_size(struct sk_buff *skb)
+{
+	int mtu, ret = 0;
+	struct dst_entry *dst = skb->dst;
+
+	mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
+	if (mtu < IPV6_MIN_MTU)
+		mtu = IPV6_MIN_MTU;
+
+	if (skb->len > mtu) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		ret = -EMSGSIZE;
+	}
+
+	return ret;
+}
+
+static int ip6ip6_output(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb->dst;
+	struct xfrm_state *x = dst->xfrm;
+	struct ipv6hdr *iph, *top_iph;
+	int err;
+
+	if ((err = xfrm6_tunnel_check_size(skb)) != 0)
+		goto error_nolock;
+
+	iph = skb->nh.ipv6h;
+
+	top_iph = (struct ipv6hdr *)skb_push(skb, x->props.header_len);
+	top_iph->version = 6;
+	top_iph->priority = iph->priority;
+	top_iph->flow_lbl[0] = iph->flow_lbl[0];
+	top_iph->flow_lbl[1] = iph->flow_lbl[1];
+	top_iph->flow_lbl[2] = iph->flow_lbl[2];
+	top_iph->nexthdr = IPPROTO_IPV6; 
+	top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	top_iph->hop_limit = iph->hop_limit;
+	memcpy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr, sizeof(struct in6_addr));
+	memcpy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr, sizeof(struct in6_addr));
+	skb->nh.raw = skb->data;
+	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
+
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+
+	spin_unlock_bh(&x->lock);
+
+	if ((skb->dst = dst_pop(dst)) == NULL) { 
+		kfree_skb(skb);
+		err = -EHOSTUNREACH;
+		goto error_nolock;
+	}
+
+	return NET_XMIT_BYPASS;
+
+error_nolock:
+	kfree_skb(skb);
+	return err;
+}
+
+static int ip6ip6_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 
+		return -EINVAL;
+
+	skb->mac.raw = skb->nh.raw;
+	skb->nh.raw = skb->data;
+	dst_release(skb->dst);
+	skb->dst = NULL;
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->pkt_type = PACKET_HOST;
+	netif_rx(skb);
+
+	return 0;
+}
+
+static int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+	struct sk_buff *skb = *pskb;
+	struct xfrm_state *x = NULL;
+	struct ipv6hdr *iph = skb->nh.ipv6h;
+	int err = 0;
+	u32 spi;
+
+	/* After device-like ip6ip6 tunnel will be implemented,
+	 * we do take precedence here.
+	 * (currently not yet exist in kernel source tree.)
+	 * For more information, see xfrm4_tunnel.c
+	 */
+	/* device-like_ip6ip6_handler() */
+
+	spi = xfrm6_tunnel_addr_hash((xfrm_address_t *)&iph->saddr);
+	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, 
+			spi,
+			IPPROTO_IPV6, AF_INET6);
+
+	if (!x)
+		goto drop;
+
+	spin_lock(&x->lock);
+
+	if (unlikely(x->km.state != XFRM_STATE_VALID))
+		goto drop_unlock;
+
+	err = ip6ip6_xfrm_rcv(x, NULL, skb);
+	if (err)
+		goto drop_unlock;
+
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++; 
+	spin_unlock(&x->lock); 
+	xfrm_state_put(x); 
+
+	*nhoffp = sizeof(struct ipv6hdr);
+
+	return 1;
+
+drop_unlock:
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+drop:
+	kfree_skb(skb);
+
+	return -1;
+}
+
+static void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			int type, int code, int offset, __u32 info)
+{
+	/* call here first for device-like ip6ip6 err handling */
+	/* foo->err_handler(),  see xfrm4_tunnel.c */
+
+	/* xfrm ip6ip6 native err handling */
+	switch (type) {
+	case ICMPV6_DEST_UNREACH: 
+		switch (code) {
+		case ICMPV6_NOROUTE: 
+		case ICMPV6_ADM_PROHIBITED:
+		case ICMPV6_NOT_NEIGHBOUR:
+		case ICMPV6_ADDR_UNREACH:
+		case ICMPV6_PORT_UNREACH:
+		default:
+			printk(KERN_ERR "xfrm ip6ip6: Destination Unreach.\n");
+			break;
+		}
+		break;
+	case ICMPV6_PKT_TOOBIG:
+			printk(KERN_ERR "xfrm ip6ip6: Packet Too Big.\n");
+		break;
+	case ICMPV6_TIME_EXCEED:
+		switch (code) {
+		case ICMPV6_EXC_HOPLIMIT:
+			printk(KERN_ERR "xfrm ip6ip6: Too small Hoplimit.\n");
+			break;
+		case ICMPV6_EXC_FRAGTIME:
+		default: 
+			break;
+		}
+		break;
+	case ICMPV6_PARAMPROB:
+		switch (code) {
+		case ICMPV6_HDR_FIELD: break;
+		case ICMPV6_UNK_NEXTHDR: break;
+		case ICMPV6_UNK_OPTION: break;
+		}
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
+static int ip6ip6_init_state(struct xfrm_state *x, void *args)
+{
+	if (!x->props.mode)
+		return -EINVAL;
+
+	x->props.header_len = sizeof(struct ipv6hdr);
+
+	return 0;
+}
+
+static void ip6ip6_destroy(struct xfrm_state *x)
+{
+}
+
+static struct xfrm_type ip6ip6_type = {
+	.description	= "IP6IP6",
+	.owner          = THIS_MODULE,
+	.proto		= IPPROTO_IPV6,
+	.init_state	= ip6ip6_init_state,
+	.destructor	= ip6ip6_destroy,
+	.input		= ip6ip6_xfrm_rcv,
+	.output		= ip6ip6_output,
+};
+
+static struct inet6_protocol ip6ip6_protocol = {
+	.handler	= ip6ip6_rcv,
+	.err_handler	= ip6ip6_err, 
+	.flags          = INET6_PROTO_NOPOLICY,
+};
+
+static int __init ip6ip6_init(void)
+{
+	if (xfrm_register_type(&ip6ip6_type, AF_INET6) < 0) {
+		printk(KERN_INFO "ip6ip6  init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
+	if (inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6) < 0) {
+		printk(KERN_INFO "ip6ip6 init: can't add protocol\n");
+		xfrm_unregister_type(&ip6ip6_type, AF_INET6);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit ip6ip6_fini(void)
+{
+	if (inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6) < 0)
+		printk(KERN_INFO "ip6ip6 close: can't remove protocol\n");
+	if (xfrm_unregister_type(&ip6ip6_type, AF_INET6) < 0)
+		printk(KERN_INFO "ip6ip6 close: can't remove xfrm type\n");
+}
+
+module_init(ip6ip6_init);
+module_exit(ip6ip6_fini);
+MODULE_LICENSE("GPL");
Index: linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/xfrm/xfrm_output.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/xfrm/xfrm_output.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.16.1
diff -u -r1.1.1.1 -r1.1.1.1.16.1
--- linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/xfrm/xfrm_output.c	6 May 2003 12:43:55 -0000	1.1.1.1
+++ linux25-b2_5_70+CS1_1254_2_15_XFRM6_TUNNEL_20030531/net/xfrm/xfrm_output.c	31 May 2003 08:54:21 -0000	1.1.1.1.16.1
@@ -28,9 +28,11 @@
 			err = xfrm4_tunnel_check_size(skb);
 			break;
 			
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		case AF_INET6:
 			err = xfrm6_tunnel_check_size(skb);
 			break;
+#endif
 			
 		default:
 			err = -EINVAL;

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6
  2003-05-31 15:20 [PATCH] xfrm ip6ip6 Mitsuru KANDA / 神田 充
@ 2003-05-31 16:01 ` James Morris
  2003-06-01  8:34   ` David S. Miller
  2003-05-31 16:06 ` James Morris
  2003-06-01  8:30 ` David S. Miller
  2 siblings, 1 reply; 11+ messages in thread
From: James Morris @ 2003-05-31 16:01 UTC (permalink / raw)
  To: Mitsuru KANDA / 神田 充; +Cc: davem, kuznet, netdev, usagi

On Sun, 1 Jun 2003, Mitsuru KANDA / [ISO-2022-JP] ^[$B?@ED^[(B ^[$B=<^[(B wrote:

> Anyway, I have one discussion point.
> When we use 'setkey -D', xfrm ipip tunnels are displayed as unspec SAs.
> Do we need to filter out these xfrm_states other than AH/ESP/IPcomp 
> in case of PF_KEY based queries?

Good question.  We need to either filter them out or make sure they are 
displayed as ipip.

Part of the answer will depend on whether we want to expose xfrm-based 
ipip tunnels for general use, or only use them internally for ipcomp.


- James
-- 
James Morris
<jmorris@intercode.com.au>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6
  2003-05-31 15:20 [PATCH] xfrm ip6ip6 Mitsuru KANDA / 神田 充
  2003-05-31 16:01 ` James Morris
@ 2003-05-31 16:06 ` James Morris
  2003-06-01  8:30 ` David S. Miller
  2 siblings, 0 replies; 11+ messages in thread
From: James Morris @ 2003-05-31 16:06 UTC (permalink / raw)
  To: Mitsuru KANDA / 神田 充; +Cc: davem, kuznet, netdev, usagi

On Sun, 1 Jun 2003, Mitsuru KANDA / [ISO-2022-JP] ^[$B?@ED^[(B ^[$B=<^[(B wrote:

> I honestly have to say it is not tested well.

Btw, one simple way to test the xfrm tunneling is to set up a plain ipcomp 
tunnel and run ssh or https over it, which should cause non-compressed 
packets to be sent (they will fail the compressability test).


- James
-- 
James Morris
<jmorris@intercode.com.au>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6
  2003-05-31 15:20 [PATCH] xfrm ip6ip6 Mitsuru KANDA / 神田 充
  2003-05-31 16:01 ` James Morris
  2003-05-31 16:06 ` James Morris
@ 2003-06-01  8:30 ` David S. Miller
  2003-06-13 16:03   ` [PATCH] xfrm ip6ip6 (revised) Mitsuru KANDA / 神田 充
  2 siblings, 1 reply; 11+ messages in thread
From: David S. Miller @ 2003-06-01  8:30 UTC (permalink / raw)
  To: mk; +Cc: jmorris, kuznet, netdev, usagi

   From: Mitsuru KANDA / 神田 充 <mk@linux-ipv6.org>
   Date: Sun, 01 Jun 2003 00:20:07 +0900

Hello Mitsuru-san!

   +	t->id.spi = xfrm6_tunnel_addr_hash((xfrm_address_t *)&x->props.saddr);

You misunderstood what I tried to explain to you.

Consider, how do you guarentee that this t->id.spi value is unique
across all xfrm6_tunnel tunnels using the same t->id.daddr and
t->id.prot?  The answer is that you cannot.

You must generate fake "spi" values, they have no meaning outside of
xfrm6_tunnel.c They serve purpose only to map 128-bit ipv6 address to
32-bit "xfrm6_tunnel" SPI value.

I would suggest following implementation:

1) Implement something similar to xfrm_alloc_spi(t, 1, ~(u32)0)

   It just needs to allocate unique SPI numbers local to
   xfrm6_tunnel.c   We mark "SPI" value zero as reserved and
   to indicate failed lookup.

2) Create hash table, it is keyed by ipv6 address and hash table
   entries give SPI values.

So on input you would say something like:

	u32 spi;

	spi = spihash_lookup(&iph->saddr);
	if (!spi)
		goto drop;
	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
			      IPPROTO_IPV6, AF_INET6);

Is the idea more clear now?

Once you fix this up I'll apply your xfrm6_tunnel.c work.

Thank you.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6
  2003-05-31 16:01 ` James Morris
@ 2003-06-01  8:34   ` David S. Miller
  0 siblings, 0 replies; 11+ messages in thread
From: David S. Miller @ 2003-06-01  8:34 UTC (permalink / raw)
  To: jmorris; +Cc: mk, kuznet, netdev, usagi

   From: James Morris <jmorris@intercode.com.au>
   Date: Sun, 1 Jun 2003 02:01:42 +1000 (EST)

   We need to either filter them out or make sure they are 
   displayed as ipip.
   
   Part of the answer will depend on whether we want to expose xfrm-based 
   ipip tunnels for general use, or only use them internally for ipcomp.
   
I think it is an error to extend PF_KEY for our Linux purposes.
Our API here is basically defined to be whatever is in KAME :-)

However, setkey should filter entries it does not understand.

Currently I see no use for exposing these tunnel transforms
outside of the kernel.  Mobile IPV6, if it decides to use
xfrm6_tunnel, can configure them itself in the kernel side support.
Or, if user side is more appropriate for MIPV6 access, we may allow
it to use xfrm netlink interface somehow.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] xfrm ip6ip6 (revised)
  2003-06-01  8:30 ` David S. Miller
@ 2003-06-13 16:03   ` Mitsuru KANDA / 神田 充
  2003-06-13 16:11     ` YOSHIFUJI Hideaki / 吉藤英明
  2003-06-13 19:07     ` David S. Miller
  0 siblings, 2 replies; 11+ messages in thread
From: Mitsuru KANDA / 神田 充 @ 2003-06-13 16:03 UTC (permalink / raw)
  To: David S. Miller; +Cc: jmorris, kuznet, netdev, usagi

Hello,

I recreated a xfrm ip6ip6 patch.
The changes to the previous patch are:
	- to allocate unique spi values in xfrm6_tunnel.c  
	  by using just simple open addressing hash, 
	- to introduce device-like ip6ip6 handling, and
	- to fix some bugs.

This patch is against CS1.1304.

Chould you check this?

Regards,
-mk

At Sun, 01 Jun 2003 01:30:40 -0700 (PDT),
"David S. Miller" <davem@redhat.com> wrote:
(snipped)
> I would suggest following implementation:
> 
> 1) Implement something similar to xfrm_alloc_spi(t, 1, ~(u32)0)
> 
>    It just needs to allocate unique SPI numbers local to
>    xfrm6_tunnel.c   We mark "SPI" value zero as reserved and
>    to indicate failed lookup.
> 
> 2) Create hash table, it is keyed by ipv6 address and hash table
>    entries give SPI values.
> 
> So on input you would say something like:
> 
> 	u32 spi;
> 
> 	spi = spihash_lookup(&iph->saddr);
> 	if (!spi)
> 		goto drop;
> 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
> 			      IPPROTO_IPV6, AF_INET6);
(snipped)


Index: linux25-XFRM6_TUNNEL-20030612/include/net/xfrm.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/xfrm.h,v
retrieving revision 1.1.1.25
retrieving revision 1.1.1.25.2.1
diff -u -r1.1.1.25 -r1.1.1.25.2.1
--- linux25-XFRM6_TUNNEL-20030612/include/net/xfrm.h	10 Jun 2003 13:21:39 -0000	1.1.1.25
+++ linux25-XFRM6_TUNNEL-20030612/include/net/xfrm.h	12 Jun 2003 15:30:16 -0000	1.1.1.25.2.1
@@ -494,10 +494,6 @@
 	return 0;
 }
 
-/* placeholder until xfrm6_tunnel.c is written */
-static inline int xfrm6_tunnel_check_size(struct sk_buff *skb)
-{ return 0; }
-
 /* A struct encoding bundle of transformations to apply to some set of flow.
  *
  * dst->child points to the next element of bundle.
@@ -748,6 +744,12 @@
 	void (*err_handler)(struct sk_buff *skb, void *info);
 };
 
+struct xfrm6_tunnel {
+	int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp);
+	void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			    int type, int code, int offset, __u32 info);
+};
+
 extern void xfrm_init(void);
 extern void xfrm4_init(void);
 extern void xfrm4_fini(void);
@@ -781,6 +783,11 @@
 extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
 extern int xfrm4_tunnel_check_size(struct sk_buff *skb);
+extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler);
+extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler);
+extern int xfrm6_tunnel_check_size(struct sk_buff *skb);
+extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
+extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
 extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
 extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
Index: linux25-XFRM6_TUNNEL-20030612/net/ipv6/Makefile
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Makefile,v
retrieving revision 1.1.1.13
retrieving revision 1.1.1.13.2.1
diff -u -r1.1.1.13 -r1.1.1.13.2.1
--- linux25-XFRM6_TUNNEL-20030612/net/ipv6/Makefile	10 Jun 2003 13:21:55 -0000	1.1.1.13
+++ linux25-XFRM6_TUNNEL-20030612/net/ipv6/Makefile	12 Jun 2003 15:29:53 -0000	1.1.1.13.2.1
@@ -9,7 +9,7 @@
 		protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
 		ip6_flowlabel.o ipv6_syms.o \
-		xfrm6_policy.o xfrm6_state.o xfrm6_input.o
+		xfrm6_policy.o xfrm6_state.o xfrm6_input.o xfrm6_tunnel.o
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
Index: linux25-XFRM6_TUNNEL-20030612/net/ipv6/ip6_tunnel.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ip6_tunnel.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -u -r1.1.1.1 -r1.1.1.1.2.1
--- linux25-XFRM6_TUNNEL-20030612/net/ipv6/ip6_tunnel.c	10 Jun 2003 13:21:55 -0000	1.1.1.1
+++ linux25-XFRM6_TUNNEL-20030612/net/ipv6/ip6_tunnel.c	12 Jun 2003 15:29:53 -0000	1.1.1.1.2.1
@@ -48,6 +48,7 @@
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/ip6_tunnel.h>
+#include <net/xfrm.h>
 
 MODULE_AUTHOR("Ville Nuorvala");
 MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
@@ -1174,10 +1175,9 @@
 	return 0;
 }
 
-static struct inet6_protocol ip6ip6_protocol = {
+static struct xfrm_tunnel ip6ip6_handler = {
 	.handler = ip6ip6_rcv,
 	.err_handler = ip6ip6_err,
-	.flags = INET6_PROTO_FINAL
 };
 
 /**
@@ -1192,6 +1192,11 @@
 	struct sock *sk;
 	struct ipv6_pinfo *np;
 
+	if (xfrm6_tunnel_register(&ip6ip6_handler) < 0) {
+		printk(KERN_INFO "ip6ip6 init: can't register tunnel\n");
+		return -EAGAIN;
+	}
+
 	ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
 
 	for (i = 0; i < NR_CPUS; i++) {
@@ -1216,10 +1221,6 @@
 
 		sk->sk_prot->unhash(sk);
 	}
-	if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) {
-		printk(KERN_ERR "Failed to register IPv6 protocol\n");
-		goto fail;
-	}
 
 	SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev);
 	register_netdev(&ip6ip6_fb_tnl_dev);
@@ -1243,9 +1244,10 @@
 {
 	int i;
 
-	unregister_netdev(&ip6ip6_fb_tnl_dev);
+	if (xfrm6_tunnel_deregister(&ip6ip6_handler) < 0)
+		printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
 
-	inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
+	unregister_netdev(&ip6ip6_fb_tnl_dev);
 
 	for (i = 0; i < NR_CPUS; i++) {
 		if (!cpu_possible(i))
Index: linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipcomp6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipcomp6.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 ipcomp6.c
--- linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipcomp6.c	10 Jun 2003 13:21:54 -0000	1.1.1.3
+++ linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipcomp6.c	13 Jun 2003 09:44:59 -0000
@@ -254,6 +254,66 @@
 	xfrm_state_put(x);
 }
 
+static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
+{
+	struct xfrm_state *t = NULL;
+
+	t = xfrm_state_alloc();
+	if (!t)
+		goto out;
+
+	t->id.proto = IPPROTO_IPV6;
+	t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr);
+	memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
+	memcpy(&t->sel, &x->sel, sizeof(t->sel));
+	t->props.family = AF_INET6;
+	t->props.mode = 1;
+	memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
+
+	t->type = xfrm_get_type(IPPROTO_IPV6, t->props.family);
+	if (t->type == NULL)
+		goto error;
+
+	if (t->type->init_state(t, NULL))
+		goto error;
+
+	t->km.state = XFRM_STATE_VALID;
+	atomic_set(&t->tunnel_users, 1);
+
+out:
+	return t;
+
+error:
+	xfrm_state_put(t);
+	goto out;
+}
+
+static int ipcomp6_tunnel_attach(struct xfrm_state *x)
+{
+	int err = 0;
+	struct xfrm_state *t = NULL;
+	u32 spi;
+
+	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
+	if (spi)
+		t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr,
+					      spi, IPPROTO_IPV6, AF_INET6);
+	if (!t) {
+		t = ipcomp6_tunnel_create(x);
+		if (!t) {
+			err = -EINVAL;
+			goto out;
+		}
+		xfrm_state_insert(t);
+		xfrm_state_hold(t);
+	}
+	x->tunnel = t;
+	atomic_inc(&t->tunnel_users);
+
+out:
+	return err;
+}
+
 static void ipcomp6_free_data(struct ipcomp_data *ipcd)
 {
 	if (ipcd->tfm)
@@ -292,6 +352,12 @@
 	ipcd->tfm = crypto_alloc_tfm(x->calg->alg_name, 0);
 	if (!ipcd->tfm)
 		goto error;
+
+	if (x->props.mode) {
+		err = ipcomp6_tunnel_attach(x);
+		if (err)
+			goto error;
+	}
 
 	calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
 	BUG_ON(!calg_desc);
Index: linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipv6_syms.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipv6_syms.c,v
retrieving revision 1.1.1.13
retrieving revision 1.1.1.13.2.1
diff -u -r1.1.1.13 -r1.1.1.13.2.1
--- linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipv6_syms.c	10 Jun 2003 13:21:55 -0000	1.1.1.13
+++ linux25-XFRM6_TUNNEL-20030612/net/ipv6/ipv6_syms.c	12 Jun 2003 15:29:53 -0000	1.1.1.13.2.1
@@ -38,6 +38,11 @@
 EXPORT_SYMBOL(ip6_find_1stfragopt);
 EXPORT_SYMBOL(xfrm6_rcv);
 EXPORT_SYMBOL(xfrm6_clear_mutable_options);
+EXPORT_SYMBOL(xfrm6_tunnel_register);
+EXPORT_SYMBOL(xfrm6_tunnel_deregister);
+EXPORT_SYMBOL(xfrm6_tunnel_check_size);
+EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
+EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
 EXPORT_SYMBOL(rt6_lookup);
 EXPORT_SYMBOL(fl6_sock_lookup);
 EXPORT_SYMBOL(ipv6_ext_hdr);
Index: linux25-XFRM6_TUNNEL-20030612/net/ipv6/xfrm6_tunnel.c
===================================================================
RCS file: linux25-XFRM6_TUNNEL-20030612/net/ipv6/xfrm6_tunnel.c
diff -N linux25-XFRM6_TUNNEL-20030612/net/ipv6/xfrm6_tunnel.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ linux25-XFRM6_TUNNEL-20030612/net/ipv6/xfrm6_tunnel.c	13 Jun 2003 09:44:59 -0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author	Mitsuru KANDA  <mk@linux-ipv6.org>
+ *
+ * Based on xfrm4_tunnel
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/xfrm.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/icmp.h>
+#include <net/ipv6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+#define XFRM6_TUNNEL_HSIZE 1024
+/* note: we assume index of xfrm_tunnel_table[] == spi */
+static xfrm_address_t *xfrm6_tunnel_table[XFRM6_TUNNEL_HSIZE];
+
+static spinlock_t xfrm6_tunnel_lock = SPIN_LOCK_UNLOCKED;
+
+static unsigned xfrm6_addr_hash(xfrm_address_t *addr)
+{
+	unsigned h;
+	h = ntohl(addr->a6[0]^addr->a6[1]^addr->a6[2]^addr->a6[3]);
+	h = (h ^ (h>>16)) % XFRM6_TUNNEL_HSIZE;
+	return h;
+}
+
+static void xfrm6_tunnel_htable_init(void)
+{
+	int i;
+	for (i=0; i<XFRM6_TUNNEL_HSIZE; i++)
+		xfrm6_tunnel_table[i] = NULL;
+}
+
+u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
+{
+	u32 spi = 0;
+	u32 index = xfrm6_addr_hash(saddr);
+	xfrm_address_t *index_addr;
+	int i;
+
+	spin_lock(&xfrm6_tunnel_lock);
+	for (i = index; i < XFRM6_TUNNEL_HSIZE; i++) {
+		index_addr = xfrm6_tunnel_table[i];
+		if (index_addr == NULL)
+			continue;
+		if (!memcmp(index_addr, saddr, sizeof(xfrm_address_t))) {
+			spi = htonl(i);
+			goto out;
+		}
+	}
+out:
+	spin_unlock(&xfrm6_tunnel_lock);
+	return spi;
+}
+
+u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
+{
+	u32 spi = 0;
+	u32 index = xfrm6_addr_hash(saddr);
+	xfrm_address_t *index_addr;
+	int i;
+
+	spin_lock(&xfrm6_tunnel_lock);
+	for (i = index; i < XFRM6_TUNNEL_HSIZE; i++) {
+		if (xfrm6_tunnel_table[i] == NULL) {
+			index_addr = kmalloc(sizeof(xfrm_address_t), GFP_ATOMIC);
+			memcpy(index_addr, saddr, sizeof(xfrm_address_t));
+			xfrm6_tunnel_table[i] = index_addr;
+			spi = htonl(i);
+			goto out;
+		}
+	}
+
+out:
+	spin_unlock(&xfrm6_tunnel_lock);
+	return spi;
+}
+
+static void xfrm6_tunnel_free_spi(xfrm_address_t *saddr){
+	u32 index = ntohl(xfrm6_tunnel_spi_lookup(saddr));
+
+	if (index) {
+		spin_lock(&xfrm6_tunnel_lock);
+		kfree(xfrm6_tunnel_table[index]);
+		xfrm6_tunnel_table[index] = NULL;
+		spin_unlock(&xfrm6_tunnel_lock);
+	}
+}
+
+
+int xfrm6_tunnel_check_size(struct sk_buff *skb)
+{
+	int mtu, ret = 0;
+	struct dst_entry *dst = skb->dst;
+
+	mtu = dst_pmtu(dst) - sizeof(struct ipv6hdr);
+	if (mtu < IPV6_MIN_MTU)
+		mtu = IPV6_MIN_MTU;
+
+	if (skb->len > mtu) {
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		ret = -EMSGSIZE;
+	}
+
+	return ret;
+}
+
+static int ip6ip6_output(struct sk_buff *skb)
+{
+	struct dst_entry *dst = skb->dst;
+	struct xfrm_state *x = dst->xfrm;
+	struct ipv6hdr *iph, *top_iph;
+	int err;
+
+	if ((err = xfrm6_tunnel_check_size(skb)) != 0)
+		goto error_nolock;
+
+	iph = skb->nh.ipv6h;
+
+	top_iph = (struct ipv6hdr *)skb_push(skb, x->props.header_len);
+	top_iph->version = 6;
+	top_iph->priority = iph->priority;
+	top_iph->flow_lbl[0] = iph->flow_lbl[0];
+	top_iph->flow_lbl[1] = iph->flow_lbl[1];
+	top_iph->flow_lbl[2] = iph->flow_lbl[2];
+	top_iph->nexthdr = IPPROTO_IPV6; 
+	top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	top_iph->hop_limit = iph->hop_limit;
+	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+	skb->nh.raw = skb->data;
+	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
+
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+
+	spin_unlock_bh(&x->lock);
+
+	if ((skb->dst = dst_pop(dst)) == NULL) { 
+		kfree_skb(skb);
+		err = -EHOSTUNREACH;
+		goto error_nolock;
+	}
+
+	return NET_XMIT_BYPASS;
+
+error_nolock:
+	kfree_skb(skb);
+	return err;
+}
+
+static int ip6ip6_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 
+		return -EINVAL;
+
+	skb->mac.raw = skb->nh.raw;
+	skb->nh.raw = skb->data;
+	dst_release(skb->dst);
+	skb->dst = NULL;
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->pkt_type = PACKET_HOST;
+	netif_rx(skb);
+
+	return 0;
+}
+
+static struct xfrm6_tunnel *ip6ip6_handler;
+static DECLARE_MUTEX(xfrm6_tunnel_sem);
+
+int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
+{
+	int ret;
+
+	down(&xfrm6_tunnel_sem);
+	ret = 0;
+	if (ip6ip6_handler != NULL)
+		ret = -EINVAL;
+	if (!ret)
+		ip6ip6_handler = handler;
+	up(&xfrm6_tunnel_sem);
+
+	return ret;
+}
+
+int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
+{
+	int ret;
+
+	down(&xfrm6_tunnel_sem);
+	ret = 0;
+	if (ip6ip6_handler != handler)
+	ret = -EINVAL;
+	if (!ret)
+		ip6ip6_handler = NULL;
+	up(&xfrm6_tunnel_sem);
+
+	synchronize_net();
+
+	return ret;
+}
+
+static int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+	struct sk_buff *skb = *pskb;
+	struct xfrm6_tunnel *handler = ip6ip6_handler;
+	struct xfrm_state *x = NULL;
+	struct ipv6hdr *iph = skb->nh.ipv6h;
+	int err = 0;
+	u32 spi;
+
+	/* device-like_ip6ip6_handler() */
+	if (handler) {
+		err = handler->handler(pskb, nhoffp);
+		if (!err)
+			goto out;
+	}
+
+	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
+	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, 
+			spi,
+			IPPROTO_IPV6, AF_INET6);
+
+	if (!x)
+		goto drop;
+
+	spin_lock(&x->lock);
+
+	if (unlikely(x->km.state != XFRM_STATE_VALID))
+		goto drop_unlock;
+
+	err = ip6ip6_xfrm_rcv(x, NULL, skb);
+	if (err)
+		goto drop_unlock;
+
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++; 
+	spin_unlock(&x->lock); 
+	xfrm_state_put(x); 
+
+out:
+	return 0;
+
+drop_unlock:
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+drop:
+	kfree_skb(skb);
+
+	return -1;
+}
+
+static void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+			int type, int code, int offset, __u32 info)
+{
+	struct xfrm6_tunnel *handler = ip6ip6_handler;
+
+	/* call here first for device-like ip6ip6 err handling */
+	if (handler) {
+		handler->err_handler(skb, opt, type, code, offset, info);
+		return;
+	}
+
+	/* xfrm ip6ip6 native err handling */
+	switch (type) {
+	case ICMPV6_DEST_UNREACH: 
+		switch (code) {
+		case ICMPV6_NOROUTE: 
+		case ICMPV6_ADM_PROHIBITED:
+		case ICMPV6_NOT_NEIGHBOUR:
+		case ICMPV6_ADDR_UNREACH:
+		case ICMPV6_PORT_UNREACH:
+		default:
+			printk(KERN_ERR "xfrm ip6ip6: Destination Unreach.\n");
+			break;
+		}
+		break;
+	case ICMPV6_PKT_TOOBIG:
+			printk(KERN_ERR "xfrm ip6ip6: Packet Too Big.\n");
+		break;
+	case ICMPV6_TIME_EXCEED:
+		switch (code) {
+		case ICMPV6_EXC_HOPLIMIT:
+			printk(KERN_ERR "xfrm ip6ip6: Too small Hoplimit.\n");
+			break;
+		case ICMPV6_EXC_FRAGTIME:
+		default: 
+			break;
+		}
+		break;
+	case ICMPV6_PARAMPROB:
+		switch (code) {
+		case ICMPV6_HDR_FIELD: break;
+		case ICMPV6_UNK_NEXTHDR: break;
+		case ICMPV6_UNK_OPTION: break;
+		}
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
+static int ip6ip6_init_state(struct xfrm_state *x, void *args)
+{
+	if (!x->props.mode)
+		return -EINVAL;
+
+	x->props.header_len = sizeof(struct ipv6hdr);
+
+	return 0;
+}
+
+static void ip6ip6_destroy(struct xfrm_state *x)
+{
+	xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
+}
+
+static struct xfrm_type ip6ip6_type = {
+	.description	= "IP6IP6",
+	.owner          = THIS_MODULE,
+	.proto		= IPPROTO_IPV6,
+	.init_state	= ip6ip6_init_state,
+	.destructor	= ip6ip6_destroy,
+	.input		= ip6ip6_xfrm_rcv,
+	.output		= ip6ip6_output,
+};
+
+static struct inet6_protocol ip6ip6_protocol = {
+	.handler	= ip6ip6_rcv,
+	.err_handler	= ip6ip6_err, 
+	.flags          = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+};
+
+static int __init ip6ip6_init(void)
+{
+	if (xfrm_register_type(&ip6ip6_type, AF_INET6) < 0) {
+		printk(KERN_INFO "ip6ip6  init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
+	if (inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6) < 0) {
+		printk(KERN_INFO "ip6ip6 init: can't add protocol\n");
+		xfrm_unregister_type(&ip6ip6_type, AF_INET6);
+		return -EAGAIN;
+	}
+	xfrm6_tunnel_htable_init();
+	return 0;
+}
+
+static void __exit ip6ip6_fini(void)
+{
+	if (inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6) < 0)
+		printk(KERN_INFO "ip6ip6 close: can't remove protocol\n");
+	if (xfrm_unregister_type(&ip6ip6_type, AF_INET6) < 0)
+		printk(KERN_INFO "ip6ip6 close: can't remove xfrm type\n");
+}
+
+module_init(ip6ip6_init);
+module_exit(ip6ip6_fini);
+MODULE_LICENSE("GPL");
Index: linux25-XFRM6_TUNNEL-20030612/net/xfrm/xfrm_output.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/xfrm/xfrm_output.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.24.1
diff -u -r1.1.1.1 -r1.1.1.1.24.1
--- linux25-XFRM6_TUNNEL-20030612/net/xfrm/xfrm_output.c	6 May 2003 12:43:55 -0000	1.1.1.1
+++ linux25-XFRM6_TUNNEL-20030612/net/xfrm/xfrm_output.c	12 Jun 2003 15:29:06 -0000	1.1.1.1.24.1
@@ -27,11 +27,11 @@
 		case AF_INET:
 			err = xfrm4_tunnel_check_size(skb);
 			break;
-			
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)			
 		case AF_INET6:
 			err = xfrm6_tunnel_check_size(skb);
 			break;
-			
+#endif	
 		default:
 			err = -EINVAL;
 		}

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6 (revised)
  2003-06-13 16:03   ` [PATCH] xfrm ip6ip6 (revised) Mitsuru KANDA / 神田 充
@ 2003-06-13 16:11     ` YOSHIFUJI Hideaki / 吉藤英明
  2003-06-13 16:13       ` YOSHIFUJI Hideaki / 吉藤英明
  2003-06-13 19:07     ` David S. Miller
  1 sibling, 1 reply; 11+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-13 16:11 UTC (permalink / raw)
  To: mk; +Cc: davem, jmorris, kuznet, netdev, yoshfuji, usagi

In article <87smqerml5.wl@karaba.org> (at Sat, 14 Jun 2003 01:03:50 +0900), Mitsuru KANDA / 神田 充 <mk@linux-ipv6.org> says:

> Chould you check this?

Kanda-san, would you use the dynamic netdev allication scheme by
alloc_netdev(), please? :-)

-- 
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6 (revised)
  2003-06-13 16:11     ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-13 16:13       ` YOSHIFUJI Hideaki / 吉藤英明
  2003-06-13 18:08         ` Ville Nuorvala
  0 siblings, 1 reply; 11+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-13 16:13 UTC (permalink / raw)
  To: mk; +Cc: davem, jmorris, kuznet, netdev, yoshfuji, usagi

In article <20030614.011146.116698702.yoshfuji@linux-ipv6.org> (at Sat, 14 Jun 2003 01:11:46 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> says:

> Kanda-san, would you use the dynamic netdev allication scheme by
> alloc_netdev(), please? :-)

Oops, this comment is absolitely wrong... Very sorry...

-- 
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6 (revised)
  2003-06-13 16:13       ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-13 18:08         ` Ville Nuorvala
  0 siblings, 0 replies; 11+ messages in thread
From: Ville Nuorvala @ 2003-06-13 18:08 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / 吉藤英明
  Cc: mk, davem, jmorris, kuznet, netdev, usagi

On Sat, 14 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:

> In article <20030614.011146.116698702.yoshfuji@linux-ipv6.org> (at Sat, 14 Jun 2003 01:11:46 +0900 (JST)), YOSHIFUJI Hideaki / ^[$B5HF#1QL@^[(B <yoshfuji@linux-ipv6.org> says:
>
> > Kanda-san, would you use the dynamic netdev allication scheme by
> > alloc_netdev(), please? :-)
>
> Oops, this comment is absolitely wrong... Very sorry...

I can do the alloc_netdev() patch :)

-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6 (revised)
  2003-06-13 16:03   ` [PATCH] xfrm ip6ip6 (revised) Mitsuru KANDA / 神田 充
  2003-06-13 16:11     ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-13 19:07     ` David S. Miller
  2003-06-13 19:19       ` David S. Miller
  1 sibling, 1 reply; 11+ messages in thread
From: David S. Miller @ 2003-06-13 19:07 UTC (permalink / raw)
  To: mk; +Cc: jmorris, kuznet, netdev, usagi

   From: Mitsuru KANDA / 神田 充 <mk@linux-ipv6.org>
   Date: Sat, 14 Jun 2003 01:03:50 +0900

   	- to allocate unique spi values in xfrm6_tunnel.c  
   	  by using just simple open addressing hash, 

Mitsuru, what happens if two tunnels use same address?

Only first one will be found in hash, this is incorrect
behavior as it will cause the wrong SPI to be used when
packets are really destined for second user of that address.

You need to add refcount to hash table entries, so that SPI can be
shared by different xfrm6 tunnels with same address.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] xfrm ip6ip6 (revised)
  2003-06-13 19:07     ` David S. Miller
@ 2003-06-13 19:19       ` David S. Miller
  0 siblings, 0 replies; 11+ messages in thread
From: David S. Miller @ 2003-06-13 19:19 UTC (permalink / raw)
  To: mk; +Cc: jmorris, kuznet, netdev, usagi

   From: "David S. Miller" <davem@redhat.com>
   Date: Fri, 13 Jun 2003 12:07:02 -0700 (PDT)

   You need to add refcount to hash table entries, so that SPI can be
   shared by different xfrm6 tunnels with same address.
   
Mitsuru, here is some example code showing what my
idea looks like.  I apologize for not making something
like this for you earlier.

struct v6spi_entry {
	struct v6spi_entry *next;
	struct in6_addr addr;
	u32 spi;
	atomic_t refcnt;
};

u32 spi v6spi_alloc(struct in6_addr *addr)
{
	int h = v6_hashfn(addr);
	struct v6spi_entry *ent;

	for (ent = hash_table[h]; ent; ent = ent->next) {
		if (!ipv6_addr_cmp(addr, &ent->addr)) {
			atomic_inc(&ent->refcnt);
			return ent->spi;
		}
	}
	ent = kmalloc(sizeof(*ent), GFP_ATOMIC);
	ent->spi = alloc_unique_spi();
	ipv6_addr_copy(&ent->addr, addr);
	atomic_set(&ent->refcnt, 1);
	ent->next = hash_table[h];
	hash_table[h] = ent;

	return ent->spi;
}

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2003-06-13 19:19 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-05-31 15:20 [PATCH] xfrm ip6ip6 Mitsuru KANDA / 神田 充
2003-05-31 16:01 ` James Morris
2003-06-01  8:34   ` David S. Miller
2003-05-31 16:06 ` James Morris
2003-06-01  8:30 ` David S. Miller
2003-06-13 16:03   ` [PATCH] xfrm ip6ip6 (revised) Mitsuru KANDA / 神田 充
2003-06-13 16:11     ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-13 16:13       ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-13 18:08         ` Ville Nuorvala
2003-06-13 19:07     ` David S. Miller
2003-06-13 19:19       ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).