All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kunihiro Ishiguro <kunihiro@ipinfusion.com>
To: "Mitsuru KANDA / 神田 充" <mk@karaba.org>
Cc: "David S. Miller" <davem@redhat.com>,
	kuznet@ms2.inr.ac.ru, netdev@oss.sgi.com,
	usagi-core@linux-ipv6.org
Subject: Re: [PATCH] IPv6 IPsec support
Date: Wed, 19 Feb 2003 15:10:53 -0800	[thread overview]
Message-ID: <87bs17hnnm.wl@ipinfusion.com> (raw)
In-Reply-To: <m3el645hv3.wl@karaba.org>

This will not be useful other than Miyazaki/Kanda.  I've applied
miyazaki's patch then try to diff against local code.

o xfrm6_selector_match() fix

o No need of option field mutation in xfrm6_rcv().  It is moved to
  ah.c.

o Setting Routing Header's segment_lefts to 0 is wrong.  Let's let it be.

o xfrm6_rcv() try to figure out he is processing AH or ESP by
  ipv6hdr->protocol...  But when other extenstion header exits this
  could be wrong.  Initial protocol value is passed from the caller.

o Some cosmetic change.

And this patch include

o Not removing AH header

o Mutation field provisioning

But there changes are no needed.  Miyazaki, would you mind to take a
look into this?  Have fun ;-).
--
Kunihiro Ishiguro

diff -ruN linux-2.5.62.orig/include/net/ipv6.h linux-2.5.62/include/net/ipv6.h
--- linux-2.5.62.orig/include/net/ipv6.h	2003-02-14 15:52:28.000000000 -0800
+++ linux-2.5.62/include/net/ipv6.h	2003-02-19 13:19:38.000000000 -0800
@@ -41,7 +41,7 @@
 
 #define NEXTHDR_MAX		255
 
-
+#define IP6OPT_MUTABLE  0x20
 
 #define IPV6_DEFAULT_HOPLIMIT   64
 #define IPV6_DEFAULT_MCASTHOPS	1
diff -ruN linux-2.5.62.orig/include/net/xfrm.h linux-2.5.62/include/net/xfrm.h
--- linux-2.5.62.orig/include/net/xfrm.h	2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/include/net/xfrm.h	2003-02-19 14:03:20.000000000 -0800
@@ -414,7 +414,7 @@
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
 extern int xfrm4_rcv(struct sk_buff *skb);
-extern int xfrm6_rcv(struct sk_buff *skb);
+extern int xfrm6_rcv(struct sk_buff *skb, u8 proto);
 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);
 
@@ -452,11 +452,37 @@
 extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name);
 extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name);
 
