aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r--net/sctp/ipv6.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e917d27328ea..ec529121f38a 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -209,6 +209,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
209 struct sock *sk = skb->sk; 209 struct sock *sk = skb->sk;
210 struct ipv6_pinfo *np = inet6_sk(sk); 210 struct ipv6_pinfo *np = inet6_sk(sk);
211 struct flowi6 *fl6 = &transport->fl.u.ip6; 211 struct flowi6 *fl6 = &transport->fl.u.ip6;
212 int res;
212 213
213 pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, 214 pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
214 skb->len, &fl6->saddr, &fl6->daddr); 215 skb->len, &fl6->saddr, &fl6->daddr);
@@ -220,7 +221,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
220 221
221 SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS); 222 SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
222 223
223 return ip6_xmit(sk, skb, fl6, np->opt, np->tclass); 224 rcu_read_lock();
225 res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass);
226 rcu_read_unlock();
227 return res;
224} 228}
225 229
226/* Returns the dst cache entry for the given source and destination ip 230/* Returns the dst cache entry for the given source and destination ip
@@ -262,7 +266,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
262 pr_debug("src=%pI6 - ", &fl6->saddr); 266 pr_debug("src=%pI6 - ", &fl6->saddr);
263 } 267 }
264 268
265 final_p = fl6_update_dst(fl6, np->opt, &final); 269 rcu_read_lock();
270 final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
271 rcu_read_unlock();
272
266 dst = ip6_dst_lookup_flow(sk, fl6, final_p); 273 dst = ip6_dst_lookup_flow(sk, fl6, final_p);
267 if (!asoc || saddr) 274 if (!asoc || saddr)
268 goto out; 275 goto out;
@@ -316,14 +323,13 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
316 } 323 }
317 } 324 }
318 } 325 }
319 rcu_read_unlock();
320
321 if (baddr) { 326 if (baddr) {
322 fl6->saddr = baddr->v6.sin6_addr; 327 fl6->saddr = baddr->v6.sin6_addr;
323 fl6->fl6_sport = baddr->v6.sin6_port; 328 fl6->fl6_sport = baddr->v6.sin6_port;
324 final_p = fl6_update_dst(fl6, np->opt, &final); 329 final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
325 dst = ip6_dst_lookup_flow(sk, fl6, final_p); 330 dst = ip6_dst_lookup_flow(sk, fl6, final_p);
326 } 331 }
332 rcu_read_unlock();
327 333
328out: 334out:
329 if (!IS_ERR_OR_NULL(dst)) { 335 if (!IS_ERR_OR_NULL(dst)) {
@@ -635,6 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
635 struct sock *newsk; 641 struct sock *newsk;
636 struct ipv6_pinfo *newnp, *np = inet6_sk(sk); 642 struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
637 struct sctp6_sock *newsctp6sk; 643 struct sctp6_sock *newsctp6sk;
644 struct ipv6_txoptions *opt;
638 645
639 newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, 0); 646 newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, 0);
640 if (!newsk) 647 if (!newsk)
@@ -654,6 +661,13 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
654 661
655 memcpy(newnp, np, sizeof(struct ipv6_pinfo)); 662 memcpy(newnp, np, sizeof(struct ipv6_pinfo));
656 663
664 rcu_read_lock();
665 opt = rcu_dereference(np->opt);
666 if (opt)
667 opt = ipv6_dup_options(newsk, opt);
668 RCU_INIT_POINTER(newnp->opt, opt);
669 rcu_read_unlock();
670
657 /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() 671 /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
658 * and getpeername(). 672 * and getpeername().
659 */ 673 */