9p: fix error path during early mount

There was some cleanup issues during early mount which would trigger
a kernel bug for certain types of failure.  This patch reorganizes the
cleanup to get rid of the bad behavior.

This also merges the 9pnet and 9pnet_fd modules for the purpose of
configuration and initialization.  Keeping the fd transport separate
from the core 9pnet code seemed like a good idea at the time, but in
practice has caused more harm and confusion than good.

Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
index bafc50c..ff34c5a 100644
--- a/net/9p/Kconfig
+++ b/net/9p/Kconfig
@@ -13,16 +13,6 @@
 
 	  If unsure, say N.
 
-config NET_9P_FD
-	depends on NET_9P
-	default y if NET_9P
-	tristate "9P File Descriptor Transports (Experimental)"
-	help
-	  This builds support for file descriptor transports for 9p
-	  which includes support for TCP/IP, named pipes, or passed
-	  file descriptors.  TCP/IP is the default transport for 9p,
-	  so if you are going to use 9p, you'll likely want this.
-
 config NET_9P_VIRTIO
 	depends on NET_9P && EXPERIMENTAL && VIRTIO
 	tristate "9P Virtio Transport (Experimental)"
diff --git a/net/9p/Makefile b/net/9p/Makefile
index 8a10511..5192194 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -1,5 +1,4 @@
 obj-$(CONFIG_NET_9P) := 9pnet.o
-obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
 obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
 
 9pnet-objs := \
@@ -9,8 +8,6 @@
 	error.o \
 	fcprint.o \
 	util.o \
-
-9pnet_fd-objs := \
 	trans_fd.o \
 
 9pnet_virtio-objs := \
diff --git a/net/9p/mod.c b/net/9p/mod.c
index c6d96959..bdee1fb 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -107,6 +107,7 @@
 
 	p9_error_init();
 	printk(KERN_INFO "Installing 9P2000 support\n");
+	p9_trans_fd_init();
 
 	return ret;
 }
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 97b103b..4507f74 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -1433,6 +1433,23 @@
 	kfree(ts);
 }
 
+/*
+ * stolen from NFS - maybe should be made a generic function?
+ */
+static inline int valid_ipaddr4(const char *buf)
+{
+	int rc, count, in[4];
+
+	rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
+	if (rc != 4)
+		return -EINVAL;
+	for (count = 0; count < 4; count++) {
+		if (in[count] > 255)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static struct p9_trans *
 p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
 {
@@ -1447,6 +1464,9 @@
 	if (err < 0)
 		return ERR_PTR(err);
 
+	if (valid_ipaddr4(addr) < 0)
+		return ERR_PTR(-EINVAL);
+
 	csocket = NULL;
 	trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
 	if (!trans)
@@ -1625,7 +1645,7 @@
 	.create = p9_trans_create_fd,
 };
 
-static int __init p9_trans_fd_init(void)
+int p9_trans_fd_init(void)
 {
 	int ret = p9_mux_global_init();
 	if (ret) {
@@ -1639,9 +1659,4 @@
 
 	return 0;
 }
-
-module_init(p9_trans_fd_init);
-
-MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
-MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
-MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(p9_trans_fd_init);