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