summaryrefslogblamecommitdiff
path: root/nuttx/fs/nfs/rpc_clnt.c
blob: 53be61c01b1ab696ddd363de2e14bb3a8e2645a4 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                                                             
  
                          
  





                                                                  
























                                                                          


                                                                          
  

                                                                                
  












                                                                             
  










                                                                              








                                                                              










                       
                          

                     
                      
                
 



                                                                              
                                                                             






                                                                             
 











                                                                              
                                                                         








                                                                            
 

                                            

                                  







                                                                              







                                                         

                            



                                                

                                             







                                               



                                                                              
                                                                     


                                                   








                                


                                        
                  
                         

                             
 

                              
                            
                                             
 



                                                                              
                                                                             
                                          
                                                                         

                                                                     




                                                    
                                                                             
      
           
                                                   

                                                     
                                                          

                                                                                                
 


                                                                              
 
                                                                           







                                                                                
 
          

                                                                           

                           
                    



                       




                                       
                       
         
 


                                               
                   
         
 
                                       
                       
                                           
      
     
                       
      



                            
                                  


                     

      


                    

                                   


                      
      


                
 














                                                                       














                                                                         











































                                                                               







                                                                      












































                                                                              
                


                      
                                                           



                                                     
                                           


                            
              


                                              

          
         
                                                     

         
                   
     

      
               
     

 
                                                                   




                                                                  
 
                                                                       

                                                                          



                       
             
      
              
             
 
                       

             
                                        


                                     
                                                                    




                                                                    
 



                                                             
         
                                                             


                       
             
 

                                                      



                                                               
 


                                                      
                       
         
 






                                                          
                           
             
 











                                                                       
                               
                 
 






                                                  
                     

             
                                                                  


                                                                      
                                               
                            
                 



                                                     
                                   
                     
                 
             
                                        


                         
                                                               
                                                       



                                         

                                                         


                                                               
 

                                  
                                                        

                                                            


                            

                    

             
                                                                   


                                                                      
                                               




                                                                     
             
                                                                                 


                         
                                                               
                                                       


                            
                        


                          


          
                                                               




                                                             
 
                     

             
                                                                   
                         

                                                                        

                                              

                                                                     

                                                   
                                   


                     
                                                  

                                      
             
                               

             
                         


                            





                                                            
             
                                                                  
                                                              

             

                                                                 



                                             
                         


                            


         
      
     

                                 
         
                        
         
 
                                                  
                 
                                                                    
                  
         
                                                            
         
     
 
                               
             

 
                                                                             



                                                                            
                                                                                              

                      
                                      

                                         

                
            
 

                                              
                                     
     
                                                                  



                                                                  
 


                                     


                       
      

                                                 
                                                                             





                                       
                                                    

                        
 


                                                        
                 
                           

                 
                                                                          

                       
                       

         
                                                                  
 
                                                            
 

                                                


                                              
             
                       

             

                   

                                                                   

                                      
 
                                                               



                                                      
                                                          

                                         
 




                                                         
 
                                                 


                                                 




                                            
                                                        

                                                          
 

                                             
                                                  





                                                       
 



                                                  



                               


                                                   
 



                                   

                                                                

             
 

                   
                                          
                                   
                        


                            
                   
         
 
                                          
         
                   
         
     
 
                

 



                                                                          

                      
 



                    
 



                                            
 
                                                  
     
                   
     

                                        
     
               
     

                 


               








                                                 
 


                                                              
                   
     
 
                 
           



















                                                                             



                       








                                        
           























                                                


                       
      


                  



                                                             



                       









                                                                           
           























                                                                   


                                   
 
           

 
           








                                                  
      








                                                                              



                        



















                                                                      
                      
 
                                 
 
                             
 

  


                    
                    
                                                               











                                                                             
                         

                              
                                

                               
                    
                 


                        
 

                         
                       

                               
                                                        
 


                                                       
                                                           

                     
 
                                                                              
                
     

                                                     
                   

     

                       

                                



                                                                      
                 



                                                               
                
     

                                                           


               




                                                                 
                                
                                   
                             
 
             


              
                                  
                                                                           




                                                         
     
                                                   


            
                                                     












                                                                     

      
      
     
                                                               
                    
         

                                                                       
                   
         
 


                                                                          
 

                                                       



                                              
 
                                                                        

                                                                           

                     
                                                             

                   
 
                                           
                                                                     

                                                               
                    
         

                                                                        




                             

                                                         
                                              
                                                        

                                                                          

                                                                            

                     
                                                             


                   

                                                          
         
                                                           

                   
 
                                                                
 



                                                                         

                                                       


                                                               
                    
         

                                                                      








                                                                        

                                                                           

                     
                                                             



                                                                     
 


                                                               
                                                             

                   



                                                      

                                                                                           



                                                                 
                       
           


                          
               








                                                                      
                       






                                          
    
     

                                   
         




                                                             
         
     
                    




                                                         
                                                          


                                                


                                         
     
 
           
 
      







                                            



                            



                                       
                              
                              

                                


                       
                                       
 


                                                                      
 

                                                   




                                                           
                                                            


               




                                          
                                                                    

                                                                    



                 
 
                                                                 

                                                           

            
                                                            



                          
 

                                                     


                                                    

                                                                       

                                                                    



                 


                                                        
                                                           


               
           


                          
               

 












                                                
                                                                           

                                                                           
                                            
  



                                                                          
 
                                                                            
                                                                      
 
                                   


                                      
                
 
                                                                      
 













                                    
 
                                     
 
                           
 
                                                      
 


                                                           
                                                              

                     
 
                                                                                          

            
                                                  


                   
                        
                          
                            

                                  


                                    
      



                                                               


                                      


                                  
      


                        
 

                               

                         
                                                                       

                                               
 
                                         
 
                                                                      


                                                                     
 
                                                    


                                                         

                                            


                                                       
      

                     
                                                                       
                                                    


                                                


                                               

         
 










                                                               

                                         
                                   
     
                                                               
     
                                     
 

                                     
                                     
 

                                                






                                                      


                   
 

                                                 
                                         


                                                                
     

                                                                    

                          
                                           
                                                                        
                                            
                                                                           
                                                      

                             
 
                         
                                                                                    
                                                     

                         
 





                             
                                            






                         
                               
                                                                    

                                                             
 
                                     
     
                             
     
                                               
     
                                       
                                                                    

                                                                       
 
                                                        
                         
     
                               





                         
              
               

 

           
                                                                         


                                                                            
 






                                                    
                                                           



                                                  



                   



                                              


                                    
              



                                                                                  
                                   



                                                             
                                  



                       
                                   


                                 
         


                                           


                                                  
                                             

                                          
 





                                              
 


                                              


                                            

                   
 
                                    


                   
 
                                                                   

                                                        
 





                                                                            


                                                                        
              
             

                                                                            
             
 
                        
             
                                                       


                                                     
 



                                                      



                                                    

                                                   



                                                   






                                                
 






                                                                        
      
 
                                                              
 
                                                                            

                                                                   
 
                    
               
 
                      

                                
 











                                                       
 


                          







                                                                          
 






                                                          
 
                                                 
 

                                                        
                           




                                                        
      
                                         
 



























                                                                           
 






























                                                                            
 









































































































































































































                                                                                  






























                                                                         






















































































































































                                                                                 

 
           




                                           
                                                     


                                                                    



                   




                             
                                                          


                                                        


                    
         
 
                       


                   

     
               
 
      
      
/****************************************************************************
 * fs/nfs/rpc_clnt.c
 *
 *   Copyright (C) 2012 Gregory Nutt. All rights reserved.
 *   Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved.
 *   Author: Jose Pablo Rojas Vargas <jrojas@nx-engineering.com>
 *
 * Leveraged from OpenBSD:
 *
 *   Copyright (c) 2004 The Regents of the University of Michigan.
 *   All rights reserved.
 *
 *   Copyright (c) 2004 Weston Andros Adamson <muzzle@umich.edu>.
 *   Copyright (c) 2004 Marius Aamodt Eriksen <marius@umich.edu>.
 *   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *   Copyright (c) 1989, 1991, 1993, 1995 The Regents of the University of
 *   California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by Rick Macklem at
 * The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer. 2.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution. 3. All advertising
 * materials mentioning features or use of this software must display the
 * following acknowledgement: This product includes software developed by the
 * University of California, Berkeley and its contributors. 4. Neither the
 * name of the University nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef __FS_NFS_NFS_SOCKET_H
#define __FS_NFS_NFS_SOCKET_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <sys/socket.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>
#include <nuttx/kmalloc.h>

#include "xdr_subs.h"
#include "nfs_proto.h"
#include "rpc.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* 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. getattr, lookup - A+2D read, write     -
 * A+4D other           - nm_timeo
 */

