rpc_clnt.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  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 at
  47. * 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 ANY
  64. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  65. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  66. * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
  67. * 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. * Included Files
  78. ****************************************************************************/
  79. #include <sys/socket.h>
  80. #include <sys/time.h>
  81. #include <queue.h>
  82. #include <netinet/in.h>
  83. #include <arpa/inet.h>
  84. #include <errno.h>
  85. #include <string.h>
  86. #include <debug.h>
  87. #include "xdr_subs.h"
  88. #include "nfs_proto.h"
  89. #include "rpc.h"
  90. /****************************************************************************
  91. * Pre-processor Definitions
  92. ****************************************************************************/
  93. /* Increment RPC statistics */
  94. #ifdef CONFIG_NFS_STATISTICS
  95. # define rpc_statistics(n) do { rpcstats.n++; } while (0)
  96. #else
  97. # define rpc_statistics(n)
  98. #endif
  99. /****************************************************************************
  100. * Private Types
  101. ****************************************************************************/
  102. /* Global RPC statistics */
  103. #ifdef CONFIG_NFS_STATISTICS
  104. struct rpcstats
  105. {
  106. int rpcretries;
  107. int rpcrequests;
  108. int rpctimeouts;
  109. int rpcinvalid;
  110. };
  111. #endif
  112. /****************************************************************************
  113. * Private Data
  114. ****************************************************************************/
  115. /* Static data, mostly RPC constants in XDR form */
  116. static uint32_t rpc_reply;
  117. static uint32_t rpc_call;
  118. static uint32_t rpc_vers;
  119. static uint32_t rpc_auth_null;
  120. static uint32_t rpc_auth_unix;
  121. /* Global statics for all client instances. Cleared by NuttX on boot-up. */
  122. #ifdef CONFIG_NFS_STATISTICS
  123. static struct rpcstats rpcstats;
  124. #endif
  125. /****************************************************************************
  126. * Private Function Prototypes
  127. ****************************************************************************/
  128. static int rpcclnt_socket(FAR struct rpcclnt *rpc, in_port_t rport);
  129. static int rpcclnt_send(FAR struct rpcclnt *rpc,
  130. FAR void *call, int reqlen);
  131. static int rpcclnt_receive(FAR struct rpcclnt *rpc,
  132. FAR void *reply, size_t resplen);
  133. static int rpcclnt_reply(FAR struct rpcclnt *rpc, uint32_t xid,
  134. FAR void *reply, size_t resplen);
  135. static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
  136. uint32_t xid, int procid, int prog, int vers);
  137. /****************************************************************************
  138. * Private Functions
  139. ****************************************************************************/
  140. /****************************************************************************
  141. * Name: rpcclnt_socket
  142. *
  143. * Description:
  144. * Close(old), create, bind and connect the socket.
  145. *
  146. * Returned Value:
  147. * Returns zero on success or a (negative) errno value on failure.
  148. *
  149. ****************************************************************************/
  150. static int rpcclnt_socket(FAR struct rpcclnt *rpc, in_port_t rport)
  151. {
  152. struct sockaddr_storage raddr;
  153. struct sockaddr_storage laddr;
  154. FAR in_port_t *lport;
  155. in_port_t port = 1024;
  156. struct timeval tv;
  157. socklen_t addrlen;
  158. int error;
  159. /* Close the old socket */
  160. psock_close(&rpc->rc_so);
  161. /* Prepare the socket address */
  162. memcpy(&raddr, rpc->rc_name, sizeof(raddr));
  163. laddr.ss_family = raddr.ss_family;
  164. memset(laddr.ss_data, 0, sizeof(laddr.ss_data));
  165. if (raddr.ss_family == AF_INET6)
  166. {
  167. FAR struct sockaddr_in6 *sin;
  168. addrlen = sizeof(struct sockaddr_in6);
  169. if (rport != 0)
  170. {
  171. sin = (FAR struct sockaddr_in6 *)&raddr;
  172. sin->sin6_port = htons(rport);
  173. }
  174. sin = (FAR struct sockaddr_in6 *)&laddr;
  175. lport = &sin->sin6_port;
  176. }
  177. else
  178. {
  179. FAR struct sockaddr_in *sin;
  180. addrlen = sizeof(struct sockaddr_in);
  181. if (rport != 0)
  182. {
  183. sin = (FAR struct sockaddr_in *)&raddr;
  184. sin->sin_port = htons(rport);
  185. }
  186. sin = (FAR struct sockaddr_in *)&laddr;
  187. lport = &sin->sin_port;
  188. }
  189. /* Create the socket */
  190. error = psock_socket(raddr.ss_family, rpc->rc_sotype, 0, &rpc->rc_so);
  191. if (error < 0)
  192. {
  193. ferr("ERROR: psock_socket failed: %d", error);
  194. return error;
  195. }
  196. /* Always set receive timeout to detect server crash and reconnect.
  197. * Otherwise, we can get stuck in psock_receive forever.
  198. */
  199. tv.tv_sec = rpc->rc_timeo / 10;
  200. tv.tv_usec = (rpc->rc_timeo % 10) * 100000;
  201. error = psock_setsockopt(&rpc->rc_so, SOL_SOCKET, SO_RCVTIMEO,
  202. (FAR const void *)&tv, sizeof(tv));
  203. if (error < 0)
  204. {
  205. ferr("ERROR: psock_setsockopt failed: %d\n", error);
  206. goto bad;
  207. }
  208. /* Some servers require that the client port be a reserved port
  209. * number. We always allocate a reserved port, as this prevents
  210. * filehandle disclosure through UDP port capture.
  211. */
  212. do
  213. {
  214. *lport = htons(--port);
  215. error = psock_bind(&rpc->rc_so, (FAR struct sockaddr *)&laddr, addrlen);
  216. if (error < 0)
  217. {
  218. ferr("ERROR: psock_bind failed: %d\n", error);
  219. }
  220. }
  221. while (error == -EADDRINUSE && port >= 512);
  222. if (error)
  223. {
  224. ferr("ERROR: psock_bind failed: %d\n", error);
  225. goto bad;
  226. }
  227. /* Protocols that do not require connections could be optionally left
  228. * unconnected. That would allow servers to reply from a port other than
  229. * the NFS_PORT.
  230. */
  231. error = psock_connect(&rpc->rc_so, (FAR struct sockaddr *)&raddr, addrlen);
  232. if (error < 0)
  233. {
  234. ferr("ERROR: psock_connect to PMAP port failed: %d", error);
  235. goto bad;
  236. }
  237. return OK;
  238. bad:
  239. psock_close(&rpc->rc_so);
  240. return error;
  241. }
  242. /****************************************************************************
  243. * Name: rpcclnt_send
  244. *
  245. * Description:
  246. * This is the nfs send routine.
  247. *
  248. * Returned Value:
  249. * Returns zero on success or a (negative) errno value on failure.
  250. *
  251. ****************************************************************************/
  252. static int rpcclnt_send(FAR struct rpcclnt *rpc,
  253. FAR void *call, int reqlen)
  254. {
  255. uint32_t mark;
  256. int ret = OK;
  257. /* Send the record marking(RM) for stream only */
  258. if (rpc->rc_sotype == SOCK_STREAM)
  259. {
  260. mark = txdr_unsigned(0x80000000 | reqlen);
  261. ret = psock_send(&rpc->rc_so, &mark, sizeof(mark), 0);
  262. if (ret < 0)
  263. {
  264. ferr("ERROR: psock_send mark failed: %d\n", ret);
  265. return ret;
  266. }
  267. }
  268. /* Send the call message
  269. *
  270. * On success, psock_send returns the number of bytes sent;
  271. * On failure, it returns a negated errno value.
  272. */
  273. ret = psock_send(&rpc->rc_so, call, reqlen, 0);
  274. if (ret < 0)
  275. {
  276. ferr("ERROR: psock_send request failed: %d\n", ret);
  277. return ret;
  278. }
  279. return OK;
  280. }
  281. /****************************************************************************
  282. * Name: rpcclnt_receive
  283. *
  284. * Description:
  285. * Receive a Sun RPC Request/Reply.
  286. *
  287. ****************************************************************************/
  288. static int rpcclnt_receive(FAR struct rpcclnt *rpc,
  289. FAR void *reply, size_t resplen)
  290. {
  291. uint32_t mark;
  292. int error = 0;
  293. /* Receive the record marking(RM) for stream only */
  294. if (rpc->rc_sotype == SOCK_STREAM)
  295. {
  296. error = psock_recv(&rpc->rc_so, &mark, sizeof(mark), 0);
  297. if (error < 0)
  298. {
  299. ferr("ERROR: psock_recv mark failed: %d\n", error);
  300. return error;
  301. }
  302. /* Limit the receive length to the marked value */
  303. mark = fxdr_unsigned(uint32_t, mark);
  304. if (!(mark & 0x80000000))
  305. {
  306. return -ENOSYS;
  307. }
  308. mark &= 0x7fffffff;
  309. if (mark > resplen)
  310. {
  311. return -E2BIG;
  312. }
  313. resplen = mark;
  314. }
  315. error = psock_recv(&rpc->rc_so, reply, resplen, 0);
  316. if (error < 0)
  317. {
  318. ferr("ERROR: psock_recv response failed: %d\n", error);
  319. return error;
  320. }
  321. return OK;
  322. }
  323. /****************************************************************************
  324. * Name: rpcclnt_reply
  325. *
  326. * Description:
  327. * Received the RPC reply on the socket.
  328. *
  329. ****************************************************************************/
  330. static int rpcclnt_reply(FAR struct rpcclnt *rpc, uint32_t xid,
  331. FAR void *reply, size_t resplen)
  332. {
  333. int error;
  334. retry:
  335. /* Get the next RPC reply from the socket */
  336. error = rpcclnt_receive(rpc, reply, resplen);
  337. if (error != 0)
  338. {
  339. ferr("ERROR: rpcclnt_receive returned: %d\n", error);
  340. }
  341. /* Get the xid and check that it is an RPC replysvr */
  342. else
  343. {
  344. FAR struct rpc_reply_header *replyheader =
  345. (FAR struct rpc_reply_header *)reply;
  346. if (replyheader->rp_direction != rpc_reply)
  347. {
  348. ferr("ERROR: Different RPC REPLY returned\n");
  349. rpc_statistics(rpcinvalid);
  350. error = -EPROTO;
  351. }
  352. else if (replyheader->rp_xid != txdr_unsigned(xid))
  353. {
  354. ferr("ERROR: Different RPC XID returned\n");
  355. rpc_statistics(rpcinvalid);
  356. goto retry;
  357. }
  358. }
  359. return error;
  360. }
  361. /****************************************************************************
  362. * Name: rpcclnt_fmtheader
  363. *
  364. * Description:
  365. * Format the common part of the call header
  366. *
  367. ****************************************************************************/
  368. static void rpcclnt_fmtheader(FAR struct rpc_call_header *ch,
  369. uint32_t xid, int prog, int vers, int procid)
  370. {
  371. /* Format the call header */
  372. ch->rp_xid = txdr_unsigned(xid);
  373. ch->rp_direction = rpc_call;
  374. ch->rp_rpcvers = rpc_vers;
  375. ch->rp_prog = txdr_unsigned(prog);
  376. ch->rp_vers = txdr_unsigned(vers);
  377. ch->rp_proc = txdr_unsigned(procid);
  378. /* rpc_auth part (auth_unix) */
  379. ch->rpc_auth.authtype = rpc_auth_unix;
  380. ch->rpc_auth.authlen = txdr_unsigned(sizeof(ch->rpc_unix));
  381. ch->rpc_unix.stamp = 0;
  382. ch->rpc_unix.hostname = 0;
  383. ch->rpc_unix.uid = 0;
  384. ch->rpc_unix.gid = 0;
  385. ch->rpc_unix.gidlist = 0;
  386. /* rpc_verf part (auth_null) */
  387. ch->rpc_verf.authtype = rpc_auth_null;
  388. ch->rpc_verf.authlen = 0;
  389. }
  390. /****************************************************************************
  391. * Public Functions
  392. ****************************************************************************/
  393. /****************************************************************************
  394. * Name: rpcclnt_init
  395. *
  396. * Description:
  397. * Initialize the RPC client
  398. *
  399. ****************************************************************************/
  400. void rpcclnt_init(void)
  401. {
  402. /* RPC constants how about actually using more than one of these! */
  403. rpc_reply = txdr_unsigned(RPC_REPLY);
  404. rpc_vers = txdr_unsigned(RPC_VER2);
  405. rpc_call = txdr_unsigned(RPC_CALL);
  406. rpc_auth_null = txdr_unsigned(RPCAUTH_NULL);
  407. rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
  408. finfo("RPC initialized\n");
  409. }
  410. /****************************************************************************
  411. * Name: rpcclnt_connect
  412. *
  413. * Description:
  414. * Initialize sockets for a new RPC connection. We do not free the
  415. * sockaddr if an error occurs.
  416. *
  417. ****************************************************************************/
  418. int rpcclnt_connect(FAR struct rpcclnt *rpc)
  419. {
  420. int error;
  421. int prot;
  422. union
  423. {
  424. struct rpc_call_pmap sdata;
  425. struct rpc_call_mount mountd;
  426. } request;
  427. union
  428. {
  429. struct rpc_reply_pmap rdata;
  430. struct rpc_reply_mount mdata;
  431. } response;
  432. finfo("Connecting\n");
  433. /* Create the socket */
  434. error = rpcclnt_socket(rpc, 0);
  435. if (error < 0)
  436. {
  437. ferr("ERROR: rpcclnt_socket failed: %d", error);
  438. return error;
  439. }
  440. prot = rpc->rc_sotype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
  441. /* Do the RPC to get a dynamic bounding with the server using ppmap.
  442. * Get port number for MOUNTD.
  443. */
  444. request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
  445. request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
  446. request.sdata.pmap.prot = txdr_unsigned(prot);
  447. request.sdata.pmap.port = 0;
  448. error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
  449. (FAR void *)&request.sdata, sizeof(struct call_args_pmap),
  450. (FAR void *)&response.rdata, sizeof(struct rpc_reply_pmap));
  451. if (error != 0)
  452. {
  453. ferr("ERROR: rpcclnt_request failed: %d\n", error);
  454. goto bad;
  455. }
  456. error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
  457. if (error < 0)
  458. {
  459. ferr("ERROR: rpcclnt_socket MOUNTD port failed: %d\n", error);
  460. goto bad;
  461. }
  462. /* Do RPC to mountd. */
  463. strncpy(request.mountd.mount.rpath, rpc->rc_path, 90);
  464. request.mountd.mount.len = txdr_unsigned(sizeof(request.mountd.mount.rpath));
  465. error = rpcclnt_request(rpc, RPCMNT_MOUNT, RPCPROG_MNT, RPCMNT_VER3,
  466. (FAR void *)&request.mountd,
  467. sizeof(struct call_args_mount),
  468. (FAR void *)&response.mdata,
  469. sizeof(struct rpc_reply_mount));
  470. if (error != 0)
  471. {
  472. ferr("ERROR: rpcclnt_request failed: %d\n", error);
  473. goto bad;
  474. }
  475. error = -fxdr_unsigned(uint32_t, response.mdata.mount.status);
  476. if (error != 0)
  477. {
  478. ferr("ERROR: Bad mount status: %d\n", error);
  479. goto bad;
  480. }
  481. rpc->rc_fhsize = fxdr_unsigned(uint32_t, response.mdata.mount.fhandle.length);
  482. memcpy(&rpc->rc_fh, &response.mdata.mount.fhandle.handle, rpc->rc_fhsize);
  483. /* Do the RPC to get a dynamic bounding with the server using PMAP.
  484. * NFS port in the socket.
  485. */
  486. error = rpcclnt_socket(rpc, 0);
  487. if (error < 0)
  488. {
  489. ferr("ERROR: rpcclnt_socket PMAP port failed: %d\n", error);
  490. goto bad;
  491. }
  492. request.sdata.pmap.prog = txdr_unsigned(NFS_PROG);
  493. request.sdata.pmap.vers = txdr_unsigned(NFS_VER3);
  494. request.sdata.pmap.prot = txdr_unsigned(prot);
  495. request.sdata.pmap.port = 0;
  496. error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
  497. (FAR void *)&request.sdata,
  498. sizeof(struct call_args_pmap),
  499. (FAR void *)&response.rdata,
  500. sizeof(struct rpc_reply_pmap));
  501. if (error != 0)
  502. {
  503. ferr("ERROR: rpcclnt_request failed: %d\n", error);
  504. goto bad;
  505. }
  506. error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
  507. if (error < 0)
  508. {
  509. ferr("ERROR: rpcclnt_socket NFS port returns %d\n", error);
  510. goto bad;
  511. }
  512. return OK;
  513. bad:
  514. psock_close(&rpc->rc_so);
  515. return error;
  516. }
  517. /****************************************************************************
  518. * Name: rpcclnt_disconnect
  519. *
  520. * Description:
  521. * Disconnect from the NFS server.
  522. *
  523. ****************************************************************************/
  524. void rpcclnt_disconnect(FAR struct rpcclnt *rpc)
  525. {
  526. union
  527. {
  528. struct rpc_call_pmap sdata;
  529. struct rpc_call_umount mountd;
  530. } request;
  531. union
  532. {
  533. struct rpc_reply_pmap rdata;
  534. struct rpc_reply_umount mdata;
  535. } response;
  536. int error;
  537. int prot;
  538. error = rpcclnt_socket(rpc, 0);
  539. if (error < 0)
  540. {
  541. ferr("ERROR: rpcclnt_socket failed: %d\n", error);
  542. goto bad;
  543. }
  544. prot = rpc->rc_sotype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
  545. request.sdata.pmap.prog = txdr_unsigned(RPCPROG_MNT);
  546. request.sdata.pmap.vers = txdr_unsigned(RPCMNT_VER3);
  547. request.sdata.pmap.prot = txdr_unsigned(prot);
  548. request.sdata.pmap.port = 0;
  549. error = rpcclnt_request(rpc, PMAPPROC_GETPORT, PMAPPROG, PMAPVERS,
  550. (FAR void *)&request.sdata,
  551. sizeof(struct call_args_pmap),
  552. (FAR void *)&response.rdata,
  553. sizeof(struct rpc_reply_pmap));
  554. if (error != 0)
  555. {
  556. ferr("ERROR: rpcclnt_request failed: %d\n", error);
  557. goto bad;
  558. }
  559. error = rpcclnt_socket(rpc, fxdr_unsigned(uint32_t, response.rdata.pmap.port));
  560. if (error < 0)
  561. {
  562. ferr("ERROR: rpcclnt_socket failed: %d\n", error);
  563. goto bad;
  564. }
  565. /* Do RPC to umountd. */
  566. strncpy(request.mountd.umount.rpath, rpc->rc_path, 90);
  567. request.mountd.umount.len = txdr_unsigned(sizeof(request.mountd.umount.rpath));
  568. error = rpcclnt_request(rpc, RPCMNT_UMOUNT, RPCPROG_MNT, RPCMNT_VER3,
  569. (FAR void *)&request.mountd,
  570. sizeof(struct call_args_umount),
  571. (FAR void *)&response.mdata,
  572. sizeof(struct rpc_reply_umount));
  573. if (error != 0)
  574. {
  575. ferr("ERROR: rpcclnt_request failed: %d\n", error);
  576. goto bad;
  577. }
  578. bad:
  579. psock_close(&rpc->rc_so);
  580. }
  581. /****************************************************************************
  582. * Name: rpcclnt_request
  583. *
  584. * Description:
  585. * Perform the RPC request. Logic formats the RPC CALL message and calls
  586. * rpcclnt_send to send the RPC CALL message. It then calls rpcclnt_reply()
  587. * to get the response. It may attempt to re-send the CALL message on
  588. * certain errors.
  589. *
  590. * On successful receipt, it verifies the RPC level of the returned values.
  591. * (There may still be be NFS layer errors that will be detected by calling
  592. * logic).
  593. *
  594. ****************************************************************************/
  595. int rpcclnt_request(FAR struct rpcclnt *rpc, int procnum, int prog,
  596. int version, FAR void *request, size_t reqlen,
  597. FAR void *response, size_t resplen)
  598. {
  599. FAR struct rpc_reply_header *replymsg;
  600. uint32_t tmp;
  601. uint32_t xid;
  602. int retries = 0;
  603. int error = 0;
  604. /* Get a new (non-zero) xid */
  605. xid = ++rpc->rc_xid;
  606. /* Initialize the RPC header fields */
  607. rpcclnt_fmtheader((FAR struct rpc_call_header *)request,
  608. xid, prog, version, procnum);
  609. /* Get the full size of the message (the size of variable data plus the size of
  610. * the messages header).
  611. */
  612. reqlen += sizeof(struct rpc_call_header);
  613. /* Send the RPC call messages and receive the RPC response. A limited
  614. * number of re-tries will be attempted, but only for the case of response
  615. * timeouts.
  616. */
  617. for (; ; )
  618. {
  619. /* Do the client side RPC. */
  620. rpc_statistics(rpcrequests);
  621. /* Send the RPC CALL message */
  622. error = rpcclnt_send(rpc, request, reqlen);
  623. if (error != OK)
  624. {
  625. finfo("ERROR rpcclnt_send failed: %d\n", error);
  626. }
  627. /* Wait for the reply from our send */
  628. else
  629. {
  630. error = rpcclnt_reply(rpc, xid, response, resplen);
  631. if (error != OK)
  632. {
  633. finfo("ERROR rpcclnt_reply failed: %d\n", error);
  634. }
  635. }
  636. /* If we failed because of a timeout, then try sending the CALL
  637. * message again.
  638. */
  639. if (error != -EAGAIN && error != -ETIMEDOUT)
  640. {
  641. break;
  642. }
  643. rpc_statistics(rpctimeouts);
  644. if (++retries >= rpc->rc_retry)
  645. {
  646. break;
  647. }
  648. rpc_statistics(rpcretries);
  649. }
  650. if (error != OK)
  651. {
  652. ferr("ERROR: RPC failed: %d\n", error);
  653. return error;
  654. }
  655. /* Break down the RPC header and check if it is OK */
  656. replymsg = (FAR struct rpc_reply_header *)response;
  657. tmp = fxdr_unsigned(uint32_t, replymsg->type);
  658. if (tmp != RPC_MSGACCEPTED)
  659. {
  660. return -EOPNOTSUPP;
  661. }
  662. tmp = fxdr_unsigned(uint32_t, replymsg->status);
  663. if (tmp == RPC_SUCCESS)
  664. {
  665. finfo("RPC_SUCCESS\n");
  666. }
  667. else
  668. {
  669. ferr("ERROR: Unsupported RPC type: %d\n", tmp);
  670. return -EOPNOTSUPP;
  671. }
  672. return OK;
  673. }