net/9p/fd: support ipv6 for trans=tcp
authorJoshua Murphy <joshuamurphy@posteo.net>
Sat, 18 Jan 2025 19:12:36 +0000 (19:12 +0000)
committerDominique Martinet <asmadeus@codewreck.org>
Mon, 20 Jan 2025 13:05:25 +0000 (22:05 +0900)
Allows specifying an IPv6 address when mounting a remote 9p file system.

Signed-off-by: Joshua Murphy <joshuamurphy@posteo.net>
Message-ID: <20250118192122.327-2-joshuamurphy@posteo.net>
Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
net/9p/trans_fd.c

index 196060dc6138af10e99ad04a76ee36a11f770c65..2fea50bf047abd9f220233111bf4d26b60c0fd09 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/ipv6.h>
@@ -954,64 +955,55 @@ static void p9_fd_close(struct p9_client *client)
        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 int p9_bind_privport(struct socket *sock)
 {
-       struct sockaddr_in cl;
+       struct sockaddr_storage stor = { 0 };
        int port, err = -EINVAL;
 
-       memset(&cl, 0, sizeof(cl));
-       cl.sin_family = AF_INET;
-       cl.sin_addr.s_addr = htonl(INADDR_ANY);
+       stor.ss_family = sock->ops->family;
+       if (stor.ss_family == AF_INET)
+               ((struct sockaddr_in *)&stor)->sin_addr.s_addr = htonl(INADDR_ANY);
+       else
+               ((struct sockaddr_in6 *)&stor)->sin6_addr = in6addr_any;
        for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) {
-               cl.sin_port = htons((ushort)port);
-               err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl));
+               if (stor.ss_family == AF_INET)
+                       ((struct sockaddr_in *)&stor)->sin_port = htons((ushort)port);
+               else
+                       ((struct sockaddr_in6 *)&stor)->sin6_port = htons((ushort)port);
+               err = kernel_bind(sock, (struct sockaddr *)&stor, sizeof(stor));
                if (err != -EADDRINUSE)
                        break;
        }
        return err;
 }
 
-
 static int
 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 {
        int err;
+       char port_str[6];
        struct socket *csocket;
-       struct sockaddr_in sin_server;
+       struct sockaddr_storage stor = { 0 };
        struct p9_fd_opts opts;
 
        err = parse_opts(args, &opts);
        if (err < 0)
                return err;
 
-       if (addr == NULL || valid_ipaddr4(addr) < 0)
+       if (!addr)
                return -EINVAL;
 
+       sprintf(port_str, "%u", opts.port);
+       err = inet_pton_with_scope(current->nsproxy->net_ns, AF_UNSPEC, addr,
+                                  port_str, &stor);
+       if (err < 0)
+               return err;
+
        csocket = NULL;
 
        client->trans_opts.tcp.port = opts.port;
        client->trans_opts.tcp.privport = opts.privport;
-       sin_server.sin_family = AF_INET;
-       sin_server.sin_addr.s_addr = in_aton(addr);
-       sin_server.sin_port = htons(opts.port);
-       err = __sock_create(current->nsproxy->net_ns, PF_INET,
+       err = __sock_create(current->nsproxy->net_ns, stor.ss_family,
                            SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
        if (err) {
                pr_err("%s (%d): problem creating socket\n",
@@ -1030,8 +1022,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
        }
 
        err = READ_ONCE(csocket->ops)->connect(csocket,
-                                   (struct sockaddr *)&sin_server,
-                                   sizeof(struct sockaddr_in), 0);
+                                              (struct sockaddr *)&stor,
+                                              sizeof(stor), 0);
        if (err < 0) {
                pr_err("%s (%d): problem connecting socket to %s\n",
                       __func__, task_pid_nr(current), addr);