You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <assert.h>
  24. #include <errno.h>
  25. #include <libgen.h>
  26. #include <byteswap.h>
  27. #include <ipxe/time.h>
  28. #include <ipxe/iobuf.h>
  29. #include <ipxe/open.h>
  30. #include <ipxe/features.h>
  31. #include <ipxe/nfs.h>
  32. #include <ipxe/oncrpc.h>
  33. #include <ipxe/oncrpc_iob.h>
  34. #include <ipxe/portmap.h>
  35. #include <ipxe/mount.h>
  36. #include <ipxe/settings.h>
  37. /** @file
  38. *
  39. * Network File System protocol
  40. *
  41. */
  42. /** NFS LOOKUP procedure */
  43. #define NFS_LOOKUP 3
  44. /** NFS READLINK procedure */
  45. #define NFS_READLINK 5
  46. /** NFS READ procedure */
  47. #define NFS_READ 6
  48. /**
  49. * Extract a file handle from the beginning of an I/O buffer
  50. *
  51. * @v io_buf I/O buffer
  52. * @v fh File handle
  53. * @ret size Size of the data read
  54. */
  55. size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ) {
  56. fh->size = oncrpc_iob_get_int ( io_buf );
  57. if ( fh->size > 64 )
  58. return sizeof ( uint32_t );
  59. memcpy (fh->fh, io_buf->data, fh->size );
  60. iob_pull ( io_buf, fh->size );
  61. return fh->size + sizeof ( uint32_t );
  62. }
  63. /**
  64. * Add a file handle to the end of an I/O buffer
  65. *
  66. * @v io_buf I/O buffer
  67. * @v fh File handle
  68. * @ret size Size of the data written
  69. */
  70. size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ) {
  71. size_t s;
  72. s = oncrpc_iob_add_int ( io_buf, fh->size );
  73. memcpy ( iob_put ( io_buf, fh->size ), &fh->fh, fh->size );
  74. return s + fh->size;
  75. }
  76. /**
  77. * Send a LOOKUP request
  78. *
  79. * @v intf Interface to send the request on
  80. * @v session ONC RPC session
  81. * @v fh The file handle of the the directory
  82. * @v filename The file name
  83. * @ret rc Return status code
  84. */
  85. int nfs_lookup ( struct interface *intf, struct oncrpc_session *session,
  86. const struct nfs_fh *fh, const char *filename ) {
  87. struct oncrpc_field fields[] = {
  88. ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
  89. ONCRPC_FIELD ( str, filename ),
  90. ONCRPC_FIELD_END,
  91. };
  92. return oncrpc_call ( intf, session, NFS_LOOKUP, fields );
  93. }
  94. /**
  95. * Send a READLINK request
  96. *
  97. * @v intf Interface to send the request on
  98. * @v session ONC RPC session
  99. * @v fh The symlink file handle
  100. * @ret rc Return status code
  101. */
  102. int nfs_readlink ( struct interface *intf, struct oncrpc_session *session,
  103. const struct nfs_fh *fh ) {
  104. struct oncrpc_field fields[] = {
  105. ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
  106. ONCRPC_FIELD_END,
  107. };
  108. return oncrpc_call ( intf, session, NFS_READLINK, fields );
  109. }
  110. /**
  111. * Send a READ request
  112. *
  113. * @v intf Interface to send the request on
  114. * @v session ONC RPC session
  115. * @v fh The file handle
  116. * @v offset Offset
  117. * @v count Byte count
  118. * @ret rc Return status code
  119. */
  120. int nfs_read ( struct interface *intf, struct oncrpc_session *session,
  121. const struct nfs_fh *fh, uint64_t offset, uint32_t count ) {
  122. struct oncrpc_field fields[] = {
  123. ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
  124. ONCRPC_FIELD ( int64, offset ),
  125. ONCRPC_FIELD ( int32, count ),
  126. ONCRPC_FIELD_END,
  127. };
  128. return oncrpc_call ( intf, session, NFS_READ, fields );
  129. }
  130. /**
  131. * Parse a LOOKUP reply
  132. *
  133. * @v lookup_reply A structure where the data will be saved
  134. * @v reply The ONC RPC reply to get data from
  135. * @ret rc Return status code
  136. */
  137. int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply,
  138. struct oncrpc_reply *reply ) {
  139. if ( ! lookup_reply || ! reply )
  140. return -EINVAL;
  141. lookup_reply->status = oncrpc_iob_get_int ( reply->data );
  142. switch ( lookup_reply->status )
  143. {
  144. case NFS3_OK:
  145. break;
  146. case NFS3ERR_PERM:
  147. return -EPERM;
  148. case NFS3ERR_NOENT:
  149. return -ENOENT;
  150. case NFS3ERR_IO:
  151. return -EIO;
  152. case NFS3ERR_ACCES:
  153. return -EACCES;
  154. case NFS3ERR_NOTDIR:
  155. return -ENOTDIR;
  156. case NFS3ERR_NAMETOOLONG:
  157. return -ENAMETOOLONG;
  158. case NFS3ERR_STALE:
  159. return -ESTALE;
  160. case NFS3ERR_BADHANDLE:
  161. case NFS3ERR_SERVERFAULT:
  162. default:
  163. return -EPROTO;
  164. }
  165. nfs_iob_get_fh ( reply->data, &lookup_reply->fh );
  166. if ( oncrpc_iob_get_int ( reply->data ) == 1 )
  167. lookup_reply->ent_type = oncrpc_iob_get_int ( reply->data );
  168. return 0;
  169. }
  170. /**
  171. * Parse a READLINK reply
  172. *
  173. * @v readlink_reply A structure where the data will be saved
  174. * @v reply The ONC RPC reply to get data from
  175. * @ret rc Return status code
  176. */
  177. int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply,
  178. struct oncrpc_reply *reply ) {
  179. if ( ! readlink_reply || ! reply )
  180. return -EINVAL;
  181. readlink_reply->status = oncrpc_iob_get_int ( reply->data );
  182. switch ( readlink_reply->status )
  183. {
  184. case NFS3_OK:
  185. break;
  186. case NFS3ERR_IO:
  187. return -EIO;
  188. case NFS3ERR_ACCES:
  189. return -EACCES;
  190. case NFS3ERR_INVAL:
  191. return -EINVAL;
  192. case NFS3ERR_NOTSUPP:
  193. return -ENOTSUP;
  194. case NFS3ERR_STALE:
  195. return -ESTALE;
  196. case NFS3ERR_BADHANDLE:
  197. case NFS3ERR_SERVERFAULT:
  198. default:
  199. return -EPROTO;
  200. }
  201. if ( oncrpc_iob_get_int ( reply->data ) == 1 )
  202. iob_pull ( reply->data, 5 * sizeof ( uint32_t ) +
  203. 8 * sizeof ( uint64_t ) );
  204. readlink_reply->path_len = oncrpc_iob_get_int ( reply->data );
  205. readlink_reply->path = reply->data->data;
  206. return 0;
  207. }
  208. /**
  209. * Parse a READ reply
  210. *
  211. * @v read_reply A structure where the data will be saved
  212. * @v reply The ONC RPC reply to get data from
  213. * @ret rc Return status code
  214. */
  215. int nfs_get_read_reply ( struct nfs_read_reply *read_reply,
  216. struct oncrpc_reply *reply ) {
  217. if ( ! read_reply || ! reply )
  218. return -EINVAL;
  219. read_reply->status = oncrpc_iob_get_int ( reply->data );
  220. switch ( read_reply->status )
  221. {
  222. case NFS3_OK:
  223. break;
  224. case NFS3ERR_PERM:
  225. return -EPERM;
  226. case NFS3ERR_NOENT:
  227. return -ENOENT;
  228. case NFS3ERR_IO:
  229. return -EIO;
  230. case NFS3ERR_NXIO:
  231. return -ENXIO;
  232. case NFS3ERR_ACCES:
  233. return -EACCES;
  234. case NFS3ERR_INVAL:
  235. return -EINVAL;
  236. case NFS3ERR_STALE:
  237. return -ESTALE;
  238. case NFS3ERR_BADHANDLE:
  239. case NFS3ERR_SERVERFAULT:
  240. default:
  241. return -EPROTO;
  242. }
  243. if ( oncrpc_iob_get_int ( reply->data ) == 1 )
  244. {
  245. iob_pull ( reply->data, 5 * sizeof ( uint32_t ) );
  246. read_reply->filesize = oncrpc_iob_get_int64 ( reply->data );
  247. iob_pull ( reply->data, 7 * sizeof ( uint64_t ) );
  248. }
  249. read_reply->count = oncrpc_iob_get_int ( reply->data );
  250. read_reply->eof = oncrpc_iob_get_int ( reply->data );
  251. read_reply->data_len = oncrpc_iob_get_int ( reply->data );
  252. read_reply->data = reply->data->data;
  253. if ( read_reply->count != read_reply->data_len )
  254. return -EPROTO;
  255. return 0;
  256. }