diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5e80e517f071013410349d1fd93afc00a394e284..aefcf08520954d510c4756ef63653c55c1f484a3 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -409,26 +409,27 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) break; hdr = (struct ipv6_opt_hdr *)(skb->data + off); - if (nexthdr == NEXTHDR_FRAGMENT) { - struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr; - if (frag_hdr->frag_off) - break; + if (nexthdr == NEXTHDR_FRAGMENT) optlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) { + else if (nexthdr == NEXTHDR_AUTH) optlen = ipv6_authlen(hdr); - } else { + else optlen = ipv6_optlen(hdr); - } /* cache hdr->nexthdr, since pskb_may_pull() might * invalidate hdr */ next = hdr->nexthdr; - if (nexthdr == NEXTHDR_DEST) { - u16 i = 2; + /* Remember : hdr is no longer valid at this point. */ + if (!pskb_may_pull(skb, off + optlen)) + break; + if (nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag_hdr = (struct frag_hdr *)(skb->data + off); - /* Remember : hdr is no longer valid at this point. */ - if (!pskb_may_pull(skb, off + optlen)) + if (frag_hdr->frag_off) break; + } + if (nexthdr == NEXTHDR_DEST) { + u16 i = 2; while (1) { struct ipv6_tlv_tnl_enc_lim *tel;