diff options
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 24 |
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 | ||
328 | out: | 334 | out: |
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 | */ |