summaryrefslogtreecommitdiff
path: root/net/rds/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds/tcp.c')
-rw-r--r--net/rds/tcp.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 351a28474667..dadb33790333 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2017 Oracle and/or its affiliates. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -37,6 +37,8 @@
#include <net/tcp.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
+#include <net/tcp.h>
+#include <net/addrconf.h>
#include "rds.h"
#include "tcp.h"
@@ -262,9 +264,33 @@ out:
spin_unlock_irqrestore(&rds_tcp_tc_list_lock, flags);
}
-static int rds_tcp_laddr_check(struct net *net, __be32 addr)
+static int rds_tcp_laddr_check(struct net *net, const struct in6_addr *addr,
+ __u32 scope_id)
{
- if (inet_addr_type(net, addr) == RTN_LOCAL)
+ struct net_device *dev = NULL;
+ int ret;
+
+ if (ipv6_addr_v4mapped(addr)) {
+ if (inet_addr_type(net, addr->s6_addr32[3]) == RTN_LOCAL)
+ return 0;
+ return -EADDRNOTAVAIL;
+ }
+
+ /* If the scope_id is specified, check only those addresses
+ * hosted on the specified interface.
+ */
+ if (scope_id != 0) {
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, scope_id);
+ /* scope_id is not valid... */
+ if (!dev) {
+ rcu_read_unlock();
+ return -EADDRNOTAVAIL;
+ }
+ rcu_read_unlock();
+ }
+ ret = ipv6_chk_addr(net, addr, dev, 0);
+ if (ret)
return 0;
return -EADDRNOTAVAIL;
}