diff options
| author | Chuck Lever <chuck.lever@oracle.com> | 2010-01-26 14:03:47 -0500 | 
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2010-01-26 17:52:33 -0500 | 
| commit | 07396051a5c6901693a97e35cb731a01b0b348e4 (patch) | |
| tree | d6d0010823464deff357fe51bf4887e048c4300c /net/sunrpc/svcauth_unix.c | |
| parent | 73834d6f90f6833663f9effd4cf9b79b63bc36e1 (diff) | |
| download | olio-linux-3.10-07396051a5c6901693a97e35cb731a01b0b348e4.tar.xz olio-linux-3.10-07396051a5c6901693a97e35cb731a01b0b348e4.zip  | |
SUNRPC: Use rpc_pton() in ip_map_parse()
The existing logic in ip_map_parse() can not currently parse
shorthanded IPv6 addresses (anything with a double colon), nor can
it parse an IPv6 presentation address with a scope ID.  An
IPv6-enabled mountd can pass down both.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net/sunrpc/svcauth_unix.c')
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 47 | 
1 files changed, 26 insertions, 21 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index d8c04111449..97f0e9e1202 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -15,6 +15,7 @@  #include <linux/kernel.h>  #define RPCDBG_FACILITY	RPCDBG_AUTH +#include <linux/sunrpc/clnt.h>  /*   * AUTHUNIX and AUTHNULL credentials are both handled here. @@ -187,10 +188,13 @@ static int ip_map_parse(struct cache_detail *cd,  	 * for scratch: */  	char *buf = mesg;  	int len; -	int b1, b2, b3, b4, b5, b6, b7, b8; -	char c;  	char class[8]; -	struct in6_addr addr; +	union { +		struct sockaddr		sa; +		struct sockaddr_in	s4; +		struct sockaddr_in6	s6; +	} address; +	struct sockaddr_in6 sin6;  	int err;  	struct ip_map *ipmp; @@ -209,24 +213,24 @@ static int ip_map_parse(struct cache_detail *cd,  	len = qword_get(&mesg, buf, mlen);  	if (len <= 0) return -EINVAL; -	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) { -		addr.s6_addr32[0] = 0; -		addr.s6_addr32[1] = 0; -		addr.s6_addr32[2] = htonl(0xffff); -		addr.s6_addr32[3] = -			htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); -       } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c", -			&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) { -		addr.s6_addr16[0] = htons(b1); -		addr.s6_addr16[1] = htons(b2); -		addr.s6_addr16[2] = htons(b3); -		addr.s6_addr16[3] = htons(b4); -		addr.s6_addr16[4] = htons(b5); -		addr.s6_addr16[5] = htons(b6); -		addr.s6_addr16[6] = htons(b7); -		addr.s6_addr16[7] = htons(b8); -       } else +	if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)  		return -EINVAL; +	switch (address.sa.sa_family) { +	case AF_INET: +		/* Form a mapped IPv4 address in sin6 */ +		memset(&sin6, 0, sizeof(sin6)); +		sin6.sin6_family = AF_INET6; +		sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); +		sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr; +		break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +	case AF_INET6: +		memcpy(&sin6, &address.s6, sizeof(sin6)); +		break; +#endif +	default: +		return -EINVAL; +	}  	expiry = get_expiry(&mesg);  	if (expiry ==0) @@ -243,7 +247,8 @@ static int ip_map_parse(struct cache_detail *cd,  	} else  		dom = NULL; -	ipmp = ip_map_lookup(class, &addr); +	/* IPv6 scope IDs are ignored for now */ +	ipmp = ip_map_lookup(class, &sin6.sin6_addr);  	if (ipmp) {  		err = ip_map_update(ipmp,  			     container_of(dom, struct unix_domain, h),  |