@@ -1177,8 +1177,13 @@ static inline bool cma_any_addr(const struct sockaddr *addr)
return cma_zero_addr(addr) || cma_loopback_addr(addr);
}
-static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
+static int cma_addr_cmp(const struct sockaddr *src, const struct sockaddr *dst)
{
+ struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *)src;
+ struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *)dst;
+ bool link_local;
+ int diff_addr;
+
if (src->sa_family != dst->sa_family)
return -1;
@@ -1187,8 +1192,17 @@ static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
((struct sockaddr_in *) dst)->sin_addr.s_addr;
case AF_INET6:
- return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
- &((struct sockaddr_in6 *) dst)->sin6_addr);
+ diff_addr = ipv6_addr_cmp(&src_addr6->sin6_addr,
+ &dst_addr6->sin6_addr);
+ /* if addresses differ, return right away that they differ */
+ if (diff_addr)
+ return 1;
+ link_local = ipv6_addr_type(&dst_addr6->sin6_addr) &
+ IPV6_ADDR_LINKLOCAL;
+ /* link local must have to match their scope_ids */
+ return link_local ?
+ (src_addr6->sin6_scope_id !=
+ dst_addr6->sin6_scope_id) : 0;
default:
return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,
&((struct sockaddr_ib *) dst)->sib_addr);