diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/exthdrs.c | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 1cdd0f0b5d34..6a6466bb5f26 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -196,8 +196,80 @@ bad: | |||
196 | Destination options header. | 196 | Destination options header. |
197 | *****************************/ | 197 | *****************************/ |
198 | 198 | ||
199 | #ifdef CONFIG_IPV6_MIP6 | ||
200 | static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) | ||
201 | { | ||
202 | struct sk_buff *skb = *skbp; | ||
203 | struct ipv6_destopt_hao *hao; | ||
204 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
205 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw; | ||
206 | struct in6_addr tmp_addr; | ||
207 | int ret; | ||
208 | |||
209 | if (opt->dsthao) { | ||
210 | LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n"); | ||
211 | goto discard; | ||
212 | } | ||
213 | opt->dsthao = opt->dst1; | ||
214 | opt->dst1 = 0; | ||
215 | |||
216 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff); | ||
217 | |||
218 | if (hao->length != 16) { | ||
219 | LIMIT_NETDEBUG( | ||
220 | KERN_DEBUG "hao invalid option length = %d\n", hao->length); | ||
221 | goto discard; | ||
222 | } | ||
223 | |||
224 | if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { | ||
225 | LIMIT_NETDEBUG( | ||
226 | KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr)); | ||
227 | goto discard; | ||
228 | } | ||
229 | |||
230 | ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr, | ||
231 | (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); | ||
232 | if (unlikely(ret < 0)) | ||
233 | goto discard; | ||
234 | |||
235 | if (skb_cloned(skb)) { | ||
236 | struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); | ||
237 | if (skb2 == NULL) | ||
238 | goto discard; | ||
239 | |||
240 | kfree_skb(skb); | ||
241 | |||
242 | /* update all variable using below by copied skbuff */ | ||
243 | *skbp = skb = skb2; | ||
244 | hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff); | ||
245 | ipv6h = (struct ipv6hdr *)skb2->nh.raw; | ||
246 | } | ||
247 | |||
248 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
249 | skb->ip_summed = CHECKSUM_NONE; | ||
250 | |||
251 | ipv6_addr_copy(&tmp_addr, &ipv6h->saddr); | ||
252 | ipv6_addr_copy(&ipv6h->saddr, &hao->addr); | ||
253 | ipv6_addr_copy(&hao->addr, &tmp_addr); | ||
254 | |||
255 | if (skb->tstamp.off_sec == 0) | ||
256 | __net_timestamp(skb); | ||
257 | |||
258 | return 1; | ||
259 | |||
260 | discard: | ||
261 | kfree_skb(skb); | ||
262 | return 0; | ||
263 | } | ||
264 | #endif | ||
265 | |||
199 | static struct tlvtype_proc tlvprocdestopt_lst[] = { | 266 | static struct tlvtype_proc tlvprocdestopt_lst[] = { |
200 | /* No destination options are defined now */ | 267 | #ifdef CONFIG_IPV6_MIP6 |
268 | { | ||
269 | .type = IPV6_TLV_HAO, | ||
270 | .func = ipv6_dest_hao, | ||
271 | }, | ||
272 | #endif | ||
201 | {-1, NULL} | 273 | {-1, NULL} |
202 | }; | 274 | }; |
203 | 275 | ||
@@ -205,6 +277,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
205 | { | 277 | { |
206 | struct sk_buff *skb = *skbp; | 278 | struct sk_buff *skb = *skbp; |
207 | struct inet6_skb_parm *opt = IP6CB(skb); | 279 | struct inet6_skb_parm *opt = IP6CB(skb); |
280 | #ifdef CONFIG_IPV6_MIP6 | ||
281 | __u16 dstbuf; | ||
282 | #endif | ||
208 | 283 | ||
209 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 284 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
210 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 285 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
@@ -215,11 +290,18 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
215 | 290 | ||
216 | opt->lastopt = skb->h.raw - skb->nh.raw; | 291 | opt->lastopt = skb->h.raw - skb->nh.raw; |
217 | opt->dst1 = skb->h.raw - skb->nh.raw; | 292 | opt->dst1 = skb->h.raw - skb->nh.raw; |
293 | #ifdef CONFIG_IPV6_MIP6 | ||
294 | dstbuf = opt->dst1; | ||
295 | #endif | ||
218 | 296 | ||
219 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { | 297 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { |
220 | skb = *skbp; | 298 | skb = *skbp; |
221 | skb->h.raw += ((skb->h.raw[1]+1)<<3); | 299 | skb->h.raw += ((skb->h.raw[1]+1)<<3); |
300 | #ifdef CONFIG_IPV6_MIP6 | ||
301 | opt->nhoff = dstbuf; | ||
302 | #else | ||
222 | opt->nhoff = opt->dst1; | 303 | opt->nhoff = opt->dst1; |
304 | #endif | ||
223 | return 1; | 305 | return 1; |
224 | } | 306 | } |
225 | 307 | ||