#define RPC_RTO(n, t) \
        ((t) == 0 ? (n)->rc_timeo : \
         ((t) < 3 ? \
          (((((n)->rc_srtt[t-1] + 3) >> 2) + (n)->rc_sdrtt[t-1] + 1) >> 1) : \
          ((((n)->rc_srtt[t-1] + 7) >> 3) + (n)->rc_sdrtt[t-1] + 1)))

#define RPC_SRTT(s,r)   (r)->r_rpcclnt->rc_srtt[rpcclnt_proct((s),\
                                (r)->r_procnum) - 1]

#define RPC_SDRTT(s,r)  (r)->r_rpcclnt->rc_sdrtt[rpcclnt_proct((s),\
                                (r)->r_procnum) - 1]

/* There is a congestion window for outstanding rpcs maintained per mount
 * point. The cwnd size is adjusted in roughly the way that: Van Jacobson,
 * Congestion avoidance and Control, In "Proceedings of SIGCOMM '88". ACM,
 * August 1988. describes for TCP. The cwnd size is chopped in half on a
 * retransmit timeout and incremented by 1/cwnd when each rpc reply is
 * received and a full cwnd of rpcs is in progress. (The sent count and cwnd
 * are scaled for integer arith.) Variants of "slow start" were tried and
 * were found to be too much of a performance hit (ave. rtt 3 times larger),
 * I suspect due to the large rtt that nfs rpcs have.
 */

#define RPC_CWNDSCALE   256
#define RPC_MAXCWND     (RPC_CWNDSCALE * 32)

#define RPC_ERRSTR_ACCEPTED_SIZE 6
#define RPC_ERRSTR_AUTH_SIZE 6

/****************************************************************************
 * Public Data
 ****************************************************************************/

char *rpc_errstr_accepted[RPC_ERRSTR_ACCEPTED_SIZE] =
{
  "",                           /* no good message... */
  "remote server hasn't exported program.",
  "remote server can't support version number.",
  "program can't support procedure.",
  "procedure can't decode params.",
  "remote error.  remote side memory allocation failure?"
};

char *rpc_errstr_denied[2] =
{
  "remote server doesnt support rpc version 2!",
  "remote server authentication error."
};

char *rpc_errstr_auth[RPC_ERRSTR_AUTH_SIZE] =
{
  "",
  "auth error: bad credential (seal broken).",
  "auth error: client must begin new session.",
  "auth error: bad verifier (seal broken).",
  "auth error: verifier expired or replayed.",
  "auth error: rejected for security reasons.",
};

/****************************************************************************
 * Private Data
 ****************************************************************************/

//static int rpcclnt_backoff[8] = { 2, 4, 8, 16, 32, 64, 128, 256, };

/* Static data, mostly RPC constants in XDR form */

static uint32_t rpc_reply;
static uint32_t rpc_call;
static uint32_t rpc_vers;
static uint32_t rpc_msgdenied;
static uint32_t rpc_mismatch;
static uint32_t rpc_auth_unix;
static uint32_t rpc_msgaccepted;
static uint32_t rpc_autherr;
static uint32_t rpc_auth_null;

static uint32_t rpcclnt_xid = 0;
static uint32_t rpcclnt_xid_touched = 0;
int rpcclnt_ticks;
struct rpcstats rpcstats;
//struct rpc_call *callmgs;
//struct rpc_reply *replymsg;

/* Queue head for rpctask's */

static dq_queue_t rpctask_q;
//struct callout_handle rpcclnt_timer_handle;

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

static int rpcclnt_send(struct socket *, struct sockaddr *, int, int, void *,
                        struct rpctask *);
static int rpcclnt_receive(struct rpctask *, struct sockaddr *, int, int,
                           void *, size_t);//, struct rpc_call *);
static int rpcclnt_reply(struct rpctask *, int, int, void *, size_t);
#ifdef CONFIG_NFS_TCPIP
static int rpcclnt_sndlock(int *, struct rpctask *);
static void rpcclnt_sndunlock(int *);
static int rpcclnt_rcvlock(struct rpctask *);
static void rpcclnt_rcvunlock(int *);
static int  rpcclnt_sigintr(struct rpcclnt *, struct rpctask *, cthread_t *);
#endif
#ifdef COMP
static void rpcclnt_softterm(struct rpctask *task);
static void rpcclnt_timer(void *, struct rpc_call *);
#endif
static uint32_t rpcclnt_proct(struct rpcclnt *, uint32_t);
static int rpcclnt_buildheader(struct rpcclnt *, int, int, int, struct xidr *, FAR const void *,
                               void *);

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/* This is the nfs send routine. For connection based socket types, it must
 * be called with an nfs_sndlock() on the socket. "rep == NULL" indicates
 * that it has been called from a server. For the client side: - return EINTR
 * if the RPC is terminated, 0 otherwise - set TASK_MUSTRESEND if the send fails
 * for any reason - do any cleanup required by recoverable socket errors
 * (???) For the server side: - return EINTR or ERESTART if interrupted by a
 * signal - return EPIPE if a connection is lost for connection based sockets
 * (TCP...) - do any cleanup required by recoverable socket errors (???)
 */