+static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
+{
+	__u32 *a1 = token1;
+	__u32 *a2 = token2;
+	int pdw;
+	int pbi;
+
+	pdw = prefixlen >> 5;	  /* num of whole __u32 in prefix */
+	pbi = prefixlen &  0x1f;  /* num of bits in incomplete u32 in prefix */
+
+	if (pdw)
+		if (memcmp(a1, a2, pdw << 2))
+			return 0;
+
+	if (pbi) {
+		__u32 mask;
+
+		mask = htonl((0xffffffff) << (32 - pbi));
+
+		if ((a1[pdw] ^ a2[pdw]) & mask)
+			return 0;
+	}
+
+	return 1;
+}
+
 static inline int
 xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
 {
-	return  !memcmp(fl->fl6_dst, &sel->daddr, (sel->prefixlen_d)/8) &&
-		!memcmp(fl->fl6_src, &sel->saddr, (sel->prefixlen_s)/8) &&
+	return  !addr_match(fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
+		!addr_match(fl->fl6_src, &sel->saddr, sel->prefixlen_s) &&
 		!((fl->uli_u.ports.dport^sel->dport)&sel->dport_mask) &&
 		!((fl->uli_u.ports.sport^sel->sport)&sel->sport_mask) &&
 		(fl->proto == sel->proto || !sel->proto) &&
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' linux-2.5.62.orig/net/ipv6/ah.c linux-2.5.62/net/ipv6/ah.c
--- linux-2.5.62.orig/net/ipv6/ah.c	2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/ah.c	2003-02-19 14:31:12.000000000 -0800
@@ -32,7 +32,6 @@
 
 #define AH_HLEN_NOICV   12
 
-/* XXX no ipv6 ah specific */
 #define NIP6(addr) \
 	ntohs((addr).s6_addr16[0]),\
 	ntohs((addr).s6_addr16[1]),\
@@ -43,6 +42,214 @@
 	ntohs((addr).s6_addr16[6]),\
 	ntohs((addr).s6_addr16[7])
 
+static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
+{
+	u8 *opt = (u8 *)opthdr;
+	int len = ipv6_optlen(opthdr);
+	int off = 0;
+	int optlen = 0;
+
+	off += 2;
+	len -= 2;
+
+	while (len > 0) {
+
+		switch (opt[off]) {
+
+		case IPV6_TLV_PAD0:
+			optlen = 1;
+			break;
+		default:
+			if (len < 2) 
+				goto bad;
+			optlen = opt[off+1]+2;
+			if (len < optlen)
+				goto bad;
+			if (opt[off] & 0x20)
+				memset(&opt[off+2], 0, opt[off+1]);
+			break;
+		}
+
+		off += optlen;
+		len -= optlen;
+	}
+	if (len == 0)
+		return 1;
+
+bad:
+	return 0;
+}
+
+int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
+{
+	u16 offset = sizeof(struct ipv6hdr);
+	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+	unsigned int packet_len = skb->tail - skb->nh.raw;
+	u8 nexthdr = skb->nh.ipv6h->nexthdr;
+	u8 nextnexthdr = 0;
+
+	*nh_offset = ((unsigned char *)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
+
+	while (offset + 1 <= packet_len) {
+
+		switch (nexthdr) {
+
+		case NEXTHDR_HOP:
+			*nh_offset = offset;
+			offset += ipv6_optlen(exthdr);
+			if (!zero_out_mutable_opts(exthdr)) {
+				if (net_ratelimit())
+					printk(KERN_WARNING "overrun hopopts\n"); 
+				return 0;
+			}
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+			break;
+
+		case NEXTHDR_ROUTING:
+			*nh_offset = offset;
+			offset += ipv6_optlen(exthdr);
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+			break;
+
+		case NEXTHDR_DEST:
+			*nh_offset = offset;
+			offset += ipv6_optlen(exthdr);
+			if (!zero_out_mutable_opts(exthdr))  {
+				if (net_ratelimit())
+					printk(KERN_WARNING "overrun destopt\n"); 
+				return 0;
+			}
+			nexthdr = exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+			break;
+
+		case NEXTHDR_AUTH:
+			if (dir == XFRM_POLICY_OUT) {
+				memset(((struct ipv6_auth_hdr*)exthdr)->auth_data, 0, 
+				       (((struct ipv6_auth_hdr*)exthdr)->hdrlen - 1) << 2);
+			}
+			if (exthdr->nexthdr == NEXTHDR_DEST) {
+				offset += (((struct ipv6_auth_hdr*)exthdr)->hdrlen + 2) << 2;
+				exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+				nextnexthdr = exthdr->nexthdr;
+				if (!zero_out_mutable_opts(exthdr)) {
+					if (net_ratelimit())
+						printk(KERN_WARNING "overrun destopt\n");
+					return 0;
+				}
+			}
+			return nexthdr;
+		default:
+			return nexthdr;
+		}
+	}
+
+	return nexthdr;
+}
+
+static int ipv6_check_mutable_options(struct sk_buff *skb, struct ipv6hdr *hdr,
+				      struct inet6_skb_parm *opt)
+{
+	int lim;
+	u8 *optpnt;
+	u8 nexthdr = hdr->nexthdr;
+	int datalen = 0;
+
+	optpnt = (u8*)(hdr+1);
+	lim = ntohs(hdr->payload_len);
+
+	while (lim > 0) {
+		struct ipv6_opt_hdr *opthdr;
+		int hdrlen;
+
+		opthdr = (struct ipv6_opt_hdr*)optpnt;
+
+		switch(nexthdr) {
+		case NEXTHDR_HOP:
+			opt->hop = optpnt - skb->nh.raw;
+			hdrlen = ipv6_optlen(opthdr);
+			datalen += (hdrlen - 2);
+			break;
+		case NEXTHDR_DEST:
+			opt->dst1 = optpnt - skb->nh.raw;
+			hdrlen = ipv6_optlen(opthdr);
+			datalen += (hdrlen - 2);
+			break;
+		case NEXTHDR_ROUTING:
+		case NEXTHDR_FRAGMENT:
+		case NEXTHDR_NONE:
+			hdrlen = ipv6_optlen(opthdr);
+			break;
+		case NEXTHDR_AUTH:
+			hdrlen = (opthdr->hdrlen + 2) << 2;
+			break;
+		default:
+			goto out;
+		}
+		nexthdr = opthdr->nexthdr;
+		optpnt += hdrlen;
+		lim -= hdrlen;
+	}
+out:
+	return datalen;
+}
+
+static int ah6_set_option(u8 *opthdr, u8 **opt_data, int erase)
+{
+	u8 *optpnt = opthdr;
+	int len = ipv6_optlen((struct ipv6_opt_hdr*)opthdr);
+	int datalen;
+	int optlen;
+
+	optpnt += 2;
+	len -= 2;
+	datalen = len;
+
+	if (erase) {
+		memcpy(*opt_data, optpnt, datalen);
+
+		while (len > 0) {
+			if (optpnt[0] == IPV6_TLV_PAD0) {
+				optlen = 1;
+			} else {
+				if (len < 2)
+					return -1;
+				optlen = optpnt[1] + 2;
+				if (optlen > len)
+					return -1;
+				if (optpnt[0] & IP6OPT_MUTABLE)
+					memset(optpnt+2, 0, optpnt[1]);
+			}
+			optpnt += optlen;
+			len -= optlen;
+		}
+	} else {
+		memcpy(optpnt, *opt_data, datalen);
+	}
+
+	*opt_data += datalen;
+
+	return 0;
+}
+
+static inline void ah6_clear_mutable_options(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 *opt_data)
+{
+	if (opt->hop)
+		ah6_set_option(skb->nh.raw+opt->hop, &opt_data, 1);
+	if (opt->dst1)
+		ah6_set_option(skb->nh.raw+opt->dst1, &opt_data, 1);
+}
+
+static inline void ah6_restore_mutable_options(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 *opt_data)
+{
+	if (opt->hop)
+		ah6_set_option(skb->nh.raw+opt->hop, &opt_data, 0);
+	if (opt->dst1)
+		ah6_set_option(skb->nh.raw+opt->dst1, &opt_data, 0);
+}
+
 int ah6_output(struct sk_buff *skb)
 {
 	int err;
@@ -50,6 +257,7 @@
 	struct dst_entry *dst = skb->dst;
 	struct xfrm_state *x  = dst->xfrm;
 	struct ipv6hdr *iph = NULL;
+	struct ipv6hdr *top_hdr;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
 	u16 nh_offset = 0;
@@ -66,13 +274,13 @@
 
 	if (x->props.mode) {
 		iph = skb->nh.ipv6h;
-		skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
-		skb->nh.ipv6h->version = 6;
-		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
-		skb->nh.ipv6h->nexthdr = IPPROTO_AH;
-		memcpy(&skb->nh.ipv6h->saddr, &x->props.saddr, sizeof(struct in6_addr));
-		memcpy(&skb->nh.ipv6h->daddr, &x->id.daddr, sizeof(struct in6_addr));
-		ah = (struct ip_auth_hdr*)(skb->nh.ipv6h+1);
+		top_hdr = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
+		top_hdr->version = 6;
+		top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+		top_hdr->nexthdr = IPPROTO_AH;
+		memcpy(&top_hdr->saddr, &x->props.saddr, sizeof(struct in6_addr));
+		memcpy(&top_hdr->daddr, &x->id.daddr, sizeof(struct in6_addr));
+		ah = (struct ip_auth_hdr*)(top_hdr+1);
 		ah->nexthdr = IPPROTO_IPV6;
 	} else {
 		hdr_len = skb->h.raw - skb->nh.raw;
@@ -82,42 +290,40 @@
 			goto error;
 		}
 		memcpy(iph, skb->data, hdr_len);
-		skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
-		memcpy(skb->nh.ipv6h, iph, hdr_len);
+		top_hdr = (struct ipv6hdr*)skb_push(skb, x->props.header_len);
+		memcpy(top_hdr, iph, hdr_len);
 		nexthdr = xfrm6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_OUT);
 		if (nexthdr == 0)
 			goto error;
 
 		skb->nh.raw[nh_offset] = IPPROTO_AH;
-		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+		top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 		ah = (struct ip_auth_hdr*)(skb->nh.raw+hdr_len);
 		ah->nexthdr = nexthdr;
 	}
 
-	skb->nh.ipv6h->priority    = 0;
-	skb->nh.ipv6h->flow_lbl[0] = 0;
-	skb->nh.ipv6h->flow_lbl[1] = 0;
-	skb->nh.ipv6h->flow_lbl[2] = 0;
-	skb->nh.ipv6h->hop_limit    = 0;
+	skb->nh.ipv6h = top_hdr;
+	top_hdr->priority    = 0;
+	memset(top_hdr->flow_lbl, 0, 3);
+	top_hdr->hop_limit    = 0;
 
 	ahp = x->data;
 	ah->hdrlen  = (XFRM_ALIGN8(ahp->icv_trunc_len +
-		AH_HLEN_NOICV) >> 2) - 2;
+			AH_HLEN_NOICV) >> 2) - 2;
+
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
 	ahp->icv(ahp, skb, ah->auth_data);
 
 	if (x->props.mode) {
-		skb->nh.ipv6h->hop_limit   = iph->hop_limit;
-		skb->nh.ipv6h->priority    = iph->priority; 	
-		skb->nh.ipv6h->flow_lbl[0] = iph->flow_lbl[0];
-		skb->nh.ipv6h->flow_lbl[1] = iph->flow_lbl[1];
-		skb->nh.ipv6h->flow_lbl[2] = iph->flow_lbl[2];
+		top_hdr->priority = iph->priority; 	
+		memcpy(top_hdr->flow_lbl, iph->flow_lbl, 3);
+		top_hdr->hop_limit = iph->hop_limit;
 	} else {
-		memcpy(skb->nh.ipv6h, iph, hdr_len);
+		memcpy(top_hdr, iph, hdr_len);
 		skb->nh.raw[nh_offset] = IPPROTO_AH;
-		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+		top_hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 		kfree (iph);
 	}
 
@@ -139,42 +345,48 @@
 int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int ah_hlen;
-	struct ipv6hdr *iph;
+	struct ipv6hdr *hdr;
 	struct ipv6_auth_hdr *ah;
 	struct ah_data *ahp;
-	unsigned char *tmp_hdr = NULL;
-	int hdr_len = skb->h.raw - skb->nh.raw;
-	u8 nexthdr = 0;
+	struct inet6_skb_parm opt;
+	char work_buf[8];
+	int optlen;
+	u8 *opt_data = NULL;
 
 	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
 		goto out;
 
 	ah = (struct ipv6_auth_hdr*)skb->data;
-
 	ahp = x->data;
-        ah_hlen = (ah->hdrlen + 2) << 2;
+	ah_hlen = (ah->hdrlen + 2) << 2;
 
-        if (ah_hlen != XFRM_ALIGN8(ahp->icv_full_len + AH_HLEN_NOICV) &&
-            ah_hlen != XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV))
-                goto out;
+	if (ah_hlen != XFRM_ALIGN8(ahp->icv_full_len + AH_HLEN_NOICV) &&
+	    ah_hlen != XFRM_ALIGN8(ahp->icv_trunc_len + AH_HLEN_NOICV))
+		goto out;
 
 	if (!pskb_may_pull(skb, (ah->hdrlen+2)<<2))
 		goto out;
 
-	/* We are going to _remove_ AH header to keep sockets happy,
-	 * so... Later this can change. */
-	if (skb_cloned(skb) &&
-	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
-		goto out;
-	tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
-	if (!tmp_hdr)
-		goto out;
-	memcpy(tmp_hdr, skb->nh.raw, hdr_len);
-	ah = (struct ipv6_auth_hdr*)skb->data;
-	iph = skb->nh.ipv6h;
+	hdr = skb->nh.ipv6h;
 
+	memcpy(work_buf, hdr, 8);
+	hdr->priority = 0;
+	memset(hdr->flow_lbl, 0, 3);
+	hdr->hop_limit = 0;
+
+	memset(&opt, 0, sizeof(struct inet6_skb_parm));
+	optlen = ipv6_check_mutable_options(skb, hdr, &opt);
+	if (optlen < 0)
+		goto out;
         {
 		u8 auth_data[ahp->icv_trunc_len];
+		
+		if (optlen) {
+			opt_data = kmalloc(optlen, GFP_ATOMIC);
+			if (!opt_data)
+				goto out;
+			ah6_clear_mutable_options(skb, &opt, opt_data);
+		}
 		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
 		memset(ah->auth_data, 0, ahp->icv_trunc_len);
 		skb_push(skb, skb->data - skb->nh.raw);
@@ -185,22 +397,19 @@
 			x->stats.integrity_failed++;
 			goto free_out;
 		}
+		if (optlen) {
+			ah6_restore_mutable_options(skb, &opt, opt_data);
+			kfree (opt_data);
+		}
 	}
+	memcpy(hdr, work_buf, 8);
+	skb->h.raw += (ah->hdrlen+2)<<2;
+	skb->data = skb->h.raw;
 
-	nexthdr = ah->nexthdr;
-	skb->nh.raw = skb_pull(skb, (ah->hdrlen+2)<<2);
-	memcpy(skb->nh.raw, tmp_hdr, hdr_len);
-	skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
-	skb_pull(skb, hdr_len);
-	skb->h.raw = skb->data;
-
-
-	kfree(tmp_hdr);
-
-	return nexthdr;
-
+	return ah->nexthdr;
 free_out:
-	kfree(tmp_hdr);
+	if (optlen)
+		kfree(opt_data);
 out:
 	return -EINVAL;
 }
@@ -208,22 +417,19 @@
 void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 
 	 int type, int code, int offset, __u32 info)
 {
-	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
 	struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
 	struct xfrm_state *x;
 
-	if (type != ICMPV6_DEST_UNREACH ||
-	    type != ICMPV6_PKT_TOOBIG)
+	if (type != ICMPV6_DEST_UNREACH || type != ICMPV6_PKT_TOOBIG)
 		return;
 
-	x = xfrm6_state_lookup(&iph->daddr, ah->spi, IPPROTO_AH);
+	x = xfrm6_state_lookup(&hdr->daddr, ah->spi, IPPROTO_AH);
 	if (!x)
 		return;
-
 	printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/"
 			"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-	       ntohl(ah->spi), NIP6(iph->daddr));
-
+	       ntohl(ah->spi), NIP6(hdr->daddr));
 	xfrm_state_put(x);
 }
 
@@ -315,26 +521,29 @@
 	.output		= ah6_output
 };
 
+static inline int
+xfrm6_ah_rcv(struct sk_buff *skb)
+{
+	return xfrm6_rcv(skb, IPPROTO_AH);
+}
+
 static struct inet6_protocol ah6_protocol = {
-	.handler	=	xfrm6_rcv,
+	.handler	=	xfrm6_ah_rcv,
 	.err_handler	=	ah6_err,
 };
 
 int __init ah6_init(void)
 {
 	SET_MODULE_OWNER(&ah6_type);
-
 	if (xfrm6_register_type(&ah6_type) < 0) {
 		printk(KERN_INFO "ipv6 ah init: can't add xfrm type\n");
 		return -EAGAIN;
 	}
-
 	if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) {
 		printk(KERN_INFO "ipv6 ah init: can't add protocol\n");
 		xfrm6_unregister_type(&ah6_type);
 		return -EAGAIN;
 	}
-
 	return 0;
 }
 
