diff options
Diffstat (limited to 'net/ipv6/exthdrs_core.c')
-rw-r--r-- | net/ipv6/exthdrs_core.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index f73d59a14131..e7d756e19d1d 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
@@ -111,3 +111,47 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, | |||
111 | return start; | 111 | return start; |
112 | } | 112 | } |
113 | EXPORT_SYMBOL(ipv6_skip_exthdr); | 113 | EXPORT_SYMBOL(ipv6_skip_exthdr); |
114 | |||
115 | int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | ||
116 | { | ||
117 | const unsigned char *nh = skb_network_header(skb); | ||
118 | int packet_len = skb->tail - skb->network_header; | ||
119 | struct ipv6_opt_hdr *hdr; | ||
120 | int len; | ||
121 | |||
122 | if (offset + 2 > packet_len) | ||
123 | goto bad; | ||
124 | hdr = (struct ipv6_opt_hdr *)(nh + offset); | ||
125 | len = ((hdr->hdrlen + 1) << 3); | ||
126 | |||
127 | if (offset + len > packet_len) | ||
128 | goto bad; | ||
129 | |||
130 | offset += 2; | ||
131 | len -= 2; | ||
132 | |||
133 | while (len > 0) { | ||
134 | int opttype = nh[offset]; | ||
135 | int optlen; | ||
136 | |||
137 | if (opttype == type) | ||
138 | return offset; | ||
139 | |||
140 | switch (opttype) { | ||
141 | case IPV6_TLV_PAD1: | ||
142 | optlen = 1; | ||
143 | break; | ||
144 | default: | ||
145 | optlen = nh[offset + 1] + 2; | ||
146 | if (optlen > len) | ||
147 | goto bad; | ||
148 | break; | ||
149 | } | ||
150 | offset += optlen; | ||
151 | len -= optlen; | ||
152 | } | ||
153 | /* not_found */ | ||
154 | bad: | ||
155 | return -1; | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(ipv6_find_tlv); | ||