diff options
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 43 |
2 files changed, 45 insertions, 0 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index ece7e8a84ffd..c4ea12710576 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -506,6 +506,8 @@ extern int ipv6_skip_exthdr(const struct sk_buff *, int start, extern int ipv6_ext_hdr(u8 nexthdr); +extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type); + extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 8d3a0e17314d..50ff49e518bc 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -49,6 +49,49 @@ #include <asm/uaccess.h> +int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) +{ + int packet_len = skb->tail - skb->nh.raw; + struct ipv6_opt_hdr *hdr; + int len; + + if (offset + 2 > packet_len) + goto bad; + hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + len = ((hdr->hdrlen + 1) << 3); + + if (offset + len > packet_len) + goto bad; + + offset += 2; + len -= 2; + + while (len > 0) { + int opttype = skb->nh.raw[offset]; + int optlen; + + if (opttype == type) + return offset; + + switch (opttype) { + case IPV6_TLV_PAD0: + optlen = 1; + break; + default: + optlen = skb->nh.raw[offset + 1] + 2; + if (optlen > len) + goto bad; + break; + } + offset += optlen; + len -= optlen; + } + /* not_found */ + return -1; + bad: + return -1; +} + /* * Parsing tlv encoded headers. * |