[linux-cifs-client] [PATCH 4/5] cifs: have cifs parse scope_id out of IPv6 addresses and use it

Jeff Layton jlayton at redhat.com
Thu Jun 11 14:27:31 GMT 2009


This patch has CIFS look for a '%' in an IPv6 address. If one is
present then it will try to treat that value as a numeric interface
index suitable for stuffing into the sin6_scope_id field.

This should allow people to mount servers on IPv6 link-local addresses.

Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
 fs/cifs/connect.c     |    6 ++++--
 fs/cifs/dns_resolve.c |    4 ++--
 fs/cifs/netmisc.c     |   34 ++++++++++++++++++++++++++++------
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6a91b5f..c9e489c 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1374,8 +1374,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
 		     server->addr.sockAddr.sin_addr.s_addr))
 			continue;
 		else if (addr->ss_family == AF_INET6 &&
-			 !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
-					  &addr6->sin6_addr))
+			 (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
+					   &addr6->sin6_addr) ||
+			  server->addr.sockAddr6.sin6_scope_id !=
+					   addr6->sin6_scope_id))
 			continue;
 
 		++server->srv_count;
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 91b5500..8794814 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -35,7 +35,7 @@
  * 		0 - name is not IP
  */
 static int
-is_ip(const char *name)
+is_ip(char *name)
 {
 	struct sockaddr_storage ss;
 
@@ -57,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data,
 	ip[datalen] = '\0';
 
 	/* make sure this looks like an address */
-	if (!is_ip((const char *) ip)) {
+	if (!is_ip(ip)) {
 		kfree(ip);
 		return -EINVAL;
 	}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 00e6e35..bd6d689 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -158,25 +158,47 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
 /*
  * Try to convert a string to an IPv4 address and then attempt to convert
  * it to an IPv6 address if that fails. Set the family field if either
- * succeeds.
+ * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to
+ * treat the part following it as a numeric sin6_scope_id.
  *
  * Returns 0 on failure.
  */
 int
 cifs_convert_address(char *src, void *dst)
 {
+	int rc;
+	char *pct, *endp;
 	struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
-	struct sockaddr_in6 *s6 = (Struct sockaddr_in6 *) dst;
+	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
 
+	/* IPv4 address */
 	if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
 		s4->sin_family = AF_INET;
 		return 1;
-	} else if (cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr)) {
-		s6->sin6_family = AF_INET6;
-		return 1;
 	}
 
-	return 0;
+	/* temporarily terminate string */
+	pct = strchr(src, '%');
+	if (pct)
+		*pct = '\0';
+
+	rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
+
+	/* repair temp termination (if any) and make pct point to scopeid */
+	if (pct)
+		*pct++ = '%';
+
+	if (!rc)
+		return rc;
+
+	s6->sin6_family = AF_INET6;
+	if (pct) {
+		s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
+		if (!*pct || *endp)
+			return 0;
+	}
+
+	return rc;
 }
 
 /*****************************************************************************
-- 
1.6.0.6



More information about the linux-cifs-client mailing list