summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-11-02 15:27:47 +0000
committerDavid Howells <dhowells@redhat.com>2017-11-13 15:38:17 +0000
commit3838d3ecdea496699a8c13c183d4df5dfe8e1a3e (patch)
tree66a9268464a94f63f65073493be06a5f4aff70a8
parent4d9df9868f31df6725481135c10ac6419ce58d44 (diff)
afs: Allow IPv6 address specification of VL servers
Allow VL server specifications to be given IPv6 addresses as well as IPv4 addresses, for example as: echo add foo.org 1111:2222:3333:0:4444:5555:6666:7777 >/proc/fs/afs/cells Note that ':' is the expected separator for separating IPv4 addresses, but if a ',' is detected or no '.' is detected in the string, the delimiter is switched to ','. This also works with DNS AFSDB or SRV record strings fetched by upcall from userspace. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/afs/cell.c31
-rw-r--r--fs/afs/proc.c2
-rw-r--r--fs/afs/rxrpc.c11
-rw-r--r--fs/afs/server.c5
-rw-r--r--fs/afs/vlclient.c13
5 files changed, 36 insertions, 26 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 5523fa3c05d9..216821fd1a61 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -15,6 +15,7 @@
#include <linux/ctype.h>
#include <linux/dns_resolver.h>
#include <linux/sched.h>
+#include <linux/inet.h>
#include <keys/rxrpc-type.h>
#include "internal.h"
@@ -86,28 +87,38 @@ static struct afs_cell *afs_cell_alloc(struct afs_net *net,
delimiter = ',';
} else {
+ if (strchr(vllist, ',') || !strchr(vllist, '.'))
+ delimiter = ',';
_vllist = vllist;
}
/* fill in the VL server list from the rest of the string */
do {
struct sockaddr_rxrpc *srx = &cell->vl_addrs[cell->vl_naddrs];
- unsigned a, b, c, d;
+ const char *end;
next = strchr(_vllist, delimiter);
if (next)
*next++ = 0;
- if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
- goto bad_address;
-
- if (a > 255 || b > 255 || c > 255 || d > 255)
+ if (in4_pton(_vllist, -1, (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3],
+ -1, &end)) {
+ srx->transport_len = sizeof(struct sockaddr_in6);
+ srx->transport.sin6.sin6_family = AF_INET6;
+ srx->transport.sin6.sin6_flowinfo = 0;
+ srx->transport.sin6.sin6_scope_id = 0;
+ srx->transport.sin6.sin6_addr.s6_addr32[0] = 0;
+ srx->transport.sin6.sin6_addr.s6_addr32[1] = 0;
+ srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+ } else if (in6_pton(_vllist, -1, srx->transport.sin6.sin6_addr.s6_addr,
+ -1, &end)) {
+ srx->transport_len = sizeof(struct sockaddr_in6);
+ srx->transport.sin6.sin6_family = AF_INET6;
+ srx->transport.sin6.sin6_flowinfo = 0;
+ srx->transport.sin6.sin6_scope_id = 0;
+ } else {
goto bad_address;
-
- srx->transport_len = sizeof(struct sockaddr_in);
- srx->transport.sin.sin_family = AF_INET;
- srx->transport.sin.sin_addr.s_addr =
- htonl((a << 24) | (b << 16) | (c << 8) | d);
+ }
} while (cell->vl_naddrs++,
cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index f76018104ae0..d00d550ff2ef 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -662,7 +662,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
/* display one cell per line on subsequent lines */
sprintf(ipaddr, "%pISp", &server->addr.transport);
- seq_printf(m, "%3d %-15.15s %5d\n",
+ seq_printf(m, "%3d %-15s %5d\n",
atomic_read(&server->usage), ipaddr, server->fs_state);
return 0;
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index c108effb54be..5d2c1a34ffd5 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -46,21 +46,20 @@ int afs_open_socket(struct afs_net *net)
_enter("");
- ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket);
+ ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
if (ret < 0)
goto error_1;
socket->sk->sk_allocation = GFP_NOFS;
/* bind the callback manager's address to make this a server socket */
+ memset(&srx, 0, sizeof(srx));
srx.srx_family = AF_RXRPC;
srx.srx_service = CM_SERVICE;
srx.transport_type = SOCK_DGRAM;
- srx.transport_len = sizeof(srx.transport.sin);
- srx.transport.sin.sin_family = AF_INET;
- srx.transport.sin.sin_port = htons(AFS_CM_PORT);
- memset(&srx.transport.sin.sin_addr, 0,
- sizeof(srx.transport.sin.sin_addr));
+ srx.transport_len = sizeof(srx.transport.sin6);
+ srx.transport.sin6.sin6_family = AF_INET6;
+ srx.transport.sin6.sin6_port = htons(AFS_CM_PORT);
ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
if (ret < 0)
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 662f7fbf5d05..c63974f06385 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -200,11 +200,6 @@ struct afs_server *afs_find_server(struct afs_net *net,
_enter("{%d,%pIS}", srx->transport.family, &srx->transport);
- if (srx->transport.family != AF_INET) {
- WARN(true, "AFS does not yes support non-IPv4 addresses\n");
- return NULL;
- }
-
read_lock(&net->servers_lock);
p = net->servers.rb_node;
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c
index 48d137628d6a..276319aa86d8 100644
--- a/fs/afs/vlclient.c
+++ b/fs/afs/vlclient.c
@@ -88,10 +88,15 @@ static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call)
entry->servers[loop].srx_family = AF_RXRPC;
entry->servers[loop].srx_service = FS_SERVICE;
entry->servers[loop].transport_type = SOCK_DGRAM;
- entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin);
- entry->servers[loop].transport.sin.sin_family = AF_INET;
- entry->servers[loop].transport.sin.sin_port = htons(AFS_FS_PORT);
- entry->servers[loop].transport.sin.sin_addr.s_addr = *bp++;
+ entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin6);
+ entry->servers[loop].transport.sin6.sin6_family = AF_INET6;
+ entry->servers[loop].transport.sin6.sin6_port = htons(AFS_FS_PORT);
+ entry->servers[loop].transport.sin6.sin6_flowinfo = 0;
+ entry->servers[loop].transport.sin6.sin6_scope_id = 0;
+ entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[0] = 0;
+ entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[1] = 0;
+ entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+ entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[3] = *bp++;
}
bp += 8; /* partition IDs */