[efi] Include installed protocol list in unknown handle names
[ipxe.git] / src / net / oncrpc / nfs.c
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
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <libgen.h>
27 #include <byteswap.h>
28 #include <ipxe/time.h>
29 #include <ipxe/iobuf.h>
30 #include <ipxe/open.h>
31 #include <ipxe/features.h>
32 #include <ipxe/nfs.h>
33 #include <ipxe/oncrpc.h>
34 #include <ipxe/oncrpc_iob.h>
35 #include <ipxe/portmap.h>
36 #include <ipxe/mount.h>
37 #include <ipxe/settings.h>
38
39 /** @file
40 *
41 * Network File System protocol
42 *
43 */
44
45 /** NFS LOOKUP procedure */
46 #define NFS_LOOKUP 3
47 /** NFS READLINK procedure */
48 #define NFS_READLINK 5
49 /** NFS READ procedure */
50 #define NFS_READ 6
51
52 /**
53 * Extract a file handle from the beginning of an I/O buffer
54 *
55 * @v io_buf I/O buffer
56 * @v fh File handle
57 * @ret size Size of the data read
58 */
59 size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ) {
60 fh->size = oncrpc_iob_get_int ( io_buf );
61
62 if ( fh->size > 64 )
63 return sizeof ( uint32_t );
64
65 memcpy (fh->fh, io_buf->data, fh->size );
66 iob_pull ( io_buf, fh->size );
67
68 return fh->size + sizeof ( uint32_t );
69 }
70
71 /**
72 * Add a file handle to the end of an I/O buffer
73 *
74 * @v io_buf I/O buffer
75 * @v fh File handle
76 * @ret size Size of the data written
77 */
78 size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ) {
79 size_t s;
80
81 s = oncrpc_iob_add_int ( io_buf, fh->size );
82 memcpy ( iob_put ( io_buf, fh->size ), &fh->fh, fh->size );
83
84 return s + fh->size;
85 }
86
87 /**
88 * Send a LOOKUP request
89 *
90 * @v intf Interface to send the request on
91 * @v session ONC RPC session
92 * @v fh The file handle of the the directory
93 * @v filename The file name
94 * @ret rc Return status code
95 */
96 int nfs_lookup ( struct interface *intf, struct oncrpc_session *session,
97 const struct nfs_fh *fh, const char *filename ) {
98 struct oncrpc_field fields[] = {
99 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
100 ONCRPC_FIELD ( str, filename ),
101 ONCRPC_FIELD_END,
102 };
103
104 return oncrpc_call ( intf, session, NFS_LOOKUP, fields );
105 }
106
107 /**
108 * Send a READLINK request
109 *
110 * @v intf Interface to send the request on
111 * @v session ONC RPC session
112 * @v fh The symlink file handle
113 * @ret rc Return status code
114 */
115 int nfs_readlink ( struct interface *intf, struct oncrpc_session *session,
116 const struct nfs_fh *fh ) {
117 struct oncrpc_field fields[] = {
118 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
119 ONCRPC_FIELD_END,
120 };
121
122 return oncrpc_call ( intf, session, NFS_READLINK, fields );
123 }
124
125 /**
126 * Send a READ request
127 *
128 * @v intf Interface to send the request on
129 * @v session ONC RPC session
130 * @v fh The file handle
131 * @v offset Offset
132 * @v count Byte count
133 * @ret rc Return status code
134 */
135 int nfs_read ( struct interface *intf, struct oncrpc_session *session,
136 const struct nfs_fh *fh, uint64_t offset, uint32_t count ) {
137 struct oncrpc_field fields[] = {
138 ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ),
139 ONCRPC_FIELD ( int64, offset ),
140 ONCRPC_FIELD ( int32, count ),
141 ONCRPC_FIELD_END,
142 };
143
144 return oncrpc_call ( intf, session, NFS_READ, fields );
145 }
146
147 /**
148 * Parse a LOOKUP reply
149 *
150 * @v lookup_reply A structure where the data will be saved
151 * @v reply The ONC RPC reply to get data from
152 * @ret rc Return status code
153 */
154 int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply,
155 struct oncrpc_reply *reply ) {
156 if ( ! lookup_reply || ! reply )
157 return -EINVAL;
158
159 lookup_reply->status = oncrpc_iob_get_int ( reply->data );
160 switch ( lookup_reply->status )
161 {
162 case NFS3_OK:
163 break;
164 case NFS3ERR_PERM:
165 return -EPERM;
166 case NFS3ERR_NOENT:
167 return -ENOENT;
168 case NFS3ERR_IO:
169 return -EIO;
170 case NFS3ERR_ACCES:
171 return -EACCES;
172 case NFS3ERR_NOTDIR:
173 return -ENOTDIR;
174 case NFS3ERR_NAMETOOLONG:
175 return -ENAMETOOLONG;
176 case NFS3ERR_STALE:
177 return -ESTALE;
178 case NFS3ERR_BADHANDLE:
179 case NFS3ERR_SERVERFAULT:
180 default:
181 return -EPROTO;
182 }
183
184 nfs_iob_get_fh ( reply->data, &lookup_reply->fh );
185
186 if ( oncrpc_iob_get_int ( reply->data ) == 1 )
187 lookup_reply->ent_type = oncrpc_iob_get_int ( reply->data );
188
189 return 0;
190 }
191 /**
192 * Parse a READLINK reply
193 *
194 * @v readlink_reply A structure where the data will be saved
195 * @v reply The ONC RPC reply to get data from
196 * @ret rc Return status code
197 */
198 int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply,
199 struct oncrpc_reply *reply ) {
200 if ( ! readlink_reply || ! reply )
201 return -EINVAL;
202
203 readlink_reply->status = oncrpc_iob_get_int ( reply->data );
204 switch ( readlink_reply->status )
205 {
206 case NFS3_OK:
207 break;
208 case NFS3ERR_IO:
209 return -EIO;
210 case NFS3ERR_ACCES:
211 return -EACCES;
212 case NFS3ERR_INVAL:
213 return -EINVAL;
214 case NFS3ERR_NOTSUPP:
215 return -ENOTSUP;
216 case NFS3ERR_STALE:
217 return -ESTALE;
218 case NFS3ERR_BADHANDLE:
219 case NFS3ERR_SERVERFAULT:
220 default:
221 return -EPROTO;
222 }
223
224 if ( oncrpc_iob_get_int ( reply->data ) == 1 )
225 iob_pull ( reply->data, 5 * sizeof ( uint32_t ) +
226 8 * sizeof ( uint64_t ) );
227
228 readlink_reply->path_len = oncrpc_iob_get_int ( reply->data );
229 readlink_reply->path = reply->data->data;
230
231 return 0;
232 }
233
234 /**
235 * Parse a READ reply
236 *
237 * @v read_reply A structure where the data will be saved
238 * @v reply The ONC RPC reply to get data from
239 * @ret rc Return status code
240 */
241 int nfs_get_read_reply ( struct nfs_read_reply *read_reply,
242 struct oncrpc_reply *reply ) {
243 if ( ! read_reply || ! reply )
244 return -EINVAL;
245
246 read_reply->status = oncrpc_iob_get_int ( reply->data );
247 switch ( read_reply->status )
248 {
249 case NFS3_OK:
250 break;
251 case NFS3ERR_PERM:
252 return -EPERM;
253 case NFS3ERR_NOENT:
254 return -ENOENT;
255 case NFS3ERR_IO:
256 return -EIO;
257 case NFS3ERR_NXIO:
258 return -ENXIO;
259 case NFS3ERR_ACCES:
260 return -EACCES;
261 case NFS3ERR_INVAL:
262 return -EINVAL;
263 case NFS3ERR_STALE:
264 return -ESTALE;
265 case NFS3ERR_BADHANDLE:
266 case NFS3ERR_SERVERFAULT:
267 default:
268 return -EPROTO;
269 }
270
271 if ( oncrpc_iob_get_int ( reply->data ) == 1 )
272 {
273 iob_pull ( reply->data, 5 * sizeof ( uint32_t ) );
274 read_reply->filesize = oncrpc_iob_get_int64 ( reply->data );
275 iob_pull ( reply->data, 7 * sizeof ( uint64_t ) );
276 }
277
278 read_reply->count = oncrpc_iob_get_int ( reply->data );
279 read_reply->eof = oncrpc_iob_get_int ( reply->data );
280 read_reply->data_len = oncrpc_iob_get_int ( reply->data );
281 read_reply->data = reply->data->data;
282
283 if ( read_reply->count != read_reply->data_len )
284 return -EPROTO;
285
286 return 0;
287 }
288