diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 57 |
1 files changed, 25 insertions, 32 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd60bcca1064..061a7bba163a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -397,10 +397,6 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
397 | return err; | 397 | return err; |
398 | } | 398 | } |
399 | 399 | ||
400 | /* No rt6_lock! If COW failed, the function returns dead route entry | ||
401 | with dst->error set to errno value. | ||
402 | */ | ||
403 | |||
404 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 400 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
405 | struct in6_addr *saddr) | 401 | struct in6_addr *saddr) |
406 | { | 402 | { |
@@ -439,26 +435,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad | |||
439 | return rt; | 435 | return rt; |
440 | } | 436 | } |
441 | 437 | ||
442 | static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | ||
443 | struct in6_addr *saddr, struct netlink_skb_parms *req) | ||
444 | { | ||
445 | struct rt6_info *rt = rt6_alloc_cow(ort, daddr, saddr); | ||
446 | int err; | ||
447 | |||
448 | if (!rt) { | ||
449 | dst_hold(&ip6_null_entry.u.dst); | ||
450 | return &ip6_null_entry; | ||
451 | } | ||
452 | |||
453 | dst_hold(&rt->u.dst); | ||
454 | |||
455 | err = ip6_ins_rt(rt, NULL, NULL, req); | ||
456 | if (err) | ||
457 | rt->u.dst.error = err; | ||
458 | |||
459 | return rt; | ||
460 | } | ||
461 | |||
462 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) | 438 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) |
463 | { | 439 | { |
464 | struct rt6_info *rt = ip6_rt_copy(ort); | 440 | struct rt6_info *rt = ip6_rt_copy(ort); |
@@ -518,15 +494,23 @@ restart: | |||
518 | 494 | ||
519 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 495 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { |
520 | struct rt6_info *nrt; | 496 | struct rt6_info *nrt; |
497 | int err; | ||
521 | 498 | ||
522 | nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, | 499 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, |
523 | &skb->nh.ipv6h->saddr, | 500 | &skb->nh.ipv6h->saddr); |
524 | &NETLINK_CB(skb)); | ||
525 | 501 | ||
526 | dst_release(&rt->u.dst); | 502 | dst_release(&rt->u.dst); |
527 | rt = nrt; | 503 | rt = nrt ? : &ip6_null_entry; |
504 | |||
505 | dst_hold(&rt->u.dst); | ||
506 | if (nrt) { | ||
507 | err = ip6_ins_rt(nrt, NULL, NULL, | ||
508 | &NETLINK_CB(skb)); | ||
509 | if (!err) | ||
510 | goto out2; | ||
511 | } | ||
528 | 512 | ||
529 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 513 | if (--attempts <= 0) |
530 | goto out2; | 514 | goto out2; |
531 | 515 | ||
532 | /* Race condition! In the gap, when rt6_lock was | 516 | /* Race condition! In the gap, when rt6_lock was |
@@ -582,13 +566,21 @@ restart: | |||
582 | 566 | ||
583 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 567 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { |
584 | struct rt6_info *nrt; | 568 | struct rt6_info *nrt; |
569 | int err; | ||
585 | 570 | ||
586 | nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); | 571 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
587 | 572 | ||
588 | dst_release(&rt->u.dst); | 573 | dst_release(&rt->u.dst); |
589 | rt = nrt; | 574 | rt = nrt ? : &ip6_null_entry; |
590 | 575 | ||
591 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 576 | dst_hold(&rt->u.dst); |
577 | if (nrt) { | ||
578 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | ||
579 | if (!err) | ||
580 | goto out2; | ||
581 | } | ||
582 | |||
583 | if (--attempts <= 0) | ||
592 | goto out2; | 584 | goto out2; |
593 | 585 | ||
594 | /* Race condition! In the gap, when rt6_lock was | 586 | /* Race condition! In the gap, when rt6_lock was |
@@ -597,6 +589,7 @@ restart: | |||
597 | dst_release(&rt->u.dst); | 589 | dst_release(&rt->u.dst); |
598 | goto relookup; | 590 | goto relookup; |
599 | } | 591 | } |
592 | |||
600 | out2: | 593 | out2: |
601 | rt->u.dst.lastuse = jiffies; | 594 | rt->u.dst.lastuse = jiffies; |
602 | rt->u.dst.__use++; | 595 | rt->u.dst.__use++; |