diff options
Diffstat (limited to 'net/ipv6/ip6_tunnel.c')
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 08d944223ec8..6022fc5e557a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -372,16 +372,16 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | |||
372 | } | 372 | } |
373 | 373 | ||
374 | /** | 374 | /** |
375 | * ip6ip6_err - tunnel error handler | 375 | * ip6_tnl_err - tunnel error handler |
376 | * | 376 | * |
377 | * Description: | 377 | * Description: |
378 | * ip6ip6_err() should handle errors in the tunnel according | 378 | * ip6_tnl_err() should handle errors in the tunnel according |
379 | * to the specifications in RFC 2473. | 379 | * to the specifications in RFC 2473. |
380 | **/ | 380 | **/ |
381 | 381 | ||
382 | static int | 382 | static int |
383 | ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 383 | ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
384 | int type, int code, int offset, __be32 info) | 384 | int *type, int *code, int *msg, __be32 *info, int offset) |
385 | { | 385 | { |
386 | struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; | 386 | struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; |
387 | struct ip6_tnl *t; | 387 | struct ip6_tnl *t; |
@@ -402,7 +402,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
402 | 402 | ||
403 | err = 0; | 403 | err = 0; |
404 | 404 | ||
405 | switch (type) { | 405 | switch (*type) { |
406 | __u32 teli; | 406 | __u32 teli; |
407 | struct ipv6_tlv_tnl_enc_lim *tel; | 407 | struct ipv6_tlv_tnl_enc_lim *tel; |
408 | __u32 mtu; | 408 | __u32 mtu; |
@@ -414,7 +414,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
414 | rel_msg = 1; | 414 | rel_msg = 1; |
415 | break; | 415 | break; |
416 | case ICMPV6_TIME_EXCEED: | 416 | case ICMPV6_TIME_EXCEED: |
417 | if (code == ICMPV6_EXC_HOPLIMIT) { | 417 | if ((*code) == ICMPV6_EXC_HOPLIMIT) { |
418 | if (net_ratelimit()) | 418 | if (net_ratelimit()) |
419 | printk(KERN_WARNING | 419 | printk(KERN_WARNING |
420 | "%s: Too small hop limit or " | 420 | "%s: Too small hop limit or " |
@@ -425,10 +425,10 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
425 | break; | 425 | break; |
426 | case ICMPV6_PARAMPROB: | 426 | case ICMPV6_PARAMPROB: |
427 | teli = 0; | 427 | teli = 0; |
428 | if (code == ICMPV6_HDR_FIELD) | 428 | if ((*code) == ICMPV6_HDR_FIELD) |
429 | teli = parse_tlv_tnl_enc_lim(skb, skb->data); | 429 | teli = parse_tlv_tnl_enc_lim(skb, skb->data); |
430 | 430 | ||
431 | if (teli && teli == ntohl(info) - 2) { | 431 | if (teli && teli == ntohl(*info) - 2) { |
432 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | 432 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; |
433 | if (tel->encap_limit == 0) { | 433 | if (tel->encap_limit == 0) { |
434 | if (net_ratelimit()) | 434 | if (net_ratelimit()) |
@@ -445,7 +445,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
445 | } | 445 | } |
446 | break; | 446 | break; |
447 | case ICMPV6_PKT_TOOBIG: | 447 | case ICMPV6_PKT_TOOBIG: |
448 | mtu = ntohl(info) - offset; | 448 | mtu = ntohl(*info) - offset; |
449 | if (mtu < IPV6_MIN_MTU) | 449 | if (mtu < IPV6_MIN_MTU) |
450 | mtu = IPV6_MIN_MTU; | 450 | mtu = IPV6_MIN_MTU; |
451 | t->dev->mtu = mtu; | 451 | t->dev->mtu = mtu; |
@@ -458,12 +458,38 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
458 | } | 458 | } |
459 | break; | 459 | break; |
460 | } | 460 | } |
461 | if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) { | 461 | |
462 | *type = rel_type; | ||
463 | *code = rel_code; | ||
464 | *info = rel_info; | ||
465 | *msg = rel_msg; | ||
466 | |||
467 | out: | ||
468 | read_unlock(&ip6ip6_lock); | ||
469 | return err; | ||
470 | } | ||
471 | |||
472 | static int | ||
473 | ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
474 | int type, int code, int offset, __u32 info) | ||
475 | { | ||
476 | int rel_msg = 0; | ||
477 | int rel_type = type; | ||
478 | int rel_code = code; | ||
479 | __u32 rel_info = info; | ||
480 | int err; | ||
481 | |||
482 | err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info, | ||
483 | offset); | ||
484 | if (err < 0) | ||
485 | return err; | ||
486 | |||
487 | if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) { | ||
462 | struct rt6_info *rt; | 488 | struct rt6_info *rt; |
463 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); | 489 | struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); |
464 | 490 | ||
465 | if (!skb2) | 491 | if (!skb2) |
466 | goto out; | 492 | return 0; |
467 | 493 | ||
468 | dst_release(skb2->dst); | 494 | dst_release(skb2->dst); |
469 | skb2->dst = NULL; | 495 | skb2->dst = NULL; |
@@ -483,9 +509,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
483 | 509 | ||
484 | kfree_skb(skb2); | 510 | kfree_skb(skb2); |
485 | } | 511 | } |
486 | out: | 512 | |
487 | read_unlock(&ip6ip6_lock); | 513 | return 0; |
488 | return err; | ||
489 | } | 514 | } |
490 | 515 | ||
491 | static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, | 516 | static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, |