diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /net/sctp/protocol.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'net/sctp/protocol.c')
| -rw-r--r-- | net/sctp/protocol.c | 48 | 
1 files changed, 34 insertions, 14 deletions
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 59e80356672b..b7143337e4fa 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -487,23 +487,43 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,  	 */  	rcu_read_lock();  	list_for_each_entry_rcu(laddr, &bp->address_list, list) { +		struct net_device *odev; +  		if (!laddr->valid)  			continue; -		if ((laddr->state == SCTP_ADDR_SRC) && -		    (AF_INET == laddr->a.sa.sa_family)) { -			fl4->fl4_sport = laddr->a.v4.sin_port; -			flowi4_update_output(fl4, -					     asoc->base.sk->sk_bound_dev_if, -					     RT_CONN_FLAGS(asoc->base.sk), -					     daddr->v4.sin_addr.s_addr, -					     laddr->a.v4.sin_addr.s_addr); - -			rt = ip_route_output_key(sock_net(sk), fl4); -			if (!IS_ERR(rt)) { -				dst = &rt->dst; -				goto out_unlock; -			} +		if (laddr->state != SCTP_ADDR_SRC || +		    AF_INET != laddr->a.sa.sa_family) +			continue; + +		fl4->fl4_sport = laddr->a.v4.sin_port; +		flowi4_update_output(fl4, +				     asoc->base.sk->sk_bound_dev_if, +				     RT_CONN_FLAGS(asoc->base.sk), +				     daddr->v4.sin_addr.s_addr, +				     laddr->a.v4.sin_addr.s_addr); + +		rt = ip_route_output_key(sock_net(sk), fl4); +		if (IS_ERR(rt)) +			continue; + +		if (!dst) +			dst = &rt->dst; + +		/* Ensure the src address belongs to the output +		 * interface. +		 */ +		odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, +				     false); +		if (!odev || odev->ifindex != fl4->flowi4_oif) { +			if (&rt->dst != dst) +				dst_release(&rt->dst); +			continue;  		} + +		if (dst != &rt->dst) +			dst_release(dst); +		dst = &rt->dst; +		break;  	}  out_unlock:  |