From 1e68b2b2756fc3488ecbade5ad5f13302b3aaafc Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@redhat.com>
Date: Thu, 11 Jun 2009 10:27:30 -0400
Subject: cifs: add new routine for converting AF_INET and AF_INET6 addrs

...to consolidate some logic used in more than one place.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/netmisc.c | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

(limited to 'fs/cifs/netmisc.c')

diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 32d6baa0a54f..00e6e357ae88 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -133,10 +133,12 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
 	{0, 0}
 };
 
-/* Convert string containing dotted ip address to binary form */
-/* returns 0 if invalid address */
-
-int
+/*
+ * Convert a string containing text IPv4 or IPv6 address to binary form.
+ *
+ * Returns 0 on failure.
+ */
+static int
 cifs_inet_pton(const int address_family, const char *cp, void *dst)
 {
 	int ret = 0;
@@ -153,6 +155,30 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
 	return ret;
 }
 
+/*
+ * 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.
+ *
+ * Returns 0 on failure.
+ */
+int
+cifs_convert_address(char *src, void *dst)
+{
+	struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
+	struct sockaddr_in6 *s6 = (Struct sockaddr_in6 *) dst;
+
+	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;
+}
+
 /*****************************************************************************
 convert a NT status code to a dos class/code
  *****************************************************************************/
-- 
cgit v1.2.3


From 361ea1ae5451040cd254eee0b6df64581080b2cc Mon Sep 17 00:00:00 2001
From: Steve French <sfrench@us.ibm.com>
Date: Mon, 15 Jun 2009 13:46:12 +0000
Subject: [CIFS] Fix build break

Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/netmisc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'fs/cifs/netmisc.c')

diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 00e6e357ae88..f9a54da97d34 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -166,7 +166,7 @@ int
 cifs_convert_address(char *src, void *dst)
 {
 	struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
-	struct sockaddr_in6 *s6 = (Struct sockaddr_in6 *) dst;
+	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
 
 	if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
 		s4->sin_family = AF_INET;
-- 
cgit v1.2.3


From 681bf72e4893a187cf6b6b62c08fc193f81c8c2f Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@redhat.com>
Date: Thu, 11 Jun 2009 10:27:31 -0400
Subject: cifs: have cifs parse scope_id out of IPv6 addresses and use it

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@redhat.com>
Acked-by: David Holder <david@erion.co.uk>
Signed-off-by: Steve French <sfrench@us.ibm.com>
---
 fs/cifs/netmisc.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

(limited to 'fs/cifs/netmisc.c')

diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index f9a54da97d34..bd6d6895730d 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;
 
+	/* 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;
 }
 
 /*****************************************************************************
-- 
cgit v1.2.3