Skip to contentSkip to conversation

IPv6 IPComp

PATCH Applied Mitsuru KANDA / 神田 充 5 participants 15 messages May 16, 2003 – May 20, 2003

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 IPv6 IPComp

Hello,

This patch is implementation of IPComp for IPv6.
I moved IPcompv4/v6 common definitions to net/ipcomp.h and also moved IPcomp header structures to general header files (linux/{ip.h,ipv6.h}).

Attached diff is for linux-2.5.69 + CS1.1137 .

Could you check it?

Regards,
-mk

Index: include/linux/ip.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/linux/ip.h,v retrieving revision 1.1.1.6
retrieving revision 1.1.1.6.6.1

linux/ip.h +6 -0
diff -u -r1.1.1.6 -r1.1.1.6.6.1
@@ -198,4 +198,10 @@
 	__u8  enc_data[0];	/* Variable len but >=8. Mind the 64 bit alignment! */
 };
 
+struct ip_comp_hdr {
+	__u8 nexthdr;
+	__u8 flags;
+	__u16 cpi;
+};
+
 #endif	/* _LINUX_IP_H */

Index: include/linux/ipv6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/linux/ipv6.h,v retrieving revision 1.1.1.6
retrieving revision 1.1.1.6.2.1

linux/ipv6.h +6 -0
diff -u -r1.1.1.6 -r1.1.1.6.2.1
@@ -89,6 +89,12 @@
 	__u8  enc_data[0];      /* Length variable but >=8. Mind the 64 bit alignment! */
 };
 
+struct ipv6_comp_hdr {
+	__u8 nexthdr;
+	__u8 flags;
+	__u16 cpi;
+};
+
 /*
  *	IPv6 fixed header
  *

Index: include/net/ipcomp.h
===================================================================
RCS file: include/net/ipcomp.h

net/ipcomp.h new file +12 -0
diff -N include/net/ipcomp.h
@@ -0,0 +1,12 @@
+#ifndef _NET_IPCOMP_H
+#define _NET_IPCOMP_H
+
+#define IPCOMP_SCRATCH_SIZE     65400
+
+struct ipcomp_data {
+	u16 threshold;
+	u8 *scratch;
+	struct crypto_tfm *tfm;
+};
+
+#endif

Index: include/net/ipv6.h
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/ipv6.h,v retrieving revision 1.1.1.7
retrieving revision 1.1.1.7.2.1

net/ipv6.h +1 -0
diff -u -r1.1.1.7 -r1.1.1.7.2.1
@@ -315,6 +315,7 @@
 					       unsigned length,
 					       struct ipv6_txoptions *opt,
 					       int hlimit, int flags);
+extern int			ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr);
 
 extern int			ip6_append_data(struct sock *sk,
 						int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),

Index: net/ipv4/ipcomp.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv4/ipcomp.c,v retrieving revision 1.1.1.5
retrieving revision 1.1.1.5.2.1

ipv4/ipcomp.c +11 -24
diff -u -r1.1.1.5 -r1.1.1.5.2.1
@@ -22,20 +22,7 @@
 #include <net/xfrm.h>
 #include <net/icmp.h>
 #include <net/esp.h>
-
-#define IPCOMP_SCRATCH_SIZE	65400
-
-struct ipcomp_hdr {
-	u8 nexthdr;
-	u8 flags;
-	u16 cpi;
-};
-
-struct ipcomp_data {
-	u16 threshold;
-	u8 *scratch;
-	struct crypto_tfm *tfm;
-};
+#include <net/ipcomp.h>
 
 static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 {
@@ -52,7 +39,7 @@
 	if (err)
 		goto out;
 
-	if (dlen < (plen + sizeof(struct ipcomp_hdr))) {
+	if (dlen < (plen + sizeof(struct ip_comp_hdr))) {
 		err = -EINVAL;
 		goto out;
 	}
@@ -93,11 +80,11 @@
 	iph = skb->nh.iph;
 	memcpy(&tmp_iph, iph, iph->ihl * 4);
 	nexthdr = *(u8 *)skb->data;
-	skb_pull(skb, sizeof(struct ipcomp_hdr));
-	skb->nh.raw += sizeof(struct ipcomp_hdr);
+	skb_pull(skb, sizeof(struct ip_comp_hdr));
+	skb->nh.raw += sizeof(struct ip_comp_hdr);
 	memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4);
 	iph = skb->nh.iph;
-	iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ipcomp_hdr));
+	iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ip_comp_hdr));
 	iph->protocol = nexthdr;
 	skb->h.raw = skb->data;
 	err = ipcomp_decompress(x, skb);
@@ -122,7 +109,7 @@
 	if (err)
 		goto out;
 
-	if ((dlen + sizeof(struct ipcomp_hdr)) >= plen) {
+	if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
 		err = -EMSGSIZE;
 		goto out;
 	}
@@ -162,7 +149,7 @@
 	struct dst_entry *dst = skb->dst;
 	struct xfrm_state *x = dst->xfrm;
 	struct iphdr *iph, *top_iph;
-	struct ipcomp_hdr *ipch;
+	struct ip_comp_hdr *ipch;
 	struct ipcomp_data *ipcd = x->data;
 	union {
 		struct iphdr	iph;
@@ -215,13 +202,13 @@
 	/* Install ipcomp header, convert into ipcomp datagram. */
 	iph = skb->nh.iph;
 	memcpy(&tmp_iph, iph, iph->ihl * 4);
