diff options
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r-- | net/sctp/ipv6.c | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 961ee59f696a..f5b45b8b8b16 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -240,12 +240,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
240 | struct sctp_bind_addr *bp; | 240 | struct sctp_bind_addr *bp; |
241 | struct ipv6_pinfo *np = inet6_sk(sk); | 241 | struct ipv6_pinfo *np = inet6_sk(sk); |
242 | struct sctp_sockaddr_entry *laddr; | 242 | struct sctp_sockaddr_entry *laddr; |
243 | union sctp_addr *baddr = NULL; | ||
244 | union sctp_addr *daddr = &t->ipaddr; | 243 | union sctp_addr *daddr = &t->ipaddr; |
245 | union sctp_addr dst_saddr; | 244 | union sctp_addr dst_saddr; |
246 | struct in6_addr *final_p, final; | 245 | struct in6_addr *final_p, final; |
247 | __u8 matchlen = 0; | 246 | __u8 matchlen = 0; |
248 | __u8 bmatchlen; | ||
249 | sctp_scope_t scope; | 247 | sctp_scope_t scope; |
250 | 248 | ||
251 | memset(fl6, 0, sizeof(struct flowi6)); | 249 | memset(fl6, 0, sizeof(struct flowi6)); |
@@ -312,23 +310,37 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
312 | */ | 310 | */ |
313 | rcu_read_lock(); | 311 | rcu_read_lock(); |
314 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | 312 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { |
315 | if (!laddr->valid) | 313 | struct dst_entry *bdst; |
314 | __u8 bmatchlen; | ||
315 | |||
316 | if (!laddr->valid || | ||
317 | laddr->state != SCTP_ADDR_SRC || | ||
318 | laddr->a.sa.sa_family != AF_INET6 || | ||
319 | scope > sctp_scope(&laddr->a)) | ||
316 | continue; | 320 | continue; |
317 | if ((laddr->state == SCTP_ADDR_SRC) && | 321 | |
318 | (laddr->a.sa.sa_family == AF_INET6) && | 322 | fl6->saddr = laddr->a.v6.sin6_addr; |
319 | (scope <= sctp_scope(&laddr->a))) { | 323 | fl6->fl6_sport = laddr->a.v6.sin6_port; |
320 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | ||
321 | if (!baddr || (matchlen < bmatchlen)) { | ||
322 | baddr = &laddr->a; | ||
323 | matchlen = bmatchlen; | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | if (baddr) { | ||
328 | fl6->saddr = baddr->v6.sin6_addr; | ||
329 | fl6->fl6_sport = baddr->v6.sin6_port; | ||
330 | final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); | 324 | final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); |
331 | dst = ip6_dst_lookup_flow(sk, fl6, final_p); | 325 | bdst = ip6_dst_lookup_flow(sk, fl6, final_p); |
326 | |||
327 | if (!IS_ERR(bdst) && | ||
328 | ipv6_chk_addr(dev_net(bdst->dev), | ||
329 | &laddr->a.v6.sin6_addr, bdst->dev, 1)) { | ||
330 | if (!IS_ERR_OR_NULL(dst)) | ||
331 | dst_release(dst); | ||
332 | dst = bdst; | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | ||
337 | if (matchlen > bmatchlen) | ||
338 | continue; | ||
339 | |||
340 | if (!IS_ERR_OR_NULL(dst)) | ||
341 | dst_release(dst); | ||
342 | dst = bdst; | ||
343 | matchlen = bmatchlen; | ||
332 | } | 344 | } |
333 | rcu_read_unlock(); | 345 | rcu_read_unlock(); |
334 | 346 | ||
@@ -665,6 +677,9 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, | |||
665 | newnp = inet6_sk(newsk); | 677 | newnp = inet6_sk(newsk); |
666 | 678 | ||
667 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); | 679 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); |
680 | newnp->ipv6_mc_list = NULL; | ||
681 | newnp->ipv6_ac_list = NULL; | ||
682 | newnp->ipv6_fl_list = NULL; | ||
668 | 683 | ||
669 | rcu_read_lock(); | 684 | rcu_read_lock(); |
670 | opt = rcu_dereference(np->opt); | 685 | opt = rcu_dereference(np->opt); |