@@ -342,10 +551,8 @@
 {
 	if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0)
 		printk(KERN_INFO "ipv6 ah close: can't remove protocol\n");
-
 	if (xfrm6_unregister_type(&ah6_type) < 0)
 		printk(KERN_INFO "ipv6 ah close: can't remove xfrm type\n");
-
 }
 
 module_init(ah6_init);
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' linux-2.5.62.orig/net/ipv6/esp.c linux-2.5.62/net/ipv6/esp.c
--- linux-2.5.62.orig/net/ipv6/esp.c	2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/esp.c	2003-02-19 14:20:43.000000000 -0800
@@ -35,10 +35,6 @@
 #include <linux/icmpv6.h>
 
 #define MAX_SG_ONSTACK 4
-#if 0
-typedef void (icv_update_fn_t)(struct crypto_tfm *,
-			struct scatterlist *, unsigned int);
-#endif
 
 /* XXX no ipv6 esp specific */
 #define NIP6(addr) \
@@ -545,8 +541,14 @@
 	.output		= esp6_output
 };
 
+static inline int
+xfrm6_esp_rcv(struct sk_buff *skb)
+{
+	return xfrm6_rcv(skb, IPPROTO_ESP);
+}
+
 static struct inet6_protocol esp6_protocol = {
-	.handler 	=	xfrm6_rcv,
+	.handler 	=	xfrm6_esp_rcv,
 	.err_handler	=	esp6_err,
 };
 
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' linux-2.5.62.orig/net/ipv6/xfrm_input.c linux-2.5.62/net/ipv6/xfrm_input.c
--- linux-2.5.62.orig/net/ipv6/xfrm_input.c	2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/xfrm_input.c	2003-02-19 14:06:49.000000000 -0800
@@ -30,11 +30,11 @@
 
 /* Fetch spi and seq frpm ipsec header */
 
