• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/nfs/rpc_clnt.c
3  *
4  *   Copyright (C) 2012-2013, 2018 Gregory Nutt. All rights reserved.
5  *   Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved.
6  *   Author: Jose Pablo Rojas Vargas <jrojas@nx-engineering.com>
7  *           Gregory Nutt <gnutt@nuttx.org>
8  *
9  * Leveraged from OpenBSD:
10  *
11  *   Copyright (c) 2004 The Regents of the University of Michigan.
12  *   All rights reserved.
13  *
14  *   Copyright (c) 2004 Weston Andros Adamson <muzzle@umich.edu>.
15  *   Copyright (c) 2004 Marius Aamodt Eriksen <marius@umich.edu>.
16  *   All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  *
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. Neither the name of the University nor the names of its
28  *    contributors may be used to endorse or promote products derived
29  *    from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  *   Copyright (c) 1989, 1991, 1993, 1995 The Regents of the University of
44  *   California.  All rights reserved.
45  *
46  * This code is derived from software contributed to Berkeley by Rick Macklem
47  * at The University of Guelph.
48  *
49  * Redistribution and use in source and binary forms, with or without
50  * modification, are permitted provided that the following conditions are
51  * met: 1. Redistributions of source code must retain the above copyright
52  * notice, this list of conditions and the following disclaimer. 2.
53  * Redistributions in binary form must reproduce the above copyright notice,
54  * this list of conditions and the following disclaimer in the documentation
55  * and/or other materials provided with the distribution. 3. All advertising
56  * materials mentioning features or use of this software must display the
57  * following acknowledgement: This product includes software developed by the
58  * University of California, Berkeley and its contributors. 4. Neither the
59  * name of the University nor the names of its contributors may be used to
60  * endorse or promote products derived from this software without specific
61  * prior written permission.
62  *
63  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
69  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
70  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73  * SUCH DAMAGE.
74  *
75  ****************************************************************************/
76 
77 /****************************************************************************
78  * Included Files
79  ****************************************************************************/
80 
81 #include <sys/time.h>
82 #include <stdlib.h>
83 #include <unistd.h>
84 #include "lwip/opt.h"
85 #include "lwip/sockets.h"
86 #include "xdr_subs.h"
87 #include "nfs_proto.h"
88 #include "rpc.h"
89 #include "nfs.h"
90 
91 /****************************************************************************
92  * Pre-processor Definitions
93  ****************************************************************************/
94 
95 /* Increment RPC statistics */
96 
97 #ifdef CONFIG_NFS_STATISTICS
98 #  define rpc_statistics(n) do { rpcstats.n++; } while (0)
99 #else
100 #  define rpc_statistics(n)
101 #endif
102 
103 #undef  OK
104 #define OK 0
105 
106 #define RPCCLNT_FH_LEN                  4
107 #define RPCCLNT_RECV_BUF_MAX_LEN        64
108 #define RPCCLNT_CONNECT_MAX_RETRY_TIMES 1024
109 
110 /****************************************************************************
111  * Private Data
112  ****************************************************************************/
113 
114 /* Static data, mostly RPC constants in XDR form */
115 
116 static uint32_t rpc_reply;
117 static uint32_t rpc_call;
118 static uint32_t rpc_vers;
119 static uint32_t rpc_msgdenied;
120 static uint32_t rpc_mismatch;
121 static uint32_t rpc_auth_unix;
122 static uint32_t rpc_msgaccepted;
123 static uint32_t rpc_autherr;
124 static uint32_t rpc_auth_null;
125 static uint32_t nfs_uid, nfs_gid;
126 
127 /* Global statics for all client instances.  Cleared by NuttX on boot-up. */
128 
129 #ifdef CONFIG_NFS_STATISTICS
130 static struct rpcstats rpcstats;
131 #endif
132 
133 /****************************************************************************
134  * Private Function Prototypes
135  ****************************************************************************/
136 
137 static int rpcclnt_send(struct rpcclnt *rpc, int procid, int prog,
138                         void *call, int reqlen);
139 static int rpcclnt_receive(struct rpcclnt *rpc, struct sockaddr *aname,
140                            int proc, int program, void *reply, size_t resplen);
141 static int rpcclnt_reply(struct rpcclnt *rpc, int procid, int prog,
142                          void *reply, size_t resplen);
143 static uint32_t rpcclnt_newxid(void);
144 static void rpcclnt_fmtheader(struct rpc_call_header *ch,
145                               uint32_t xid, int procid, int prog, int vers, size_t reqlen);
146 static int rpcclnt_reconnect(struct rpcclnt *rpc, struct sockaddr *saddr);
147 
148 /****************************************************************************
149  * Private Functions
150  ****************************************************************************/
151 
152 /****************************************************************************
153  * Name: rpcclnt_send
154  *
155  * Description:
156  *   This is the nfs send routine.
157  *
158  * Returned Value:
159  *   Returns zero on success or a (positive) errno value on failure.
160  *
161  ****************************************************************************/
162 
rpcclnt_send(struct rpcclnt * rpc,int procid,int prog,void * call,int reqlen)163 static int rpcclnt_send(struct rpcclnt *rpc, int procid, int prog,
164                         void *call, int reqlen)
165 {
166   ssize_t nbytes;
167   int ret = OK;
168 
169   /* Send the call message
170    *
171    * On success, psock_sendto returns the number of bytes sent;
172    * On failure, it returns -1 with the specific error in errno.
173    */
174 
175   nbytes = sendto(rpc->rc_so, call, reqlen, 0,
176                   rpc->rc_name, sizeof(struct sockaddr));
177   if (nbytes < 0)
178     {
179       /* psock_sendto failed */
180 
181       ret = get_errno();
182       nfs_debug_error("psock_sendto failed: %d\n", ret);
183     }
184 
185   return ret;
186 }
187 
188 #if (NFS_PROTO_TYPE == NFS_IPPROTO_UDP)
189 #define CONFIG_NFS_RECV_TIMEOUT 200 /* udp-nfs recv timeout in milli seconds */
190 
191 /****************************************************************************
192  * Name: rpcclnt_receive
193  *
194  * Description:
195  *   Receive a Sun RPC Request/Reply. Only for SOCK_DGRAM
196  *
197  ****************************************************************************/
198 
rpcclnt_receive(struct rpcclnt * rpc,struct sockaddr * aname,int proc,int program,void * reply,size_t resplen)199 static int rpcclnt_receive(struct rpcclnt *rpc, struct sockaddr *aname,
200                            int proc, int program, void *reply,
201                            size_t resplen)
202 {
203   ssize_t nbytes;
204   int error = 0;
205   int ret;
206   fd_set fdreadset;
207   struct timeval timeval = {0};
208   socklen_t fromlen = sizeof(struct sockaddr);
209   uint32_t xid;
210 retry:
211   FD_ZERO(&fdreadset);
212   FD_SET((uint32_t)(rpc->rc_so), &fdreadset);
213 
214   timeval.tv_sec = (CONFIG_NFS_RECV_TIMEOUT / 1000);
215   timeval.tv_usec = (CONFIG_NFS_RECV_TIMEOUT % 1000) * 1000;
216 
217   ret = select(rpc->rc_so + 1, &fdreadset, 0, 0, &timeval);
218   if (ret == 0)
219     {
220       nfs_debug_error("rpcclnt_receive select nothing\n");
221       return EAGAIN;
222     }
223   else if (ret < 0)
224     {
225       error = get_errno();
226       nfs_debug_error("rpcclnt_receive select error %d\n", error);
227       return error;
228     }
229 
230   nbytes = recvfrom(rpc->rc_so, reply, resplen, 0, aname, &fromlen);
231   if (nbytes <= (ssize_t)sizeof(xid))
232     {
233       error = get_errno();
234       nfs_debug_error("psock_recvfrom failed: %d\n", error);
235       goto retry;
236     }
237 
238   error = memcpy_s((void *)&xid, sizeof(xid), ((char *)reply + RPC_RMSIZE), sizeof(xid));
239   if (error != EOK)
240     {
241       return ENOBUFS;
242     }
243 
244   if (fxdr_unsigned(uint32_t, xid) != rpc->xid)
245     {
246       nfs_debug_error("psock_recvfrom a wrong packet\n");
247       goto retry;
248     }
249 
250   return error;
251 }
252 
253 #elif (NFS_PROTO_TYPE == NFS_IPPROTO_TCP)
254 #define CONFIG_NFS_RECV_TIMEOUT 5000 /* tcp-nfs recv timeout in milli seconds */
255 
256 /****************************************************************************
257  * Name: rpcclnt_receive
258  *
259  * Description:
260  *   Receive a Sun RPC Request/Reply. Only for SOCK_STREAM
261  *
262  ****************************************************************************/
263 
rpcclnt_receive(struct rpcclnt * rpc,struct sockaddr * aname,int proc,int program,void * reply,size_t resplen)264 static int rpcclnt_receive(struct rpcclnt *rpc, struct sockaddr *aname,
265                            int proc, int program, void *reply,
266                            size_t resplen)
267 {
268   ssize_t   nbytes;
269   size_t    offset = 0;
270   size_t    hdrlen = 0;
271   uint32_t  total = 0;
272   int       error;
273   int       ret;
274   fd_set    fdreadset;
275   struct    timeval timeval = {0};
276   socklen_t fromlen = sizeof(struct sockaddr);
277 
278   do
279     {
280       FD_ZERO(&fdreadset);
281       FD_SET((uint32_t)(rpc->rc_so), &fdreadset);
282 
283       timeval.tv_sec = (CONFIG_NFS_RECV_TIMEOUT / 1000);
284       timeval.tv_usec = (CONFIG_NFS_RECV_TIMEOUT % 1000) * 1000;
285 
286       ret = select(rpc->rc_so + 1, &fdreadset, 0, 0, &timeval);
287       if (ret == 0) /* no reply */
288         {
289           nfs_debug_error("rpcclnt_receive select nothing\n");
290           return EAGAIN;
291         }
292       else if (ret < 0) /* select error */
293         {
294           error = get_errno();
295           nfs_debug_error("rpcclnt_receive select error %d\n", error);
296           return error;
297         }
298 
299       nbytes = recvfrom(rpc->rc_so, (char *)reply + offset, resplen - offset, 0, aname, &fromlen);
300       if (nbytes < 0)
301         {
302           error = get_errno();
303           nfs_debug_error("rpcclnt_receive recvfrom error %d\n", error);
304           return error;
305         }
306       else if (nbytes == 0)
307         {
308           /* connection closed by peer side */
309 
310           nfs_debug_error("rpcclnt_receive connection closed by peer\n");
311           return EIO;
312         }
313       else
314         {
315           offset += nbytes;
316 
317           /* parse fragment header */
318 
319           if (offset == 0 || hdrlen < sizeof(struct rpc_reply_header))
320             {
321               hdrlen += nbytes;
322 
323               /* unlikely */
324 
325               if (hdrlen < sizeof(struct rpc_reply_header))
326                 {
327                   continue;
328                 }
329 
330               error = memcpy_s(&total, RPC_RMSIZE, reply, RPC_RMSIZE);
331               if (error != EOK)
332                 {
333                   return ENOBUFS;
334                 }
335               total = (fxdr_unsigned(uint32_t, total) & RPC_RM_FLAGMENT_LEN_MASK) + RPC_RMSIZE;
336             }
337         }
338     }
339   while (offset < total);
340 
341   return 0;
342 }
343 #endif
344 
345 /****************************************************************************
346  * Name: rpcclnt_reply
347  *
348  * Description:
349  *   Received the RPC reply on the socket.
350  *
351  ****************************************************************************/
352 
rpcclnt_reply(struct rpcclnt * rpc,int procid,int prog,void * reply,size_t resplen)353 static int rpcclnt_reply(struct rpcclnt *rpc, int procid, int prog,
354                          void *reply, size_t resplen)
355 {
356   int error;
357 
358   /* Get the next RPC reply from the socket */
359 
360   error = rpcclnt_receive(rpc, rpc->rc_name, procid, prog, reply, resplen);
361   if (error != 0)
362     {
363       nfs_debug_error("rpcclnt_receive returned: %d\n", error);
364 
365       /* For UDP, If we failed because of a timeout, then try sending the CALL
366        * message again. While for TCP, just return errno.
367        */
368 
369 #if (NFS_PROTO_TYPE == NFS_IPPROTO_UDP)
370       if (error == EAGAIN || error == ETIMEDOUT)
371         {
372           rpc->rc_timeout = true;
373         }
374 #endif
375     }
376 
377   /* Get the xid and check that it is an RPC replysvr */
378 
379   else
380     {
381       struct rpc_reply_header *replyheader =
382         (struct rpc_reply_header *)reply;
383 
384       if (replyheader->rp_direction != rpc_reply)
385         {
386           nfs_debug_error("Different RPC REPLY returned\n");
387           rpc_statistics(rpcinvalid);
388           error = EPROTO;
389         }
390     }
391 
392   return error;
393 }
394 
395 /****************************************************************************
396  * Name: rpcclnt_newxid
397  *
398  * Description:
399  *   Get a new (non-zero) xid
400  *
401  ****************************************************************************/
402 extern VOID LOS_GetCpuCycle(UINT32 *puwCntHi, UINT32 *puwCntLo);
403 
seed_gen_func(void)404 static uint32_t seed_gen_func(void)
405 {
406   uint32_t seedhsb, seedlsb;
407   LOS_GetCpuCycle(&seedhsb, &seedlsb);
408   return seedlsb;
409 }
410 
rpcclnt_newxid(void)411 static uint32_t rpcclnt_newxid(void)
412 {
413   static uint32_t rpcclnt_xid = 0;
414   static uint32_t rpcclnt_xid_touched = 0;
415 
416   if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0))
417     {
418       unsigned int seed = seed_gen_func();
419       srand(seed);
420       rpcclnt_xid = rand();
421       rpcclnt_xid_touched = 1;
422     }
423   else
424     {
425       int xidp = 0;
426       do
427         {
428           xidp = rand();
429         }
430       while ((xidp % 256) == 0);
431 
432       rpcclnt_xid += xidp;
433     }
434 
435   return rpcclnt_xid;
436 }
437 
438 /****************************************************************************
439  * Name: rpcclnt_alivecheck
440  *
441  * Description:
442  *   Check if the connection is alive
443  *
444  ****************************************************************************/
445 
rpcclnt_alivecheck(struct rpcclnt * rpc)446 static int rpcclnt_alivecheck(struct rpcclnt *rpc)
447 {
448     fd_set    rfd;
449     int       recvlen;
450     char      buf[RPCCLNT_RECV_BUF_MAX_LEN];
451     const int bufsize = RPCCLNT_RECV_BUF_MAX_LEN;
452     int       ret;
453     int       sockfd = rpc->rc_so;
454     struct timeval timeout;
455 
456     FD_ZERO(&rfd);
457     if (sockfd < 0)
458       {
459         return ENETDOWN;
460       }
461     FD_SET((uint32_t)sockfd, &rfd);
462 
463     timeout.tv_sec = 0;
464     timeout.tv_usec = 0;
465 
466     /* no wait */
467 
468     ret = select(sockfd + 1, &rfd, NULL, NULL, &timeout);
469     if (ret < 0)
470       {
471         nfs_debug_error("rpc_alivecheck : select failure\n");
472         return get_errno();
473       }
474 
475     if (sockfd)
476       {
477         if (FD_ISSET((uint32_t)sockfd, &rfd))
478           {
479             recvlen = recv(sockfd, buf, bufsize, 0);
480             if (recvlen <= 0)
481               {
482                 (void)close(rpc->rc_so);
483                 rpc->rc_so = -1;
484               }
485             else
486               {
487                 nfs_debug_error("rpc_alivecheck : recv unsolocit %d data from server\n", recvlen);
488                 return ENOTSOCK;
489               }
490           }
491       }
492 
493     return 0;
494 }
495 
496 /****************************************************************************
497  * Name: rpcclnt_fmtheader
498  *
499  * Description:
500  *   Format the common part of the call header
501  *
502  ****************************************************************************/
503 
rpcclnt_fmtheader(struct rpc_call_header * ch,uint32_t xid,int prog,int vers,int procid,size_t reqlen)504 static void rpcclnt_fmtheader(struct rpc_call_header *ch,
505                               uint32_t xid, int prog, int vers, int procid, size_t reqlen)
506 {
507   unsigned int high = 0;
508   unsigned int low = 0;
509   int          error;
510 
511   LOS_GetCpuCycle(&high, &low);
512 
513   /* Format the call header */
514 
515 #if (NFS_PROTO_TYPE == NFS_IPPROTO_TCP)
516   ch->rp_recmark        = txdr_unsigned(0x80000000 | (reqlen - RPC_RMSIZE));
517 #endif
518   ch->rp_xid            = txdr_unsigned(xid);
519   ch->rp_direction      = rpc_call;
520   ch->rp_rpcvers        = rpc_vers;
521   ch->rp_prog           = txdr_unsigned(prog);
522   ch->rp_vers           = txdr_unsigned(vers);
523   ch->rp_proc           = txdr_unsigned(procid);
524 
525   ch->rpc_auth.authtype = rpc_auth_unix;
526   ch->rpc_auth.authlen  = htonl(sizeof(ch->rpc_auth_unix));
527   ch->rpc_auth_unix.stamp = txdr_unsigned((uint32_t)(((UINT64)high << 32) + low));
528   ch->rpc_auth_unix.hostname_len = htonl(CONFIG_NFS_MACHINE_NAME_SIZE);
529   (void)memset_s(ch->rpc_auth_unix.hostname, sizeof(ch->rpc_auth_unix.hostname),
530                  0, sizeof(ch->rpc_auth_unix.hostname));
531   error = memcpy_s(ch->rpc_auth_unix.hostname, sizeof(ch->rpc_auth_unix.hostname),
532                    CONFIG_NFS_MACHINE_NAME, CONFIG_NFS_MACHINE_NAME_SIZE);
533   if (error != EOK)
534     {
535       return;
536     }
537   ch->rpc_auth_unix.uid = htonl(nfs_uid);
538   ch->rpc_auth_unix.gid = htonl(nfs_gid);
539   ch->rpc_auth_unix.gidlist = htonl(1);
540   ch->rpc_auth_unix.gidlist_value = nfs_gid;
541 
542   /* rpc_verf part (auth_null) */
543 
544   ch->rpc_verf.authtype  = rpc_auth_null;
545   ch->rpc_verf.authlen   = 0;
546 }
547 
rpcclnt_reconnect(struct rpcclnt * rpc,struct sockaddr * saddr)548 static int rpcclnt_reconnect(struct rpcclnt *rpc, struct sockaddr *saddr)
549 {
550   int errval;
551   int error;
552 
553 #if (NFS_PROTO_TYPE == NFS_IPPROTO_TCP)
554   extern long random(void);
555   unsigned short tport = 0;
556   unsigned short trycount = 0;
557   struct sockaddr_in sock_in;
558 
559   rpcclnt_disconnect(rpc);
560 
561   error = socket(rpc->rc_name->sa_family, rpc->rc_sotype, IPPROTO_TCP);
562   if (error < 0)
563     {
564       nfs_debug_error("psock_socket failed: %d", get_errno());
565       return -error;
566     }
567 
568   rpc->rc_so              = error;
569   sock_in.sin_family      = AF_INET;
570   sock_in.sin_addr.s_addr = INADDR_ANY;
571   trycount                = RPCCLNT_CONNECT_MAX_RETRY_TIMES;
572 
573   do
574     {
575       errval = 0;
576       trycount--;
577       tport = random() % (RPCCONN_MAXPORT - RPCCONN_MINPORT) + RPCCONN_MINPORT;
578       sock_in.sin_port = htons(tport);
579       error = bind(rpc->rc_so, (struct sockaddr *)&sock_in, sizeof(sock_in));
580       if (error < 0)
581         {
582           errval = get_errno();
583           nfs_debug_error("psock_bind failed: %d\n", errval);
584         }
585     }
586   while (errval == EADDRINUSE && trycount > 0);
587 
588   if (error)
589     {
590       nfs_debug_error("psock_bind failed: %d, port = %d\n", errval, tport);
591       goto bad;
592     }
593 #endif
594   error = connect(rpc->rc_so, saddr, sizeof(*saddr));
595   if (error < 0)
596     {
597       errval = get_errno();
598       nfs_debug_error("psock_connect failed [port=%d]: %d\n",
599            ntohs(((struct sockaddr_in *)saddr)->sin_port), errval);
600       goto bad;
601     }
602   return error;
603 bad:
604   rpcclnt_disconnect(rpc);
605   return errval;
606 }
607 
608 /****************************************************************************
609  * Public Functions
610  ****************************************************************************/
611 
612 /****************************************************************************
613  * Name: rpcclnt_init
614  *
615  * Description:
616  *   Initialize the RPC client
617  *
618  ****************************************************************************/
619 
rpcclnt_init(void)620 void rpcclnt_init(void)
621 {
622   /* RPC constants how about actually using more than one of these! */
623 
624   rpc_reply = txdr_unsigned(RPC_REPLY);
625   rpc_vers = txdr_unsigned(RPC_VER2);
626   rpc_call = txdr_unsigned(RPC_CALL);
627   rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
628   rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
629   rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
630   rpc_autherr = txdr_unsigned(RPC_AUTHERR);
631   rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
632   rpc_auth_null = txdr_unsigned(RPCAUTH_NULL);
633 
634   nfs_debug_info("RPC initialized\n");
635 }
636 
637 /****************************************************************************
638  * Name: rpcclnt_connect
639  *
640  * Description:
641  *   Initialize sockets for a new RPC connection.  We do not free the
642  *   sockaddr if an error occurs.
643  *
644  ****************************************************************************/
645 
rpcclnt_connect(struct rpcclnt * rpc)646 int rpcclnt_connect(struct rpcclnt *rpc)
647 {
648   extern long random(void);
649   int error;
650   struct sockaddr *saddr;
651   struct sockaddr_in sin;
652   struct sockaddr_in *sa;
653 
654   union
655   {
656     struct rpc_call_pmap  sdata;
657     struct rpc_call_mount mountd;
658   } request;
659 
660   union
661   {
662     struct rpc_reply_pmap  rdata;
663     struct rpc_reply_mount mdata;
664   } response;
665 
666   uint16_t trycount;
667   uint16_t tport = 0;
668   int errval;
669 
670   nfs_debug_info("Connecting\n");
671 
672   /* Create the socket */
673 
674   saddr = rpc->rc_name;
675 
676   /* Create an instance of the socket state structure */
677 
678   error = socket(saddr->sa_family, rpc->rc_sotype, NFS_PROTOTYPE);
679   if (error < 0)
680     {
681       nfs_debug_error("psock_socket failed: %d", get_errno());
682       return -error;
683     }
684 
685   rpc->rc_so              = error;
686   sin.sin_family      = AF_INET;
687   sin.sin_addr.s_addr = INADDR_ANY;
688   trycount                = RPCCLNT_CONNECT_MAX_RETRY_TIMES;
689 
690   do
691     {
692       errval = 0;
693       trycount--;
694       tport = random() % (RPCCONN_MAXPORT - RPCCONN_MINPORT) + RPCCONN_MINPORT;
695       sin.sin_port = htons(tport);
696 
697       error = bind(rpc->rc_so, (struct sockaddr *)&sin, sizeof(sin));
698       if (error < 0)
699         {
700           errval = get_errno();
701           nfs_debug_error("psock_bind failed: %d\n", errval);
702         }
703     }
704   while (errval == EADDRINUSE && trycount > 0);
705 
706   if (error)
707     {
708       nfs_debug_error("psock_bind failed: %d, port = %d\n", errval, tport);
709       goto bad;
710     }
711 
712   /* Protocols that do not require connections could be optionally left
713    * unconnected.  That would allow servers to reply from a port other than
714    * the NFS_PORT.
715    */
716 
717   error = connect(rpc->rc_so, saddr, sizeof(*saddr));
718   if (error < 0)
719     {
720       error = get_errno();
721       nfs_debug_error("psock_connect to PMAP port failed: %d", error);
722       goto bad;
723     }
724 
725   /* Do the RPC to get a dynamic bounding with the server using ppmap.
726    * Get port number for MOUNTD.
727    */
728 
729   request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
730   request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
731   request.sdata.pmap.proc = txdr_unsigned(NFS_PROTOTYPE);
732   request.sdata.pmap.port = 0;
733 
734   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
735                           (void *)&request.sdata, sizeof(struct call_args_pmap),
736                           (void *)&response.rdata, sizeof(struct rpc_reply_pmap));
737   if (error != 0)
738     {
739       nfs_error("rpcclnt_request failed: %d\n", error);
740       goto bad;
741     }
742 
743   sa = (struct sockaddr_in *)saddr;
744   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
745 
746   error = rpcclnt_reconnect(rpc, saddr);
747   if (error != 0)
748     {
749       nfs_error("rpcclnt_reconnect failed: %d\n", error);
750       goto bad;
751     }
752 
753   /* Do RPC to mountd. */
754 
755   error = memset_s(&request, sizeof(request), 0, sizeof(request));
756   if (error != EOK)
757     {
758       error = ENOBUFS;
759       goto bad;
760     }
761   error = strncpy_s(request.mountd.mount.rpath, sizeof(request.mountd.mount.rpath),
762                     rpc->rc_path, RPC_RPATH_MAXSIZE - 1);
763   if (error != EOK)
764     {
765       error = ENOBUFS;
766       goto bad;
767     }
768   request.mountd.mount.len =  txdr_unsigned(sizeof(request.mountd.mount.rpath));
769 
770   error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER3,
771                           (void *)&request.mountd,
772                           sizeof(struct call_args_mount),
773                           (void *)&response.mdata,
774                           sizeof(struct rpc_reply_mount));
775   if (error != 0)
776     {
777       nfs_error("rpcclnt_request failed: %d\n", error);
778       goto bad;
779     }
780 
781   error = fxdr_unsigned(uint32_t, response.mdata.mount.status);
782   if (error != 0)
783     {
784       nfs_debug_error("Bad mount status: %d\n", error);
785       goto bad;
786     }
787 
788   rpc->rc_fhsize = fxdr_unsigned(uint32_t, response.mdata.mount.fhandle.length);
789   memcpy(&rpc->rc_fh, &response.mdata.mount.fhandle.handle, rpc->rc_fhsize);
790 
791   /* Do the RPC to get a dynamic bounding with the server using PMAP.
792    * NFS port in the socket.
793    */
794 
795   sa->sin_port = htons(PMAPPORT);
796 
797   error = rpcclnt_reconnect(rpc, saddr);
798   if (error != 0)
799     {
800       nfs_error("rpcclnt_reconnect failed: %d\n", error);
801       goto bad;
802     }
803 
804   request.sdata.pmap.prog = txdr_unsigned(NFS_PROG);
805   request.sdata.pmap.vers = txdr_unsigned(NFS_VER3);
806   request.sdata.pmap.proc = txdr_unsigned(NFS_PROTOTYPE);
807   request.sdata.pmap.port = 0;
808 
809   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
810                           (void *)&request.sdata,
811                           sizeof(struct call_args_pmap),
812                           (void *)&response.rdata,
813                           sizeof(struct rpc_reply_pmap));
814   if (error != 0)
815     {
816       nfs_error("rpcclnt_request failed: %d\n", error);
817       goto bad;
818     }
819 
820   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
821 
822   error = rpcclnt_reconnect(rpc, saddr);
823   if (error != 0)
824     {
825       nfs_error("rpcclnt_reconnect failed: %d\n", error);
826       goto bad;
827     }
828 
829   return OK;
830 
831 bad:
832   rpcclnt_disconnect(rpc);
833   return error;
834 }
835 
836 /****************************************************************************
837  * Name: rpcclnt_disconnect
838  *
839  * Description:
840  *   Disconnect from the NFS server.
841  *
842  ****************************************************************************/
843 
rpcclnt_disconnect(struct rpcclnt * rpc)844 void rpcclnt_disconnect(struct rpcclnt *rpc)
845 {
846   if (rpc->rc_so != -1)
847     {
848       (void)lwip_close(rpc->rc_so);
849       rpc->rc_so = -1;
850     }
851 }
852 
853 /****************************************************************************
854  * Name: rpcclnt_umount
855  *
856  * Description:
857  *   Un-mount the NFS file system.
858  *
859  ****************************************************************************/
860 
rpcclnt_umount(struct rpcclnt * rpc)861 int rpcclnt_umount(struct rpcclnt *rpc)
862 {
863   struct sockaddr *saddr;
864   struct sockaddr_in *sa;
865 
866   union
867   {
868     struct rpc_call_pmap   sdata;
869     struct rpc_call_umount mountd;
870   } request;
871 
872   union
873   {
874     struct rpc_reply_pmap   rdata;
875     struct rpc_reply_umount mdata;
876   } response;
877 
878   int error;
879 
880   saddr = rpc->rc_name;
881   sa = (struct sockaddr_in *)saddr;
882 
883   /* Do the RPC to get a dynamic bounding with the server using ppmap.
884    * Get port number for MOUNTD.
885    */
886 
887   sa->sin_port = htons(PMAPPORT);
888 
889   error = rpcclnt_reconnect(rpc, saddr);
890   if (error != 0)
891     {
892       nfs_error("rpcclnt_reconnect failed: %d\n", error);
893       goto bad;
894     }
895 
896   request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
897   request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
898   request.sdata.pmap.proc = txdr_unsigned(NFS_PROTOTYPE);
899   request.sdata.pmap.port = 0;
900 
901   error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
902                           (void *)&request.sdata,
903                           sizeof(struct call_args_pmap),
904                           (void *)&response.rdata,
905                           sizeof(struct rpc_reply_pmap));
906   if (error != 0)
907     {
908       nfs_error("rpcclnt_request failed: %d\n", error);
909       goto bad;
910     }
911 
912   sa->sin_port = htons(fxdr_unsigned(uint32_t, response.rdata.pmap.port));
913 
914   error = rpcclnt_reconnect(rpc, saddr);
915   if (error != 0)
916     {
917       nfs_error("rpcclnt_reconnect failed: %d\n", error);
918       goto bad;
919     }
920 
921   /* Do RPC to umountd. */
922 
923   (void)strncpy_s(request.mountd.umount.rpath, sizeof(request.mountd.umount.rpath),
924                   rpc->rc_path, sizeof(request.mountd.umount.rpath) - 1);
925   request.mountd.umount.rpath[sizeof(request.mountd.umount.rpath) - 1] = 0;
926   request.mountd.umount.len =  txdr_unsigned(sizeof(request.mountd.umount.rpath));
927 
928   error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER3,
929                           (void *)&request.mountd,
930                           sizeof(struct call_args_umount),
931                           (void *)&response.mdata,
932                           sizeof(struct rpc_reply_umount));
933   if (error != 0)
934     {
935       nfs_error("rpcclnt_request failed: %d\n", error);
936       goto bad;
937     }
938 
939   return OK;
940 
941 bad:
942 
943   /* No need to close the socket here, if umount failed. user has to call nfs_unbind again */
944 
945   return error;
946 }
947 
948 /****************************************************************************
949  * Name: rpcclnt_request
950  *
951  * Description:
952  *   Perform the RPC request.  Logic formats the RPC CALL message and calls
953  *   rpcclnt_send to send the RPC CALL message.  It then calls rpcclnt_reply()
954  *   to get the response.  It may attempt to re-send the CALL message on
955  *   certain errors.
956  *
957  *   On successful receipt, it verifies the RPC level of the returned values.
958  *   (There may still be be NFS layer errors that will be deted by calling
959  *   logic).
960  *
961  ****************************************************************************/
962 
rpcclnt_request(struct rpcclnt * rpc,int procnum,int prog,int version,void * request,size_t reqlen,void * response,size_t resplen)963 int rpcclnt_request(struct rpcclnt *rpc, int procnum, int prog,
964                     int version, void *request, size_t reqlen,
965                     void *response, size_t resplen)
966 {
967   struct rpc_reply_header *replymsg;
968   uint32_t tmp;
969 #if (NFS_PROTO_TYPE == NFS_IPPROTO_UDP)
970   int retries;
971 #endif
972   int error = 0;
973 
974   /* Get a new (non-zero) xid */
975 
976   rpc->xid = rpcclnt_newxid();
977 
978   /* Get the full size of the message (the size of variable data plus the size of
979    * the messages header).
980    */
981 
982   reqlen += sizeof(struct rpc_call_header);
983 
984   /* Initialize the RPC header fields */
985 
986   rpcclnt_fmtheader((struct rpc_call_header *)request,
987                     rpc->xid, prog, version, procnum, reqlen);
988 
989   /* Send the RPC call messsages and receive the RPC response. For UDP-RPC, A limited
990    * number of re-tries will be attempted, but only for the case of response
991    * timeouts. While for TCP-RPC, no retry attempted.
992    */
993 
994 #if (NFS_PROTO_TYPE == NFS_IPPROTO_UDP)
995   retries = 0;
996   do
997     {
998       /* Do the client side RPC. */
999 
1000       rpc_statistics(rpcrequests);
1001       rpc->rc_timeout = false;
1002 
1003       /* Send the RPC CALL message */
1004 
1005       error = rpcclnt_send(rpc, procnum, prog, request, reqlen);
1006       if (error != OK)
1007         {
1008           nfs_debug_info("ERROR rpcclnt_send failed: %d\n", error);
1009         }
1010 
1011       /* Wait for the reply from our send */
1012 
1013       else
1014         {
1015           error = rpcclnt_reply(rpc, procnum, prog, response, resplen);
1016           if (error != OK)
1017             {
1018               nfs_debug_info("ERROR rpcclnt_reply failed: %d\n", error);
1019             }
1020         }
1021 
1022       retries++;
1023     }
1024   while (rpc->rc_timeout && retries <= rpc->rc_retry);
1025 
1026   if (error != OK)
1027     {
1028       nfs_debug_error("RPC failed: %d\n", error);
1029       return error;
1030     }
1031 
1032 #else
1033 
1034   /* check tcp connection alive or not as server would close connection if long time no data transfer */
1035 
1036   if (rpc->rc_so != -1)
1037     {
1038       error = rpcclnt_alivecheck(rpc);
1039       if (error != OK)
1040         {
1041           nfs_debug_error("rpc_alivecheck failed: %d\n", error);
1042           return error;
1043         }
1044     }
1045 
1046   /* reconnect due to previous connection down */
1047 
1048   if (rpc->rc_so == -1)
1049     {
1050       error = rpcclnt_reconnect(rpc, rpc->rc_name);
1051       if (error != OK)
1052         {
1053           nfs_debug_error("rpcclnt_send failed: %d\n", error);
1054           return error;
1055         }
1056     }
1057 
1058   rpc_statistics(rpcrequests);
1059 
1060   /* Send the RPC CALL message */
1061 
1062   error = rpcclnt_send(rpc, procnum, prog, request, reqlen);
1063   if (error != OK)
1064     {
1065       rpcclnt_disconnect(rpc);
1066       nfs_debug_error("rpcclnt_send failed: %d\n", error);
1067       return error;
1068     }
1069 
1070   /* Wait for the reply from our send */
1071 
1072   error = rpcclnt_reply(rpc, procnum, prog, response, resplen);
1073   if (error != OK)
1074     {
1075       rpcclnt_disconnect(rpc);
1076       nfs_debug_error("rpcclnt_reply failed: %d\n", error);
1077       return error;
1078     }
1079 
1080 #endif
1081 
1082   /* Break down the RPC header and check if it is OK */
1083 
1084   replymsg = (struct rpc_reply_header *)response;
1085 
1086   tmp = fxdr_unsigned(uint32_t, replymsg->type);
1087   if (tmp == RPC_MSGDENIED)
1088     {
1089       tmp = fxdr_unsigned(uint32_t, replymsg->status);
1090       switch (tmp)
1091         {
1092         case RPC_MISMATCH:
1093           nfs_debug_error("RPC_MSGDENIED: RPC_MISMATCH error\n");
1094           return EOPNOTSUPP;
1095 
1096         case RPC_AUTHERR:
1097           nfs_debug_error("RPC_MSGDENIED: RPC_AUTHERR error\n");
1098           return EACCES;
1099 
1100         default:
1101           return EOPNOTSUPP;
1102         }
1103     }
1104   else if (tmp != RPC_MSGACCEPTED)
1105     {
1106       return EOPNOTSUPP;
1107     }
1108 
1109   tmp = fxdr_unsigned(uint32_t, replymsg->status);
1110   if (tmp == RPC_SUCCESS)
1111     {
1112       nfs_debug_info("RPC_SUCCESS\n");
1113     }
1114   else if (tmp == RPC_PROGMISMATCH)
1115     {
1116       nfs_debug_error("RPC_MSGACCEPTED: RPC_PROGMISMATCH error\n");
1117       return EOPNOTSUPP;
1118     }
1119   else if (tmp > 5)
1120     {
1121       nfs_debug_error("Unsupported RPC type: %d\n", tmp);
1122       return EOPNOTSUPP;
1123     }
1124 
1125   return OK;
1126 }
1127 
rpcclnt_setuidgid(uint32_t uid,uint32_t gid)1128 void rpcclnt_setuidgid(uint32_t uid, uint32_t gid)
1129 {
1130   nfs_uid = uid;
1131   nfs_gid = gid;
1132 }
1133