fs/nfs: Support both IPv6 and TCP
And correctly handle the retransmission
This commit is contained in:
parent
6c77829940
commit
7794214a7d
8 changed files with 278 additions and 269 deletions
|
|
@ -6,7 +6,7 @@
|
|||
config NFS
|
||||
bool "NFS client file system"
|
||||
default n
|
||||
depends on NET_UDP && NET_IPv4 && !DISABLE_MOUNTPOINT
|
||||
depends on !DISABLE_MOUNTPOINT
|
||||
select FS_READABLE
|
||||
select FS_WRITABLE
|
||||
---help---
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
#define NFS_RETRANS 10 /* Num of retrans for soft mounts */
|
||||
#define NFS_WSIZE 8192 /* Def. write data size <= 8192 */
|
||||
#define NFS_RSIZE 8192 /* Def. read data size <= 8192 */
|
||||
#define NFS_READDIRSIZE 8192 /* Def. readdir size */
|
||||
#define NFS_READDIRSIZE 1024 /* Def. readdir size */
|
||||
|
||||
/* Ideally, NFS_DIRBLKSIZ should be bigger, but I've seen servers with
|
||||
* broken NFS/ethernet drivers that won't work with anything bigger (Linux..)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ struct nfsmount
|
|||
char nm_path[90]; /* server's path of the directory being mounted */
|
||||
struct nfs_fattr nm_fattr; /* nfs file attribute cache */
|
||||
FAR struct rpcclnt *nm_rpcclnt; /* RPC state */
|
||||
struct sockaddr nm_nam; /* Addr of server */
|
||||
struct sockaddr_storage nm_nam; /* Addr of server */
|
||||
uint8_t nm_fhsize; /* Size of root file handle (host order) */
|
||||
uint16_t nm_rsize; /* Max size of read RPC */
|
||||
uint16_t nm_wsize; /* Max size of write RPC */
|
||||
|
|
@ -87,8 +87,6 @@ struct nfsmount
|
|||
|
||||
union
|
||||
{
|
||||
struct rpc_call_pmap pmap;
|
||||
struct rpc_call_mount mountd;
|
||||
struct rpc_call_create create;
|
||||
struct rpc_call_lookup lookup;
|
||||
struct rpc_call_read read;
|
||||
|
|
|
|||
|
|
@ -149,18 +149,9 @@ int nfs_request(FAR struct nfsmount *nmp, int procnum,
|
|||
|
||||
if (replyh.nfs_status != 0)
|
||||
{
|
||||
if (fxdr_unsigned(uint32_t, replyh.nfs_status) > 32)
|
||||
{
|
||||
error = -EOPNOTSUPP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NFS_ERRORS are the same as NuttX errno values */
|
||||
/* NFS_ERRORS are the same as NuttX errno values */
|
||||
|
||||
error = -fxdr_unsigned(uint32_t, replyh.nfs_status);
|
||||
}
|
||||
|
||||
return error;
|
||||
return -fxdr_unsigned(uint32_t, replyh.nfs_status);
|
||||
}
|
||||
|
||||
if (replyh.rh.rpc_verfi.authtype != 0)
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@
|
|||
#include <nuttx/fs/dirent.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/fs/nfs.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
#include <nuttx/net/netconfig.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
|
@ -1634,16 +1632,20 @@ static void nfs_decode_args(FAR struct nfs_mount_parameters *nprmt,
|
|||
|
||||
/* Get the maximum amount of data that can be transferred in one packet */
|
||||
|
||||
if ((argp->sotype == SOCK_DGRAM) != 0)
|
||||
if (argp->sotype == SOCK_DGRAM)
|
||||
{
|
||||
maxio = NFS_MAXDGRAMDATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
ferr("ERROR: Only SOCK_DRAM is supported\n");
|
||||
maxio = NFS_MAXDATA;
|
||||
}
|
||||
|
||||
if (maxio > MAXBSIZE)
|
||||
{
|
||||
maxio = MAXBSIZE;
|
||||
}
|
||||
|
||||
/* Get the maximum amount of data that can be transferred in one write transfer */
|
||||
|
||||
if ((argp->flags & NFSMNT_WSIZE) != 0 && argp->wsize > 0)
|
||||
|
|
@ -1664,11 +1666,6 @@ static void nfs_decode_args(FAR struct nfs_mount_parameters *nprmt,
|
|||
nprmt->wsize = maxio;
|
||||
}
|
||||
|
||||
if (nprmt->wsize > MAXBSIZE)
|
||||
{
|
||||
nprmt->wsize = MAXBSIZE;
|
||||
}
|
||||
|
||||
/* Get the maximum amount of data that can be transferred in one read transfer */
|
||||
|
||||
if ((argp->flags & NFSMNT_RSIZE) != 0 && argp->rsize > 0)
|
||||
|
|
@ -1689,11 +1686,6 @@ static void nfs_decode_args(FAR struct nfs_mount_parameters *nprmt,
|
|||
nprmt->rsize = maxio;
|
||||
}
|
||||
|
||||
if (nprmt->rsize > MAXBSIZE)
|
||||
{
|
||||
nprmt->rsize = MAXBSIZE;
|
||||
}
|
||||
|
||||
/* Get the maximum amount of data that can be transferred in directory transfer */
|
||||
|
||||
if ((argp->flags & NFSMNT_READDIRSIZE) != 0 && argp->readdirsize > 0)
|
||||
|
|
@ -1767,6 +1759,14 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|||
|
||||
/* The buffer size will be the maximum of those two sizes */
|
||||
|
||||
if (tmp > buflen)
|
||||
{
|
||||
buflen = tmp;
|
||||
}
|
||||
|
||||
/* And consider the maximum size of a read dir transfer too */
|
||||
|
||||
tmp = SIZEOF_rpc_reply_readdir(nprmt.readdirsize);
|
||||
if (tmp > buflen)
|
||||
{
|
||||
buflen = tmp;
|
||||
|
|
@ -1780,9 +1780,9 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|||
* that case.
|
||||
*/
|
||||
|
||||
if (buflen > MIN_IPv4_UDP_MSS)
|
||||
if (argp->sotype == SOCK_DGRAM && buflen > MIN_UDP_MSS)
|
||||
{
|
||||
buflen = MIN_IPv4_UDP_MSS;
|
||||
buflen = MIN_UDP_MSS;
|
||||
}
|
||||
|
||||
/* Create an instance of the mountpt state structure */
|
||||
|
|
@ -1824,43 +1824,36 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|||
strncpy(nmp->nm_path, argp->path, 90);
|
||||
memcpy(&nmp->nm_nam, &argp->addr, argp->addrlen);
|
||||
|
||||
/* Set up the sockets and per-host congestion */
|
||||
/* Create an instance of the rpc state structure */
|
||||
|
||||
if (argp->sotype == SOCK_DGRAM)
|
||||
rpc = (FAR struct rpcclnt *)kmm_zalloc(sizeof(struct rpcclnt));
|
||||
if (!rpc)
|
||||
{
|
||||
/* Connection-less... connect now */
|
||||
|
||||
/* Create an instance of the rpc state structure */
|
||||
|
||||
rpc = (FAR struct rpcclnt *)kmm_zalloc(sizeof(struct rpcclnt));
|
||||
if (!rpc)
|
||||
{
|
||||
ferr("ERROR: Failed to allocate rpc structure\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
finfo("Connecting\n");
|
||||
|
||||
/* Translate nfsmnt flags -> rpcclnt flags */
|
||||
|
||||
rpc->rc_path = nmp->nm_path;
|
||||
rpc->rc_name = &nmp->nm_nam;
|
||||
rpc->rc_sotype = argp->sotype;
|
||||
rpc->rc_timeo = nprmt.timeo;
|
||||
rpc->rc_retry = nprmt.retry;
|
||||
|
||||
nmp->nm_rpcclnt = rpc;
|
||||
|
||||
error = rpcclnt_connect(nmp->nm_rpcclnt);
|
||||
if (error != OK)
|
||||
{
|
||||
ferr("ERROR: nfs_connect failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
ferr("ERROR: Failed to allocate rpc structure\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nmp->nm_fhsize = nmp->nm_rpcclnt->rc_fhsize;
|
||||
nmp->nm_fh = &nmp->nm_rpcclnt->rc_fh;
|
||||
finfo("Connecting\n");
|
||||
|
||||
/* Translate nfsmnt flags -> rpcclnt flags */
|
||||
|
||||
rpc->rc_path = nmp->nm_path;
|
||||
rpc->rc_name = &nmp->nm_nam;
|
||||
rpc->rc_sotype = argp->sotype;
|
||||
rpc->rc_timeo = nprmt.timeo;
|
||||
rpc->rc_retry = nprmt.retry;
|
||||
|
||||
nmp->nm_rpcclnt = rpc;
|
||||
|
||||
error = rpcclnt_connect(nmp->nm_rpcclnt);
|
||||
if (error != OK)
|
||||
{
|
||||
ferr("ERROR: nfs_connect failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
nmp->nm_fhsize = nmp->nm_rpcclnt->rc_fhsize;
|
||||
nmp->nm_fh = &nmp->nm_rpcclnt->rc_fh;
|
||||
|
||||
/* Get the file sytem info */
|
||||
|
||||
|
|
@ -1880,22 +1873,19 @@ static int nfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|||
return OK;
|
||||
|
||||
bad:
|
||||
if (nmp)
|
||||
/* Disconnect from the server */
|
||||
|
||||
if (nmp->nm_rpcclnt)
|
||||
{
|
||||
/* Disconnect from the server */
|
||||
|
||||
if (nmp->nm_rpcclnt)
|
||||
{
|
||||
rpcclnt_disconnect(nmp->nm_rpcclnt);
|
||||
kmm_free(nmp->nm_rpcclnt);
|
||||
}
|
||||
|
||||
/* Free connection-related resources */
|
||||
|
||||
nxsem_destroy(&nmp->nm_sem);
|
||||
kmm_free(nmp);
|
||||
rpcclnt_disconnect(nmp->nm_rpcclnt);
|
||||
kmm_free(nmp->nm_rpcclnt);
|
||||
}
|
||||
|
||||
/* Free connection-related resources */
|
||||
|
||||
nxsem_destroy(&nmp->nm_sem);
|
||||
kmm_free(nmp);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -1941,14 +1931,6 @@ static int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|||
goto errout_with_semaphore;
|
||||
}
|
||||
|
||||
/* No open file... Umount the file system. */
|
||||
|
||||
error = rpcclnt_umount(nmp->nm_rpcclnt);
|
||||
if (error)
|
||||
{
|
||||
ferr("ERROR: rpcclnt_umount failed: %d\n", error);
|
||||
}
|
||||
|
||||
/* Disconnect from the server */
|
||||
|
||||
rpcclnt_disconnect(nmp->nm_rpcclnt);
|
||||
|
|
@ -1959,7 +1941,7 @@ static int nfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|||
kmm_free(nmp->nm_rpcclnt);
|
||||
kmm_free(nmp);
|
||||
|
||||
return error;
|
||||
return OK;
|
||||
|
||||
errout_with_semaphore:
|
||||
nfs_semgive(nmp);
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@
|
|||
|
||||
/* RPC definitions for the portmapper. */
|
||||
|
||||
#define PMAPPORT 111
|
||||
#define PMAPPROG 100000
|
||||
#define PMAPVERS 2
|
||||
|
||||
|
|
@ -450,12 +449,13 @@ struct rpcclnt
|
|||
uint8_t rc_fhsize; /* File size of the root directory */
|
||||
FAR char *rc_path; /* Server's path of the mounted directory */
|
||||
|
||||
FAR struct sockaddr *rc_name;
|
||||
FAR struct sockaddr_storage *rc_name;
|
||||
struct socket rc_so; /* RPC socket */
|
||||
|
||||
uint8_t rc_sotype; /* Type of socket */
|
||||
uint8_t rc_timeo; /* Timeout value (in deciseconds) */
|
||||
uint8_t rc_retry; /* Max retries */
|
||||
uint32_t rc_xid; /* Transaction id */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -465,7 +465,6 @@ struct rpcclnt
|
|||
void rpcclnt_init(void);
|
||||
int rpcclnt_connect(FAR struct rpcclnt *rpc);
|
||||
void rpcclnt_disconnect(FAR struct rpcclnt *rpc);
|
||||
int rpcclnt_umount(FAR struct rpcclnt *rpc);
|
||||
int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
|
||||
int version, FAR void *request, size_t reqlen,
|
||||
FAR void *response, size_t resplen);
|
||||
|
|
|
|||
|
|
@ -81,12 +81,9 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <queue.h>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
|
@ -143,13 +140,13 @@ static struct rpcstats rpcstats;
|
|||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int rpcclnt_socket(FAR struct rpcclnt *rpc, in_port_t rport);
|
||||
static int rpcclnt_send(FAR struct rpcclnt *rpc,
|
||||
FAR void *call, int reqlen);
|
||||
static int rpcclnt_receive(FAR struct rpcclnt *rpc,
|
||||
FAR void *reply, size_t resplen);
|
||||
static int rpcclnt_reply(FAR struct rpcclnt *rpc,
|
||||
static int rpcclnt_reply(FAR struct rpcclnt *rpc, uint32_t xid,
|
||||
FAR void *reply, size_t resplen);
|
||||
static uint32_t rpcclnt_newxid(void);
|
||||
static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
|
||||
uint32_t xid, int procid, int prog, int vers);
|
||||
|
||||
|
|
@ -157,6 +154,132 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpcclnt_socket
|
||||
*
|
||||
* Description:
|
||||
* Close(old), create, bind and connect the socket.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns zero on success or a (negative) errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rpcclnt_socket(FAR struct rpcclnt *rpc, in_port_t rport)
|
||||
{
|
||||
struct sockaddr_storage raddr;
|
||||
struct sockaddr_storage laddr;
|
||||
FAR in_port_t *lport;
|
||||
in_port_t port = 1024;
|
||||
struct timeval tv;
|
||||
socklen_t addrlen;
|
||||
int error;
|
||||
|
||||
/* Close the old socket */
|
||||
|
||||
psock_close(&rpc->rc_so);
|
||||
|
||||
/* Prepare the socket address */
|
||||
|
||||
memcpy(&raddr, rpc->rc_name, sizeof(raddr));
|
||||
|
||||
laddr.ss_family = raddr.ss_family;
|
||||
memset(laddr.ss_data, 0, sizeof(laddr.ss_data));
|
||||
|
||||
if (raddr.ss_family == AF_INET6)
|
||||
{
|
||||
FAR struct sockaddr_in6 *sin;
|
||||
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
if (rport != 0)
|
||||
{
|
||||
sin = (FAR struct sockaddr_in6 *)&raddr;
|
||||
sin->sin6_port = htons(rport);
|
||||
}
|
||||
|
||||
sin = (FAR struct sockaddr_in6 *)&laddr;
|
||||
lport = &sin->sin6_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
FAR struct sockaddr_in *sin;
|
||||
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
if (rport != 0)
|
||||
{
|
||||
sin = (FAR struct sockaddr_in *)&raddr;
|
||||
sin->sin_port = htons(rport);
|
||||
}
|
||||
|
||||
sin = (FAR struct sockaddr_in *)&laddr;
|
||||
lport = &sin->sin_port;
|
||||
}
|
||||
|
||||
/* Create the socket */
|
||||
|
||||
error = psock_socket(raddr.ss_family, rpc->rc_sotype, 0, &rpc->rc_so);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_socket failed: %d", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Always set receive timeout to detect server crash and reconnect.
|
||||
* Otherwise, we can get stuck in psock_receive forever.
|
||||
*/
|
||||
|
||||
tv.tv_sec = rpc->rc_timeo / 10;
|
||||
tv.tv_usec = (rpc->rc_timeo % 10) * 100000;
|
||||
|
||||
error = psock_setsockopt(&rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
|
||||
(FAR const void *)&tv, sizeof(tv));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_setsockopt failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Some servers require that the client port be a reserved port
|
||||
* number. We always allocate a reserved port, as this prevents
|
||||
* filehandle disclosure through UDP port capture.
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
*lport = htons(--port);
|
||||
error = psock_bind(&rpc->rc_so, (FAR struct sockaddr *)&laddr, addrlen);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_bind failed: %d\n", error);
|
||||
}
|
||||
}
|
||||
while (error == -EADDRINUSE && port >= 512);
|
||||
|
||||
if (error)
|
||||
{
|
||||
ferr("ERROR: psock_bind failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Protocols that do not require connections could be optionally left
|
||||
* unconnected. That would allow servers to reply from a port other than
|
||||
* the NFS_PORT.
|
||||
*/
|
||||
|
||||
error = psock_connect(&rpc->rc_so, (FAR struct sockaddr *)&raddr, addrlen);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect to PMAP port failed: %d", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
bad:
|
||||
psock_close(&rpc->rc_so);
|
||||
return error;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpcclnt_send
|
||||
*
|
||||
|
|
@ -171,26 +294,36 @@ static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
|
|||
static int rpcclnt_send(FAR struct rpcclnt *rpc,
|
||||
FAR void *call, int reqlen)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
uint32_t mark;
|
||||
int ret = OK;
|
||||
|
||||
/* Send the record marking(RM) for stream only */
|
||||
|
||||
if (rpc->rc_sotype == SOCK_STREAM)
|
||||
{
|
||||
mark = txdr_unsigned(0x80000000 | reqlen);
|
||||
ret = psock_send(&rpc->rc_so, &mark, sizeof(mark), 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: psock_send mark failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the call message
|
||||
*
|
||||
* On success, psock_send returns the number of bytes sent;
|
||||
* On failure, it returns a negated errno value.
|
||||
*/
|
||||
|
||||
nbytes = psock_send(&rpc->rc_so, call, reqlen, 0);
|
||||
|
||||
if (nbytes < 0)
|
||||
ret = psock_send(&rpc->rc_so, call, reqlen, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* psock_sendto failed */
|
||||
|
||||
ret = nbytes;
|
||||
ferr("ERROR: psock_sendto failed: %d\n", ret);
|
||||
ferr("ERROR: psock_send request failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -204,17 +337,45 @@ static int rpcclnt_send(FAR struct rpcclnt *rpc,
|
|||
static int rpcclnt_receive(FAR struct rpcclnt *rpc,
|
||||
FAR void *reply, size_t resplen)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
uint32_t mark;
|
||||
int error = 0;
|
||||
|
||||
nbytes = psock_recv(&rpc->rc_so, reply, resplen, 0);
|
||||
if (nbytes < 0)
|
||||
/* Receive the record marking(RM) for stream only */
|
||||
|
||||
if (rpc->rc_sotype == SOCK_STREAM)
|
||||
{
|
||||
error = nbytes;
|
||||
ferr("ERROR: psock_recv failed: %d\n", error);
|
||||
error = psock_recv(&rpc->rc_so, &mark, sizeof(mark), 0);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_recv mark failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Limit the receive length to the marked value */
|
||||
|
||||
mark = fxdr_unsigned(uint32_t, mark);
|
||||
if (!(mark & 0x80000000))
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
mark &= 0x7fffffff;
|
||||
if (mark > resplen)
|
||||
{
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
resplen = mark;
|
||||
}
|
||||
|
||||
return error;
|
||||
error = psock_recv(&rpc->rc_so, reply, resplen, 0);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_recv response failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -225,11 +386,12 @@ static int rpcclnt_receive(FAR struct rpcclnt *rpc,
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rpcclnt_reply(FAR struct rpcclnt *rpc,
|
||||
static int rpcclnt_reply(FAR struct rpcclnt *rpc, uint32_t xid,
|
||||
FAR void *reply, size_t resplen)
|
||||
{
|
||||
int error;
|
||||
|
||||
retry:
|
||||
/* Get the next RPC reply from the socket */
|
||||
|
||||
error = rpcclnt_receive(rpc, reply, resplen);
|
||||
|
|
@ -251,45 +413,17 @@ static int rpcclnt_reply(FAR struct rpcclnt *rpc,
|
|||
rpc_statistics(rpcinvalid);
|
||||
error = -EPROTO;
|
||||
}
|
||||
else if (replyheader->rp_xid != txdr_unsigned(xid))
|
||||
{
|
||||
ferr("ERROR: Different RPC XID returned\n");
|
||||
rpc_statistics(rpcinvalid);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpcclnt_newxid
|
||||
*
|
||||
* Description:
|
||||
* Get a new (non-zero) xid
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t rpcclnt_newxid(void)
|
||||
{
|
||||
static uint32_t rpcclnt_xid = 0;
|
||||
static uint32_t rpcclnt_xid_touched = 0;
|
||||
|
||||
if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0))
|
||||
{
|
||||
srand(time(NULL));
|
||||
rpcclnt_xid = rand();
|
||||
rpcclnt_xid_touched = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int xidp = 0;
|
||||
do
|
||||
{
|
||||
xidp = rand();
|
||||
}
|
||||
while ((xidp % 256) == 0);
|
||||
|
||||
rpcclnt_xid += xidp;
|
||||
}
|
||||
|
||||
return rpcclnt_xid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpcclnt_fmtheader
|
||||
*
|
||||
|
|
@ -357,9 +491,7 @@ void rpcclnt_init(void)
|
|||
int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
||||
{
|
||||
int error;
|
||||
FAR struct sockaddr *saddr;
|
||||
struct sockaddr_in sin;
|
||||
FAR struct sockaddr_in *sa;
|
||||
int prot;
|
||||
|
||||
union
|
||||
{
|
||||
|
|
@ -373,76 +505,18 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
struct rpc_reply_mount mdata;
|
||||
} response;
|
||||
|
||||
struct timeval tv;
|
||||
uint16_t tport;
|
||||
|
||||
finfo("Connecting\n");
|
||||
|
||||
/* Create the socket */
|
||||
|
||||
saddr = rpc->rc_name;
|
||||
|
||||
error = psock_socket(saddr->sa_family, rpc->rc_sotype, IPPROTO_UDP, &rpc->rc_so);
|
||||
error = rpcclnt_socket(rpc, 0);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_socket failed: %d", error);
|
||||
ferr("ERROR: rpcclnt_socket failed: %d", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Always set receive timeout to detect server crash and reconnect.
|
||||
* Otherwise, we can get stuck in psock_receive forever.
|
||||
*/
|
||||
|
||||
tv.tv_sec = rpc->rc_timeo / 10;
|
||||
tv.tv_usec = (rpc->rc_timeo % 10) * 100000;
|
||||
|
||||
error = psock_setsockopt(&rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
|
||||
(FAR const void *)&tv, sizeof(tv));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_setsockopt failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Some servers require that the client port be a reserved port
|
||||
* number. We always allocate a reserved port, as this prevents
|
||||
* filehandle disclosure through UDP port capture.
|
||||
*/
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
tport = 1024;
|
||||
|
||||
do
|
||||
{
|
||||
tport--;
|
||||
sin.sin_port = htons(tport);
|
||||
|
||||
error = psock_bind(&rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_bind failed: %d\n", error);
|
||||
}
|
||||
}
|
||||
while (error == -EADDRINUSE && tport > 1024 / 2);
|
||||
|
||||
if (error)
|
||||
{
|
||||
ferr("ERROR: psock_bind failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Protocols that do not require connections could be optionally left
|
||||
* unconnected. That would allow servers to reply from a port other than
|
||||
* the NFS_PORT.
|
||||
*/
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect to PMAP port failed: %d", error);
|
||||
goto bad;
|
||||
}
|
||||
prot = rpc->rc_sotype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
/* Do the RPC to get a dynamic bounding with the server using ppmap.
|
||||
* Get port number for MOUNTD.
|
||||
|
|
@ -450,7 +524,7 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
|
||||
request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
|
||||
request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
|
||||
request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
|
||||
request.sdata.pmap.prot = txdr_unsigned(prot);
|
||||
request.sdata.pmap.port = 0;
|
||||
|
||||
error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
|
||||
|
|
@ -462,20 +536,17 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
sa = (FAR struct sockaddr_in *)saddr;
|
||||
sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect MOUNTD port failed: %d\n", error);
|
||||
ferr("ERROR: rpcclnt_socket MOUNTD port failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Do RPC to mountd. */
|
||||
|
||||
strncpy(request.mountd.mount.rpath, rpc->rc_path, 90);
|
||||
request.mountd.mount.len = txdr_unsigned(sizeof(request.mountd.mount.rpath));
|
||||
request.mountd.mount.len = txdr_unsigned(sizeof(request.mountd.mount.rpath));
|
||||
|
||||
error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER3,
|
||||
(FAR void *)&request.mountd,
|
||||
|
|
@ -488,7 +559,7 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
error = fxdr_unsigned(uint32_t, response.mdata.mount.status);
|
||||
error = -fxdr_unsigned(uint32_t, response.mdata.mount.status);
|
||||
if (error != 0)
|
||||
{
|
||||
ferr("ERROR: Bad mount status: %d\n", error);
|
||||
|
|
@ -502,18 +573,16 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
* NFS port in the socket.
|
||||
*/
|
||||
|
||||
sa->sin_port = htons(PMAPPORT);
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
error = rpcclnt_socket(rpc, 0);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect PMAP port failed: %d\n", error);
|
||||
ferr("ERROR: rpcclnt_socket PMAP port failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
request.sdata.pmap.prog = txdr_unsigned(NFS_PROG);
|
||||
request.sdata.pmap.vers = txdr_unsigned(NFS_VER3);
|
||||
request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
|
||||
request.sdata.pmap.prot = txdr_unsigned(prot);
|
||||
request.sdata.pmap.port = 0;
|
||||
|
||||
error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
|
||||
|
|
@ -527,19 +596,17 @@ int rpcclnt_connect(FAR struct rpcclnt *rpc)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect NFS port returns %d\n", error);
|
||||
ferr("ERROR: rpcclnt_socket NFS port returns %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
bad:
|
||||
rpcclnt_disconnect(rpc);
|
||||
psock_close(&rpc->rc_so);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
@ -553,22 +620,6 @@ bad:
|
|||
|
||||
void rpcclnt_disconnect(FAR struct rpcclnt *rpc)
|
||||
{
|
||||
psock_close(&rpc->rc_so);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpcclnt_umount
|
||||
*
|
||||
* Description:
|
||||
* Un-mount the NFS file system.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rpcclnt_umount(FAR struct rpcclnt *rpc)
|
||||
{
|
||||
FAR struct sockaddr *saddr;
|
||||
FAR struct sockaddr_in *sa;
|
||||
|
||||
union
|
||||
{
|
||||
struct rpc_call_pmap sdata;
|
||||
|
|
@ -582,27 +633,20 @@ int rpcclnt_umount(FAR struct rpcclnt *rpc)
|
|||
} response;
|
||||
|
||||
int error;
|
||||
int prot;
|
||||
|
||||
saddr = rpc->rc_name;
|
||||
sa = (FAR struct sockaddr_in *)saddr;
|
||||
|
||||
/* Do the RPC to get a dynamic bounding with the server using ppmap.
|
||||
* Get port number for MOUNTD.
|
||||
*/
|
||||
|
||||
sa->sin_port = htons(PMAPPORT);
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
error = rpcclnt_socket(rpc, 0);
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect failed [port=%d]: %d\n",
|
||||
ntohs(sa->sin_port), error);
|
||||
ferr("ERROR: rpcclnt_socket failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
prot = rpc->rc_sotype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
|
||||
|
||||
request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
|
||||
request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
|
||||
request.sdata.pmap.prot = txdr_unsigned(IPPROTO_UDP);
|
||||
request.sdata.pmap.prot = txdr_unsigned(prot);
|
||||
request.sdata.pmap.port = 0;
|
||||
|
||||
error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
|
||||
|
|
@ -616,20 +660,17 @@ int rpcclnt_umount(FAR struct rpcclnt *rpc)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
|
||||
error = psock_connect(&rpc->rc_so, saddr, sizeof(*saddr));
|
||||
error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
|
||||
if (error < 0)
|
||||
{
|
||||
ferr("ERROR: psock_connect failed [port=%d]: %d\n",
|
||||
ntohs(sa->sin_port), error);
|
||||
ferr("ERROR: rpcclnt_socket failed: %d\n", error);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Do RPC to umountd. */
|
||||
|
||||
strncpy(request.mountd.umount.rpath, rpc->rc_path, 92);
|
||||
request.mountd.umount.len = txdr_unsigned(sizeof(request.mountd.umount.rpath));
|
||||
strncpy(request.mountd.umount.rpath, rpc->rc_path, 90);
|
||||
request.mountd.umount.len = txdr_unsigned(sizeof(request.mountd.umount.rpath));
|
||||
|
||||
error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER3,
|
||||
(FAR void *)&request.mountd,
|
||||
|
|
@ -642,11 +683,8 @@ int rpcclnt_umount(FAR struct rpcclnt *rpc)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
bad:
|
||||
rpcclnt_disconnect(rpc);
|
||||
return error;
|
||||
psock_close(&rpc->rc_so);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -676,7 +714,7 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
|
|||
|
||||
/* Get a new (non-zero) xid */
|
||||
|
||||
xid = rpcclnt_newxid();
|
||||
xid = ++rpc->rc_xid;
|
||||
|
||||
/* Initialize the RPC header fields */
|
||||
|
||||
|
|
@ -712,7 +750,7 @@ int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
|
|||
|
||||
else
|
||||
{
|
||||
error = rpcclnt_reply(rpc, response, resplen);
|
||||
error = rpcclnt_reply(rpc, xid, response, resplen);
|
||||
if (error != OK)
|
||||
{
|
||||
finfo("ERROR rpcclnt_reply failed: %d\n", error);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/net/ethernet.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Definitions
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue