diff options
author | David Howells <dhowells@redhat.com> | 2017-11-02 18:27:47 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2017-11-13 18:38:17 +0300 |
commit | 3838d3ecdea496699a8c13c183d4df5dfe8e1a3e (patch) | |
tree | 66a9268464a94f63f65073493be06a5f4aff70a8 /fs/afs/cell.c | |
parent | 4d9df9868f31df6725481135c10ac6419ce58d44 (diff) | |
download | linux-3838d3ecdea496699a8c13c183d4df5dfe8e1a3e.tar.xz |
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>
Diffstat (limited to 'fs/afs/cell.c')
-rw-r--r-- | fs/afs/cell.c | 31 |
1 files changed, 21 insertions, 10 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)); |