static int
rpcclnt_send(struct socket *so, struct sockaddr *nam, int procid, int prog,
             void *call, struct rpctask *rep)
{
  struct sockaddr *sendnam;
  int error = ESRCH;
#ifdef CONFIG_NFS_TCPIP
  int soflags;
#endif
  int flags;

  if (rep != NULL)
    {
      if (rep->r_flags & TASK_SOFTTERM)
        {
          return EINTR;
        }

      if ((so = rep->r_rpcclnt->rc_so) == NULL)
        {
          rep->r_flags |= TASK_MUSTRESEND;
          return 0;
        }

      rep->r_flags &= ~TASK_MUSTRESEND;
#ifdef CONFIG_NFS_TCPIP
      soflags = rep->r_rpcclnt->rc_soflags;
#endif
    }
#ifdef CONFIG_NFS_TCPIP
  else
    {
      soflags = so->s_flags;
    }

  if ((soflags & PR_CONNREQUIRED))
    {
      sendnam = NULL;
    {
  else
#endif
    {
      sendnam = nam;
    }

  if (so->s_type == SOCK_SEQPACKET)
    {
      flags = MSG_EOR;
    }
  else
    {
      flags = 0;
    }

  if (prog == PMAPPROG)
    {
      if (procid == PMAPPROC_GETPORT)
        {
          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)call;
          error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                               sendnam, sizeof(*sendnam));
        }
      else if (procid == PMAPPROC_UNSET)
        {
          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)call;
          error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                               sendnam, sizeof(*sendnam));
        }
    }
  else if (prog == RPCPROG_MNT)
    {
      if (procid == RPCMNT_UMOUNT)
        {
          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)call;
          error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                               sendnam, sizeof(*sendnam));
        }
      else if (procid == RPCMNT_MOUNT)
        {
          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)call;
          error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                               sendnam, sizeof(*sendnam));
        }
    }
  else if (prog == NFS_PROG)
    {
      switch (procid)
        {
        case NFSPROC_CREATE:
          {
            struct rpc_call_create *callmsg = (struct rpc_call_create *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_READ:
          {
            struct rpc_call_read *callmsg = (struct rpc_call_read *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_WRITE:
          {
            struct rpc_call_write *callmsg = (struct rpc_call_write *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_READDIR:
          {
            struct rpc_call_readdir *callmsg = (struct rpc_call_readdir *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_FSSTAT:
          {
            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_GETATTR:
          {
            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_REMOVE:
          {
            struct rpc_call_remove *callmsg  = (struct rpc_call_remove *)call;
                  error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                           sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_MKDIR:
          {
            struct rpc_call_mkdir *callmsg = (struct rpc_call_mkdir *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_RMDIR:
          {
            struct rpc_call_rmdir *callmsg  = (struct rpc_call_rmdir *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_RENAME:
          {
            struct rpc_call_rename *callmsg  = (struct rpc_call_rename *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        case NFSPROC_FSINFO:
          {
            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)call;
            error = psock_sendto(so, callmsg, sizeof(*callmsg), flags,
                                 sendnam, sizeof(*sendnam));
          }
          break;

        default:
          break;
        }
    }

  if (error < 0)
    {
      if (rep != NULL)
        {
          fdbg("rpc send error %d for service %s\n", error,
               rep->r_rpcclnt->rc_prog->prog_name);

          /* Deal with errors for the client side. */

          if (rep->r_flags & TASK_SOFTTERM)
            {
              error = EINTR;
            }
          else
            {
              rep->r_flags |= TASK_MUSTRESEND;
            }
        }
      else
        {
          fdbg("rpc service send error %d\n", error);
        }

      return error;
    }
  else
    {
      return 0;
    }
}

/* Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all
 * done by soreceive().For SOCK_STREAM, first get the
 * Record Mark to find out how much more there is to get. We must
 * lock the socket against other receivers until we have an entire
 * rpc request/reply.
 */

static int rpcclnt_receive(struct rpctask *rep, struct sockaddr *aname,
                           int proc, int program, void *reply, size_t len)
                           //, struct rpc_call *call)
{
  struct socket *so;
#ifdef CONFIG_NFS_TCPIP
  uint32_t len;
  int sotype;
#endif
  int ret = 0;
  int rcvflg;

#ifdef CONFIG_NFS_TCPIP
  int errval;

  /* Set up arguments for soreceive() */

  sotype = rep->r_rpcclnt->rc_sotype;

  /* For reliable protocols, lock against other senders/receivers in
   * case a reconnect is necessary. For SOCK_STREAM, first get the
   * Record Mark to find out how much more there is to get. We must
   * lock the socket against other receivers until we have an entire
   * rpc request/reply.
   */

  if (sotype != SOCK_DGRAM)
    {
      error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_sndlock failed: %d\n", error);
          return error;
        }

    tryagain:

      /* Check for fatal errors and resending request.
       *
       * Ugh: If a reconnect attempt just happened, rc_so would
       * have changed. NULL indicates a failed attempt that has
       * essentially shut down this mount point.
       */

      if (rep->r_flags & TASK_SOFTTERM)
        {
          rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
          return EINTR;
        }

      so = rep->r_rpcclnt->rc_so;
      if (so == NULL)
        {
          error = rpcclnt_reconnect(rep);
          if (error)
            {
              rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
              return error;
            }

          goto tryagain;
        }
      while (rep->r_flags & TASK_MUSTRESEND)
        {
          rpcstats.rpcretries++;
          error = rpcclnt_send(so, rep->r_rpcclnt->rc_name, call, rep);
          if (error)
            {
              if (error == EINTR || error == ERESTART ||
                  (error = rpcclnt_reconnect(rep)) != 0)
                {
                  rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
                  return error;
                }

              goto tryagain;
            }
        }

      rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
      if (sotype == SOCK_STREAM)
        {
          errval = 0;
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name)
              rcvflg = MSG_WAITALL;
              error = psock_recvfrom(so, reply, sizeof(*reply),
                                     &rcvflg, rep->r_rpcclnt->rc_name,
                                     &fromlen);
              if (error < 0)
                {
                  errval = errno;
                  if (errval == EWOULDBLOCK && rep &&
                      (rep->r_flags & TASK_SOFTTERM))
                    {
                      return EINTR;
                    }
                }
            }
          while (errval == EWOULDBLOCK);

          if (error == 0)
            {
              fdbg("ERROR: Short receive from rpc server %s\n",
                   rep->r_rpcclnt->rc_prog->prog_name);
              error = EPIPE;
            }

          len = ntohl(len) & ~0x80000000;

          /* This is SERIOUS! We are out of sync with the
           * sender and forcing a disconnect/reconnect is all I
           * can do.
           */

          if (len > RPC_MAXPACKET)
            {
              fdbg("ERROR %s (%d) from rpc server %s\n",
                   "impossible packet length",
                   len, rep->r_rpcclnt->rc_prog->prog_name);
              error = EFBIG;
              goto errout;
            }

          errval = 0
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name);
              rcvflg = MSG_WAITALL;
              error = psock_recvfrom(so, reply, sizeof(*reply),
                                     &rcvflg, rep->r_rpcclnt->rc_name,
                                     &fromlen);
              if (error < 0)
                {
                  errval = errno;
                  fdbg("ERROR: psock_recvfrom failed: %d\n", errval);
                }
            }
          while (errval == EWOULDBLOCK || errval == EINTR || errval == ERESTART);

          if (error == 0)
            {
              fdbg("ERROR: Short receive from rpc server %s\n",
                   rep->r_rpcclnt->rc_prog->prog_name);
              error = EPIPE;
            }

          if (error < 0)
            {
              goto errout;
            }
        }
      else
        {
          /* NB: Since uio_resid is big, MSG_WAITALL is ignored
           * and soreceive() will return when it has either a
           * control msg or a data msg. We have no use for
           * control msg., but must grab them and then throw
           * them away so we know what is going on.
           */

          errval = 0;
          do
            {
              socklen_t fromlen = sizeof(*rep->r_rpcclnt->rc_name);
              rcvflg = 0;
              error = psock_recvfrom(so, reply, sizeof(*reply), &rcvflg,
                                     rep->r_rpcclnt->rc_name, &fromlen);
              if (error == EWOULDBLOCK && rep)
                {
                  errval = errno;
                  fdbg("ERROR: psock_recvfrom failed: %d\n", errval);
                  if (rep->r_flags & TASK_SOFTTERM)
                    {
                      return EINTR;
                    }
                }
            }
          while (errval == EWOULDBLOCK || !error);

          if ((rcvflg & MSG_EOR) == 0)
            {
              fdbg("Egad!!\n");
            }

          if (error == 0)
            {
              error = EPIPE;
            }
        }

    errout:
      if (error != 0 && error != EINTR && error != ERESTART)
        {
          if (error != EPIPE)
            {
              fdbg("ERROR: Receive error %d from rpc server %s\n",
                   error, rep->r_rpcclnt->rc_prog->prog_name);
            }

          error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
          if (error == 0)
            {
              error = rpcclnt_reconnect(rep);
            }

          if (error == 0)
            {
              goto tryagain;
            }
        }
    }
  else
#endif
    {
      so = rep->r_rpcclnt->rc_so;
      if (so == NULL)
        {
          return EACCES;
        }

      socklen_t fromlen = sizeof(struct sockaddr);
      rcvflg = 0;
      ret = psock_recvfrom(so, reply, len, rcvflg, aname, &fromlen);
      if (ret < 0)
        {
          fdbg("ERROR: psock_recvfrom failed: %d\n", errno);
        }
    }

  fvdbg("Returning %d\n", ret);
  return ret;
}

/* Implement receipt of reply on a socket. We must search through the list of
 * received datagrams matching them with outstanding requests using the xid,
 * until ours is found.
 */

static int rpcclnt_reply(struct rpctask *myrep, int procid, int prog, void *reply, size_t len)
{
  struct rpctask *rep;
  struct rpc_reply_header replyheader;
  struct rpcclnt *rpc = myrep->r_rpcclnt;
  int32_t t1;
  uint32_t rxid;
  int error;
  int count;

  /* Loop around until we get our own reply */

  for (count = 0; count < 9; count++)
    {
      /* Lock against other receivers so that I don't get stuck in
       * sbwait() after someone else has received my reply for me.
       * Also necessary for connection based protocols to avoid
       * race conditions during a reconnect.
       */

#ifdef CONFIG_NFS_TCPIP
      error = rpcclnt_rcvlock(myrep);
      if (error)
        {
          return error;
        }
#endif
      /* Get the next Rpc reply off the socket */

      error = rpcclnt_receive(myrep, rpc->rc_name, procid, prog, reply, len);
#ifdef CONFIG_NFS_TCPIP
      rpcclnt_rcvunlock(&rpc->rc_flag);
#endif

      if (error != 0)
        {
          /* Ignore routing errors on connectionless
           * protocols??
           */

          if (RPCIGNORE_SOERROR(rpc->rc_soflags, error))
            {
              if (myrep->r_flags & TASK_GETONEREP)
                {
                  return 0;
                }

              fdbg("ignoring routing error on connectionless protocol\n");
              continue;
            }
          return error;
        }

      bcopy(reply, &replyheader, sizeof(struct rpc_reply_header));

      /* Get the xid and check that it is an rpc replysvr */

      rxid = replyheader.rp_xid;
      if (replyheader.rp_direction != rpc_reply)
        {
          rpcstats.rpcinvalid++;
          if (myrep->r_flags & TASK_GETONEREP)
            {
              return 0;
            }

          continue;
        }

      /* Loop through the request list to match up the reply Iff no
       * match, just drop the datagram
       */

      for (rep = (struct rpctask *)rpctask_q.head; rep != NULL;
           rep = (struct rpctask *)rep->r_chain.flink)
        {
          if (rxid == rep->r_xid)
            {
              /* Update congestion window. Do the additive
               * increase of one rpc/rtt.
               */

              if (rpc->rc_cwnd <= rpc->rc_sent)
                {
                  rpc->rc_cwnd +=
                    (RPC_CWNDSCALE * RPC_CWNDSCALE +
                     (rpc->rc_cwnd >> 1)) / rpc->rc_cwnd;

                  if (rpc->rc_cwnd > RPC_MAXCWND)
                    {
                      rpc->rc_cwnd = RPC_MAXCWND;
                    }
                }

              rep->r_flags &= ~TASK_SENT;
              rpc->rc_sent -= RPC_CWNDSCALE;

              /* Update rtt using a gain of 0.125 on the
               * mean and a gain of 0.25 on the deviation.
               */

              if (rep->r_flags & TASK_TIMING)
                {
                  /* Since the timer resolution of
                   * NFS_HZ is so course, it can often
                   * result in r_rtt == 0. Since r_rtt
                   * == N means that the actual rtt is
                   * between N+dt and N+2-dt ticks, add
                   * 1.
                   */

                  t1 = rep->r_rtt + 1;
                  t1 -= (RPC_SRTT(rpc, rep) >> 3);
                  RPC_SRTT(rpc, rep) += t1;
                  if (t1 < 0)
                    {
                      t1 = -t1;
                    }

                  t1 -= (RPC_SDRTT(rpc, rep) >> 2);
                  RPC_SDRTT(rpc, rep) += t1;
                }

              rpc->rc_timeouts = 0;
              break;
            }
        }

      /* If not matched to a request, drop it. If it's mine, get
       * out.
       */

      if (rep == 0)
        {
          fdbg("rpc reply not matched\n");
          rpcstats.rpcunexpected++;
          return ENOMSG;
        }
      else if (rep == myrep)
        {
          return 0;
        }

      if (myrep->r_flags & TASK_GETONEREP)
        {
          return 0;
        }
    }

  return ENONET;
}

#ifdef CONFIG_NFS_TCPIP
static int
rpcclnt_sigintr( struct rpcclnt *rpc, struct rpctask *task, cthread_t *td)
{
  struct proc *p;
  sigset_t     tmpset;

  if (rpc == NULL)
    {
      return EFAULT;
    }

  if (ISSET(rpc->rc_flag, RPCCLNT_REDIRECT))
    {
      return 0;
    }

  if (task && ISSET(task->r_flags, TASK_SOFTTERM))
    {
      return EINTR;
    }

  if (!ISSET(rpc->rc_flag, RPCCLNT_INT))
    {
      return 0;
    }

  if (td == NULL)
    {
      return 0;
    }

  p = cthread_proc(td);

  PROC_LOCK(p);
  tmpset = p->p_siglist;
  SIGSETNAND(tmpset, td->td_sigmask);
  mtx_lock(&p->p_sigacts->ps_mtx);
  SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
  mtx_unlock(&p->p_sigacts->ps_mtx);

  if (SIGNOTEMPTY(p->p_siglist) && RPCCLNTINT_SIGMASK(tmpset))
    {
      PROC_UNLOCK(p);
      return EINTR;
    }

  PROC_UNLOCK(p);
  return 0;
}

/* Lock a socket against others. Necessary for STREAM sockets to ensure you
 * get an entire rpc request/reply and also to avoid race conditions between
 * the processes with nfs requests in progress when a reconnect is necessary.
 */

static int rpcclnt_sndlock(int *flagp, struct rpctask *task)
{
  int slpflag = 0, slptimeo = 0;

  if (task)
    {
      if (task->r_rpcclnt->rc_flag & RPCCLNT_INT)
        slpflag = PCATCH;
    }

  while (*flagp & RPCCLNT_SNDLOCK)
    {
      if (rpcclnt_sigintr(task->r_rpcclnt, task, p))
        {
          return EINTR;
        }

      *flagp |= RPCCLNT_WANTSND;
      if (slpflag == PCATCH)
        {
          slpflag = 0;
          slptimeo = 2 * CLOCKS_PER_SEC;
        }
    }

  *flagp |= RPCCLNT_SNDLOCK;
  return 0;
}

/* Unlock the stream socket for others. */

static void rpcclnt_sndunlock(int *flagp)
{
  if ((*flagp & RPCCLNT_SNDLOCK) == 0)
    {
      panic("rpc sndunlock");
    }

  *flagp &= ~RPCCLNT_SNDLOCK;
  if (*flagp & RPCCLNT_WANTSND)
    {
      *flagp &= ~RPCCLNT_WANTSND;
    }
}

static int rpcclnt_rcvlock(struct rpctask *task)
{
  int *flagp = &task->r_rpcclnt->rc_flag;
  int slpflag, slptimeo = 0;

  if (*flagp & RPCCLNT_INT)
    {
      slpflag = PCATCH;
    }
  else
    {
      slpflag = 0;
    }

  while (*flagp & RPCCLNT_RCVLOCK)
    {
      if (rpcclnt_sigintr(task->r_rpcclnt, task, task->r_td))
        {
          return EINTR;
        }

      *flagp |= RPCCLNT_WANTRCV;
      tsleep((caddr_t) flagp, slpflag | (PZERO - 1), "rpcrcvlk", slptimeo);
      if (slpflag == PCATCH)
        {
          slpflag = 0;
          slptimeo = 2 * CLOCKS_PER_SEC;
        }
    }

  *flagp |= RPCCLNT_RCVLOCK;
  return 0;
}

/* Unlock the stream socket for others. */

static void rpcclnt_rcvunlock(int *flagp)
{
  if ((*flagp & RPCCLNT_RCVLOCK) == 0)
    {
      panic("nfs rcvunlock");
    }

  *flagp &= ~RPCCLNT_RCVLOCK;
  if (*flagp & RPCCLNT_WANTRCV)
    {
      *flagp &= ~RPCCLNT_WANTRCV;
      wakeup((caddr_t) flagp);
    }
}
#endif

static uint32_t rpcclnt_proct(struct rpcclnt *rpc, uint32_t procid)
{
  if (rpc->rc_proctlen != 0 && rpc->rc_proct != NULL &&
      procid < rpc->rc_proctlen)
    {
      return rpc->rc_proct[procid];
    }

  return 0;
}

#ifdef COMP
static void rpcclnt_softterm(struct rpctask *task)
{
  task->r_flags |= TASK_SOFTTERM;
  if (task->r_flags & TASK_SENT)
    {
      task->r_rpcclnt->rc_sent -= RPC_CWNDSCALE;
      task->r_flags &= ~TASK_SENT;
    }
}
#endif

/****************************************************************************
 * Public Functions
 ****************************************************************************/

void rpcclnt_init(void)
{
  rpcclnt_ticks = (CLOCKS_PER_SEC * RPC_TICKINTVL + 500) / 1000;
  if (rpcclnt_ticks < 1)
    {
      rpcclnt_ticks = 1;
    }

  rpcstats.rpcretries = 0;
  rpcstats.rpcrequests = 0;
  rpcstats.rpctimeouts = 0;
  rpcstats.rpcunexpected = 0;
  rpcstats.rpcinvalid = 0;

  /* RPC constants how about actually using more than one of these! */

  rpc_reply = txdr_unsigned(RPC_REPLY);
  rpc_vers = txdr_unsigned(RPC_VER2);
  rpc_call = txdr_unsigned(RPC_CALL);
  rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
  rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
  rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
  rpc_autherr = txdr_unsigned(RPC_AUTHERR);
  rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
  rpc_auth_null = txdr_unsigned(RPCAUTH_NULL);

  /* Initialize rpctask queue */

  dq_init(&rpctask_q);

  //rpcclnt_timer(NULL, callmgs);

  fvdbg("rpc initialized\n");
}

/*
void
rpcclnt_uninit(void)
{
  fvdbg("uninit\n");
  untimeout(rpcclnt_timer, (void *)NULL, rpcclnt_timer_handle);
}
*/

/* Initialize sockets and congestion for a new RPC connection. We do not free
 * the sockaddr if error.
 */

int rpcclnt_connect(struct rpcclnt *rpc)
{
  struct socket *so;
  int error;
  struct sockaddr *saddr;
  struct sockaddr_in sin;
  struct sockaddr_in *sa;
  struct call_args_pmap sdata;
  struct call_args_mount mountd;
  struct rpc_reply_pmap rdata;
  struct rpc_reply_mount mdata;
  struct timeval tv;
  uint16_t tport;
  int errval;

  fvdbg("Connecting\n");

  /* Create the socket */

  saddr = rpc->rc_name;
  memset(&sin, 0, sizeof(sin));

  /* Create an instance of the socket state structure */

  so = (struct socket *)kzalloc(sizeof(struct socket));
  if (!so)
    {
      fdbg("ERROR: Failed to allocate socket structure\n");
      return -ENOMEM;
    }

  error = psock_socket(saddr->sa_family, rpc->rc_sotype, rpc->rc_soproto, so);
  if (error < 0)
    {
      errval = errno;
      fdbg("ERROR: psock_socket failed: %d", errval);
      return error;
    }

  so->s_crefs     = 1;
  rpc->rc_so      = so;
  rpc->rc_soflags = so->s_flags;

   /* Always set receive timeout to detect server crash and reconnect.
    * Otherwise, we can get stuck in psock_receive forever.
    */

  tv.tv_sec  = 1;
  tv.tv_usec = 0;

  error = psock_setsockopt(rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
                          (const void *)&tv, sizeof(tv));
  if (error < 0)
    {
      errval = errno;
      fdbg("ERROR: psock_setsockopt failed: %d\n", errval);
      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;

  errval = 0;
  do
    {
      tport--;
      sin.sin_port = htons(tport);
      error = psock_bind(rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_bind failed: %d\n", errval);
        }
    }
  while (errval == EADDRINUSE && tport > 1024 / 2);

  if (error)
    {
      fdbg("ERROR: psock_bind failed: %d\n", errval);
      goto bad;
    }

  /* Protocols that do not require connections may be optionally left
   * unconnected for servers that reply from a port other than
   * NFS_PORT.
   */

#ifdef CONFIG_NFS_TCPIP
  if (rpc->rc_soflags == PR_CONNREQUIRED)
    {
      error = ENOTCONN;
      goto bad;
    }
  else
#endif
    {
      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect to PMAP port failed: %d", errval);
          goto bad;
        }

      /* Do the RPC to get a dynamic bounding with the server using ppmap.
       * Get port number for MOUNTD.
       */

      memset(&sdata, 0, sizeof(struct call_args_pmap));
      memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
      sdata.prog = txdr_unsigned(RPCPROG_MNT);
      sdata.vers = txdr_unsigned(RPCMNT_VER1);
      sdata.proc = txdr_unsigned(IPPROTO_UDP);
      sdata.port = 0;

      error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                              (FAR void *)&rdata, (FAR const void *)&sdata,
                              sizeof(struct rpc_reply_pmap));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      sa = (FAR struct sockaddr_in *)saddr;
      sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect MOUNTD port failed: %d\n", errval);
          goto bad;
        }

      /* Do RPC to mountd. */

      memset(&mountd, 0, sizeof(struct call_args_mount));
      memset(&mdata, 0, sizeof(struct rpc_reply_mount));
      strncpy(mountd.rpath, rpc->rc_path, 90);
      mountd.len =  txdr_unsigned(sizeof(mountd.rpath));

      error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER1,
                              (FAR void *)&mdata, (FAR const void *)&mountd,
                              sizeof(struct rpc_reply_mount));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      error = fxdr_unsigned(uint32_t, mdata.mount.status);
      if (error != 0)
        {
          fdbg("ERROR: fxdr_unsigned failed: %d\n", error);
          goto bad;
        }

      bcopy(&mdata.mount.fhandle, &rpc->rc_fh, sizeof(nfsfh_t));

      /* Do the RPC to get a dynamic bounding with the server using PMAP.
       * NFS port in the socket.
       */

      memset(&sdata, 0, sizeof(struct call_args_pmap));
      memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
      sa->sin_port = htons(PMAPPORT);

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error < 0)
        {
          errval = errno;
          fdbg("ERROR: psock_connect PMAP port failed: %d\n", errval);
          goto bad;
        }

      sdata.prog = txdr_unsigned(NFS_PROG);
      sdata.vers = txdr_unsigned(NFS_VER3);
      sdata.proc = txdr_unsigned(IPPROTO_UDP);
      sdata.port = 0;

      error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                              (FAR void *)&rdata, (FAR const void *)&sdata,
                              sizeof(struct rpc_reply_pmap));
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_request failed: %d\n", error);
          goto bad;
        }

      sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

      error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
      if (error)
        {
          fdbg("psock_connect NFS port returns %d\n", error);
          goto bad;
        }
    }

  /* Initialize other non-zero congestion variables */

  rpc->rc_srtt[0] = rpc->rc_srtt[1] = rpc->rc_srtt[2] = rpc->rc_srtt[3] = (RPC_TIMEO << 3);
  rpc->rc_sdrtt[0] = rpc->rc_sdrtt[1] = rpc->rc_sdrtt[2] = rpc->rc_sdrtt[3] = 0;
  rpc->rc_cwnd = RPC_MAXCWND / 2;       /* Initial send window */
  rpc->rc_sent = 0;
  rpc->rc_timeouts = 0;

  fvdbg("Succeeded\n");
  return 0;

bad:
  rpcclnt_disconnect(rpc);
  return error;
}

/* Reconnect routine: Called when a connection is broken on a reliable
 * protocol. - clean up the old socket - nfs_connect() again - set
 * TASK_MUSTRESEND for all outstanding requests on mount point If this
 * fails the mount point is DEAD! nb: Must be called with the
 * nfs_sndlock() set on the mount point.
 */

#ifdef CONFIG_NFS_TCPIP
int rpcclnt_reconnect(struct rpctask *rep)
{
  struct rpctask *rp;
  struct rpcclnt *rpc = rep->r_rpcclnt;
  int error;

  rpcclnt_disconnect(rpc);
  do
    {
      error = rpcclnt_connect(rpc);
      if (error != 0)
        {
          fdbg("ERROR: rpcclnt_connect failed: %d\n", error);
          if (error == EINTR || error == ERESTART)
            {
              return EINTR;
            }
        }
    }
  while (error != 0)

  /* Loop through outstanding request list and fix up all
   * requests on old socket.
   */

  for (rp = (struct rpctask *)rpctask_q->head; rp != NULL;
       rp = (struct rpctask *)rp->r_chain.blink)
    {
      if (rp->r_rpcclnt == rpc)
        {
          rp->r_flags |= TASK_MUSTRESEND;
        }
    }

  return 0;
}
#endif

void rpcclnt_disconnect(struct rpcclnt *rpc)
{
  struct socket *so;

  if (rpc->rc_so != NULL)
    {
      so = rpc->rc_so;
      (void)psock_close(so);
    }
}

int rpcclnt_umount(struct rpcclnt *rpc)
{
  struct sockaddr *saddr;
  struct sockaddr_in *sa;
  struct call_args_pmap sdata;
  struct rpc_reply_pmap rdata;
  struct call_args_mount mountd;
  struct rpc_reply_mount mdata;
  int error;

  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.
   */

  memset(&sdata, 0, sizeof(struct call_args_pmap));
  memset(&rdata, 0, sizeof(struct rpc_reply_pmap));
  sa->sin_port = htons(PMAPPORT);

  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
  if (error)
    {
      fdbg("psock_connect MOUNTD port returns %d\n", error);
      goto bad;
    }

  sdata.prog = txdr_unsigned(RPCPROG_MNT);
  sdata.vers = txdr_unsigned(RPCMNT_VER1);
  sdata.proc = txdr_unsigned(IPPROTO_UDP);
  sdata.port = 0;

  error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
                           (void *)&rdata, (FAR const void *)&sdata,
                           sizeof(struct rpc_reply_pmap));
  if (error != 0)
    {
      goto bad;
    }

  sa->sin_port = htons(fxdr_unsigned(uint32_t, rdata.pmap.port));

  error = psock_connect(rpc->rc_so, saddr, sizeof(*saddr));
  if (error)
    {
      fdbg("psock_connect MOUNTD port returns %d\n", error);
      goto bad;
    }

  /* Do RPC to umountd. */

  memset(&mountd, 0, sizeof(struct call_args_mount));
  memset(&mdata, 0, sizeof(struct rpc_reply_mount));

  strncpy(mountd.rpath, rpc->rc_path, 92);
  mountd.len =  txdr_unsigned(sizeof(mountd.rpath));

  error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER1,
                          (void *)&mdata, (FAR const void *)&mountd,
                          sizeof(struct rpc_reply_mount));
  if (error != 0)
    {
      goto bad;
    }

 if ((fxdr_unsigned(uint32_t, mdata.mount.status)) != 0)
    {
      fdbg("error unmounting with the server %d\n", error);
      goto bad;
    }

  return 0;

bad:
  rpcclnt_disconnect(rpc);
  return error;
}

#ifdef CONFIG_NFS_TCPIP
void rpcclnt_safedisconnect(struct rpcclnt *rpc)
{
  struct rpctask dummytask;

  memset((void *)dummytask, 0, sizeof(*call));
  dummytask.r_rpcclnt = rpc;
  rpcclnt_rcvlock(&dummytask);
  rpcclnt_disconnect(rpc);
  rpcclnt_rcvunlock(&rpc->rc_flag);
}
#endif

/* Code from nfs_request - goes something like this - fill in task struct -
 * links task into list - calls nfs_send() for first transmit - calls
 * nfs_receive() to get reply - fills in reply (which should be initialized
 * prior to calling), which is valid when 0.
 *
 * note that reply->result_* are invalid unless reply->type ==
 * RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_*
 * are invalid unless reply->type == RPC_MSGACCEPTED
 */

int rpcclnt_request(struct rpcclnt *rpc, int procnum, int prog, int version,
                    void *dataout, FAR const void *datain, size_t len)
{
  struct rpc_reply_header replymgs;
  struct rpc_reply_header replyheader;
  struct rpctask *task = NULL;
  struct xidr value;
  int error = 0;

  /* Set aside memory on the stack to hold the largest call message */

  union
  {
    struct rpc_call_pmap    pmap;
    struct rpc_call_mount   mountd;
    struct rpc_call_create  create;
    struct rpc_call_write   write;
    struct rpc_call_read    read;
    struct rpc_call_remove  removef;
    struct rpc_call_rename  renamef;
    struct rpc_call_mkdir   mkdir;
    struct rpc_call_rmdir   rmdir;
    struct rpc_call_readdir readdir;
    struct rpc_call_fs      fs;
  } u;

  /* Clear the call message memory */

  memset(&u, 0, sizeof(u));

  /* Create an instance of the task state structure */

  task = (struct rpctask *)kzalloc(sizeof(struct rpctask));
  if (!task)
    {
      fdbg("ERROR: Failed to allocate reply msg structure\n");
      return -ENOMEM;
    }

  error = rpcclnt_buildheader(rpc, procnum, prog, version, &value, datain, (FAR void*)&u);
  if (error)
    {
      fdbg("ERROR: Building call header error\n");
      goto rpcmout;
    }

  task->r_rpcclnt = rpc;
  task->r_xid = value.xid;
  task->r_procnum = procnum;

  if (rpc->rc_flag & RPCCLNT_SOFT)
    {
      task->r_retry = rpc->rc_retry;
    }
  else
    {
      task->r_retry = RPC_MAXREXMIT + 1;  /* past clip limit */
    }

  task->r_rtt = task->r_rexmit = 0;

  if (rpcclnt_proct(rpc, procnum) > 0)
    {
      task->r_flags = TASK_TIMING;
    }
  else
    {
      task->r_flags = 0;
    }

  /* Do the client side RPC. */

  rpcstats.rpcrequests++;

  /* Chain request into list of outstanding requests. Be sure to put it
   * LAST so timer finds oldest requests first.
   */

  dq_addlast(&task->r_chain, &rpctask_q);

  /* If backing off another request or avoiding congestion, don't send
   * this one now but let timer do it. If not timing a request, do it
   * now.
   */

  if (rpc->rc_so && (rpc->rc_sotype == SOCK_DGRAM ||
                     (rpc->rc_flag & RPCCLNT_DUMBTIMR) ||
                     rpc->rc_sent < rpc->rc_cwnd))
    {
#ifdef CONFIG_NFS_TCPIP
      if (rpc->rc_soflags & PR_CONNREQUIRED)
        {
          error = rpcclnt_sndlock(&rpc->rc_flag, task);
        }
#endif
      if (error == 0)
        {
          error = rpcclnt_send(rpc->rc_so, rpc->rc_name, procnum, prog,
                               (FAR void*)&u, task);

#ifdef CONFIG_NFS_TCPIP
          if (rpc->rc_soflags & PR_CONNREQUIRED)
            {
              rpcclnt_sndunlock(&rpc->rc_flag);
            }
#endif
        }

      if (error == 0 && (task->r_flags & TASK_MUSTRESEND) == 0)
        {
          rpc->rc_sent += RPC_CWNDSCALE;
          task->r_flags |= TASK_SENT;
        }
    }
  else
    {
      task->r_rtt = -1;
    }

  /* Wait for the reply from our send. */

  if (error == 0 || error == EPIPE)
    {
      error = rpcclnt_reply(task, procnum, prog, dataout, len);
    }
  fvdbg("out for reply %d\n", error);

  /* RPC done, unlink the request. */

  dq_rem(&task->r_chain, &rpctask_q);

  /* Decrement the outstanding request count. */

  if (task->r_flags & TASK_SENT)
    {
      task->r_flags &= ~TASK_SENT;      /* paranoia */
      rpc->rc_sent -= RPC_CWNDSCALE;
    }

  if (error != 0)
    {
      goto rpcmout;
    }

  /* Break down the rpc header and check if ok */

  memset(&replymgs, 0, sizeof(replymgs));
  bcopy(dataout, &replyheader, sizeof(struct rpc_reply_header));
  replymgs.type = fxdr_unsigned(uint32_t, replyheader.type);
  if (replymgs.type == RPC_MSGDENIED)
    {
      replymgs.status = fxdr_unsigned(uint32_t, replyheader.status);
      switch (replymgs.status)
        {
        case RPC_MISMATCH:
        /*replymgs.stat.mismatch_info.low =
            fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.low);
          replymgs.stat.mismatch_info.high =
            fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.high);*/
          fdbg("RPC_MSGDENIED: RPC_MISMATCH error\n");
          error = EOPNOTSUPP;
          break;

        case RPC_AUTHERR:
        //replymgs.stat.autherr = fxdr_unsigned(uint32_t, replyheader.stat.autherr);
          fdbg("RPC_MSGDENIED: RPC_AUTHERR error\n");
          error = EACCES;
          break;

        default:
          error = EOPNOTSUPP;
          break;
        }
      goto rpcmout;
    }
  else if (replymgs.type != RPC_MSGACCEPTED)
    {
      error = EOPNOTSUPP;
      goto rpcmout;
    }

  /* Verifier */

/*replymgs.rpc_verfi.authtype =
    fxdr_unsigned(enum auth_flavor, replyheader.rpc_verfi.authtype);
  replymgs.rpc_verfi.authlen =
    fxdr_unsigned(uint32_t, replyheader.rpc_verfi.authlen);*/

  if (replymgs.status == RPC_SUCCESS)
    {
      fvdbg("RPC_SUCCESS\n");
    }
  else if (replymgs.status == RPC_PROGMISMATCH)
    {
    /*replymgs.stat.mismatch_info.low =
        fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.low);
      replymgs.stat.mismatch_info.high =
        fxdr_unsigned(uint32_t, replyheader.stat.mismatch_info.high);*/

      fdbg("RPC_MSGACCEPTED: RPC_PROGMISMATCH error\n");
      error = EOPNOTSUPP;
    }
  else if (replymgs.status > 5)
    {
      error = EOPNOTSUPP;
      goto rpcmout;
    }

rpcmout:
  kfree(task);
  return error;
}

#undef COMP
#ifdef COMP
/* Nfs timer routine Scan the nfsreq list and retranmit any requests that
 * have timed out To avoid retransmission attempts on STREAM sockets (in the
 * future) make sure to set the r_retry field to 0 (implies nm_retry == 0).
 */

void rpcclnt_timer(void *arg, struct rpc_call *call)
{
  struct rpctask *rep;
  struct socket *so;
  struct rpcclnt *rpc;
  int timeo, error;

  for (rep = (struct rpctask *)rpctask_q.head; rep != NULL;
       rep = (struct rpctask *)rep->r_chain.flink)
    {
      rpc = rep->r_rpcclnt;
      if (rep->r_flags & TASK_SOFTTERM)
        {
          continue;
        }

      if (rep->r_rtt >= 0)
        {
          rep->r_rtt++;
          if (rpc->rc_flag & RPCCLNT_DUMBTIMR)
            {
              timeo = rpc->rc_timeo;
            }
          else
            {
              timeo = RPC_RTO(rpc, rpcclnt_proct(rep->r_rpcclnt, rep->r_procnum));
            }

          if (rpc->rc_timeouts > 0)
            {
              timeo *= rpcclnt_backoff[rpc->rc_timeouts - 1];
            }

          if (rep->r_rtt <= timeo)
            {
              continue;
            }

          if (rpc->rc_timeouts < 8)
            {
              rpc->rc_timeouts++;
            }
        }

      /* Check for server not responding */

      if ((rep->r_flags & TASK_TPRINTFMSG) == 0 &&
          rep->r_rexmit > rpc->rc_deadthresh)
        {
          fdbg("Server is not responding\n");
          rep->r_flags |= TASK_TPRINTFMSG;
        }

      if (rep->r_rexmit >= rep->r_retry)
        {                       /* too many */
          rpcstats.rpctimeouts++;
          rep->r_flags |= TASK_SOFTTERM;
          continue;
        }

      if (rpc->rc_sotype != SOCK_DGRAM)
        {
          if (++rep->r_rexmit > RPC_MAXREXMIT)
            {
              rep->r_rexmit = RPC_MAXREXMIT;
            }
          continue;
        }

      if ((so = rpc->rc_so) == NULL)
        {
          continue;
        }

      /* If there is enough space and the window allows.. Resend it
       * Set r_rtt to -1 in case we fail to send it now.
       */

      rep->r_rtt = -1;
      if ((rpc->rc_flag & RPCCLNT_DUMBTIMR) || (rep->r_flags & TASK_SENT) ||
          rpc->rc_sent < rpc->rc_cwnd)
        {

          if ((rpc->rc_flag & RPCCLNT_NOCONN) == 0)
            {
              error = psock_sendto(so, call, sizeof(*call), 0, NULL, 0);
            }
          else
            {
              error = psock_sendto(so, call, sizeof(*call), 0, rpc->rc_name,
                                   sizeof(*rpc->rc_name));
            }

          if (error < 0)
            {
              /* Iff first send, start timing else turn
               * timing off, backoff timer and divide
               * congestion window by 2.
               */

              if (rep->r_flags & TASK_SENT)
                {
                  rep->r_flags &= ~TASK_TIMING;
                  if (++rep->r_rexmit > RPC_MAXREXMIT)
                    {
                      rep->r_rexmit = RPC_MAXREXMIT;
                    }

                  rpc->rc_cwnd >>= 1;
                  if (rpc->rc_cwnd < RPC_CWNDSCALE)
                    {
                      rpc->rc_cwnd = RPC_CWNDSCALE;
                    }

                  rpcstats.rpcretries++;
                }
              else
                {
                  rep->r_flags |= TASK_SENT;
                  rpc->rc_sent += RPC_CWNDSCALE;
                }

              rep->r_rtt = 0;
            }
        }
    }

  // rpcclnt_timer_handle = timeout(rpcclnt_timer, NULL, rpcclnt_ticks);
}
#endif

/* Build the RPC header and fill in the authorization info. */

int rpcclnt_buildheader(struct rpcclnt *rpc, int procid, int prog, int vers,
                        struct xidr *value, FAR const void *datain,
                        void *dataout)
{
  srand(time(NULL));
  int xidp = 0;

  /* The RPC header.*/

  /* Get a new (non-zero) xid */

  if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0))
    {
      rpcclnt_xid = rand();
      rpcclnt_xid_touched = 1;
    }
  else
    {
      do
        {
          xidp = rand();
        }
      while ((xidp % 256) == 0);

      rpcclnt_xid += xidp;
    }

  /* Perform the binding depending on the protocol type */

  if (prog == PMAPPROG)
    {
      if (procid == PMAPPROC_GETPORT)
        {
          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)dataout;
          bcopy(datain, &callmsg->pmap, sizeof(struct call_args_pmap));

          callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
          value->xid = callmsg->ch.rp_xid;
          callmsg->ch.rp_direction = rpc_call;
          callmsg->ch.rp_rpcvers = rpc_vers;
          callmsg->ch.rp_prog = txdr_unsigned(prog);
          callmsg->ch.rp_vers = txdr_unsigned(vers);
          callmsg->ch.rp_proc = txdr_unsigned(procid);

          /* rpc_auth part (auth_unix as root) */

          callmsg->ch.rpc_auth.authtype = rpc_auth_null;
        //call->rpc_auth.authlen = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
          callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
          callmsg->ch.rpc_unix.hostname = 0;
          callmsg->ch.rpc_unix.uid = setuid;
          callmsg->ch.rpc_unix.gid = setgid;
          callmsg->ch.rpc_unix.gidlist = 0;
#endif
          /* rpc_verf part (auth_null) */

          callmsg->ch.rpc_verf.authtype = rpc_auth_null;
        //call->rpc_verf.authlen = 0;
          return 0;
        }
      else if (procid == PMAPPROC_UNSET)
        {
          struct rpc_call_pmap *callmsg = (struct rpc_call_pmap *)dataout;;
          bcopy(datain, &callmsg->pmap, sizeof(struct call_args_pmap));
          callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
          value->xid = callmsg->ch.rp_xid;
          callmsg->ch.rp_direction = rpc_call;
          callmsg->ch.rp_rpcvers = rpc_vers;
          callmsg->ch.rp_prog = txdr_unsigned(prog);
          callmsg->ch.rp_vers = txdr_unsigned(vers);
          callmsg->ch.rp_proc = txdr_unsigned(procid);

          /* rpc_auth part (auth_unix as root) */

          callmsg->ch.rpc_auth.authtype = rpc_auth_null;
        //call->rpc_auth.authlen = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
          callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
          callmsg->ch.rpc_unix.hostname = 0;
          callmsg->ch.rpc_unix.uid = setuid;
          callmsg->ch.rpc_unix.gid = setgid;
          callmsg->ch.rpc_unix.gidlist = 0;
#endif
          /* rpc_verf part (auth_null) */

          callmsg->ch.rpc_verf.authtype = rpc_auth_null;
        //call->rpc_verf.authlen = 0;
          return 0;
        }
    }
  else if (prog == RPCPROG_MNT)
    {
      if (procid == RPCMNT_UMOUNT)
        {
          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)dataout;
          bcopy(datain, &callmsg->mount, sizeof(struct call_args_mount));
          callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
          value->xid = callmsg->ch.rp_xid;
          callmsg->ch.rp_direction = rpc_call;
          callmsg->ch.rp_rpcvers = rpc_vers;
          callmsg->ch.rp_prog = txdr_unsigned(prog);
          callmsg->ch.rp_vers = txdr_unsigned(vers);
          callmsg->ch.rp_proc = txdr_unsigned(procid);

          /* rpc_auth part (auth_unix as root) */

          callmsg->ch.rpc_auth.authtype = rpc_auth_null;
        //call->rpc_auth.authlen = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
          callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
          callmsg->ch.rpc_unix.hostname = 0;
          callmsg->ch.rpc_unix.uid = setuid;
          callmsg->ch.rpc_unix.gid = setgid;
          callmsg->ch.rpc_unix.gidlist = 0;
#endif
          /* rpc_verf part (auth_null) */

          callmsg->ch.rpc_verf.authtype = rpc_auth_null;
        //call->rpc_verf.authlen = 0;
          return 0;
        }
      else if (procid == RPCMNT_MOUNT)
        {
          struct rpc_call_mount *callmsg = (struct rpc_call_mount *)dataout;
          bcopy(datain, &callmsg->mount, sizeof(struct call_args_mount));
          callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
          value->xid = callmsg->ch.rp_xid;
          callmsg->ch.rp_direction = rpc_call;
          callmsg->ch.rp_rpcvers = rpc_vers;
          callmsg->ch.rp_prog = txdr_unsigned(prog);
          callmsg->ch.rp_vers = txdr_unsigned(vers);
          callmsg->ch.rp_proc = txdr_unsigned(procid);

          /* rpc_auth part (auth_unix as root) */

          callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
          callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
          callmsg->ch.rpc_unix.hostname = 0;
          callmsg->ch.rpc_unix.uid = setuid;
          callmsg->ch.rpc_unix.gid = setgid;
          callmsg->ch.rpc_unix.gidlist = 0;
#endif
          /* rpc_verf part (auth_null) */

          callmsg->ch.rpc_verf.authtype = rpc_auth_null;
        //call->rpc_verf.authlen = 0;
          return 0;
        }
    }
  else if (prog == NFS_PROG)
    {
      switch (procid)
        {
        case NFSPROC_CREATE:
          {
            struct rpc_call_create *callmsg = (struct rpc_call_create *)dataout;
            bcopy(datain, &callmsg->create, sizeof(struct CREATE3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;
#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_READ:
          {
            struct rpc_call_read *callmsg = (struct rpc_call_read *)dataout;
            bcopy(datain, &callmsg->read, sizeof(struct READ3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_WRITE:
          {
            struct rpc_call_write *callmsg = (struct rpc_call_write *)dataout;
            bcopy(datain, &callmsg->write, sizeof(struct WRITE3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_READDIR:
          {
            struct rpc_call_readdir *callmsg = (struct rpc_call_readdir *)dataout;
            bcopy(datain, &callmsg->readdir, sizeof(struct READDIR3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_FSSTAT:
          {
            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)dataout;
            bcopy(datain, &callmsg->fs, sizeof(struct FS3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_REMOVE:
          {
            struct rpc_call_remove *callmsg  = (struct rpc_call_remove *)dataout;
            bcopy(datain, &callmsg->remove, sizeof(struct REMOVE3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

         case NFSPROC_GETATTR:
          {
            struct rpc_call_fs *callmsg  = (struct rpc_call_fs *)dataout;
            bcopy(datain, &callmsg->fs, sizeof(struct FS3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_MKDIR:
          {
            struct rpc_call_mkdir *callmsg = (struct rpc_call_mkdir *)dataout;
            bcopy(datain, &callmsg->mkdir, sizeof(struct MKDIR3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_RMDIR:
          {
            struct rpc_call_rmdir *callmsg  = (struct rpc_call_rmdir *)dataout;
            bcopy(datain, &callmsg->rmdir, sizeof(struct RMDIR3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_RENAME:
          {
            struct rpc_call_rename *callmsg  = (struct rpc_call_rename *)dataout;
            bcopy(datain, &callmsg->rename, sizeof(struct RENAME3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
            //call->rpc_verf.authlen = 0;
            return 0;
          }

        case NFSPROC_FSINFO:
          {
            struct rpc_call_fs *callmsg = (struct rpc_call_fs *)dataout;
            bcopy(datain, &callmsg->fs, sizeof(struct FS3args));
            callmsg->ch.rp_xid = txdr_unsigned(rpcclnt_xid);
            value->xid = callmsg->ch.rp_xid;
            callmsg->ch.rp_direction = rpc_call;
            callmsg->ch.rp_rpcvers = rpc_vers;
            callmsg->ch.rp_prog = txdr_unsigned(prog);
            callmsg->ch.rp_vers = txdr_unsigned(vers);
            callmsg->ch.rp_proc = txdr_unsigned(procid);

            /* rpc_auth part (auth_unix as root) */

            callmsg->ch.rpc_auth.authtype = rpc_auth_null;
          //call->rpc_auth.authlen = 0;

#ifdef CONFIG_NFS_UNIX_AUTH
            callmsg->ch.rpc_unix.stamp = txdr_unsigned(1);
            callmsg->ch.rpc_unix.hostname = 0;
            callmsg->ch.rpc_unix.uid = setuid;
            callmsg->ch.rpc_unix.gid = setgid;
            callmsg->ch.rpc_unix.gidlist = 0;
#endif
            /* rpc_verf part (auth_null) */

            callmsg->ch.rpc_verf.authtype = rpc_auth_null;
          //call->rpc_verf.authlen = 0;
            return 0;
          }

        default:
          break;
        }
    }

  return ESRCH;
}

#ifdef COMP
int rpcclnt_cancelreqs(struct rpcclnt *rpc)
{
  struct rpctask *task;
  int i;

  for (task = (struct rpctask *)rpctask_q.head; task;
       task = (struct rpctask *)task->r_chain.flink)
    {
      if (rpc != task->r_rpcclnt || (task->r_flags & TASK_SOFTTERM))
        {
          continue;
        }

      rpcclnt_softterm(task);
    }

  for (i = 0; i < 30; i++)
    {
      for (task = (struct rpctask *)&rpctask_q.head; task;
           task = (struct rpctask *)task->r_chain.flink)
        {
          if (rpc == task->r_rpcclnt)
            {
              break;
            }
        }

      if (task == NULL)
        {
          return 0;
        }
    }

  return EBUSY;
}
#endif
#endif