-	top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ipcomp_hdr));
+	top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr));
 	memcpy(top_iph, &tmp_iph, iph->ihl * 4);
 	iph = top_iph;
 	iph->tot_len = htons(skb->len);
 	iph->protocol = IPPROTO_COMP;
 	iph->check = 0;
-	ipch = (struct ipcomp_hdr *)((char *)iph + iph->ihl * 4);
+	ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4);
 	ipch->nexthdr = x->props.mode ? IPPROTO_IPIP : tmp_iph.iph.protocol;
 	ipch->flags = 0;
 	ipch->cpi = htons((u16 )ntohl(x->id.spi));
@@ -252,7 +239,7 @@
 {
 	u32 spi;
 	struct iphdr *iph = (struct iphdr *)skb->data;
-	struct ipcomp_hdr *ipch = (struct ipcomp_hdr *)(skb->data+(iph->ihl<<2));
+	struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
 	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
@@ -356,7 +343,7 @@
 		goto error;
 
 	memset(ipcd, 0, sizeof(*ipcd));
-	x->props.header_len = sizeof(struct ipcomp_hdr);
+	x->props.header_len = sizeof(struct ip_comp_hdr);
 	if (x->props.mode)
 		x->props.header_len += sizeof(struct iphdr);
 	x->data = ipcd;

Index: net/ipv6/Kconfig
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Kconfig,v retrieving revision 1.1.1.3
retrieving revision 1.1.1.3.38.1

ipv6/Kconfig +9 -0
diff -u -r1.1.1.3 -r1.1.1.3.38.1
@@ -33,4 +33,13 @@
 
 	  If unsure, say Y.
 
+config INET6_IPCOMP
+	tristate "IPv6: IPComp transformation"
+	depends on IPV6
+	---help---
+	  Support for IP Paylod Compression (RFC3173), typically needed
+	  for IPsec.
+
+	  If unsure, say Y.
+
 source "net/ipv6/netfilter/Kconfig"

Index: net/ipv6/Makefile
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Makefile,v retrieving revision 1.1.1.9
retrieving revision 1.1.1.9.22.1

ipv6/Makefile +1 -0
diff -u -r1.1.1.9 -r1.1.1.9.22.1
@@ -13,4 +13,5 @@
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
+obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/

Index: net/ipv6/ip6_output.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ip6_output.c,v retrieving revision 1.1.1.12
retrieving revision 1.1.1.12.2.1

ipv6/ip6_output.c +1 -1
diff -u -r1.1.1.12 -r1.1.1.12.2.1
@@ -887,7 +887,7 @@
 #endif
 }
 
-static int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr)
+int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr)
 {
 	u16 offset = sizeof(struct ipv6hdr);
 	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);

Index: net/ipv6/ipcomp6.c
===================================================================
RCS file: net/ipv6/ipcomp6.c

ipv6/ipcomp6.c new file +368 -0

368 lines not on this page · raw message

Index: net/ipv6/ipv6_syms.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipv6_syms.c,v retrieving revision 1.1.1.9
retrieving revision 1.1.1.9.4.1

