diff options
Diffstat (limited to 'net/l2tp/l2tp_ip.c')
-rw-r--r-- | net/l2tp/l2tp_ip.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index b6466e71f5e1..d21e7ebd91ca 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -480,18 +480,16 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
480 | if (connected) | 480 | if (connected) |
481 | rt = (struct rtable *) __sk_dst_check(sk, 0); | 481 | rt = (struct rtable *) __sk_dst_check(sk, 0); |
482 | 482 | ||
483 | rcu_read_lock(); | ||
483 | if (rt == NULL) { | 484 | if (rt == NULL) { |
484 | struct ip_options_rcu *inet_opt; | 485 | const struct ip_options_rcu *inet_opt; |
485 | 486 | ||
486 | rcu_read_lock(); | ||
487 | inet_opt = rcu_dereference(inet->inet_opt); | 487 | inet_opt = rcu_dereference(inet->inet_opt); |
488 | 488 | ||
489 | /* Use correct destination address if we have options. */ | 489 | /* Use correct destination address if we have options. */ |
490 | if (inet_opt && inet_opt->opt.srr) | 490 | if (inet_opt && inet_opt->opt.srr) |
491 | daddr = inet_opt->opt.faddr; | 491 | daddr = inet_opt->opt.faddr; |
492 | 492 | ||
493 | rcu_read_unlock(); | ||
494 | |||
495 | /* If this fails, retransmit mechanism of transport layer will | 493 | /* If this fails, retransmit mechanism of transport layer will |
496 | * keep trying until route appears or the connection times | 494 | * keep trying until route appears or the connection times |
497 | * itself out. | 495 | * itself out. |
@@ -503,12 +501,20 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
503 | sk->sk_bound_dev_if); | 501 | sk->sk_bound_dev_if); |
504 | if (IS_ERR(rt)) | 502 | if (IS_ERR(rt)) |
505 | goto no_route; | 503 | goto no_route; |
506 | sk_setup_caps(sk, &rt->dst); | 504 | if (connected) |
505 | sk_setup_caps(sk, &rt->dst); | ||
506 | else | ||
507 | dst_release(&rt->dst); /* safe since we hold rcu_read_lock */ | ||
507 | } | 508 | } |
508 | skb_dst_set(skb, dst_clone(&rt->dst)); | 509 | |
510 | /* We dont need to clone dst here, it is guaranteed to not disappear. | ||
511 | * __dev_xmit_skb() might force a refcount if needed. | ||
512 | */ | ||
513 | skb_dst_set_noref(skb, &rt->dst); | ||
509 | 514 | ||
510 | /* Queue the packet to IP for output */ | 515 | /* Queue the packet to IP for output */ |
511 | rc = ip_queue_xmit(skb, &inet->cork.fl); | 516 | rc = ip_queue_xmit(skb, &inet->cork.fl); |
517 | rcu_read_unlock(); | ||
512 | 518 | ||
513 | error: | 519 | error: |
514 | /* Update stats */ | 520 | /* Update stats */ |
@@ -525,6 +531,7 @@ out: | |||
525 | return rc; | 531 | return rc; |
526 | 532 | ||
527 | no_route: | 533 | no_route: |
534 | rcu_read_unlock(); | ||
528 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 535 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
529 | kfree_skb(skb); | 536 | kfree_skb(skb); |
530 | rc = -EHOSTUNREACH; | 537 | rc = -EHOSTUNREACH; |