aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorWeixing Shi <Weixing.Shi@windriver.com>2011-04-26 17:36:32 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-27 16:14:04 -0400
commit625034113bd45c71fb9e329f52f25fef9e6993a3 (patch)
treef4bd4ffc34bcf7993f8815ed55adc7cf0f4c2be9 /net/sctp
parent66e6961c8e53c0c0079d5b67faf9b7fe33525892 (diff)
sctp: fix sctp to work with ipv6 source address routing
In the below test case, using the source address routing, sctp can not work. Node-A 1)ifconfig eth0 inet6 add 2001:1::1/64 2)ip -6 rule add from 2001:1::1 table 100 pref 100 3)ip -6 route add 2001:2::1 dev eth0 table 100 4)sctp_darn -H 2001:1::1 -P 250 -l & Node-B 1)ifconfig eth0 inet6 add 2001:2::1/64 2)ip -6 rule add from 2001:2::1 table 100 pref 100 3)ip -6 route add 2001:1::1 dev eth0 table 100 4)sctp_darn -H 2001:2::1 -P 250 -h 2001:1::1 -p 250 -s root cause: Node-A and Node-B use the source address routing, and at begining, source address will be NULL,sctp will search the routing table by the destination address, because using the source address routing table, and the result dst_entry will be NULL. solution: walk through the bind address list to get the source address and then lookup the routing table again to get the correct dst_entry. Signed-off-by: Weixing Shi <Weixing.Shi@windriver.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/ipv6.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 321f175055bf..3a571d6614f9 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -80,6 +80,9 @@
80 80
81#include <asm/uaccess.h> 81#include <asm/uaccess.h>
82 82
83static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
84 union sctp_addr *s2);
85
83/* Event handler for inet6 address addition/deletion events. 86/* Event handler for inet6 address addition/deletion events.
84 * The sctp_local_addr_list needs to be protocted by a spin lock since 87 * The sctp_local_addr_list needs to be protocted by a spin lock since
85 * multiple notifiers (say IPv4 and IPv6) may be running at the same 88 * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -244,8 +247,14 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
244 union sctp_addr *daddr, 247 union sctp_addr *daddr,
245 union sctp_addr *saddr) 248 union sctp_addr *saddr)
246{ 249{
247 struct dst_entry *dst; 250 struct dst_entry *dst = NULL;
248 struct flowi6 fl6; 251 struct flowi6 fl6;
252 struct sctp_bind_addr *bp;
253 struct sctp_sockaddr_entry *laddr;
254 union sctp_addr *baddr = NULL;
255 __u8 matchlen = 0;
256 __u8 bmatchlen;
257 sctp_scope_t scope;
249 258
250 memset(&fl6, 0, sizeof(fl6)); 259 memset(&fl6, 0, sizeof(fl6));
251 ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); 260 ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr);
@@ -261,6 +270,39 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
261 } 270 }
262 271
263 dst = ip6_route_output(&init_net, NULL, &fl6); 272 dst = ip6_route_output(&init_net, NULL, &fl6);
273 if (!asoc || saddr)
274 goto out;
275
276 if (dst->error) {
277 dst_release(dst);
278 dst = NULL;
279 bp = &asoc->base.bind_addr;
280 scope = sctp_scope(daddr);
281 /* Walk through the bind address list and try to get a dst that
282 * matches a bind address as the source address.
283 */
284 rcu_read_lock();
285 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
286 if (!laddr->valid)
287 continue;
288 if ((laddr->state == SCTP_ADDR_SRC) &&
289 (laddr->a.sa.sa_family == AF_INET6) &&
290 (scope <= sctp_scope(&laddr->a))) {
291 bmatchlen = sctp_v6_addr_match_len(daddr,
292 &laddr->a);
293 if (!baddr || (matchlen < bmatchlen)) {
294 baddr = &laddr->a;
295 matchlen = bmatchlen;
296 }
297 }
298 }
299 rcu_read_unlock();
300 if (baddr) {
301 ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr);
302 dst = ip6_route_output(&init_net, NULL, &fl6);
303 }
304 }
305out:
264 if (!dst->error) { 306 if (!dst->error) {
265 struct rt6_info *rt; 307 struct rt6_info *rt;
266 rt = (struct rt6_info *)dst; 308 rt = (struct rt6_info *)dst;