Change the interface with the mount command for NFSv2 and v3 in order
to allow the use of non-IPv4 addresses.
The 'nfs_mount_data' structure is extended with the fields host_addrlen (int)
and host_addr (sockaddr *) to carry addresses which may be other than IPv4
addresses. The mount version number is incremented to 7 to assume the
compatibility with previous versions.
So according to the mount version, the server address will be retrieved from the
addr or host_addr field.

Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>

 fs/nfs/inode.c        |   20 ++++++++------------
 net/sunrpc/xprtsock.c |   18 ++++++++++++++++++
 2 files changed, 26 insertions(+), 12 deletions(-)
--------
diff -Nru linux-2.6.12-03/fs/nfs/inode.c linux-2.6.12-04/fs/nfs/inode.c
--- linux-2.6.12-03/fs/nfs/inode.c	2005-06-23 14:49:17.000000000 +0200
+++ linux-2.6.12-04/fs/nfs/inode.c	2005-06-27 13:20:08.000000000 +0200
@@ -1795,7 +1795,10 @@
 			}
 		case 5:
 			memset(data->context, 0, sizeof(data->context));
-	}
+		case 6:
+			data->addrlen = sizeof(struct sockaddr_in);
+			memcpy(&data->addr, &data->old_addr, sizeof(struct sockaddr_in));
+		}
 #ifndef CONFIG_NFS_V3
 	/* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
 	s = ERR_PTR(-EPROTONOSUPPORT);
@@ -1827,7 +1830,7 @@
 	memcpy(root->data, data->root.data, root->size);
 
 	/* We now require that the mount process passes the remote address */
-	server->addrlen = sizeof(struct sockaddr_in);
+	server->addrlen = data->addrlen;
 	server->addr = kmalloc(server->addrlen, GFP_KERNEL);
 	if (!server->addr) {
 		kfree(server->addr);
@@ -1835,12 +1838,6 @@
 		return ERR_PTR(-ENOMEM);
 	}
 	memcpy(server->addr, &data->addr, server->addrlen);
-	if (((struct sockaddr_in *)server->addr)->sin_addr.s_addr == INADDR_ANY) {
-
-		dprintk("%s: mount program didn't pass remote address!\n",
-				__FUNCTION__);
-		goto out_err;
-	}
 
 	/* Fire up rpciod if not yet running */
 	s = ERR_PTR(rpciod_up());
@@ -2207,10 +2204,9 @@
 		s = ERR_PTR(-EFAULT);
 		goto out_free;
 	}
-	if (server->addr->sa_family != AF_INET ||
-	    ((struct sockaddr_in *)server->addr)->sin_addr.s_addr == INADDR_ANY) {
-		dprintk("%s: mount program didn't pass remote IP address!\n",
-				__FUNCTION__);
+
+	if (server->addr->sa_family != AF_INET) {
+		printk("NFS: mount program didn't pass remote IPv4 address!\n");
 		s = ERR_PTR(-EINVAL);
 		goto out_free;
 	}
diff -Nru linux-2.6.12-03/net/sunrpc/xprtsock.c linux-2.6.12-04/net/sunrpc/xprtsock.c
--- linux-2.6.12-03/net/sunrpc/xprtsock.c	2005-06-27 13:28:06.000000000 +0200
+++ linux-2.6.12-04/net/sunrpc/xprtsock.c	2005-06-27 13:41:04.000000000 +0200
@@ -1700,12 +1700,16 @@
  */
 static int xs_setup_udp4(struct rpc_xprt *xprt, struct rpc_timeout *to)
 {
+	struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
 	struct xs_private *priv;
 	char buf[RPC_MAX_ADDRBUFLEN];
 
 	xs_print_ipv4_address(xprt, RPC_DISPLAY_ALL, buf, sizeof(buf));
 	dprintk("RPC:       setting up transport to address %s\n", buf);
 
+	if (sap->sin_addr.s_addr == INADDR_ANY)
+		return -EINVAL;
+
   	priv = xs_alloc_private();
   	if (priv == NULL)
   		return -ENOMEM;
@@ -1731,12 +1735,17 @@
  */
 static int xs_setup_udp6(struct rpc_xprt *xprt, struct rpc_timeout *to)
 {
+	struct in6_addr *addr = &((struct sockaddr_in6 *)&xprt->addr)->sin6_addr;
 	struct xs_private *priv;
 	char buf[RPC_MAX_ADDRBUFLEN];
 
 	xs_print_ipv6_address(xprt, RPC_DISPLAY_ALL, buf, sizeof(buf));
 	dprintk("RPC:       setting up transport to address %s\n", buf);
 
+	if (addr->s6_addr32[0] == 0 && addr->s6_addr32[1] == 0 &&
+	    addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)
+		return -EINVAL;
+
   	priv = xs_alloc_private();
   	if (priv == NULL)
   		return -ENOMEM;
@@ -1784,12 +1793,16 @@
  */
 static int xs_setup_tcp4(struct rpc_xprt *xprt, struct rpc_timeout *to)
 {
+	struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr;
 	struct xs_private *priv;
 	char buf[RPC_MAX_ADDRBUFLEN];
 
 	xs_print_ipv4_address(xprt, RPC_DISPLAY_ALL, buf, sizeof(buf));
 	dprintk("RPC:       setting up transport to address %s\n", buf);
 
+	if (sap->sin_addr.s_addr == INADDR_ANY)
+		return -EINVAL;
+
   	priv = xs_alloc_private();
   	if (priv == NULL)
   		return -ENOMEM;
@@ -1815,12 +1828,17 @@
  */
 static int xs_setup_tcp6(struct rpc_xprt *xprt, struct rpc_timeout *to)
 {
+	struct in6_addr *addr = &((struct sockaddr_in6 *)&xprt->addr)->sin6_addr;
 	struct xs_private *priv;
 	char buf[RPC_MAX_ADDRBUFLEN];
 
 	xs_print_ipv6_address(xprt, RPC_DISPLAY_ALL, buf, sizeof(buf));
 	dprintk("RPC:       setting up transport to address %s\n", buf);
 
+	if (addr->s6_addr32[0] == 0 && addr->s6_addr32[1] == 0 &&
+	    addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)
+		return -EINVAL;
+
   	priv = xs_alloc_private();
   	if (priv == NULL)
   		return -ENOMEM;

