|
@@ -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.
|
|
|
*
|