ipv6/ipv6_syms.c +1 -0
diff -u -r1.1.1.9 -r1.1.1.9.4.1
@@ -35,5 +35,6 @@
 EXPORT_SYMBOL(in6addr_any);
 EXPORT_SYMBOL(in6addr_loopback);
 EXPORT_SYMBOL(in6_dev_finish_destroy);
+EXPORT_SYMBOL(ip6_found_nexthdr);
 EXPORT_SYMBOL(xfrm6_rcv);
 EXPORT_SYMBOL(xfrm6_clear_mutable_options);

Index: net/xfrm/xfrm_input.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/xfrm/xfrm_input.c,v retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.14.1

xfrm/xfrm_input.c +1 -1
diff -u -r1.1.1.2 -r1.1.1.2.14.1
@@ -34,7 +34,7 @@
 		offset_seq = offsetof(struct ip_esp_hdr, seq_no);
 		break;
 	case IPPROTO_COMP:
-		if (!pskb_may_pull(skb, 4))
+		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
 			return -EINVAL;
 		*spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
 		*seq = 0;
#1 lore raw
Quoted 9 lines · On Fri, 16 May 2003, Mitsuru KANDA / [ISO-2022-JP] $B?@ED(B $B=<(B wrote:

This patch is implementation of IPComp for IPv6.
I moved IPcompv4/v6 common definitions to net/ipcomp.h and also moved IPcomp header structures to general header files (linux/{ip.h,ipv6.h}).

Attached diff is for linux-2.5.69 + CS1.1137 .

Could you check it?

Looks good!

A few issues:

The crypto/Kconfig file needs to be updated so that the deflate module is enabled when ipcomp6 is.

In a subsequent patch, it would be good to define single NIP6() in a header file, as local versions are spreading.

With current bk, you need to attach internal ipip xfrms to allow reception of uncompressed ipcomp packets in tunnel mode. See the current ipv4 ipcomp code as an example. Any generic code for this should probably live in net/xfrm/xfrm_tunnel.c

- James

Signature · 2 lines
James Morris
<[email protected]>
#2 lore raw

At Fri, 16 May 2003 23:40:18 +1000 (EST),
James Morris <[email protected]> wrote:
...

Quoted 6 lines
Quoted 4 lines

Attached diff is for linux-2.5.69 + CS1.1137 .

Could you check it?

Looks good!

Thank you!

Quoted 4 lines

A few issues:

The crypto/Kconfig file needs to be updated so that the deflate module is enabled when ipcomp6 is.

OK, I will send a small patch after this ipcomp6 patch is committed.

Quoted 2 lines

In a subsequent patch, it would be good to define single NIP6() in a header file, as local versions are spreading.

Yes, this is a next issue for me.
I have a plan to do various small cleanups w/r AH6/ESP6/IPComp6...

Quoted 4 lines

With current bk, you need to attach internal ipip xfrms to allow reception of uncompressed ipcomp packets in tunnel mode. See the current ipv4 ipcomp code as an example. Any generic code for this should probably live in net/xfrm/xfrm_tunnel.c

I think so,
but it may take a time because currently ip6ip6 does not exist.

Regards,
-mk

#3 lore raw

From: Mitsuru KANDA / 神田 充 <[email protected]>
Date: Sat, 17 May 2003 02:59:30 +0900

but it may take a time because currently ip6ip6 does not exist.

Once you implement xfrm6_tunnel.c the problem is mostly solved. You do not need to have an ip6ip6 device-like tunnel first.

I will integrate your patch, thanks.

#4 lore raw

Hello,

At Fri, 16 May 2003 14:00:14 -0700 (PDT),

Quoted 8 lines · David S. Miller

From: Mitsuru KANDA / 神田 充 <[email protected]>
Date: Sat, 17 May 2003 02:59:30 +0900

but it may take a time because currently ip6ip6 does not exist.

Once you implement xfrm6_tunnel.c the problem is mostly solved. You do not need to have an ip6ip6 device-like tunnel first.

OK, we will do this.

Quoted 1 line

I will integrate your patch, thanks.

Thank you.

Regards,
-mk

#5 lore raw
In reply to David S. Miller

At Fri, 16 May 2003 14:00:14 -0700 (PDT),

Quoted 8 lines · David S. Miller

From: Mitsuru KANDA / 神田 充 <[email protected]>
Date: Sat, 17 May 2003 02:59:30 +0900

but it may take a time because currently ip6ip6 does not exist.

Once you implement xfrm6_tunnel.c the problem is mostly solved. You do not need to have an ip6ip6 device-like tunnel first.

Sorry just a novice question,
I would like to try to configure xfrm4 ipip tunnel for testing. What is the suitable tool?, setkey???

Regards,
-mk

#6 lore raw

From: Mitsuru KANDA / 神田 充 <[email protected]>
Date: Mon, 19 May 2003 17:24:31 +0900

I would like to try to configure xfrm4 ipip tunnel for testing. What is the suitable tool?, setkey???

Unfortunately setkey is not powerful enough to do this currently. Only the netlink based ipsec configuration can set these things up.

However, all of the testing we did was via tunnel mode IPCOMP.

Note that for xfrm6_tunnel.c you will need to use some kind of "u32 --> in6_addr" mapping table. You can do this with a simple hash table of some kind. Then you can use xfrm_state_lookup() just like xfrm4_tunnel.c does.

#7 lore raw
Quoted 6 lines

Unfortunately setkey is not powerful enough to do this currently. Only the netlink based ipsec configuration can set these things up.

However, all of the testing we did was via tunnel mode IPCOMP.

OK, I'll also do test.

Quoted 4 lines

Note that for xfrm6_tunnel.c you will need to use some kind of "u32 --> in6_addr" mapping table. You can do this with a simple hash table of some kind. Then you can use xfrm_state_lookup() just like xfrm4_tunnel.c does.

I see, thank you.

Regards,
-mk

#8 lore raw
In reply to Mitsuru KANDA / 神田 充

Hello,

At Sat, 17 May 2003 02:59:30 +0900,

Quoted 4 lines · Mitsuru KANDA / 神田 充

At Fri, 16 May 2003 23:40:18 +1000 (EST),
James Morris <[email protected]> wrote:

...

Quoted 5 lines
Quoted 4 lines

A few issues:

The crypto/Kconfig file needs to be updated so that the deflate module is enabled when ipcomp6 is.

OK, I will send a small patch after this ipcomp6 patch is committed.

Please apply this diff.

Thank you,
-mk

===== Kconfig 1.13 vs edited =====

Kconfig renamed from crypto/Kconfig +1 -1
@@ -138,7 +138,7 @@
 config CRYPTO_DEFLATE
 	tristate "Deflate compression algorithm"
 	depends on CRYPTO
-	default y if INET_IPCOMP=y || INET_IPCOMP=m
+	default y if INET_IPCOMP=y || INET_IPCOMP=m || INET6_IPCOMP=y || INET6_IPCOMP=m
 	help
 	  This is the Deflate algorithm (RFC1951), specified for use in
 	  IPSec with the IPCOMP protocol (RFC3173, RFC2394).
#10 lore raw
In reply to Mitsuru KANDA / 神田 充
Quoted 1 line · On Fri, 16 May 2003, Mitsuru KANDA / [ISO-2022-JP] $B?@ED(B $B=<(B wrote:

+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3713

What?!? Such RFC does not exist :-)

Quoted 399 lines

+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Author Mitsuru KANDA <[email protected]>
+ *
+ * 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
+ */

ipv6/ipcomp6.c new file +347 -0
+/* 
+ * [Memo]
+ *
+ * Outbound:
+ *  The compression of IP datagram MUST be done before AH/ESP processing, 
+ *  fragmentation, and the addition of Hop-by-Hop/Routing header. 
+ *
+ * Inbound:
+ *  The decompression of IP datagram MUST be done after the reassembly, 
+ *  AH/ESP processing.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/ipcomp.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+#include <linux/pfkeyv2.h>
+#include <linux/random.h>
+#include <net/icmp.h>
+#include <net/ipv6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+/* XXX no ipv6 ipcomp specific */
+#define NIP6(addr) \
+	ntohs((addr).s6_addr16[0]),\
+	ntohs((addr).s6_addr16[1]),\
+	ntohs((addr).s6_addr16[2]),\
+	ntohs((addr).s6_addr16[3]),\
+	ntohs((addr).s6_addr16[4]),\
+	ntohs((addr).s6_addr16[5]),\
+	ntohs((addr).s6_addr16[6]),\
+	ntohs((addr).s6_addr16[7])
+
+static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+	int err = 0;
+	u8 nexthdr = 0;
+	u8 *prevhdr;
+	int hdr_len = skb->h.raw - skb->nh.raw;
+	unsigned char *tmp_hdr = NULL;
+	struct ipv6hdr *iph;
+	int plen, dlen;
+	struct ipcomp_data *ipcd = x->data;
+	u8 *start, *scratch = ipcd->scratch;
+
+	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+		skb_linearize(skb, GFP_ATOMIC) != 0) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Remove ipcomp header and decompress original payload */
+	iph = skb->nh.ipv6h;
+	tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
+	if (!tmp_hdr)
+		goto out;
+	memcpy(tmp_hdr, iph, hdr_len);
+	nexthdr = *(u8 *)skb->data;
+	skb_pull(skb, sizeof(struct ipv6_comp_hdr)); 
+	skb->nh.raw += sizeof(struct ipv6_comp_hdr);
+	memcpy(skb->nh.raw, tmp_hdr, hdr_len);
+	iph = skb->nh.ipv6h;
+	iph->payload_len = htons(ntohs(iph->payload_len) - sizeof(struct ipv6_comp_hdr));
+	skb->h.raw = skb->data;
+
+	/* decompression */
+	plen = skb->len;
+	dlen = IPCOMP_SCRATCH_SIZE;
+	start = skb->data;
+
+	err = crypto_comp_decompress(ipcd->tfm, start, plen, scratch, &dlen);
+	if (err) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (dlen < (plen + sizeof(struct ipv6_comp_hdr))) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
+	if (err) {
+		goto out;
+	}
+
+	skb_put(skb, dlen - plen);
+	memcpy(skb->data, scratch, dlen);
+
+	iph = skb->nh.ipv6h;
+	iph->payload_len = htons(skb->len);
+	
+	ip6_found_nexthdr(skb, &prevhdr);
+	*prevhdr = nexthdr;
+out:
+	if (tmp_hdr)
+		kfree(tmp_hdr);
+	if (err)
+		goto error_out;
+	return nexthdr;
+error_out:
+	return err;
+}
+
+static int ipcomp6_output(struct sk_buff *skb)
+{
+	int err;
+	struct dst_entry *dst = skb->dst;
+	struct xfrm_state *x = dst->xfrm;
+	struct ipv6hdr *tmp_iph = NULL, *iph, *top_iph;
+	int hdr_len = 0;
+	struct ipv6_comp_hdr *ipch;
+	struct ipcomp_data *ipcd = x->data;
+	u8 *prevhdr;
+	u8 nexthdr = 0;
+	int plen, dlen;
+	u8 *start, *scratch = ipcd->scratch;
+
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
+
+	spin_lock_bh(&x->lock);
+
+	err = xfrm_check_output(x, skb, AF_INET6);
+	if (err)
+		goto error;
+
+	if (x->props.mode) {
+		hdr_len = sizeof(struct ipv6hdr);
+		nexthdr = IPPROTO_IPV6;
+		iph = skb->nh.ipv6h;
+		top_iph = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));
+		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; /* initial */
+		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; /* == top_iph */
+		skb->h.raw = skb->nh.raw + hdr_len;
+	} else {
+		hdr_len = ip6_found_nexthdr(skb, &prevhdr);
+		nexthdr = *prevhdr;
+	}
+
+	/* check whether datagram len is larger than threshold */
+	if ((skb->len - hdr_len) < ipcd->threshold) {
+		goto out_ok;
+	}
+
+	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+		skb_linearize(skb, GFP_ATOMIC) != 0) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* compression */
+	plen = skb->len - hdr_len;
+	dlen = IPCOMP_SCRATCH_SIZE;
+	start = skb->data + hdr_len;
+
+	err = crypto_comp_compress(ipcd->tfm, start, plen, scratch, &dlen);
+	if (err) {
+		goto error;
+	}
+	if ((dlen + sizeof(struct ipv6_comp_hdr)) >= plen) {
+		goto out_ok;
+	}
+	memcpy(start, scratch, dlen);
+	pskb_trim(skb, hdr_len+dlen);
+
+	/* insert ipcomp header and replace datagram */
+	tmp_iph = kmalloc(hdr_len, GFP_ATOMIC);
+	if (!tmp_iph) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(tmp_iph, skb->nh.raw, hdr_len);
+	top_iph = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6_comp_hdr));
+	memcpy(top_iph, tmp_iph, hdr_len);
+	kfree(tmp_iph);
+
+	top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	skb->nh.raw = skb->data; /* top_iph */
+	ip6_found_nexthdr(skb, &prevhdr); 
+	*prevhdr = IPPROTO_COMP;
+
+	ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len);
+	ipch->nexthdr = nexthdr;
+	ipch->flags = 0;
+	ipch->cpi = htons((u16 )ntohl(x->id.spi));
+
+	skb->h.raw = (unsigned char*)ipch;
+out_ok:
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+	spin_unlock_bh(&x->lock);
+
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
+		goto error_nolock;
+	}
+	err = NET_XMIT_BYPASS;
+
+out_exit:
+	return err;
+error:
+	spin_unlock_bh(&x->lock);
+error_nolock:
+	kfree_skb(skb);
+	goto out_exit;
+}
+
+static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		                int type, int code, int offset, __u32 info)
+{
+	u32 spi;
+	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+	struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset);
+	struct xfrm_state *x;
+
+	if (type != ICMPV6_DEST_UNREACH || type != ICMPV6_PKT_TOOBIG)
+		return;
+
+	spi = ntohl(ntohs(ipcomph->cpi));
+	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
+	if (!x)
+		return;
+
+	printk(KERN_DEBUG "pmtu discvovery on SA IPCOMP/%08x/"
+			"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			spi, NIP6(iph->daddr));
+	xfrm_state_put(x);
+}
+
+static void ipcomp6_free_data(struct ipcomp_data *ipcd)
+{
+	if (ipcd->tfm)
+		crypto_free_tfm(ipcd->tfm);
+	if (ipcd->scratch)
+		kfree(ipcd->scratch);
+}
+
+static void ipcomp6_destroy(struct xfrm_state *x)
+{
+	struct ipcomp_data *ipcd = x->data;
+	ipcomp6_free_data(ipcd);
+	kfree(ipcd);
+}
+
+static int ipcomp6_init_state(struct xfrm_state *x, void *args)
+{
+	int err = -ENOMEM;
+	struct ipcomp_data *ipcd;
+	struct xfrm_algo_desc *calg_desc;
+
+	ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL);
+	if (!ipcd)
+		goto error;
+
+	memset(ipcd, 0, sizeof(*ipcd));
+	x->props.header_len = sizeof(struct ipv6_comp_hdr);
+	if (x->props.mode)
+		x->props.header_len += sizeof(struct ipv6hdr);
+	x->data = ipcd;
+	
+	ipcd->scratch = kmalloc(IPCOMP_SCRATCH_SIZE, GFP_KERNEL);
+	if (!ipcd->scratch)
+		goto error;
+
+	ipcd->tfm = crypto_alloc_tfm(x->calg->alg_name, 0);
+	if (!ipcd->tfm)
+		goto error;
+
+	calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
+	BUG_ON(!calg_desc);
+	ipcd->threshold = calg_desc->uinfo.comp.threshold;
+	err = 0;
+out:
+	return err;
+error:
+	if (ipcd) {
+		ipcomp6_free_data(ipcd);
+		kfree(ipcd);
+	}
+
+	goto out;
+}
+
+static struct xfrm_type ipcomp6_type = 
+{
+	.description	= "IPCOMP6",
+	.owner		= THIS_MODULE,
+	.proto		= IPPROTO_COMP,
+	.init_state	= ipcomp6_init_state,
+	.destructor	= ipcomp6_destroy,
+	.input		= ipcomp6_input,
+	.output		= ipcomp6_output,
+};
+
+static struct inet6_protocol ipcomp6_protocol = 
+{
+	.handler	= xfrm6_rcv,
+	.err_handler	= ipcomp6_err,
+	.flags		= INET6_PROTO_NOPOLICY,
+};
+
+static int __init ipcomp6_init(void)
+{
+	if (xfrm_register_type(&ipcomp6_type, AF_INET6) < 0) {
+		printk(KERN_INFO "ipcomp6 init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
+	if (inet6_add_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
+		printk(KERN_INFO "ipcomp6 init: can't add protocol\n");
+		xfrm_unregister_type(&ipcomp6_type, AF_INET6);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit ipcomp6_fini(void)
+{
+	if (inet6_del_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) 
+		printk(KERN_INFO "ipv6 ipcomp close: can't remove protocol\n");
+	if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0)
+		printk(KERN_INFO "ipv6 ipcomp close: can't remove xfrm type\n");
+}
+
+module_init(ipcomp6_init);
+module_exit(ipcomp6_fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173");
+MODULE_AUTHOR("Mitsuru KANDA <[email protected]>");
+
+

Index: net/ipv6/ipv6_syms.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipv6_syms.c,v retrieving revision 1.1.1.9
retrieving revision 1.1.1.9.4.1
diff -u -r1.1.1.9 -r1.1.1.9.4.1

ipv6/ipv6_syms.c +1 -0
@@ -35,5 +35,6 @@
 EXPORT_SYMBOL(in6addr_any);
 EXPORT_SYMBOL(in6addr_loopback);
 EXPORT_SYMBOL(in6_dev_finish_destroy);
+EXPORT_SYMBOL(ip6_found_nexthdr);
 EXPORT_SYMBOL(xfrm6_rcv);
 EXPORT_SYMBOL(xfrm6_clear_mutable_options);

Index: net/xfrm/xfrm_input.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/xfrm/xfrm_input.c,v retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.14.1
diff -u -r1.1.1.2 -r1.1.1.2.14.1

xfrm/xfrm_input.c +1 -1
@@ -34,7 +34,7 @@
 		offset_seq = offsetof(struct ip_esp_hdr, seq_no);
 		break;
 	case IPPROTO_COMP:
-		if (!pskb_may_pull(skb, 4))
+		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
 			return -EINVAL;
 		*spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
 		*seq = 0;
Signature · 3 lines
Pekka Savola                 "You each name yourselves king, yet the
Netcore Oy                    kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings
#11 lore raw

In article <[email protected]> (at Sat, 17 May 2003 00:35:43 +0300 (EEST)), Pekka Savola <[email protected]> says:

Quoted 3 lines
Quoted 1 line

+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3713

What?!? Such RFC does not exist :-)

Oops... :-p

Index: net/ipv6/ipcomp6.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/Attic/ipcomp6.c,v retrieving revision 1.1.2.3
retrieving revision 1.1.2.4

ipv6/ipcomp6.c +1 -1
diff -u -r1.1.2.3 -r1.1.2.4
@@ -1,5 +1,5 @@
 /*
- * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3713
+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173
  *
  * Copyright (C)2003 USAGI/WIDE Project
  *
Signature · 2 lines
Hideaki YOSHIFUJI @ USAGI Project <[email protected]>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA
#12 lore raw

From: YOSHIFUJI Hideaki / 吉藤英明 <[email protected]>
Date: Sat, 17 May 2003 07:27:45 +0900 (JST)

In article <[email protected]> (at Sat, 17 May 2003 00:35:43 +0300 (EEST)), Pekka Savola <[email protected]> says:

Quoted 3 lines
Quoted 1 line

+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3713

What?!? Such RFC does not exist :-)

Oops... :-p

Fix applied, thanks :-)

#13 lore raw
Quoted 4 lines · David S. Miller

Date: Sat, 17 May 2003 07:27:45 +0900 (JST)

In article <[email protected]> (at Sat, 17 May 2003 00:35:43 +0300 (EEST)), Pekka Savola <[email protected]> says:

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3713

What?!? Such RFC does not exist :-)

   Oops... :-p

Fix applied, thanks :-)

IPv4 was using an RFC from the future as well.

- James

Signature · 19 lines
James Morris
<[email protected]>

--- bk.pending/net/ipv4/ipcomp.c	Thu May 15 15:55:41 2003
+++ bk.w1/net/ipv4/ipcomp.c	Sat May 17 10:53:09 2003
@@ -1,5 +1,5 @@
 /*
- * IP Payload Compression Protocol (IPComp) - RFC3713.
+ * IP Payload Compression Protocol (IPComp) - RFC3173.
  *
  * Copyright (c) 2003 James Morris <[email protected]>
  *
@@ -433,6 +433,6 @@
 module_exit(ipcomp4_fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3713");
+MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173");
 MODULE_AUTHOR("James Morris <[email protected]>");