summaryrefslogtreecommitdiffstats
path: root/net/dccp/ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ipv6.c')
-rw-r--r--net/dccp/ipv6.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index db5fc2440a23..e7e0b9bc2a43 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -202,7 +202,9 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
202 security_req_classify_flow(req, flowi6_to_flowi(&fl6)); 202 security_req_classify_flow(req, flowi6_to_flowi(&fl6));
203 203
204 204
205 final_p = fl6_update_dst(&fl6, np->opt, &final); 205 rcu_read_lock();
206 final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
207 rcu_read_unlock();
206 208
207 dst = ip6_dst_lookup_flow(sk, &fl6, final_p); 209 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
208 if (IS_ERR(dst)) { 210 if (IS_ERR(dst)) {
@@ -219,7 +221,10 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
219 &ireq->ir_v6_loc_addr, 221 &ireq->ir_v6_loc_addr,
220 &ireq->ir_v6_rmt_addr); 222 &ireq->ir_v6_rmt_addr);
221 fl6.daddr = ireq->ir_v6_rmt_addr; 223 fl6.daddr = ireq->ir_v6_rmt_addr;
222 err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); 224 rcu_read_lock();
225 err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
226 np->tclass);
227 rcu_read_unlock();
223 err = net_xmit_eval(err); 228 err = net_xmit_eval(err);
224 } 229 }
225 230
@@ -387,6 +392,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
387 struct inet_request_sock *ireq = inet_rsk(req); 392 struct inet_request_sock *ireq = inet_rsk(req);
388 struct ipv6_pinfo *newnp; 393 struct ipv6_pinfo *newnp;
389 const struct ipv6_pinfo *np = inet6_sk(sk); 394 const struct ipv6_pinfo *np = inet6_sk(sk);
395 struct ipv6_txoptions *opt;
390 struct inet_sock *newinet; 396 struct inet_sock *newinet;
391 struct dccp6_sock *newdp6; 397 struct dccp6_sock *newdp6;
392 struct sock *newsk; 398 struct sock *newsk;
@@ -488,13 +494,15 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
488 * Yes, keeping reference count would be much more clever, but we make 494 * Yes, keeping reference count would be much more clever, but we make
489 * one more one thing there: reattach optmem to newsk. 495 * one more one thing there: reattach optmem to newsk.
490 */ 496 */
491 if (np->opt != NULL) 497 opt = rcu_dereference(np->opt);
492 newnp->opt = ipv6_dup_options(newsk, np->opt); 498 if (opt) {
493 499 opt = ipv6_dup_options(newsk, opt);
500 RCU_INIT_POINTER(newnp->opt, opt);
501 }
494 inet_csk(newsk)->icsk_ext_hdr_len = 0; 502 inet_csk(newsk)->icsk_ext_hdr_len = 0;
495 if (newnp->opt != NULL) 503 if (opt)
496 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + 504 inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
497 newnp->opt->opt_flen); 505 opt->opt_flen;
498 506
499 dccp_sync_mss(newsk, dst_mtu(dst)); 507 dccp_sync_mss(newsk, dst_mtu(dst));
500 508
@@ -757,6 +765,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
757 struct ipv6_pinfo *np = inet6_sk(sk); 765 struct ipv6_pinfo *np = inet6_sk(sk);
758 struct dccp_sock *dp = dccp_sk(sk); 766 struct dccp_sock *dp = dccp_sk(sk);
759 struct in6_addr *saddr = NULL, *final_p, final; 767 struct in6_addr *saddr = NULL, *final_p, final;
768 struct ipv6_txoptions *opt;
760 struct flowi6 fl6; 769 struct flowi6 fl6;
761 struct dst_entry *dst; 770 struct dst_entry *dst;
762 int addr_type; 771 int addr_type;
@@ -856,7 +865,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
856 fl6.fl6_sport = inet->inet_sport; 865 fl6.fl6_sport = inet->inet_sport;
857 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); 866 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
858 867
859 final_p = fl6_update_dst(&fl6, np->opt, &final); 868 opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
869 final_p = fl6_update_dst(&fl6, opt, &final);
860 870
861 dst = ip6_dst_lookup_flow(sk, &fl6, final_p); 871 dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
862 if (IS_ERR(dst)) { 872 if (IS_ERR(dst)) {
@@ -876,9 +886,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
876 __ip6_dst_store(sk, dst, NULL, NULL); 886 __ip6_dst_store(sk, dst, NULL, NULL);
877 887
878 icsk->icsk_ext_hdr_len = 0; 888 icsk->icsk_ext_hdr_len = 0;
879 if (np->opt != NULL) 889 if (opt)
880 icsk->icsk_ext_hdr_len = (np->opt->opt_flen + 890 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
881 np->opt->opt_nflen);
882 891
883 inet->inet_dport = usin->sin6_port; 892 inet->inet_dport = usin->sin6_port;
884 893