-static int xfrm6_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+static int xfrm6_parse_spi(struct sk_buff *skb, u8 proto, u32 *spi, u32 *seq)
 {
 	int offset, offset_seq;
 
-	switch (nexthdr) {
+	switch (proto) {
 	case IPPROTO_AH:
 		offset = offsetof(struct ip_auth_hdr, spi);
 		offset_seq = offsetof(struct ip_auth_hdr, seq_no);
@@ -61,115 +61,7 @@
 	return 0;
 }
 
-static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
-{
-	u8 *opt = (u8 *)opthdr;
-	int len = ipv6_optlen(opthdr);
-	int off = 0;
-	int optlen = 0;
-
-	off += 2;
-	len -= 2;
-
-	while (len > 0) {
-
-		switch (opt[off]) {
-
-		case IPV6_TLV_PAD0:
-			optlen = 1;
-			break;
-		default:
-			if (len < 2) 
-				goto bad;
-			optlen = opt[off+1]+2;
-			if (len < optlen)
-				goto bad;
-			if (opt[off] & 0x20)
-				memset(&opt[off+2], 0, opt[off+1]);
-			break;
-		}
-
-		off += optlen;
-		len -= optlen;
-	}
-	if (len == 0)
-		return 1;
-
-bad:
-	return 0;
-}
-
-int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir)
-{
-	u16 offset = sizeof(struct ipv6hdr);
-	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-	unsigned int packet_len = skb->tail - skb->nh.raw;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
-	u8 nextnexthdr = 0;
-
-	*nh_offset = ((unsigned char *)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
-
-	while (offset + 1 <= packet_len) {
-
-		switch (nexthdr) {
-
-		case NEXTHDR_HOP:
-			*nh_offset = offset;
-			offset += ipv6_optlen(exthdr);
-			if (!zero_out_mutable_opts(exthdr)) {
-				if (net_ratelimit())
-					printk(KERN_WARNING "overrun hopopts\n"); 
-				return 0;
-			}
-			nexthdr = exthdr->nexthdr;
-			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-			break;
-
-		case NEXTHDR_ROUTING:
-			*nh_offset = offset;
-			offset += ipv6_optlen(exthdr);
-			((struct ipv6_rt_hdr*)exthdr)->segments_left = 0; 
-			nexthdr = exthdr->nexthdr;
-			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-			break;
-
-		case NEXTHDR_DEST:
-			*nh_offset = offset;
-			offset += ipv6_optlen(exthdr);
-			if (!zero_out_mutable_opts(exthdr))  {
-				if (net_ratelimit())
-					printk(KERN_WARNING "overrun destopt\n"); 
-				return 0;
-			}
-			nexthdr = exthdr->nexthdr;
-			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-			break;
-
-		case NEXTHDR_AUTH:
-			if (dir == XFRM_POLICY_OUT) {
-				memset(((struct ipv6_auth_hdr*)exthdr)->auth_data, 0, 
-				       (((struct ipv6_auth_hdr*)exthdr)->hdrlen - 1) << 2);
-			}
-			if (exthdr->nexthdr == NEXTHDR_DEST) {
-				offset += (((struct ipv6_auth_hdr*)exthdr)->hdrlen + 2) << 2;
-				exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
-				nextnexthdr = exthdr->nexthdr;
-				if (!zero_out_mutable_opts(exthdr)) {
-					if (net_ratelimit())
-						printk(KERN_WARNING "overrun destopt\n");
-					return 0;
-				}
-			}
-			return nexthdr;
-		default:
-			return nexthdr;
-		}
-	}
-
-	return nexthdr;
-}
-
-int xfrm6_rcv(struct sk_buff *skb)
+int xfrm6_rcv(struct sk_buff *skb, u8 proto)
 {
 	int err;
 	u32 spi, seq;
@@ -177,32 +69,10 @@
 	struct xfrm_state *x;
 	int xfrm_nr = 0;
 	int decaps = 0;
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
-	unsigned char *tmp_hdr = NULL;
-	int hdr_len = 0;
 	u16 nh_offset = 0;
 	u8 nexthdr = 0;
 
-	if (hdr->nexthdr == IPPROTO_AH || hdr->nexthdr == IPPROTO_ESP) {
-		nh_offset = ((unsigned char*)&skb->nh.ipv6h->nexthdr) - skb->nh.raw;
-		hdr_len = sizeof(struct ipv6hdr);
-	} else {
-		hdr_len = skb->h.raw - skb->nh.raw;
-	}
-
-	tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
-	if (!tmp_hdr)
-		goto drop;
-	memcpy(tmp_hdr, skb->nh.raw, hdr_len);
-
-	nexthdr = xfrm6_clear_mutable_options(skb, &nh_offset, XFRM_POLICY_IN);
-	hdr->priority    = 0;
-	hdr->flow_lbl[0] = 0;
-	hdr->flow_lbl[1] = 0;
-	hdr->flow_lbl[2] = 0;
-	hdr->hop_limit   = 0;
-
-	if ((err = xfrm6_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
+	if ((err = xfrm6_parse_spi(skb, proto, &spi, &seq)) != 0)
 		goto drop;
 	
 	do {
@@ -211,9 +81,10 @@
 		if (xfrm_nr == XFRM_MAX_DEPTH)
 			goto drop;
 
-		x = xfrm6_state_lookup(&iph->daddr, spi, nexthdr);
+		x = xfrm6_state_lookup(&iph->daddr, spi, proto);
 		if (x == NULL)
 			goto drop;
+
 		spin_lock(&x->lock);
 		if (unlikely(x->km.state != XFRM_STATE_VALID))
 			goto drop_unlock;
@@ -221,8 +92,8 @@
 		if (x->props.replay_window && xfrm_replay_check(x, seq))
 			goto drop_unlock;
 
-		nexthdr = x->type->input(x, skb);
-		if (nexthdr <= 0)
+		proto = x->type->input(x, skb);
+		if (proto <= 0)
 			goto drop_unlock;
 
 		if (x->props.replay_window)
@@ -237,13 +108,13 @@
 
 		iph = skb->nh.ipv6h; /* ??? */ 
 
-		if (nexthdr == NEXTHDR_DEST) {
+		if (proto == NEXTHDR_DEST) {
 			if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
 		    	!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
 				err = -EINVAL;
 				goto drop;
 			}
-			nexthdr = skb->h.raw[0];
+			proto = skb->h.raw[0];
 			nh_offset = skb->h.raw - skb->nh.raw;
 			skb_pull(skb, (skb->h.raw[1]+1)<<3);
 			skb->h.raw = skb->data;
@@ -258,14 +129,10 @@
 			break;
 		}
 
-		if ((err = xfrm6_parse_spi(skb, nexthdr, &spi, &seq)) < 0)
+		if ((err = xfrm6_parse_spi(skb, proto, &spi, &seq)) < 0)
 			goto drop;
 	} while (!err);
 
-	memcpy(skb->nh.raw, tmp_hdr, hdr_len);
-	skb->nh.raw[nh_offset] = nexthdr;
-	skb->nh.ipv6h->payload_len = htons(hdr_len + skb->len - sizeof(struct ipv6hdr));
-
 	/* Allocate new secpath or COW existing one. */
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 		struct sec_path *sp;
@@ -295,14 +162,13 @@
 		netif_rx(skb);
 		return 0;
 	} else {
-		return -nexthdr;
+		return -proto;
 	}
 
 drop_unlock:
 	spin_unlock(&x->lock);
 	xfrm_state_put(x);
 drop:
-	if (tmp_hdr) kfree(tmp_hdr);
 	while (--xfrm_nr >= 0)
 		xfrm_state_put(xfrm_vec[xfrm_nr]);
 	kfree_skb(skb);
diff -ruN -x '*.o' -x '*.cmd' -x '*.ko' -x '*.mod.c' linux-2.5.62.orig/net/ipv6/xfrm_policy.c linux-2.5.62/net/ipv6/xfrm_policy.c
--- linux-2.5.62.orig/net/ipv6/xfrm_policy.c	2003-02-19 14:24:53.000000000 -0800
+++ linux-2.5.62/net/ipv6/xfrm_policy.c	2003-02-19 02:50:41.000000000 -0800
@@ -229,7 +229,7 @@
 	read_lock_bh(&xfrm_policy_lock);
 	for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
 		struct xfrm_selector *sel = &pol->selector;
-		if (pol->family != AF_INET6) continue);
+		if (pol->family != AF_INET6) continue;
 		if (xfrm6_selector_match(sel, fl)) {
 			atomic_inc(&pol->refcnt);
 			break;

  parent reply	other threads:[~2003-02-19 23:10 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-02-19  4:48 [PATCH] IPv6 IPsec support Kazunori MIyazawa
2003-02-19  4:50 ` David S. Miller
2003-02-19  5:10   ` Kunihiro Ishiguro
2003-02-19  5:17     ` Mitsuru KANDA / 神田 充
2003-02-19  5:58       ` Kazunori Miyazawa
2003-02-19  5:30   ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-19  5:57 ` Kunihiro Ishiguro
2003-02-19  7:02   ` David S. Miller
2003-02-19  9:13     ` Kunihiro Ishiguro
2003-02-19  7:13 ` David S. Miller
2003-02-19  7:33 ` David S. Miller
2003-02-19 14:39   ` (usagi-core 11926) " Kazunori MIyazawa
2003-02-19 21:27     ` David S. Miller
2003-02-19 16:56   ` Mitsuru KANDA / 神田 充
2003-02-19 21:43     ` David S. Miller
2003-02-19 23:10     ` Kunihiro Ishiguro [this message]
2003-02-20  0:37       ` David S. Miller
  -- strict thread matches above, loose matches on Subject: below --
2003-02-22 11:26 [PATCH] IPv6 IPSEC support Kazunori Miyazawa
2003-02-22 11:13 ` David S. Miller
2003-02-22 12:15   ` Kazunori Miyazawa
2003-02-22 12:49   ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-22 23:47     ` David S. Miller
2003-02-23  0:44       ` YOSHIFUJI Hideaki / 吉藤英明
2003-02-23 15:35   ` Kazunori Miyazawa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87bs17hnnm.wl@ipinfusion.com \
    --to=kunihiro@ipinfusion.com \
    --cc=davem@redhat.com \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=mk@karaba.org \
    --cc=netdev@oss.sgi.com \
    --cc=usagi-core@linux-ipv6.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.