mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
Merge branch 'patches_cel-for-2.6.32' into nfs-for-2.6.32
This commit is contained in:
commit
976a6f921c
@ -87,18 +87,6 @@ static unsigned int nlm_hash_address(const struct sockaddr *sap)
|
||||
return hash & (NLM_HOST_NRHASH - 1);
|
||||
}
|
||||
|
||||
static void nlm_clear_port(struct sockaddr *sap)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sap)->sin_port = 0;
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sap)->sin6_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Common host lookup routine for server & client
|
||||
*/
|
||||
@ -177,7 +165,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
|
||||
host->h_addrbuf = nsm->sm_addrbuf;
|
||||
memcpy(nlm_addr(host), ni->sap, ni->salen);
|
||||
host->h_addrlen = ni->salen;
|
||||
nlm_clear_port(nlm_addr(host));
|
||||
rpc_set_port(nlm_addr(host), 0);
|
||||
memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
|
||||
host->h_version = ni->version;
|
||||
host->h_proto = ni->protocol;
|
||||
|
@ -61,43 +61,6 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
|
||||
return (struct sockaddr *)&nsm->sm_addr;
|
||||
}
|
||||
|
||||
static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf,
|
||||
const size_t len)
|
||||
{
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf,
|
||||
const size_t len)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
|
||||
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
|
||||
snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]);
|
||||
else if (sin6->sin6_scope_id != 0)
|
||||
snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr,
|
||||
sin6->sin6_scope_id);
|
||||
else
|
||||
snprintf(buf, len, "%pI6", &sin6->sin6_addr);
|
||||
}
|
||||
|
||||
static void nsm_display_address(const struct sockaddr *sap,
|
||||
char *buf, const size_t len)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
nsm_display_ipv4_address(sap, buf, len);
|
||||
break;
|
||||
case AF_INET6:
|
||||
nsm_display_ipv6_address(sap, buf, len);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, len, "unsupported address family");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rpc_clnt *nsm_create(void)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
@ -307,8 +270,11 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
|
||||
memcpy(nsm_addr(new), sap, salen);
|
||||
new->sm_addrlen = salen;
|
||||
nsm_init_private(new);
|
||||
nsm_display_address((const struct sockaddr *)&new->sm_addr,
|
||||
new->sm_addrbuf, sizeof(new->sm_addrbuf));
|
||||
|
||||
if (rpc_ntop(nsm_addr(new), new->sm_addrbuf,
|
||||
sizeof(new->sm_addrbuf)) == 0)
|
||||
(void)snprintf(new->sm_addrbuf, sizeof(new->sm_addrbuf),
|
||||
"unsupported address family");
|
||||
memcpy(new->sm_name, hostname, hostname_len);
|
||||
new->sm_name[hostname_len] = '\0';
|
||||
|
||||
|
@ -102,6 +102,7 @@ struct nfs_mount_request {
|
||||
};
|
||||
|
||||
extern int nfs_mount(struct nfs_mount_request *info);
|
||||
extern void nfs_umount(const struct nfs_mount_request *info);
|
||||
|
||||
/* client.c */
|
||||
extern struct rpc_program nfs_program;
|
||||
@ -213,7 +214,6 @@ void nfs_zap_acl_cache(struct inode *inode);
|
||||
extern int nfs_wait_bit_killable(void *word);
|
||||
|
||||
/* super.c */
|
||||
void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
|
||||
extern struct file_system_type nfs_xdev_fs_type;
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern struct file_system_type nfs4_xdev_fs_type;
|
||||
@ -374,24 +374,3 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
|
||||
return ((unsigned long)len + (unsigned long)base +
|
||||
PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
#define IPV6_SCOPE_DELIMITER '%'
|
||||
|
||||
/*
|
||||
* Set the port number in an address. Be agnostic about the address
|
||||
* family.
|
||||
*/
|
||||
static inline void nfs_set_port(struct sockaddr *sap, unsigned short port)
|
||||
{
|
||||
struct sockaddr_in *ap = (struct sockaddr_in *)sap;
|
||||
struct sockaddr_in6 *ap6 = (struct sockaddr_in6 *)sap;
|
||||
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
ap->sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ap6->sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +209,71 @@ out_mnt_err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_umount - Notify a server that we have unmounted this export
|
||||
* @info: pointer to umount request arguments
|
||||
*
|
||||
* MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
|
||||
* use UDP.
|
||||
*/
|
||||
void nfs_umount(const struct nfs_mount_request *info)
|
||||
{
|
||||
static const struct rpc_timeout nfs_umnt_timeout = {
|
||||
.to_initval = 1 * HZ,
|
||||
.to_maxval = 3 * HZ,
|
||||
.to_retries = 2,
|
||||
};
|
||||
struct rpc_create_args args = {
|
||||
.protocol = IPPROTO_UDP,
|
||||
.address = info->sap,
|
||||
.addrsize = info->salen,
|
||||
.timeout = &nfs_umnt_timeout,
|
||||
.servername = info->hostname,
|
||||
.program = &mnt_program,
|
||||
.version = info->version,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = RPC_CLNT_CREATE_NOPING,
|
||||
};
|
||||
struct mountres result;
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = info->dirpath,
|
||||
.rpc_resp = &result,
|
||||
};
|
||||
struct rpc_clnt *clnt;
|
||||
int status;
|
||||
|
||||
if (info->noresvport)
|
||||
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
|
||||
|
||||
clnt = rpc_create(&args);
|
||||
if (unlikely(IS_ERR(clnt)))
|
||||
goto out_clnt_err;
|
||||
|
||||
dprintk("NFS: sending UMNT request for %s:%s\n",
|
||||
(info->hostname ? info->hostname : "server"), info->dirpath);
|
||||
|
||||
if (info->version == NFS_MNT3_VERSION)
|
||||
msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
|
||||
else
|
||||
msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
|
||||
|
||||
status = rpc_call_sync(clnt, &msg, 0);
|
||||
rpc_shutdown_client(clnt);
|
||||
|
||||
if (unlikely(status < 0))
|
||||
goto out_call_err;
|
||||
|
||||
return;
|
||||
|
||||
out_clnt_err:
|
||||
dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
|
||||
PTR_ERR(clnt));
|
||||
return;
|
||||
|
||||
out_call_err:
|
||||
dprintk("NFS: UMNT request failed, status=%d\n", status);
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR encode/decode functions for MOUNT
|
||||
*/
|
||||
@ -407,6 +472,13 @@ static struct rpc_procinfo mnt_procedures[] = {
|
||||
.p_statidx = MOUNTPROC_MNT,
|
||||
.p_name = "MOUNT",
|
||||
},
|
||||
[MOUNTPROC_UMNT] = {
|
||||
.p_proc = MOUNTPROC_UMNT,
|
||||
.p_encode = (kxdrproc_t)mnt_enc_dirpath,
|
||||
.p_arglen = MNT_enc_dirpath_sz,
|
||||
.p_statidx = MOUNTPROC_UMNT,
|
||||
.p_name = "UMOUNT",
|
||||
},
|
||||
};
|
||||
|
||||
static struct rpc_procinfo mnt3_procedures[] = {
|
||||
@ -419,6 +491,13 @@ static struct rpc_procinfo mnt3_procedures[] = {
|
||||
.p_statidx = MOUNTPROC3_MNT,
|
||||
.p_name = "MOUNT",
|
||||
},
|
||||
[MOUNTPROC3_UMNT] = {
|
||||
.p_proc = MOUNTPROC3_UMNT,
|
||||
.p_encode = (kxdrproc_t)mnt_enc_dirpath,
|
||||
.p_arglen = MNT_enc_dirpath_sz,
|
||||
.p_statidx = MOUNTPROC3_UMNT,
|
||||
.p_name = "UMOUNT",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -121,11 +121,11 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
|
||||
|
||||
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
|
||||
continue;
|
||||
nfs_parse_ip_address(buf->data, buf->len,
|
||||
mountdata->addr, &mountdata->addrlen);
|
||||
if (mountdata->addr->sa_family == AF_UNSPEC)
|
||||
mountdata->addrlen = rpc_pton(buf->data, buf->len,
|
||||
mountdata->addr, mountdata->addrlen);
|
||||
if (mountdata->addrlen == 0)
|
||||
continue;
|
||||
nfs_set_port(mountdata->addr, NFS_PORT);
|
||||
rpc_set_port(mountdata->addr, NFS_PORT);
|
||||
|
||||
memcpy(page2, buf->data, buf->len);
|
||||
page2[buf->len] = '\0';
|
||||
|
247
fs/nfs/super.c
247
fs/nfs/super.c
@ -158,7 +158,7 @@ static const match_table_t nfs_mount_option_tokens = {
|
||||
{ Opt_mountvers, "mountvers=%s" },
|
||||
{ Opt_nfsvers, "nfsvers=%s" },
|
||||
{ Opt_nfsvers, "vers=%s" },
|
||||
{ Opt_minorversion, "minorversion=%u" },
|
||||
{ Opt_minorversion, "minorversion=%s" },
|
||||
|
||||
{ Opt_sec, "sec=%s" },
|
||||
{ Opt_proto, "proto=%s" },
|
||||
@ -742,129 +742,10 @@ static int nfs_verify_server_address(struct sockaddr *addr)
|
||||
}
|
||||
}
|
||||
|
||||
dfprintk(MOUNT, "NFS: Invalid IP address specified\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfs_parse_ipv4_address(char *string, size_t str_len,
|
||||
struct sockaddr *sap, size_t *addr_len)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
u8 *addr = (u8 *)&sin->sin_addr.s_addr;
|
||||
|
||||
if (str_len <= INET_ADDRSTRLEN) {
|
||||
dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n",
|
||||
(int)str_len, string);
|
||||
|
||||
sin->sin_family = AF_INET;
|
||||
*addr_len = sizeof(*sin);
|
||||
if (in4_pton(string, str_len, addr, '\0', NULL))
|
||||
return;
|
||||
}
|
||||
|
||||
sap->sa_family = AF_UNSPEC;
|
||||
*addr_len = 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
|
||||
const char *delim,
|
||||
struct sockaddr_in6 *sin6)
|
||||
{
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
if ((string + str_len) == delim)
|
||||
return 1;
|
||||
|
||||
if (*delim != IPV6_SCOPE_DELIMITER)
|
||||
return 0;
|
||||
|
||||
if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
|
||||
return 0;
|
||||
|
||||
len = (string + str_len) - delim - 1;
|
||||
p = kstrndup(delim + 1, len, GFP_KERNEL);
|
||||
if (p) {
|
||||
unsigned long scope_id = 0;
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_name(&init_net, p);
|
||||
if (dev != NULL) {
|
||||
scope_id = dev->ifindex;
|
||||
dev_put(dev);
|
||||
} else {
|
||||
if (strict_strtoul(p, 10, &scope_id) == 0) {
|
||||
kfree(p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
|
||||
sin6->sin6_scope_id = scope_id;
|
||||
dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfs_parse_ipv6_address(char *string, size_t str_len,
|
||||
struct sockaddr *sap, size_t *addr_len)
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
|
||||
const char *delim;
|
||||
|
||||
if (str_len <= INET6_ADDRSTRLEN) {
|
||||
dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n",
|
||||
(int)str_len, string);
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
*addr_len = sizeof(*sin6);
|
||||
if (in6_pton(string, str_len, addr,
|
||||
IPV6_SCOPE_DELIMITER, &delim) != 0) {
|
||||
if (nfs_parse_ipv6_scope_id(string, str_len,
|
||||
delim, sin6) != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sap->sa_family = AF_UNSPEC;
|
||||
*addr_len = 0;
|
||||
}
|
||||
#else
|
||||
static void nfs_parse_ipv6_address(char *string, size_t str_len,
|
||||
struct sockaddr *sap, size_t *addr_len)
|
||||
{
|
||||
sap->sa_family = AF_UNSPEC;
|
||||
*addr_len = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Construct a sockaddr based on the contents of a string that contains
|
||||
* an IP address in presentation format.
|
||||
*
|
||||
* If there is a problem constructing the new sockaddr, set the address
|
||||
* family to AF_UNSPEC.
|
||||
*/
|
||||
void nfs_parse_ip_address(char *string, size_t str_len,
|
||||
struct sockaddr *sap, size_t *addr_len)
|
||||
{
|
||||
unsigned int i, colons;
|
||||
|
||||
colons = 0;
|
||||
for (i = 0; i < str_len; i++)
|
||||
if (string[i] == ':')
|
||||
colons++;
|
||||
|
||||
if (colons >= 2)
|
||||
nfs_parse_ipv6_address(string, str_len, sap, addr_len);
|
||||
else
|
||||
nfs_parse_ipv4_address(string, str_len, sap, addr_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check the NFS transport protocol.
|
||||
*
|
||||
@ -904,8 +785,6 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
|
||||
|
||||
/*
|
||||
* Parse the value of the 'sec=' option.
|
||||
*
|
||||
* The flavor_len setting is for v4 mounts.
|
||||
*/
|
||||
static int nfs_parse_security_flavors(char *value,
|
||||
struct nfs_parsed_mount_data *mnt)
|
||||
@ -916,53 +795,43 @@ static int nfs_parse_security_flavors(char *value,
|
||||
|
||||
switch (match_token(value, nfs_secflavor_tokens, args)) {
|
||||
case Opt_sec_none:
|
||||
mnt->auth_flavor_len = 0;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_NULL;
|
||||
break;
|
||||
case Opt_sec_sys:
|
||||
mnt->auth_flavor_len = 0;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_UNIX;
|
||||
break;
|
||||
case Opt_sec_krb5:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
|
||||
break;
|
||||
case Opt_sec_krb5i:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
|
||||
break;
|
||||
case Opt_sec_krb5p:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
|
||||
break;
|
||||
case Opt_sec_lkey:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
|
||||
break;
|
||||
case Opt_sec_lkeyi:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
|
||||
break;
|
||||
case Opt_sec_lkeyp:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
|
||||
break;
|
||||
case Opt_sec_spkm:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
|
||||
break;
|
||||
case Opt_sec_spkmi:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
|
||||
break;
|
||||
case Opt_sec_spkmp:
|
||||
mnt->auth_flavor_len = 1;
|
||||
mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
mnt->auth_flavor_len = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1001,7 +870,6 @@ static int nfs_parse_mount_options(char *raw,
|
||||
while ((p = strsep(&raw, ",")) != NULL) {
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
unsigned long option;
|
||||
int int_option;
|
||||
int token;
|
||||
|
||||
if (!*p)
|
||||
@ -1273,11 +1141,16 @@ static int nfs_parse_mount_options(char *raw,
|
||||
}
|
||||
break;
|
||||
case Opt_minorversion:
|
||||
if (match_int(args, &int_option))
|
||||
return 0;
|
||||
if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION)
|
||||
return 0;
|
||||
mnt->minorversion = int_option;
|
||||
string = match_strdup(args);
|
||||
if (string == NULL)
|
||||
goto out_nomem;
|
||||
rc = strict_strtoul(string, 10, &option);
|
||||
kfree(string);
|
||||
if (rc != 0)
|
||||
goto out_invalid_value;
|
||||
if (option > NFS4_MAX_MINOR_VERSION)
|
||||
goto out_invalid_value;
|
||||
mnt->minorversion = option;
|
||||
break;
|
||||
|
||||
/*
|
||||
@ -1352,11 +1225,14 @@ static int nfs_parse_mount_options(char *raw,
|
||||
string = match_strdup(args);
|
||||
if (string == NULL)
|
||||
goto out_nomem;
|
||||
nfs_parse_ip_address(string, strlen(string),
|
||||
(struct sockaddr *)
|
||||
&mnt->nfs_server.address,
|
||||
&mnt->nfs_server.addrlen);
|
||||
mnt->nfs_server.addrlen =
|
||||
rpc_pton(string, strlen(string),
|
||||
(struct sockaddr *)
|
||||
&mnt->nfs_server.address,
|
||||
sizeof(mnt->nfs_server.address));
|
||||
kfree(string);
|
||||
if (mnt->nfs_server.addrlen == 0)
|
||||
goto out_invalid_address;
|
||||
break;
|
||||
case Opt_clientaddr:
|
||||
string = match_strdup(args);
|
||||
@ -1376,11 +1252,14 @@ static int nfs_parse_mount_options(char *raw,
|
||||
string = match_strdup(args);
|
||||
if (string == NULL)
|
||||
goto out_nomem;
|
||||
nfs_parse_ip_address(string, strlen(string),
|
||||
(struct sockaddr *)
|
||||
&mnt->mount_server.address,
|
||||
&mnt->mount_server.addrlen);
|
||||
mnt->mount_server.addrlen =
|
||||
rpc_pton(string, strlen(string),
|
||||
(struct sockaddr *)
|
||||
&mnt->mount_server.address,
|
||||
sizeof(mnt->mount_server.address));
|
||||
kfree(string);
|
||||
if (mnt->mount_server.addrlen == 0)
|
||||
goto out_invalid_address;
|
||||
break;
|
||||
case Opt_lookupcache:
|
||||
string = match_strdup(args);
|
||||
@ -1432,8 +1311,11 @@ static int nfs_parse_mount_options(char *raw,
|
||||
|
||||
return 1;
|
||||
|
||||
out_invalid_address:
|
||||
printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
|
||||
return 0;
|
||||
out_invalid_value:
|
||||
printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
|
||||
printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
|
||||
return 0;
|
||||
out_nomem:
|
||||
printk(KERN_INFO "NFS: not enough memory to parse option\n");
|
||||
@ -1444,6 +1326,42 @@ out_security_failure:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match the requested auth flavors with the list returned by
|
||||
* the server. Returns zero and sets the mount's authentication
|
||||
* flavor on success; returns -EACCES if server does not support
|
||||
* the requested flavor.
|
||||
*/
|
||||
static int nfs_walk_authlist(struct nfs_parsed_mount_data *args,
|
||||
struct nfs_mount_request *request)
|
||||
{
|
||||
unsigned int i, j, server_authlist_len = *(request->auth_flav_len);
|
||||
|
||||
/*
|
||||
* We avoid sophisticated negotiating here, as there are
|
||||
* plenty of cases where we can get it wrong, providing
|
||||
* either too little or too much security.
|
||||
*
|
||||
* RFC 2623, section 2.7 suggests we SHOULD prefer the
|
||||
* flavor listed first. However, some servers list
|
||||
* AUTH_NULL first. Our caller plants AUTH_SYS, the
|
||||
* preferred default, in args->auth_flavors[0] if user
|
||||
* didn't specify sec= mount option.
|
||||
*/
|
||||
for (i = 0; i < args->auth_flavor_len; i++)
|
||||
for (j = 0; j < server_authlist_len; j++)
|
||||
if (args->auth_flavors[i] == request->auth_flavs[j]) {
|
||||
dfprintk(MOUNT, "NFS: using auth flavor %d\n",
|
||||
request->auth_flavs[j]);
|
||||
args->auth_flavors[0] = request->auth_flavs[j];
|
||||
return 0;
|
||||
}
|
||||
|
||||
dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n");
|
||||
nfs_umount(request);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the remote server's MOUNT service to request the NFS file handle
|
||||
* corresponding to the provided path.
|
||||
@ -1451,7 +1369,8 @@ out_security_failure:
|
||||
static int nfs_try_mount(struct nfs_parsed_mount_data *args,
|
||||
struct nfs_fh *root_fh)
|
||||
{
|
||||
unsigned int auth_flavor_len = 0;
|
||||
rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS];
|
||||
unsigned int server_authlist_len = ARRAY_SIZE(server_authlist);
|
||||
struct nfs_mount_request request = {
|
||||
.sap = (struct sockaddr *)
|
||||
&args->mount_server.address,
|
||||
@ -1459,7 +1378,8 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
|
||||
.protocol = args->mount_server.protocol,
|
||||
.fh = root_fh,
|
||||
.noresvport = args->flags & NFS_MOUNT_NORESVPORT,
|
||||
.auth_flav_len = &auth_flavor_len,
|
||||
.auth_flav_len = &server_authlist_len,
|
||||
.auth_flavs = server_authlist,
|
||||
};
|
||||
int status;
|
||||
|
||||
@ -1489,19 +1409,25 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
|
||||
/*
|
||||
* autobind will be used if mount_server.port == 0
|
||||
*/
|
||||
nfs_set_port(request.sap, args->mount_server.port);
|
||||
rpc_set_port(request.sap, args->mount_server.port);
|
||||
|
||||
/*
|
||||
* Now ask the mount server to map our export path
|
||||
* to a file handle.
|
||||
*/
|
||||
status = nfs_mount(&request);
|
||||
if (status == 0)
|
||||
return 0;
|
||||
if (status != 0) {
|
||||
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
|
||||
request.hostname, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
|
||||
request.hostname, status);
|
||||
return status;
|
||||
/*
|
||||
* MNTv1 (NFSv2) does not support auth flavor negotiation.
|
||||
*/
|
||||
if (args->mount_server.version != NFS_MNT3_VERSION)
|
||||
return 0;
|
||||
return nfs_walk_authlist(args, &request);
|
||||
}
|
||||
|
||||
static int nfs_parse_simple_hostname(const char *dev_name,
|
||||
@ -1676,6 +1602,7 @@ static int nfs_validate_mount_data(void *options,
|
||||
args->nfs_server.port = 0; /* autobind unless user sets port */
|
||||
args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
|
||||
args->auth_flavors[0] = RPC_AUTH_UNIX;
|
||||
args->auth_flavor_len = 1;
|
||||
|
||||
switch (data->version) {
|
||||
case 1:
|
||||
@ -1776,7 +1703,7 @@ static int nfs_validate_mount_data(void *options,
|
||||
&args->nfs_server.address))
|
||||
goto out_no_address;
|
||||
|
||||
nfs_set_port((struct sockaddr *)&args->nfs_server.address,
|
||||
rpc_set_port((struct sockaddr *)&args->nfs_server.address,
|
||||
args->nfs_server.port);
|
||||
|
||||
nfs_set_mount_transport_protocol(args);
|
||||
@ -2339,7 +2266,7 @@ static int nfs4_validate_mount_data(void *options,
|
||||
args->acdirmax = NFS_DEF_ACDIRMAX;
|
||||
args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */
|
||||
args->auth_flavors[0] = RPC_AUTH_UNIX;
|
||||
args->auth_flavor_len = 0;
|
||||
args->auth_flavor_len = 1;
|
||||
args->minorversion = 0;
|
||||
|
||||
switch (data->version) {
|
||||
@ -2409,7 +2336,7 @@ static int nfs4_validate_mount_data(void *options,
|
||||
&args->nfs_server.address))
|
||||
return -EINVAL;
|
||||
|
||||
nfs_set_port((struct sockaddr *)&args->nfs_server.address,
|
||||
rpc_set_port((struct sockaddr *)&args->nfs_server.address,
|
||||
args->nfs_server.port);
|
||||
|
||||
nfs_validate_transport_protocol(args);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <linux/nfsd/xdr.h>
|
||||
#include <linux/nfsd/syscall.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <net/ipv6.h>
|
||||
@ -490,22 +491,18 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
|
||||
*
|
||||
* Input:
|
||||
* buf: '\n'-terminated C string containing a
|
||||
* presentation format IPv4 address
|
||||
* presentation format IP address
|
||||
* size: length of C string in @buf
|
||||
* Output:
|
||||
* On success: returns zero if all specified locks were released;
|
||||
* returns one if one or more locks were not released
|
||||
* On error: return code is negative errno value
|
||||
*
|
||||
* Note: Only AF_INET client addresses are passed in
|
||||
*/
|
||||
static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
};
|
||||
int b1, b2, b3, b4;
|
||||
char c;
|
||||
struct sockaddr_storage address;
|
||||
struct sockaddr *sap = (struct sockaddr *)&address;
|
||||
size_t salen = sizeof(address);
|
||||
char *fo_path;
|
||||
|
||||
/* sanity check */
|
||||
@ -519,14 +516,10 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
if (qword_get(&buf, fo_path, size) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* get ipv4 address */
|
||||
if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
|
||||
if (rpc_pton(fo_path, size, sap, salen) == 0)
|
||||
return -EINVAL;
|
||||
if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255)
|
||||
return -EINVAL;
|
||||
sin.sin_addr.s_addr = htonl((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
|
||||
|
||||
return nlmsvc_unlock_all_by_ip((struct sockaddr *)&sin);
|
||||
return nlmsvc_unlock_all_by_ip(sap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,10 @@
|
||||
#ifndef _LINUX_SUNRPC_CLNT_H
|
||||
#define _LINUX_SUNRPC_CLNT_H
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
|
||||
#include <linux/sunrpc/msg_prot.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
@ -151,5 +155,39 @@ void rpc_force_rebind(struct rpc_clnt *);
|
||||
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
|
||||
const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
|
||||
|
||||
size_t rpc_ntop(const struct sockaddr *, char *, const size_t);
|
||||
size_t rpc_pton(const char *, const size_t,
|
||||
struct sockaddr *, const size_t);
|
||||
char * rpc_sockaddr2uaddr(const struct sockaddr *);
|
||||
size_t rpc_uaddr2sockaddr(const char *, const size_t,
|
||||
struct sockaddr *, const size_t);
|
||||
|
||||
static inline unsigned short rpc_get_port(const struct sockaddr *sap)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(((struct sockaddr_in *)sap)->sin_port);
|
||||
case AF_INET6:
|
||||
return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rpc_set_port(struct sockaddr *sap,
|
||||
const unsigned short port)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sap)->sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define IPV6_SCOPE_DELIMITER '%'
|
||||
#define IPV6_SCOPE_ID_LEN sizeof("%nnnnnnnnnn")
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_SUNRPC_CLNT_H */
|
||||
|
@ -189,7 +189,22 @@ typedef __be32 rpc_fraghdr;
|
||||
* Additionally, the two alternative forms specified in Section 2.2 of
|
||||
* [RFC2373] are also acceptable.
|
||||
*/
|
||||
#define RPCBIND_MAXUADDRLEN (56u)
|
||||
|
||||
#include <linux/inet.h>
|
||||
|
||||
/* Maximum size of the port number part of a universal address */
|
||||
#define RPCBIND_MAXUADDRPLEN sizeof(".255.255")
|
||||
|
||||
/* Maximum size of an IPv4 universal address */
|
||||
#define RPCBIND_MAXUADDR4LEN \
|
||||
(INET_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN)
|
||||
|
||||
/* Maximum size of an IPv6 universal address */
|
||||
#define RPCBIND_MAXUADDR6LEN \
|
||||
(INET6_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN)
|
||||
|
||||
/* Assume INET6_ADDRSTRLEN will always be larger than INET_ADDRSTRLEN... */
|
||||
#define RPCBIND_MAXUADDRLEN RPCBIND_MAXUADDR6LEN
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
|
||||
|
@ -38,10 +38,8 @@ enum rpc_display_format_t {
|
||||
RPC_DISPLAY_ADDR = 0,
|
||||
RPC_DISPLAY_PORT,
|
||||
RPC_DISPLAY_PROTO,
|
||||
RPC_DISPLAY_ALL,
|
||||
RPC_DISPLAY_HEX_ADDR,
|
||||
RPC_DISPLAY_HEX_PORT,
|
||||
RPC_DISPLAY_UNIVERSAL_ADDR,
|
||||
RPC_DISPLAY_NETID,
|
||||
RPC_DISPLAY_MAX,
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
|
||||
sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
|
||||
auth.o auth_null.o auth_unix.o auth_generic.o \
|
||||
svc.o svcsock.o svcauth.o svcauth_unix.o \
|
||||
rpcb_clnt.o timer.o xdr.o \
|
||||
addr.o rpcb_clnt.o timer.o xdr.o \
|
||||
sunrpc_syms.o cache.o rpc_pipe.o \
|
||||
svc_xprt.o
|
||||
sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o
|
||||
|
364
net/sunrpc/addr.c
Normal file
364
net/sunrpc/addr.c
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright 2009, Oracle. All rights reserved.
|
||||
*
|
||||
* Convert socket addresses to presentation addresses and universal
|
||||
* addresses, and vice versa.
|
||||
*
|
||||
* Universal addresses are introduced by RFC 1833 and further refined by
|
||||
* recent RFCs describing NFSv4. The universal address format is part
|
||||
* of the external (network) interface provided by rpcbind version 3
|
||||
* and 4, and by NFSv4. Such an address is a string containing a
|
||||
* presentation format IP address followed by a port number in
|
||||
* "hibyte.lobyte" format.
|
||||
*
|
||||
* IPv6 addresses can also include a scope ID, typically denoted by
|
||||
* a '%' followed by a device name or a non-negative integer. Refer to
|
||||
* RFC 4291, Section 2.2 for details on IPv6 presentation formats.
|
||||
*/
|
||||
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
|
||||
static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
|
||||
char *buf, const int buflen)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
const struct in6_addr *addr = &sin6->sin6_addr;
|
||||
|
||||
/*
|
||||
* RFC 4291, Section 2.2.2
|
||||
*
|
||||
* Shorthanded ANY address
|
||||
*/
|
||||
if (ipv6_addr_any(addr))
|
||||
return snprintf(buf, buflen, "::");
|
||||
|
||||
/*
|
||||
* RFC 4291, Section 2.2.2
|
||||
*
|
||||
* Shorthanded loopback address
|
||||
*/
|
||||
if (ipv6_addr_loopback(addr))
|
||||
return snprintf(buf, buflen, "::1");
|
||||
|
||||
/*
|
||||
* RFC 4291, Section 2.2.3
|
||||
*
|
||||
* Special presentation address format for mapped v4
|
||||
* addresses.
|
||||
*/
|
||||
if (ipv6_addr_v4mapped(addr))
|
||||
return snprintf(buf, buflen, "::ffff:%pI4",
|
||||
&addr->s6_addr32[3]);
|
||||
|
||||
/*
|
||||
* RFC 4291, Section 2.2.1
|
||||
*
|
||||
* To keep the result as short as possible, especially
|
||||
* since we don't shorthand, we don't want leading zeros
|
||||
* in each halfword, so avoid %pI6.
|
||||
*/
|
||||
return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]),
|
||||
ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]),
|
||||
ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]),
|
||||
ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7]));
|
||||
}
|
||||
|
||||
static size_t rpc_ntop6(const struct sockaddr *sap,
|
||||
char *buf, const size_t buflen)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
char scopebuf[IPV6_SCOPE_ID_LEN];
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
len = rpc_ntop6_noscopeid(sap, buf, buflen);
|
||||
if (unlikely(len == 0))
|
||||
return len;
|
||||
|
||||
if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
|
||||
!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL))
|
||||
return len;
|
||||
|
||||
rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u",
|
||||
IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id);
|
||||
if (unlikely((size_t)rc > sizeof(scopebuf)))
|
||||
return 0;
|
||||
|
||||
len += rc;
|
||||
if (unlikely(len > buflen))
|
||||
return 0;
|
||||
|
||||
strcat(buf, scopebuf);
|
||||
return len;
|
||||
}
|
||||
|
||||
#else /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
|
||||
|
||||
static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
|
||||
char *buf, const int buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t rpc_ntop6(const struct sockaddr *sap,
|
||||
char *buf, const size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */
|
||||
|
||||
static int rpc_ntop4(const struct sockaddr *sap,
|
||||
char *buf, const size_t buflen)
|
||||
{
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
|
||||
return snprintf(buf, buflen, "%pI4", &sin->sin_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpc_ntop - construct a presentation address in @buf
|
||||
* @sap: socket address
|
||||
* @buf: construction area
|
||||
* @buflen: size of @buf, in bytes
|
||||
*
|
||||
* Plants a %NUL-terminated string in @buf and returns the length
|
||||
* of the string, excluding the %NUL. Otherwise zero is returned.
|
||||
*/
|
||||
size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
|
||||
{
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
return rpc_ntop4(sap, buf, buflen);
|
||||
case AF_INET6:
|
||||
return rpc_ntop6(sap, buf, buflen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_ntop);
|
||||
|
||||
static size_t rpc_pton4(const char *buf, const size_t buflen,
|
||||
struct sockaddr *sap, const size_t salen)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
u8 *addr = (u8 *)&sin->sin_addr.s_addr;
|
||||
|
||||
if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in))
|
||||
return 0;
|
||||
|
||||
memset(sap, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
if (in4_pton(buf, buflen, addr, '\0', NULL) == 0)
|
||||
return 0;
|
||||
|
||||
sin->sin_family = AF_INET;
|
||||
return sizeof(struct sockaddr_in);;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static int rpc_parse_scope_id(const char *buf, const size_t buflen,
|
||||
const char *delim, struct sockaddr_in6 *sin6)
|
||||
{
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
if ((buf + buflen) == delim)
|
||||
return 1;
|
||||
|
||||
if (*delim != IPV6_SCOPE_DELIMITER)
|
||||
return 0;
|
||||
|
||||
if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
|
||||
!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL))
|
||||
return 0;
|
||||
|
||||
len = (buf + buflen) - delim - 1;
|
||||
p = kstrndup(delim + 1, len, GFP_KERNEL);
|
||||
if (p) {
|
||||
unsigned long scope_id = 0;
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_name(&init_net, p);
|
||||
if (dev != NULL) {
|
||||
scope_id = dev->ifindex;
|
||||
dev_put(dev);
|
||||
} else {
|
||||
if (strict_strtoul(p, 10, &scope_id) == 0) {
|
||||
kfree(p);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
|
||||
sin6->sin6_scope_id = scope_id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t rpc_pton6(const char *buf, const size_t buflen,
|
||||
struct sockaddr *sap, const size_t salen)
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
|
||||
const char *delim;
|
||||
|
||||
if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) ||
|
||||
salen < sizeof(struct sockaddr_in6))
|
||||
return 0;
|
||||
|
||||
memset(sap, 0, sizeof(struct sockaddr_in6));
|
||||
|
||||
if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
|
||||
return 0;
|
||||
|
||||
if (!rpc_parse_scope_id(buf, buflen, delim, sin6))
|
||||
return 0;
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
return sizeof(struct sockaddr_in6);
|
||||
}
|
||||
#else
|
||||
static size_t rpc_pton6(const char *buf, const size_t buflen,
|
||||
struct sockaddr *sap, const size_t salen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* rpc_pton - Construct a sockaddr in @sap
|
||||
* @buf: C string containing presentation format IP address
|
||||
* @buflen: length of presentation address in bytes
|
||||
* @sap: buffer into which to plant socket address
|
||||
* @salen: size of buffer in bytes
|
||||
*
|
||||
* Returns the size of the socket address if successful; otherwise
|
||||
* zero is returned.
|
||||
*
|
||||
* Plants a socket address in @sap and returns the size of the
|
||||
* socket address, if successful. Returns zero if an error
|
||||
* occurred.
|
||||
*/
|
||||
size_t rpc_pton(const char *buf, const size_t buflen,
|
||||
struct sockaddr *sap, const size_t salen)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < buflen; i++)
|
||||
if (buf[i] == ':')
|
||||
return rpc_pton6(buf, buflen, sap, salen);
|
||||
return rpc_pton4(buf, buflen, sap, salen);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_pton);
|
||||
|
||||
/**
|
||||
* rpc_sockaddr2uaddr - Construct a universal address string from @sap.
|
||||
* @sap: socket address
|
||||
*
|
||||
* Returns a %NUL-terminated string in dynamically allocated memory;
|
||||
* otherwise NULL is returned if an error occurred. Caller must
|
||||
* free the returned string.
|
||||
*/
|
||||
char *rpc_sockaddr2uaddr(const struct sockaddr *sap)
|
||||
{
|
||||
char portbuf[RPCBIND_MAXUADDRPLEN];
|
||||
char addrbuf[RPCBIND_MAXUADDRLEN];
|
||||
unsigned short port;
|
||||
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0)
|
||||
return NULL;
|
||||
port = ntohs(((struct sockaddr_in *)sap)->sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0)
|
||||
return NULL;
|
||||
port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (snprintf(portbuf, sizeof(portbuf),
|
||||
".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf))
|
||||
return NULL;
|
||||
|
||||
if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
|
||||
return NULL;
|
||||
|
||||
return kstrdup(addrbuf, GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr);
|
||||
|
||||
/**
|
||||
* rpc_uaddr2sockaddr - convert a universal address to a socket address.
|
||||
* @uaddr: C string containing universal address to convert
|
||||
* @uaddr_len: length of universal address string
|
||||
* @sap: buffer into which to plant socket address
|
||||
* @salen: size of buffer
|
||||
*
|
||||
* Returns the size of the socket address if successful; otherwise
|
||||
* zero is returned.
|
||||
*/
|
||||
size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
|
||||
struct sockaddr *sap, const size_t salen)
|
||||
{
|
||||
char *c, buf[RPCBIND_MAXUADDRLEN];
|
||||
unsigned long portlo, porthi;
|
||||
unsigned short port;
|
||||
|
||||
if (uaddr_len > sizeof(buf))
|
||||
return 0;
|
||||
|
||||
memcpy(buf, uaddr, uaddr_len);
|
||||
|
||||
buf[uaddr_len] = '\n';
|
||||
buf[uaddr_len + 1] = '\0';
|
||||
|
||||
c = strrchr(buf, '.');
|
||||
if (unlikely(c == NULL))
|
||||
return 0;
|
||||
if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0))
|
||||
return 0;
|
||||
if (unlikely(portlo > 255))
|
||||
return 0;
|
||||
|
||||
c[0] = '\n';
|
||||
c[1] = '\0';
|
||||
|
||||
c = strrchr(buf, '.');
|
||||
if (unlikely(c == NULL))
|
||||
return 0;
|
||||
if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0))
|
||||
return 0;
|
||||
if (unlikely(porthi > 255))
|
||||
return 0;
|
||||
|
||||
port = (unsigned short)((porthi << 8) | portlo);
|
||||
|
||||
c[0] = '\0';
|
||||
|
||||
if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
|
||||
return 0;
|
||||
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sap)->sin_port = htons(port);
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
|
||||
return sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);
|
@ -75,6 +75,37 @@ enum {
|
||||
#define RPCB_OWNER_STRING "0"
|
||||
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
|
||||
|
||||
/*
|
||||
* XDR data type sizes
|
||||
*/
|
||||
#define RPCB_program_sz (1)
|
||||
#define RPCB_version_sz (1)
|
||||
#define RPCB_protocol_sz (1)
|
||||
#define RPCB_port_sz (1)
|
||||
#define RPCB_boolean_sz (1)
|
||||
|
||||
#define RPCB_netid_sz (1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
|
||||
#define RPCB_addr_sz (1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
|
||||
#define RPCB_ownerstring_sz (1 + XDR_QUADLEN(RPCB_MAXOWNERLEN))
|
||||
|
||||
/*
|
||||
* XDR argument and result sizes
|
||||
*/
|
||||
#define RPCB_mappingargs_sz (RPCB_program_sz + RPCB_version_sz + \
|
||||
RPCB_protocol_sz + RPCB_port_sz)
|
||||
#define RPCB_getaddrargs_sz (RPCB_program_sz + RPCB_version_sz + \
|
||||
RPCB_netid_sz + RPCB_addr_sz + \
|
||||
RPCB_ownerstring_sz)
|
||||
|
||||
#define RPCB_getportres_sz RPCB_port_sz
|
||||
#define RPCB_setres_sz RPCB_boolean_sz
|
||||
|
||||
/*
|
||||
* Note that RFC 1833 does not put any size restrictions on the
|
||||
* address string returned by the remote rpcbind database.
|
||||
*/
|
||||
#define RPCB_getaddrres_sz RPCB_addr_sz
|
||||
|
||||
static void rpcb_getport_done(struct rpc_task *, void *);
|
||||
static void rpcb_map_release(void *data);
|
||||
static struct rpc_program rpcb_program;
|
||||
@ -122,6 +153,7 @@ static void rpcb_map_release(void *data)
|
||||
|
||||
rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status);
|
||||
xprt_put(map->r_xprt);
|
||||
kfree(map->r_addr);
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
@ -268,12 +300,9 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
|
||||
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
|
||||
struct rpcbind_args *map = msg->rpc_argp;
|
||||
unsigned short port = ntohs(sin->sin_port);
|
||||
char buf[32];
|
||||
int result;
|
||||
|
||||
/* Construct AF_INET universal address */
|
||||
snprintf(buf, sizeof(buf), "%pI4.%u.%u",
|
||||
&sin->sin_addr.s_addr, port >> 8, port & 0xff);
|
||||
map->r_addr = buf;
|
||||
map->r_addr = rpc_sockaddr2uaddr(sap);
|
||||
|
||||
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
|
||||
"local rpcbind\n", (port ? "" : "un"),
|
||||
@ -284,7 +313,9 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
|
||||
if (port)
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
||||
|
||||
return rpcb_register_call(RPCBVERS_4, msg);
|
||||
result = rpcb_register_call(RPCBVERS_4, msg);
|
||||
kfree(map->r_addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -296,16 +327,9 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
|
||||
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
|
||||
struct rpcbind_args *map = msg->rpc_argp;
|
||||
unsigned short port = ntohs(sin6->sin6_port);
|
||||
char buf[64];
|
||||
int result;
|
||||
|
||||
/* Construct AF_INET6 universal address */
|
||||
if (ipv6_addr_any(&sin6->sin6_addr))
|
||||
snprintf(buf, sizeof(buf), "::.%u.%u",
|
||||
port >> 8, port & 0xff);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%pI6.%u.%u",
|
||||
&sin6->sin6_addr, port >> 8, port & 0xff);
|
||||
map->r_addr = buf;
|
||||
map->r_addr = rpc_sockaddr2uaddr(sap);
|
||||
|
||||
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
|
||||
"local rpcbind\n", (port ? "" : "un"),
|
||||
@ -316,7 +340,9 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
|
||||
if (port)
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
||||
|
||||
return rpcb_register_call(RPCBVERS_4, msg);
|
||||
result = rpcb_register_call(RPCBVERS_4, msg);
|
||||
kfree(map->r_addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
|
||||
@ -428,7 +454,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT],
|
||||
.rpc_argp = &map,
|
||||
.rpc_resp = &map.r_port,
|
||||
.rpc_resp = &map,
|
||||
};
|
||||
struct rpc_clnt *rpcb_clnt;
|
||||
int status;
|
||||
@ -458,7 +484,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = proc,
|
||||
.rpc_argp = map,
|
||||
.rpc_resp = &map->r_port,
|
||||
.rpc_resp = map,
|
||||
};
|
||||
struct rpc_task_setup task_setup_data = {
|
||||
.rpc_client = rpcb_clnt,
|
||||
@ -539,6 +565,7 @@ void rpcb_getport_async(struct rpc_task *task)
|
||||
goto bailout_nofree;
|
||||
}
|
||||
|
||||
/* Parent transport's destination address */
|
||||
salen = rpc_peeraddr(clnt, sap, sizeof(addr));
|
||||
|
||||
/* Don't ever use rpcbind v2 for AF_INET6 requests */
|
||||
@ -589,11 +616,22 @@ void rpcb_getport_async(struct rpc_task *task)
|
||||
map->r_prot = xprt->prot;
|
||||
map->r_port = 0;
|
||||
map->r_xprt = xprt_get(xprt);
|
||||
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
|
||||
map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
|
||||
map->r_owner = "";
|
||||
map->r_status = -EIO;
|
||||
|
||||
switch (bind_version) {
|
||||
case RPCBVERS_4:
|
||||
case RPCBVERS_3:
|
||||
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
|
||||
map->r_addr = rpc_sockaddr2uaddr(sap);
|
||||
map->r_owner = "";
|
||||
break;
|
||||
case RPCBVERS_2:
|
||||
map->r_addr = NULL;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
child = rpcb_call_async(rpcb_clnt, map, proc);
|
||||
rpc_release_client(rpcb_clnt);
|
||||
if (IS_ERR(child)) {
|
||||
@ -656,176 +694,278 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
|
||||
* XDR functions for rpcbind
|
||||
*/
|
||||
|
||||
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
|
||||
struct rpcbind_args *rpcb)
|
||||
static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p,
|
||||
const struct rpcbind_args *rpcb)
|
||||
{
|
||||
dprintk("RPC: encoding rpcb request (%u, %u, %d, %u)\n",
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
|
||||
dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name,
|
||||
rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
|
||||
p = xdr_reserve_space(&xdr, sizeof(__be32) * RPCB_mappingargs_sz);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
*p++ = htonl(rpcb->r_prog);
|
||||
*p++ = htonl(rpcb->r_vers);
|
||||
*p++ = htonl(rpcb->r_prot);
|
||||
*p++ = htonl(rpcb->r_port);
|
||||
*p = htonl(rpcb->r_port);
|
||||
|
||||
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
|
||||
unsigned short *portp)
|
||||
static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p,
|
||||
struct rpcbind_args *rpcb)
|
||||
{
|
||||
*portp = (unsigned short) ntohl(*p++);
|
||||
dprintk("RPC: rpcb getport result: %u\n",
|
||||
*portp);
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
unsigned long port;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
|
||||
rpcb->r_port = 0;
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
port = ntohl(*p);
|
||||
dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
|
||||
task->tk_msg.rpc_proc->p_name, port);
|
||||
if (unlikely(port > USHORT_MAX))
|
||||
return -EIO;
|
||||
|
||||
rpcb->r_port = port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
|
||||
unsigned int *boolp)
|
||||
static int rpcb_dec_set(struct rpc_rqst *req, __be32 *p,
|
||||
unsigned int *boolp)
|
||||
{
|
||||
*boolp = (unsigned int) ntohl(*p++);
|
||||
dprintk("RPC: rpcb set/unset call %s\n",
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
*boolp = 0;
|
||||
if (*p)
|
||||
*boolp = 1;
|
||||
|
||||
dprintk("RPC: %5u RPCB_%s call %s\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name,
|
||||
(*boolp ? "succeeded" : "failed"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
struct rpcbind_args *rpcb)
|
||||
static int encode_rpcb_string(struct xdr_stream *xdr, const char *string,
|
||||
const u32 maxstrlen)
|
||||
{
|
||||
dprintk("RPC: encoding rpcb request (%u, %u, %s)\n",
|
||||
rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
|
||||
*p++ = htonl(rpcb->r_prog);
|
||||
*p++ = htonl(rpcb->r_vers);
|
||||
u32 len;
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_encode_string(p, rpcb->r_netid);
|
||||
p = xdr_encode_string(p, rpcb->r_addr);
|
||||
p = xdr_encode_string(p, rpcb->r_owner);
|
||||
if (unlikely(string == NULL))
|
||||
return -EIO;
|
||||
len = strlen(string);
|
||||
if (unlikely(len > maxstrlen))
|
||||
return -EIO;
|
||||
|
||||
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
|
||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
xdr_encode_opaque(p, string, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
unsigned short *portp)
|
||||
static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
const struct rpcbind_args *rpcb)
|
||||
{
|
||||
char *addr;
|
||||
u32 addr_len;
|
||||
int c, i, f, first, val;
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
|
||||
*portp = 0;
|
||||
addr_len = ntohl(*p++);
|
||||
dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name,
|
||||
rpcb->r_prog, rpcb->r_vers,
|
||||
rpcb->r_netid, rpcb->r_addr);
|
||||
|
||||
if (addr_len == 0) {
|
||||
dprintk("RPC: rpcb_decode_getaddr: "
|
||||
"service is not registered\n");
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
|
||||
p = xdr_reserve_space(&xdr,
|
||||
sizeof(__be32) * (RPCB_program_sz + RPCB_version_sz));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
*p++ = htonl(rpcb->r_prog);
|
||||
*p = htonl(rpcb->r_vers);
|
||||
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN))
|
||||
return -EIO;
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN))
|
||||
return -EIO;
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_owner, RPCB_MAXOWNERLEN))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
struct rpcbind_args *rpcb)
|
||||
{
|
||||
struct sockaddr_storage address;
|
||||
struct sockaddr *sap = (struct sockaddr *)&address;
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
u32 len;
|
||||
|
||||
rpcb->r_port = 0;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
if (unlikely(p == NULL))
|
||||
goto out_fail;
|
||||
len = ntohl(*p);
|
||||
|
||||
/*
|
||||
* If the returned universal address is a null string,
|
||||
* the requested RPC service was not registered.
|
||||
*/
|
||||
if (len == 0) {
|
||||
dprintk("RPC: %5u RPCB reply: program not registered\n",
|
||||
task->tk_pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple sanity check.
|
||||
*/
|
||||
if (addr_len > RPCBIND_MAXUADDRLEN)
|
||||
goto out_err;
|
||||
if (unlikely(len > RPCBIND_MAXUADDRLEN))
|
||||
goto out_fail;
|
||||
|
||||
/*
|
||||
* Start at the end and walk backwards until the first dot
|
||||
* is encountered. When the second dot is found, we have
|
||||
* both parts of the port number.
|
||||
*/
|
||||
addr = (char *)p;
|
||||
val = 0;
|
||||
first = 1;
|
||||
f = 1;
|
||||
for (i = addr_len - 1; i > 0; i--) {
|
||||
c = addr[i];
|
||||
if (c >= '0' && c <= '9') {
|
||||
val += (c - '0') * f;
|
||||
f *= 10;
|
||||
} else if (c == '.') {
|
||||
if (first) {
|
||||
*portp = val;
|
||||
val = first = 0;
|
||||
f = 1;
|
||||
} else {
|
||||
*portp |= (val << 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = xdr_inline_decode(&xdr, len);
|
||||
if (unlikely(p == NULL))
|
||||
goto out_fail;
|
||||
dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid,
|
||||
task->tk_msg.rpc_proc->p_name, (char *)p);
|
||||
|
||||
/*
|
||||
* Simple sanity check. If we never saw a dot in the reply,
|
||||
* then this was probably just garbage.
|
||||
*/
|
||||
if (first)
|
||||
goto out_err;
|
||||
if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0)
|
||||
goto out_fail;
|
||||
rpcb->r_port = rpc_get_port(sap);
|
||||
|
||||
dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
dprintk("RPC: rpcbind server returned malformed reply\n");
|
||||
out_fail:
|
||||
dprintk("RPC: %5u malformed RPCB_%s reply\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#define RPCB_program_sz (1u)
|
||||
#define RPCB_version_sz (1u)
|
||||
#define RPCB_protocol_sz (1u)
|
||||
#define RPCB_port_sz (1u)
|
||||
#define RPCB_boolean_sz (1u)
|
||||
|
||||
#define RPCB_netid_sz (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
|
||||
#define RPCB_addr_sz (1+XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
|
||||
#define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
|
||||
|
||||
#define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \
|
||||
RPCB_protocol_sz+RPCB_port_sz
|
||||
#define RPCB_getaddrargs_sz RPCB_program_sz+RPCB_version_sz+ \
|
||||
RPCB_netid_sz+RPCB_addr_sz+ \
|
||||
RPCB_ownerstring_sz
|
||||
|
||||
#define RPCB_setres_sz RPCB_boolean_sz
|
||||
#define RPCB_getportres_sz RPCB_port_sz
|
||||
|
||||
/*
|
||||
* Note that RFC 1833 does not put any size restrictions on the
|
||||
* address string returned by the remote rpcbind database.
|
||||
*/
|
||||
#define RPCB_getaddrres_sz RPCB_addr_sz
|
||||
|
||||
#define PROC(proc, argtype, restype) \
|
||||
[RPCBPROC_##proc] = { \
|
||||
.p_proc = RPCBPROC_##proc, \
|
||||
.p_encode = (kxdrproc_t) rpcb_encode_##argtype, \
|
||||
.p_decode = (kxdrproc_t) rpcb_decode_##restype, \
|
||||
.p_arglen = RPCB_##argtype##args_sz, \
|
||||
.p_replen = RPCB_##restype##res_sz, \
|
||||
.p_statidx = RPCBPROC_##proc, \
|
||||
.p_timer = 0, \
|
||||
.p_name = #proc, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Not all rpcbind procedures described in RFC 1833 are implemented
|
||||
* since the Linux kernel RPC code requires only these.
|
||||
*/
|
||||
|
||||
static struct rpc_procinfo rpcb_procedures2[] = {
|
||||
PROC(SET, mapping, set),
|
||||
PROC(UNSET, mapping, set),
|
||||
PROC(GETPORT, mapping, getport),
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
.p_timer = 0,
|
||||
.p_name = "SET",
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
.p_timer = 0,
|
||||
.p_name = "UNSET",
|
||||
},
|
||||
[RPCBPROC_GETPORT] = {
|
||||
.p_proc = RPCBPROC_GETPORT,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getport,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_getportres_sz,
|
||||
.p_statidx = RPCBPROC_GETPORT,
|
||||
.p_timer = 0,
|
||||
.p_name = "GETPORT",
|
||||
},
|
||||
};
|
||||
|
||||
static struct rpc_procinfo rpcb_procedures3[] = {
|
||||
PROC(SET, getaddr, set),
|
||||
PROC(UNSET, getaddr, set),
|
||||
PROC(GETADDR, getaddr, getaddr),
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
.p_timer = 0,
|
||||
.p_name = "SET",
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
.p_timer = 0,
|
||||
.p_name = "UNSET",
|
||||
},
|
||||
[RPCBPROC_GETADDR] = {
|
||||
.p_proc = RPCBPROC_GETADDR,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getaddr,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_getaddrres_sz,
|
||||
.p_statidx = RPCBPROC_GETADDR,
|
||||
.p_timer = 0,
|
||||
.p_name = "GETADDR",
|
||||
},
|
||||
};
|
||||
|
||||
static struct rpc_procinfo rpcb_procedures4[] = {
|
||||
PROC(SET, getaddr, set),
|
||||
PROC(UNSET, getaddr, set),
|
||||
PROC(GETADDR, getaddr, getaddr),
|
||||
PROC(GETVERSADDR, getaddr, getaddr),
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
.p_timer = 0,
|
||||
.p_name = "SET",
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
.p_timer = 0,
|
||||
.p_name = "UNSET",
|
||||
},
|
||||
[RPCBPROC_GETADDR] = {
|
||||
.p_proc = RPCBPROC_GETADDR,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getaddr,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_getaddrres_sz,
|
||||
.p_statidx = RPCBPROC_GETADDR,
|
||||
.p_timer = 0,
|
||||
.p_name = "GETADDR",
|
||||
},
|
||||
};
|
||||
|
||||
static struct rpcb_info rpcb_next_version[] = {
|
||||
|
@ -25,8 +25,13 @@
|
||||
#define RPC_RTO_INIT (HZ/5)
|
||||
#define RPC_RTO_MIN (HZ/10)
|
||||
|
||||
void
|
||||
rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
|
||||
/**
|
||||
* rpc_init_rtt - Initialize an RPC RTT estimator context
|
||||
* @rt: context to initialize
|
||||
* @timeo: initial timeout value, in jiffies
|
||||
*
|
||||
*/
|
||||
void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
|
||||
{
|
||||
unsigned long init = 0;
|
||||
unsigned i;
|
||||
@ -43,12 +48,16 @@ rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_init_rtt);
|
||||
|
||||
/*
|
||||
/**
|
||||
* rpc_update_rtt - Update an RPC RTT estimator context
|
||||
* @rt: context to update
|
||||
* @timer: timer array index (request type)
|
||||
* @m: recent actual RTT, in jiffies
|
||||
*
|
||||
* NB: When computing the smoothed RTT and standard deviation,
|
||||
* be careful not to produce negative intermediate results.
|
||||
*/
|
||||
void
|
||||
rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
|
||||
void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
|
||||
{
|
||||
long *srtt, *sdrtt;
|
||||
|
||||
@ -79,21 +88,25 @@ rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_update_rtt);
|
||||
|
||||
/*
|
||||
* Estimate rto for an nfs rpc sent via. an unreliable datagram.
|
||||
* Use the mean and mean deviation of rtt for the appropriate type of rpc
|
||||
* for the frequent rpcs and a default for the others.
|
||||
* The justification for doing "other" this way is that these rpcs
|
||||
* happen so infrequently that timer est. would probably be stale.
|
||||
* Also, since many of these rpcs are
|
||||
* non-idempotent, a conservative timeout is desired.
|
||||
/**
|
||||
* rpc_calc_rto - Provide an estimated timeout value
|
||||
* @rt: context to use for calculation
|
||||
* @timer: timer array index (request type)
|
||||
*
|
||||
* Estimate RTO for an NFS RPC sent via an unreliable datagram. Use
|
||||
* the mean and mean deviation of RTT for the appropriate type of RPC
|
||||
* for frequently issued RPCs, and a fixed default for the others.
|
||||
*
|
||||
* The justification for doing "other" this way is that these RPCs
|
||||
* happen so infrequently that timer estimation would probably be
|
||||
* stale. Also, since many of these RPCs are non-idempotent, a
|
||||
* conservative timeout is desired.
|
||||
*
|
||||
* getattr, lookup,
|
||||
* read, write, commit - A+4D
|
||||
* other - timeo
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
|
||||
unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
|
@ -168,47 +168,25 @@ static struct rpc_xprt_ops xprt_rdma_procs; /* forward reference */
|
||||
static void
|
||||
xprt_rdma_format_addresses(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)
|
||||
struct sockaddr *sap = (struct sockaddr *)
|
||||
&rpcx_to_rdmad(xprt).addr;
|
||||
char *buf;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sap;
|
||||
char buf[64];
|
||||
|
||||
buf = kzalloc(20, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr);
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
|
||||
(void)rpc_ntop(sap, buf, sizeof(buf));
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 8, "%u", ntohs(addr->sin_port));
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = buf;
|
||||
(void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap));
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO] = "rdma";
|
||||
|
||||
buf = kzalloc(48, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 48, "addr=%pI4 port=%u proto=%s",
|
||||
&addr->sin_addr.s_addr,
|
||||
ntohs(addr->sin_port), "rdma");
|
||||
xprt->address_strings[RPC_DISPLAY_ALL] = buf;
|
||||
(void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x",
|
||||
NIPQUAD(sin->sin_addr.s_addr));
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
buf = kzalloc(10, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 10, "%02x%02x%02x%02x",
|
||||
NIPQUAD(addr->sin_addr.s_addr));
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 8, "%4hx", ntohs(addr->sin_port));
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
|
||||
|
||||
buf = kzalloc(30, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 30, "%pI4.%u.%u",
|
||||
&addr->sin_addr.s_addr,
|
||||
ntohs(addr->sin_port) >> 8,
|
||||
ntohs(addr->sin_port) & 0xff);
|
||||
xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
|
||||
(void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap));
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
/* netid */
|
||||
xprt->address_strings[RPC_DISPLAY_NETID] = "rdma";
|
||||
|
@ -248,8 +248,8 @@ struct sock_xprt {
|
||||
* Connection of transports
|
||||
*/
|
||||
struct delayed_work connect_worker;
|
||||
struct sockaddr_storage addr;
|
||||
unsigned short port;
|
||||
struct sockaddr_storage srcaddr;
|
||||
unsigned short srcport;
|
||||
|
||||
/*
|
||||
* UDP socket buffer size parameters
|
||||
@ -296,117 +296,60 @@ static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt)
|
||||
return (struct sockaddr_in6 *) &xprt->addr;
|
||||
}
|
||||
|
||||
static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt,
|
||||
const char *protocol,
|
||||
const char *netid)
|
||||
static void xs_format_common_peer_addresses(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sockaddr_in *addr = xs_addr_in(xprt);
|
||||
char *buf;
|
||||
struct sockaddr *sap = xs_addr(xprt);
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct sockaddr_in *sin;
|
||||
char buf[128];
|
||||
|
||||
buf = kzalloc(20, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr);
|
||||
(void)rpc_ntop(sap, buf, sizeof(buf));
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
sin = xs_addr_in(xprt);
|
||||
(void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x",
|
||||
NIPQUAD(sin->sin_addr.s_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
sin6 = xs_addr_in6(xprt);
|
||||
(void)snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 8, "%u",
|
||||
ntohs(addr->sin_port));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = buf;
|
||||
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO] = protocol;
|
||||
|
||||
buf = kzalloc(48, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 48, "addr=%pI4 port=%u proto=%s",
|
||||
&addr->sin_addr.s_addr,
|
||||
ntohs(addr->sin_port),
|
||||
protocol);
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ALL] = buf;
|
||||
|
||||
buf = kzalloc(10, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 10, "%02x%02x%02x%02x",
|
||||
NIPQUAD(addr->sin_addr.s_addr));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 8, "%4hx",
|
||||
ntohs(addr->sin_port));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
|
||||
|
||||
buf = kzalloc(30, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 30, "%pI4.%u.%u",
|
||||
&addr->sin_addr.s_addr,
|
||||
ntohs(addr->sin_port) >> 8,
|
||||
ntohs(addr->sin_port) & 0xff);
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
|
||||
|
||||
xprt->address_strings[RPC_DISPLAY_NETID] = netid;
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt,
|
||||
const char *protocol,
|
||||
const char *netid)
|
||||
static void xs_format_common_peer_ports(struct rpc_xprt *xprt)
|
||||
{
|
||||
struct sockaddr_in6 *addr = xs_addr_in6(xprt);
|
||||
char *buf;
|
||||
struct sockaddr *sap = xs_addr(xprt);
|
||||
char buf[128];
|
||||
|
||||
buf = kzalloc(40, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 40, "%pI6",&addr->sin6_addr);
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
|
||||
(void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap));
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 8, "%u",
|
||||
ntohs(addr->sin6_port));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_PORT] = buf;
|
||||
(void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap));
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void xs_format_peer_addresses(struct rpc_xprt *xprt,
|
||||
const char *protocol,
|
||||
const char *netid)
|
||||
{
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO] = protocol;
|
||||
|
||||
buf = kzalloc(64, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 64, "addr=%pI6 port=%u proto=%s",
|
||||
&addr->sin6_addr,
|
||||
ntohs(addr->sin6_port),
|
||||
protocol);
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_ALL] = buf;
|
||||
|
||||
buf = kzalloc(36, GFP_KERNEL);
|
||||
if (buf)
|
||||
snprintf(buf, 36, "%pi6", &addr->sin6_addr);
|
||||
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
|
||||
|
||||
buf = kzalloc(8, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 8, "%4hx",
|
||||
ntohs(addr->sin6_port));
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
|
||||
|
||||
buf = kzalloc(50, GFP_KERNEL);
|
||||
if (buf) {
|
||||
snprintf(buf, 50, "%pI6.%u.%u",
|
||||
&addr->sin6_addr,
|
||||
ntohs(addr->sin6_port) >> 8,
|
||||
ntohs(addr->sin6_port) & 0xff);
|
||||
}
|
||||
xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
|
||||
|
||||
xprt->address_strings[RPC_DISPLAY_NETID] = netid;
|
||||
xs_format_common_peer_addresses(xprt);
|
||||
xs_format_common_peer_ports(xprt);
|
||||
}
|
||||
|
||||
static void xs_update_peer_port(struct rpc_xprt *xprt)
|
||||
{
|
||||
kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
|
||||
kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
|
||||
|
||||
xs_format_common_peer_ports(xprt);
|
||||
}
|
||||
|
||||
static void xs_free_peer_addresses(struct rpc_xprt *xprt)
|
||||
@ -1587,25 +1530,15 @@ static unsigned short xs_get_random_port(void)
|
||||
*/
|
||||
static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
|
||||
{
|
||||
struct sockaddr *addr = xs_addr(xprt);
|
||||
|
||||
dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)addr)->sin_port = htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
rpc_set_port(xs_addr(xprt), port);
|
||||
xs_update_peer_port(xprt);
|
||||
}
|
||||
|
||||
static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
|
||||
{
|
||||
unsigned short port = transport->port;
|
||||
unsigned short port = transport->srcport;
|
||||
|
||||
if (port == 0 && transport->xprt.resvport)
|
||||
port = xs_get_random_port();
|
||||
@ -1614,8 +1547,8 @@ static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket
|
||||
|
||||
static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
|
||||
{
|
||||
if (transport->port != 0)
|
||||
transport->port = 0;
|
||||
if (transport->srcport != 0)
|
||||
transport->srcport = 0;
|
||||
if (!transport->xprt.resvport)
|
||||
return 0;
|
||||
if (port <= xprt_min_resvport || port > xprt_max_resvport)
|
||||
@ -1633,7 +1566,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
|
||||
unsigned short port = xs_get_srcport(transport, sock);
|
||||
unsigned short last;
|
||||
|
||||
sa = (struct sockaddr_in *)&transport->addr;
|
||||
sa = (struct sockaddr_in *)&transport->srcaddr;
|
||||
myaddr.sin_addr = sa->sin_addr;
|
||||
do {
|
||||
myaddr.sin_port = htons(port);
|
||||
@ -1642,7 +1575,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
|
||||
if (port == 0)
|
||||
break;
|
||||
if (err == 0) {
|
||||
transport->port = port;
|
||||
transport->srcport = port;
|
||||
break;
|
||||
}
|
||||
last = port;
|
||||
@ -1666,7 +1599,7 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
|
||||
unsigned short port = xs_get_srcport(transport, sock);
|
||||
unsigned short last;
|
||||
|
||||
sa = (struct sockaddr_in6 *)&transport->addr;
|
||||
sa = (struct sockaddr_in6 *)&transport->srcaddr;
|
||||
myaddr.sin6_addr = sa->sin6_addr;
|
||||
do {
|
||||
myaddr.sin6_port = htons(port);
|
||||
@ -1675,7 +1608,7 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
|
||||
if (port == 0)
|
||||
break;
|
||||
if (err == 0) {
|
||||
transport->port = port;
|
||||
transport->srcport = port;
|
||||
break;
|
||||
}
|
||||
last = port;
|
||||
@ -1780,8 +1713,11 @@ static void xs_udp_connect_worker4(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("RPC: worker connecting xprt %p to address: %s\n",
|
||||
xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
dprintk("RPC: worker connecting xprt %p via %s to "
|
||||
"%s (port %s)\n", xprt,
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO],
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PORT]);
|
||||
|
||||
xs_udp_finish_connecting(xprt, sock);
|
||||
status = 0;
|
||||
@ -1822,8 +1758,11 @@ static void xs_udp_connect_worker6(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("RPC: worker connecting xprt %p to address: %s\n",
|
||||
xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
dprintk("RPC: worker connecting xprt %p via %s to "
|
||||
"%s (port %s)\n", xprt,
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO],
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PORT]);
|
||||
|
||||
xs_udp_finish_connecting(xprt, sock);
|
||||
status = 0;
|
||||
@ -1948,8 +1887,11 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
|
||||
goto out_eagain;
|
||||
}
|
||||
|
||||
dprintk("RPC: worker connecting xprt %p to address: %s\n",
|
||||
xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
dprintk("RPC: worker connecting xprt %p via %s to "
|
||||
"%s (port %s)\n", xprt,
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO],
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PORT]);
|
||||
|
||||
status = xs_tcp_finish_connecting(xprt, sock);
|
||||
dprintk("RPC: %p connect status %d connected %d sock state %d\n",
|
||||
@ -2120,7 +2062,7 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
|
||||
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
|
||||
|
||||
seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
|
||||
transport->port,
|
||||
transport->srcport,
|
||||
xprt->stat.bind_count,
|
||||
xprt->stat.sends,
|
||||
xprt->stat.recvs,
|
||||
@ -2144,7 +2086,7 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
|
||||
idle_time = (long)(jiffies - xprt->last_used) / HZ;
|
||||
|
||||
seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
|
||||
transport->port,
|
||||
transport->srcport,
|
||||
xprt->stat.bind_count,
|
||||
xprt->stat.connect_count,
|
||||
xprt->stat.connect_time,
|
||||
@ -2223,7 +2165,7 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
|
||||
memcpy(&xprt->addr, args->dstaddr, args->addrlen);
|
||||
xprt->addrlen = args->addrlen;
|
||||
if (args->srcaddr)
|
||||
memcpy(&new->addr, args->srcaddr, args->addrlen);
|
||||
memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
|
||||
|
||||
return xprt;
|
||||
}
|
||||
@ -2272,7 +2214,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
|
||||
|
||||
INIT_DELAYED_WORK(&transport->connect_worker,
|
||||
xs_udp_connect_worker4);
|
||||
xs_format_ipv4_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
|
||||
xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
|
||||
@ -2280,15 +2222,22 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
|
||||
|
||||
INIT_DELAYED_WORK(&transport->connect_worker,
|
||||
xs_udp_connect_worker6);
|
||||
xs_format_ipv6_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
|
||||
xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
|
||||
break;
|
||||
default:
|
||||
kfree(xprt);
|
||||
return ERR_PTR(-EAFNOSUPPORT);
|
||||
}
|
||||
|
||||
dprintk("RPC: set up transport to address %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
if (xprt_bound(xprt))
|
||||
dprintk("RPC: set up xprt to %s (port %s) via %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PORT],
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]);
|
||||
else
|
||||
dprintk("RPC: set up xprt to %s (autobind) via %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]);
|
||||
|
||||
if (try_module_get(THIS_MODULE))
|
||||
return xprt;
|
||||
@ -2337,23 +2286,33 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
|
||||
if (((struct sockaddr_in *)addr)->sin_port != htons(0))
|
||||
xprt_set_bound(xprt);
|
||||
|
||||
INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4);
|
||||
xs_format_ipv4_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
|
||||
INIT_DELAYED_WORK(&transport->connect_worker,
|
||||
xs_tcp_connect_worker4);
|
||||
xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
|
||||
xprt_set_bound(xprt);
|
||||
|
||||
INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6);
|
||||
xs_format_ipv6_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
|
||||
INIT_DELAYED_WORK(&transport->connect_worker,
|
||||
xs_tcp_connect_worker6);
|
||||
xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
|
||||
break;
|
||||
default:
|
||||
kfree(xprt);
|
||||
return ERR_PTR(-EAFNOSUPPORT);
|
||||
}
|
||||
|
||||
dprintk("RPC: set up transport to address %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ALL]);
|
||||
if (xprt_bound(xprt))
|
||||
dprintk("RPC: set up xprt to %s (port %s) via %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PORT],
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]);
|
||||
else
|
||||
dprintk("RPC: set up xprt to %s (autobind) via %s\n",
|
||||
xprt->address_strings[RPC_DISPLAY_ADDR],
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]);
|
||||
|
||||
|
||||
if (try_module_get(THIS_MODULE))
|
||||
return xprt;
|
||||
|
Loading…
Reference in New Issue
Block a user