From mboxrd@z Thu Jan 1 00:00:00 1970 From: Mitsuru KANDA / =?ISO-2022-JP?B?GyRCP0BFRBsoQiAbJEI9PBsoQg==?= Subject: [PATCH] fix esp6 extension headers handling Date: Sat, 07 Jun 2003 03:17:10 +0900 Sender: netdev-bounce@oss.sgi.com Message-ID: <87wufzxe8p.wl@karaba.org> References: <3EDF36AA.9020403@tml.hut.fi> <20030605.051709.104035049.davem@redhat.com> <3EDF3EB4.8010105@tml.hut.fi> <873cioqxch.wl@karaba.org> Mime-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") Content-Type: text/plain; charset=US-ASCII Cc: netdev@oss.sgi.com, usagi@linux-ipv6.org Return-path: To: "David S. Miller" In-Reply-To: <873cioqxch.wl@karaba.org> <3EDF36AA.9020403@tml.hut.fi> <3EDF3EB4.8010105@tml.hut.fi> Errors-to: netdev-bounce@oss.sgi.com List-Id: netdev.vger.kernel.org Hello, At Thu, 05 Jun 2003 15:59:32 +0300, Henrik Petander wrote: > > David S. Miller wrote: > > From: Henrik Petander > > Date: Thu, 05 Jun 2003 15:25:14 +0300 > > > > A possible fix is to change the pointer into an offset from the start of > > the packet and use the offset later to set the nexthdr value in the > > extension header. > > > > Please indicate the version of the sources you are looking > > at when making reports. > > Sure, esp6.c bitkeeper version was 1.16. Also a fix to the bug report: > the problem is with esp6 and not with ah6, which does not use the > get_offset function. > > Henrik > The attached diff fixes esp6 extension headers handling bug which reported by Henrik. I introduced ip6_find_1stfragopt() instead of get_offset(). # ip6_found_nexthdr() is just renamed ip6_find_1stfragopt() # in order to represent collect functionality. Regards, -mk Index: linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/include/net/ipv6.h =================================================================== RCS file: /cvsroot/usagi/usagi-backport/linux25/include/net/ipv6.h,v retrieving revision 1.1.1.12 retrieving revision 1.1.1.12.8.1 diff -u -r1.1.1.12 -r1.1.1.12.8.1 --- linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/include/net/ipv6.h 31 May 2003 07:30:34 -0000 1.1.1.12 +++ linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/include/net/ipv6.h 6 Jun 2003 15:43:46 -0000 1.1.1.12.8.1 @@ -315,7 +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_find_1stfragopt(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: linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/esp6.c =================================================================== RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/esp6.c,v retrieving revision 1.1.1.13 retrieving revision 1.1.1.13.12.1 diff -u -r1.1.1.13 -r1.1.1.13.12.1 --- linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/esp6.c 26 May 2003 08:04:11 -0000 1.1.1.13 +++ linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/esp6.c 6 Jun 2003 16:23:01 -0000 1.1.1.13.12.1 @@ -39,57 +39,6 @@ #define MAX_SG_ONSTACK 4 -/* BUGS: - * - we assume replay seqno is always present. - */ - -/* Move to common area: it is shared with AH. */ -/* Common with AH after some work on arguments. */ - -static int get_offset(u8 *packet, u32 packet_len, u8 *nexthdr, struct ipv6_opt_hdr **prevhdr) -{ - u16 offset = sizeof(struct ipv6hdr); - struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(packet + offset); - u8 nextnexthdr; - - *nexthdr = ((struct ipv6hdr*)packet)->nexthdr; - - while (offset + 1 < packet_len) { - - switch (*nexthdr) { - - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - offset += ipv6_optlen(exthdr); - *nexthdr = exthdr->nexthdr; - *prevhdr = exthdr; - exthdr = (struct ipv6_opt_hdr*)(packet + offset); - break; - - case NEXTHDR_DEST: - nextnexthdr = - ((struct ipv6_opt_hdr*)(packet + offset + ipv6_optlen(exthdr)))->nexthdr; - /* XXX We know the option is inner dest opt - with next next header check. */ - if (nextnexthdr != NEXTHDR_HOP && - nextnexthdr != NEXTHDR_ROUTING && - nextnexthdr != NEXTHDR_DEST) { - return offset; - } - offset += ipv6_optlen(exthdr); - *nexthdr = exthdr->nexthdr; - *prevhdr = exthdr; - exthdr = (struct ipv6_opt_hdr*)(packet + offset); - break; - - default : - return offset; - } - } - - return offset; -} - int esp6_output(struct sk_buff *skb) { int err; @@ -101,12 +50,12 @@ struct crypto_tfm *tfm; struct esp_data *esp; struct sk_buff *trailer; - struct ipv6_opt_hdr *prevhdr = NULL; int blksize; int clen; int alen; int nfrags; - u8 nexthdr; + u8 *prevhdr; + u8 nexthdr = 0; /* First, if the skb is not checksummed, complete checksum. */ if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { @@ -123,7 +72,9 @@ /* Strip IP header in transport mode. Save it. */ if (!x->props.mode) { - hdr_len = get_offset(skb->nh.raw, skb->len, &nexthdr, &prevhdr); + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); + nexthdr = *prevhdr; + *prevhdr = IPPROTO_ESP; iph = kmalloc(hdr_len, GFP_ATOMIC); if (!iph) { err = -ENOMEM; @@ -178,18 +129,12 @@ ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); } else { - /* XXX exthdr */ esph = (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len); skb->h.raw = (unsigned char*)esph; top_iph = (struct ipv6hdr*)skb_push(skb, hdr_len); memcpy(top_iph, iph, hdr_len); kfree(iph); top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr)); - if (prevhdr) { - prevhdr->nexthdr = IPPROTO_ESP; - } else { - top_iph->nexthdr = IPPROTO_ESP; - } *(u8*)(trailer->tail - 1) = nexthdr; } @@ -302,6 +247,7 @@ struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; struct scatterlist *sg = sgbuf; u8 padlen; + u8 *prevhdr; if (unlikely(nfrags > MAX_SG_ONSTACK)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); @@ -325,11 +271,13 @@ } /* ... check padding bits here. Silly. :-) */ - ret_nexthdr = ((struct ipv6hdr*)tmp_hdr)->nexthdr = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen); skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, tmp_hdr, hdr_len); + skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + ip6_find_1stfragopt(skb, &prevhdr); + ret_nexthdr = *prevhdr = nexthdr[1]; } kfree(tmp_hdr); return ret_nexthdr; Index: linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ip6_output.c =================================================================== RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ip6_output.c,v retrieving revision 1.1.1.16 retrieving revision 1.1.1.16.16.1 diff -u -r1.1.1.16 -r1.1.1.16.16.1 --- linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ip6_output.c 26 May 2003 08:04:10 -0000 1.1.1.16 +++ linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ip6_output.c 6 Jun 2003 15:43:34 -0000 1.1.1.16.16.1 @@ -887,7 +887,7 @@ #endif } -int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr) +int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); @@ -929,7 +929,7 @@ u8 *prevhdr, nexthdr = 0; dev = rt->u.dst.dev; - hlen = ip6_found_nexthdr(skb, &prevhdr); + hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); Index: linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/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.14.1 diff -u -r1.1.1.2 -r1.1.1.2.14.1 --- linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ipcomp6.c 21 May 2003 13:15:20 -0000 1.1.1.2 +++ linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ipcomp6.c 6 Jun 2003 15:43:34 -0000 1.1.1.2.14.1 @@ -105,7 +105,7 @@ iph = skb->nh.ipv6h; iph->payload_len = htons(skb->len); - ip6_found_nexthdr(skb, &prevhdr); + ip6_find_1stfragopt(skb, &prevhdr); *prevhdr = nexthdr; out: if (tmp_hdr) @@ -160,7 +160,7 @@ skb->nh.raw = skb->data; /* == top_iph */ skb->h.raw = skb->nh.raw + hdr_len; } else { - hdr_len = ip6_found_nexthdr(skb, &prevhdr); + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; } @@ -203,7 +203,7 @@ top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); skb->nh.raw = skb->data; /* top_iph */ - ip6_found_nexthdr(skb, &prevhdr); + ip6_find_1stfragopt(skb, &prevhdr); *prevhdr = IPPROTO_COMP; ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len); Index: linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ipv6_syms.c =================================================================== RCS file: /cvsroot/usagi/usagi-backport/linux25/net/ipv6/ipv6_syms.c,v retrieving revision 1.1.1.12 retrieving revision 1.1.1.12.16.4 diff -u -r1.1.1.12 -r1.1.1.12.16.4 --- linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ipv6_syms.c 26 May 2003 08:04:11 -0000 1.1.1.12 +++ linux25-b2_5_70+CS1_1314_IPSEC6_CLEANUP/net/ipv6/ipv6_syms.c 6 Jun 2003 17:38:20 -0000 1.1.1.12.16.4 @@ -35,6 +35,6 @@ EXPORT_SYMBOL(in6addr_any); EXPORT_SYMBOL(in6addr_loopback); EXPORT_SYMBOL(in6_dev_finish_destroy); -EXPORT_SYMBOL(ip6_found_nexthdr); +EXPORT_SYMBOL(ip6_find_1stfragopt); EXPORT_SYMBOL(xfrm6_rcv); EXPORT_SYMBOL(xfrm6_clear_mutable_options);