diff options
author | Sean Hefty <sean.hefty@intel.com> | 2009-11-19 19:46:25 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-11-19 19:46:25 -0500 |
commit | d14714df61681cfecf945a58436edf197327e87f (patch) | |
tree | 1dc232e98f17c531d75b0646ea519264e49a63b1 /drivers/infiniband/core/cma.c | |
parent | 923c100ef019bf15fb89b6fa3d3ad0485d25d59b (diff) |
IB/addr: Fix IPv6 routing lookup
Include link scope as part of address resolution. Combine local
and remote address resolution into a single, simpler code path.
Fix error checking in the IPv6 routing lookups.
Based on work from:
David Wilder <dwilder@us.ibm.com>
Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
[ Fix up cma_check_linklocal() for !IPV6 case. - Roland ]
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/cma.c')
-rw-r--r-- | drivers/infiniband/core/cma.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 38867a46d39e..fbdd73106000 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c | |||
@@ -1472,15 +1472,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv) | |||
1472 | mutex_unlock(&lock); | 1472 | mutex_unlock(&lock); |
1473 | } | 1473 | } |
1474 | 1474 | ||
1475 | static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) | ||
1476 | { | ||
1477 | struct sockaddr_storage addr_in; | ||
1478 | |||
1479 | memset(&addr_in, 0, sizeof addr_in); | ||
1480 | addr_in.ss_family = af; | ||
1481 | return rdma_bind_addr(id, (struct sockaddr *) &addr_in); | ||
1482 | } | ||
1483 | |||
1484 | int rdma_listen(struct rdma_cm_id *id, int backlog) | 1475 | int rdma_listen(struct rdma_cm_id *id, int backlog) |
1485 | { | 1476 | { |
1486 | struct rdma_id_private *id_priv; | 1477 | struct rdma_id_private *id_priv; |
@@ -1488,7 +1479,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog) | |||
1488 | 1479 | ||
1489 | id_priv = container_of(id, struct rdma_id_private, id); | 1480 | id_priv = container_of(id, struct rdma_id_private, id); |
1490 | if (id_priv->state == CMA_IDLE) { | 1481 | if (id_priv->state == CMA_IDLE) { |
1491 | ret = cma_bind_any(id, AF_INET); | 1482 | ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; |
1483 | ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); | ||
1492 | if (ret) | 1484 | if (ret) |
1493 | return ret; | 1485 | return ret; |
1494 | } | 1486 | } |
@@ -1885,10 +1877,14 @@ err: | |||
1885 | static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, | 1877 | static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, |
1886 | struct sockaddr *dst_addr) | 1878 | struct sockaddr *dst_addr) |
1887 | { | 1879 | { |
1888 | if (src_addr && src_addr->sa_family) | 1880 | if (!src_addr || !src_addr->sa_family) { |
1889 | return rdma_bind_addr(id, src_addr); | 1881 | src_addr = (struct sockaddr *) &id->route.addr.src_addr; |
1890 | else | 1882 | if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { |
1891 | return cma_bind_any(id, dst_addr->sa_family); | 1883 | ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = |
1884 | ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; | ||
1885 | } | ||
1886 | } | ||
1887 | return rdma_bind_addr(id, src_addr); | ||
1892 | } | 1888 | } |
1893 | 1889 | ||
1894 | int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, | 1890 | int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, |
@@ -2084,6 +2080,25 @@ static int cma_get_port(struct rdma_id_private *id_priv) | |||
2084 | return ret; | 2080 | return ret; |
2085 | } | 2081 | } |
2086 | 2082 | ||
2083 | static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, | ||
2084 | struct sockaddr *addr) | ||
2085 | { | ||
2086 | #if defined(CONFIG_IPv6) || defined(CONFIG_IPV6_MODULE) | ||
2087 | struct sockaddr_in6 *sin6; | ||
2088 | |||
2089 | if (addr->sa_family != AF_INET6) | ||
2090 | return 0; | ||
2091 | |||
2092 | sin6 = (struct sockaddr_in6 *) addr; | ||
2093 | if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && | ||
2094 | !sin6->sin6_scope_id) | ||
2095 | return -EINVAL; | ||
2096 | |||
2097 | dev_addr->bound_dev_if = sin6->sin6_scope_id; | ||
2098 | #endif | ||
2099 | return 0; | ||
2100 | } | ||
2101 | |||
2087 | int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) | 2102 | int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) |
2088 | { | 2103 | { |
2089 | struct rdma_id_private *id_priv; | 2104 | struct rdma_id_private *id_priv; |
@@ -2096,6 +2111,10 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) | |||
2096 | if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) | 2111 | if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) |
2097 | return -EINVAL; | 2112 | return -EINVAL; |
2098 | 2113 | ||
2114 | ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); | ||
2115 | if (ret) | ||
2116 | goto err1; | ||
2117 | |||
2099 | if (cma_loopback_addr(addr)) { | 2118 | if (cma_loopback_addr(addr)) { |
2100 | ret = cma_bind_loopback(id_priv); | 2119 | ret = cma_bind_loopback(id_priv); |
2101 | } else if (!cma_zero_addr(addr)) { | 2120 | } else if (!cma_zero_addr(addr)) { |