aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>2006-10-31 09:11:25 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:37 -0400
commite490d1d85cf5e191791979e5f260d32eb4f703a8 (patch)
tree7de61c8d4f1807ae2675889d06f16058b60fbac6
parent7159039a128fa0a73ca7b532f6e1d30d9885277f (diff)
[IPV6] IP6TUNNEL: Split out generic routine in ip6ip6_err().
This enables to add IPv4/IPv6 specific error handling later, Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/ip6_tunnel.c53
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
382static int 382static int
383ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 383ip6_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
467out:
468 read_unlock(&ip6ip6_lock);
469 return err;
470}
471
472static int
473ip6ip6_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 }
486out: 512
487 read_unlock(&ip6ip6_lock); 513 return 0;
488 return err;
489} 514}
490 515
491static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, 516static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,