~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/net/oncrpc/nfs_open.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/socket.h>
 
30
#include <ipxe/tcpip.h>
 
31
#include <ipxe/in.h>
 
32
#include <ipxe/iobuf.h>
 
33
#include <ipxe/xfer.h>
 
34
#include <ipxe/open.h>
 
35
#include <ipxe/uri.h>
 
36
#include <ipxe/features.h>
 
37
#include <ipxe/nfs.h>
 
38
#include <ipxe/nfs_open.h>
 
39
#include <ipxe/oncrpc.h>
 
40
#include <ipxe/oncrpc_iob.h>
 
41
#include <ipxe/portmap.h>
 
42
#include <ipxe/mount.h>
 
43
#include <ipxe/nfs_uri.h>
 
44
 
 
45
/** @file
 
46
 *
 
47
 * Network File System protocol
 
48
 *
 
49
 */
 
50
 
 
51
FEATURE ( FEATURE_PROTOCOL, "NFS", DHCP_EB_FEATURE_NFS, 1 );
 
52
 
 
53
#define NFS_RSIZE 100000
 
54
 
 
55
enum nfs_pm_state {
 
56
        NFS_PORTMAP_NONE = 0,
 
57
        NFS_PORTMAP_MOUNTPORT,
 
58
        NFS_PORTMAP_NFSPORT,
 
59
        MFS_PORTMAP_CLOSED,
 
60
};
 
61
 
 
62
enum nfs_mount_state {
 
63
        NFS_MOUNT_NONE = 0,
 
64
        NFS_MOUNT_MNT,
 
65
        NFS_MOUNT_UMNT,
 
66
        NFS_MOUNT_CLOSED,
 
67
};
 
68
 
 
69
enum nfs_state {
 
70
        NFS_NONE = 0,
 
71
        NFS_LOOKUP,
 
72
        NFS_LOOKUP_SENT,
 
73
        NFS_READLINK,
 
74
        NFS_READLINK_SENT,
 
75
        NFS_READ,
 
76
        NFS_READ_SENT,
 
77
        NFS_CLOSED,
 
78
};
 
79
 
 
80
/**
 
81
 * A NFS request
 
82
 *
 
83
 */
 
84
struct nfs_request {
 
85
        /** Reference counter */
 
86
        struct refcnt           refcnt;
 
87
        /** Data transfer interface */
 
88
        struct interface        xfer;
 
89
 
 
90
        struct interface        pm_intf;
 
91
        struct interface        mount_intf;
 
92
        struct interface        nfs_intf;
 
93
 
 
94
        enum nfs_pm_state       pm_state;
 
95
        enum nfs_mount_state    mount_state;
 
96
        enum nfs_state          nfs_state;
 
97
 
 
98
        struct oncrpc_session   pm_session;
 
99
        struct oncrpc_session   mount_session;
 
100
        struct oncrpc_session   nfs_session;
 
101
 
 
102
        struct oncrpc_cred_sys  auth_sys;
 
103
 
 
104
        char *                  hostname;
 
105
        struct nfs_uri          uri;
 
106
 
 
107
        struct nfs_fh           readlink_fh;
 
108
        struct nfs_fh           current_fh;
 
109
        uint64_t                file_offset;
 
110
 
 
111
        size_t                  remaining;
 
112
        int                     eof;
 
113
};
 
114
 
 
115
static void nfs_step ( struct nfs_request *nfs );
 
116
 
 
117
/**
 
118
 * Free NFS request
 
119
 *
 
120
 * @v refcnt            Reference counter
 
121
 */
 
122
static void nfs_free ( struct refcnt *refcnt ) {
 
123
        struct nfs_request      *nfs;
 
124
 
 
125
        nfs = container_of ( refcnt, struct nfs_request, refcnt );
 
126
        DBGC ( nfs, "NFS_OPEN %p freed\n", nfs );
 
127
 
 
128
        nfs_uri_free ( &nfs->uri );
 
129
 
 
130
        free ( nfs->hostname );
 
131
        free ( nfs->auth_sys.hostname );
 
132
        free ( nfs );
 
133
}
 
134
 
 
135
/**
 
136
 * Mark NFS operation as complete
 
137
 *
 
138
 * @v nfs               NFS request
 
139
 * @v rc                Return status code
 
140
 */
 
141
static void nfs_done ( struct nfs_request *nfs, int rc ) {
 
142
        if ( rc == 0 && nfs->nfs_state != NFS_CLOSED )
 
143
                rc = -ECONNRESET;
 
144
 
 
145
        DBGC ( nfs, "NFS_OPEN %p completed (%s)\n", nfs, strerror ( rc ) );
 
146
 
 
147
        intf_shutdown ( &nfs->xfer, rc );
 
148
        intf_shutdown ( &nfs->pm_intf, rc );
 
149
        intf_shutdown ( &nfs->mount_intf, rc );
 
150
        intf_shutdown ( &nfs->nfs_intf, rc );
 
151
}
 
152
 
 
153
static int nfs_connect ( struct interface *intf, uint16_t port,
 
154
                         const char *hostname ) {
 
155
        struct sockaddr_tcpip   peer;
 
156
        struct sockaddr_tcpip   local;
 
157
 
 
158
        if ( ! intf || ! hostname || ! port )
 
159
                return -EINVAL;
 
160
 
 
161
        memset ( &peer, 0, sizeof ( peer ) );
 
162
        memset ( &local, 0, sizeof ( local ) );
 
163
        peer.st_port = htons ( port );
 
164
 
 
165
        /* Use a local port < 1024 to avoid using the 'insecure' option in
 
166
         * /etc/exports file. */
 
167
        local.st_flags = TCPIP_BIND_PRIVILEGED;
 
168
 
 
169
        return xfer_open_named_socket ( intf, SOCK_STREAM,
 
170
                                        ( struct sockaddr * ) &peer, hostname,
 
171
                                        ( struct sockaddr * ) &local );
 
172
}
 
173
 
 
174
static void nfs_pm_step ( struct nfs_request *nfs ) {
 
175
        int     rc;
 
176
 
 
177
        if ( ! xfer_window ( &nfs->pm_intf ) )
 
178
                return;
 
179
 
 
180
        if ( nfs->pm_state == NFS_PORTMAP_NONE ) {
 
181
                DBGC ( nfs, "NFS_OPEN %p GETPORT call (mount)\n", nfs );
 
182
 
 
183
                rc = portmap_getport ( &nfs->pm_intf, &nfs->pm_session,
 
184
                                       ONCRPC_MOUNT, MOUNT_VERS,
 
185
                                       PORTMAP_PROTO_TCP );
 
186
                if ( rc != 0 )
 
187
                        goto err;
 
188
 
 
189
                nfs->pm_state++;
 
190
                return;
 
191
        }
 
192
 
 
193
        if ( nfs->pm_state == NFS_PORTMAP_NFSPORT ) {
 
194
                DBGC ( nfs, "NFS_OPEN %p GETPORT call (nfs)\n", nfs );
 
195
 
 
196
                rc = portmap_getport ( &nfs->pm_intf, &nfs->pm_session,
 
197
                                       ONCRPC_NFS, NFS_VERS,
 
198
                                       PORTMAP_PROTO_TCP );
 
199
                if ( rc != 0 )
 
200
                        goto err;
 
201
 
 
202
                return;
 
203
        }
 
204
 
 
205
        return;
 
206
err:
 
207
        nfs_done ( nfs, rc );
 
208
}
 
209
 
 
210
static int nfs_pm_deliver ( struct nfs_request *nfs,
 
211
                            struct io_buffer *io_buf,
 
212
                            struct xfer_metadata *meta __unused ) {
 
213
        int                             rc;
 
214
        struct oncrpc_reply             reply;
 
215
        struct portmap_getport_reply    getport_reply;
 
216
 
 
217
        oncrpc_get_reply ( &nfs->pm_session, &reply, io_buf );
 
218
        if ( reply.accept_state != 0 )
 
219
        {
 
220
                rc = -EPROTO;
 
221
                goto err;
 
222
        }
 
223
 
 
224
        if ( nfs->pm_state == NFS_PORTMAP_MOUNTPORT ) {
 
225
                DBGC ( nfs, "NFS_OPEN %p got GETPORT reply (mount)\n", nfs );
 
226
 
 
227
                rc = portmap_get_getport_reply ( &getport_reply, &reply );
 
228
                if ( rc != 0 )
 
229
                        goto err;
 
230
 
 
231
                rc = nfs_connect ( &nfs->mount_intf, getport_reply.port,
 
232
                                   nfs->hostname );
 
233
                if ( rc != 0 )
 
234
                        goto err;
 
235
 
 
236
                nfs->pm_state++;
 
237
                nfs_pm_step ( nfs );
 
238
 
 
239
                goto done;
 
240
        }
 
241
 
 
242
        if ( nfs->pm_state == NFS_PORTMAP_NFSPORT ) {
 
243
                DBGC ( nfs, "NFS_OPEN %p got GETPORT reply (nfs)\n", nfs );
 
244
 
 
245
                rc = portmap_get_getport_reply ( &getport_reply, &reply );
 
246
                if ( rc != 0 )
 
247
                        goto err;
 
248
 
 
249
                rc = nfs_connect ( &nfs->nfs_intf, getport_reply.port,
 
250
                                   nfs->hostname );
 
251
                if ( rc != 0 )
 
252
                        goto err;
 
253
 
 
254
                intf_shutdown ( &nfs->pm_intf, 0 );
 
255
                nfs->pm_state++;
 
256
 
 
257
                goto done;
 
258
        }
 
259
 
 
260
        rc = -EPROTO;
 
261
err:
 
262
        nfs_done ( nfs, rc );
 
263
done:
 
264
        free_iob ( io_buf );
 
265
        return 0;
 
266
}
 
267
 
 
268
static void nfs_mount_step ( struct nfs_request *nfs ) {
 
269
        int     rc;
 
270
 
 
271
        if ( ! xfer_window ( &nfs->mount_intf ) )
 
272
                return;
 
273
 
 
274
        if ( nfs->mount_state == NFS_MOUNT_NONE ) {
 
275
                DBGC ( nfs, "NFS_OPEN %p MNT call (%s)\n", nfs,
 
276
                       nfs_uri_mountpoint ( &nfs->uri ) );
 
277
 
 
278
                rc = mount_mnt ( &nfs->mount_intf, &nfs->mount_session,
 
279
                                 nfs_uri_mountpoint ( &nfs->uri ) );
 
280
                if ( rc != 0 )
 
281
                        goto err;
 
282
 
 
283
                nfs->mount_state++;
 
284
                return;
 
285
        }
 
286
 
 
287
        if ( nfs->mount_state == NFS_MOUNT_UMNT ) {
 
288
                DBGC ( nfs, "NFS_OPEN %p UMNT call\n", nfs );
 
289
 
 
290
                rc = mount_umnt ( &nfs->mount_intf, &nfs->mount_session,
 
291
                                 nfs_uri_mountpoint ( &nfs->uri ) );
 
292
                if ( rc != 0 )
 
293
                        goto err;
 
294
        }
 
295
 
 
296
        return;
 
297
err:
 
298
        nfs_done ( nfs, rc );
 
299
}
 
300
 
 
301
static int nfs_mount_deliver ( struct nfs_request *nfs,
 
302
                               struct io_buffer *io_buf,
 
303
                               struct xfer_metadata *meta __unused ) {
 
304
        int                     rc;
 
305
        struct oncrpc_reply     reply;
 
306
        struct mount_mnt_reply  mnt_reply;
 
307
 
 
308
        oncrpc_get_reply ( &nfs->mount_session, &reply, io_buf );
 
309
        if ( reply.accept_state != 0 )
 
310
        {
 
311
                rc = -EPROTO;
 
312
                goto err;
 
313
        }
 
314
 
 
315
        if ( nfs->mount_state == NFS_MOUNT_MNT ) {
 
316
                DBGC ( nfs, "NFS_OPEN %p got MNT reply\n", nfs );
 
317
                rc = mount_get_mnt_reply ( &mnt_reply, &reply );
 
318
                if ( rc != 0 ) {
 
319
                        switch ( mnt_reply.status ) {
 
320
                                case MNT3ERR_NOTDIR:
 
321
                                case MNT3ERR_NOENT:
 
322
                                case MNT3ERR_ACCES:
 
323
                                        break;
 
324
 
 
325
                                default:
 
326
                                        goto err;
 
327
                        }
 
328
 
 
329
                        if ( ! strcmp ( nfs_uri_mountpoint ( &nfs->uri ),
 
330
                                        "/" ) )
 
331
                                goto err;
 
332
 
 
333
                        if ( ( rc = nfs_uri_next_mountpoint ( &nfs->uri ) ) )
 
334
                                goto err;
 
335
 
 
336
                        DBGC ( nfs, "NFS_OPEN %p MNT failed retrying with " \
 
337
                               "%s\n", nfs, nfs_uri_mountpoint ( &nfs->uri ) );
 
338
 
 
339
                        nfs->mount_state--;
 
340
                        nfs_mount_step ( nfs );
 
341
 
 
342
                        goto done;
 
343
                }
 
344
 
 
345
                nfs->current_fh = mnt_reply.fh;
 
346
                nfs->nfs_state = NFS_LOOKUP;
 
347
                nfs_step ( nfs );
 
348
 
 
349
                goto done;
 
350
        }
 
351
 
 
352
        if ( nfs->mount_state == NFS_MOUNT_UMNT ) {
 
353
                DBGC ( nfs, "NFS_OPEN %p got UMNT reply\n", nfs );
 
354
                nfs_done ( nfs, 0 );
 
355
 
 
356
                goto done;
 
357
        }
 
358
 
 
359
        rc = -EPROTO;
 
360
err:
 
361
        nfs_done ( nfs, rc );
 
362
done:
 
363
        free_iob ( io_buf );
 
364
        return 0;
 
365
}
 
366
 
 
367
static void nfs_step ( struct nfs_request *nfs ) {
 
368
        int     rc;
 
369
        char    *path_component;
 
370
 
 
371
        if ( ! xfer_window ( &nfs->nfs_intf ) )
 
372
                return;
 
373
 
 
374
        if ( nfs->nfs_state == NFS_LOOKUP ) {
 
375
                path_component = nfs_uri_next_path_component ( &nfs->uri );
 
376
 
 
377
                DBGC ( nfs, "NFS_OPEN %p LOOKUP call (%s)\n", nfs,
 
378
                       path_component );
 
379
 
 
380
                rc = nfs_lookup ( &nfs->nfs_intf, &nfs->nfs_session,
 
381
                                  &nfs->current_fh, path_component );
 
382
                if ( rc != 0 )
 
383
                        goto err;
 
384
 
 
385
                nfs->nfs_state++;
 
386
                return;
 
387
        }
 
388
 
 
389
 
 
390
        if ( nfs->nfs_state == NFS_READLINK ) {
 
391
                DBGC ( nfs, "NFS_OPEN %p READLINK call\n", nfs );
 
392
 
 
393
                rc = nfs_readlink ( &nfs->nfs_intf, &nfs->nfs_session,
 
394
                                    &nfs->readlink_fh );
 
395
                if ( rc != 0 )
 
396
                        goto err;
 
397
 
 
398
                nfs->nfs_state++;
 
399
                return;
 
400
        }
 
401
 
 
402
        if ( nfs->nfs_state == NFS_READ ) {
 
403
                DBGC ( nfs, "NFS_OPEN %p READ call\n", nfs );
 
404
 
 
405
                rc = nfs_read ( &nfs->nfs_intf, &nfs->nfs_session,
 
406
                                &nfs->current_fh, nfs->file_offset,
 
407
                                NFS_RSIZE );
 
408
                if ( rc != 0 )
 
409
                        goto err;
 
410
 
 
411
                nfs->nfs_state++;
 
412
                return;
 
413
        }
 
414
 
 
415
        return;
 
416
err:
 
417
        nfs_done ( nfs, rc );
 
418
}
 
419
 
 
420
static int nfs_deliver ( struct nfs_request *nfs,
 
421
                         struct io_buffer *io_buf,
 
422
                         struct xfer_metadata *meta __unused ) {
 
423
        int                     rc;
 
424
        struct oncrpc_reply     reply;
 
425
 
 
426
        if ( nfs->remaining == 0 ) {
 
427
                oncrpc_get_reply ( &nfs->nfs_session, &reply, io_buf );
 
428
                if ( reply.accept_state != 0 ) {
 
429
                        rc = -EPROTO;
 
430
                        goto err;
 
431
                }
 
432
        }
 
433
 
 
434
        if ( nfs->nfs_state == NFS_LOOKUP_SENT ) {
 
435
                struct nfs_lookup_reply lookup_reply;
 
436
 
 
437
                DBGC ( nfs, "NFS_OPEN %p got LOOKUP reply\n", nfs );
 
438
 
 
439
                rc = nfs_get_lookup_reply ( &lookup_reply, &reply );
 
440
                if ( rc != 0 )
 
441
                        goto err;
 
442
 
 
443
                if ( lookup_reply.ent_type == NFS_ATTR_SYMLINK ) {
 
444
                        nfs->readlink_fh = lookup_reply.fh;
 
445
                        nfs->nfs_state   = NFS_READLINK;
 
446
                } else {
 
447
                        nfs->current_fh = lookup_reply.fh;
 
448
 
 
449
                        if ( nfs->uri.lookup_pos[0] == '\0' )
 
450
                                nfs->nfs_state = NFS_READ;
 
451
                        else
 
452
                                nfs->nfs_state--;
 
453
                }
 
454
 
 
455
                nfs_step ( nfs );
 
456
                goto done;
 
457
        }
 
458
 
 
459
        if ( nfs->nfs_state == NFS_READLINK_SENT ) {
 
460
                char                      *path;
 
461
                struct nfs_readlink_reply readlink_reply;
 
462
 
 
463
                DBGC ( nfs, "NFS_OPEN %p got READLINK reply\n", nfs );
 
464
 
 
465
                rc = nfs_get_readlink_reply ( &readlink_reply, &reply );
 
466
                if ( rc != 0 )
 
467
                        goto err;
 
468
 
 
469
                if ( readlink_reply.path_len == 0 )
 
470
                {
 
471
                        rc = -EINVAL;
 
472
                        goto err;
 
473
                }
 
474
 
 
475
                if ( ! ( path = strndup ( readlink_reply.path,
 
476
                                          readlink_reply.path_len ) ) )
 
477
                {
 
478
                        rc = -ENOMEM;
 
479
                        goto err;
 
480
                }
 
481
 
 
482
                nfs_uri_symlink ( &nfs->uri, path );
 
483
                free ( path );
 
484
 
 
485
                DBGC ( nfs, "NFS_OPEN %p new path: %s\n", nfs,
 
486
                       nfs->uri.path );
 
487
 
 
488
                nfs->nfs_state = NFS_LOOKUP;
 
489
                nfs_step ( nfs );
 
490
                goto done;
 
491
        }
 
492
 
 
493
        if ( nfs->nfs_state == NFS_READ_SENT ) {
 
494
                if ( nfs->remaining == 0 ) {
 
495
                        DBGC ( nfs, "NFS_OPEN %p got READ reply\n", nfs );
 
496
 
 
497
                        struct nfs_read_reply read_reply;
 
498
 
 
499
                        rc = nfs_get_read_reply ( &read_reply, &reply );
 
500
                        if ( rc != 0 )
 
501
                                goto err;
 
502
 
 
503
                        if ( nfs->file_offset == 0 ) {
 
504
                                DBGC2 ( nfs, "NFS_OPEN %p size: %llu bytes\n",
 
505
                                        nfs, read_reply.filesize );
 
506
 
 
507
                                xfer_seek ( &nfs->xfer, read_reply.filesize );
 
508
                                xfer_seek ( &nfs->xfer, 0 );
 
509
                        }
 
510
 
 
511
                        nfs->file_offset += read_reply.count;
 
512
                        nfs->remaining    = read_reply.count;
 
513
                        nfs->eof          = read_reply.eof;
 
514
                }
 
515
 
 
516
                size_t len = iob_len ( io_buf );
 
517
                if ( len > nfs->remaining )
 
518
                        iob_unput ( io_buf, len - nfs->remaining );
 
519
 
 
520
                nfs->remaining -= iob_len ( io_buf );
 
521
 
 
522
                DBGC ( nfs, "NFS_OPEN %p got %zd bytes\n", nfs,
 
523
                       iob_len ( io_buf ) );
 
524
 
 
525
                rc = xfer_deliver_iob ( &nfs->xfer, iob_disown ( io_buf ) );
 
526
                if ( rc != 0 )
 
527
                        goto err;
 
528
 
 
529
                if ( nfs->remaining == 0 ) {
 
530
                        if ( ! nfs->eof ) {
 
531
                                nfs->nfs_state--;
 
532
                                nfs_step ( nfs );
 
533
                        } else {
 
534
                                intf_shutdown ( &nfs->nfs_intf, 0 );
 
535
                                nfs->nfs_state++;
 
536
                                nfs->mount_state++;
 
537
                                nfs_mount_step ( nfs );
 
538
                        }
 
539
                }
 
540
 
 
541
                return 0;
 
542
        }
 
543
 
 
544
        rc = -EPROTO;
 
545
err:
 
546
        nfs_done ( nfs, rc );
 
547
done:
 
548
        free_iob ( io_buf );
 
549
        return 0;
 
550
}
 
551
 
 
552
/*****************************************************************************
 
553
 * Interfaces
 
554
 *
 
555
 */
 
556
 
 
557
static struct interface_operation nfs_xfer_operations[] = {
 
558
        INTF_OP ( intf_close, struct nfs_request *, nfs_done ),
 
559
};
 
560
 
 
561
/** NFS data transfer interface descriptor */
 
562
static struct interface_descriptor nfs_xfer_desc =
 
563
        INTF_DESC ( struct nfs_request, xfer, nfs_xfer_operations );
 
564
 
 
565
static struct interface_operation nfs_pm_operations[] = {
 
566
        INTF_OP ( intf_close, struct nfs_request *, nfs_done ),
 
567
        INTF_OP ( xfer_deliver, struct nfs_request *, nfs_pm_deliver ),
 
568
        INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_pm_step ),
 
569
};
 
570
 
 
571
static struct interface_descriptor nfs_pm_desc =
 
572
        INTF_DESC ( struct nfs_request, pm_intf, nfs_pm_operations );
 
573
 
 
574
static struct interface_operation nfs_mount_operations[] = {
 
575
        INTF_OP ( intf_close, struct nfs_request *, nfs_done ),
 
576
        INTF_OP ( xfer_deliver, struct nfs_request *, nfs_mount_deliver ),
 
577
        INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_mount_step ),
 
578
};
 
579
 
 
580
static struct interface_descriptor nfs_mount_desc =
 
581
        INTF_DESC ( struct nfs_request, mount_intf, nfs_mount_operations );
 
582
 
 
583
static struct interface_operation nfs_operations[] = {
 
584
        INTF_OP ( intf_close, struct nfs_request *, nfs_done ),
 
585
        INTF_OP ( xfer_deliver, struct nfs_request *, nfs_deliver ),
 
586
        INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_step ),
 
587
};
 
588
 
 
589
static struct interface_descriptor nfs_desc =
 
590
        INTF_DESC_PASSTHRU ( struct nfs_request, nfs_intf, nfs_operations,
 
591
                             xfer );
 
592
 
 
593
/*****************************************************************************
 
594
 *
 
595
 * URI opener
 
596
 *
 
597
 */
 
598
 
 
599
static int nfs_parse_uri ( struct nfs_request *nfs, const struct uri *uri ) {
 
600
        int     rc;
 
601
 
 
602
        if ( ! uri || ! uri->host || ! uri->path )
 
603
                return -EINVAL;
 
604
 
 
605
        if ( ( rc = nfs_uri_init ( &nfs->uri, uri ) ) != 0 )
 
606
                return rc;
 
607
 
 
608
        if ( ! ( nfs->hostname = strdup ( uri->host ) ) ) {
 
609
                rc = -ENOMEM;
 
610
                goto err_hostname;
 
611
        }
 
612
 
 
613
        DBGC ( nfs, "NFS_OPEN %p URI parsed: (mountpoint=%s, path=%s)\n",
 
614
               nfs, nfs_uri_mountpoint ( &nfs->uri), nfs->uri.path );
 
615
 
 
616
        return 0;
 
617
 
 
618
err_hostname:
 
619
        nfs_uri_free ( &nfs->uri );
 
620
        return rc;
 
621
}
 
622
 
 
623
/**
 
624
 * Initiate a NFS connection
 
625
 *
 
626
 * @v xfer              Data transfer interface
 
627
 * @v uri               Uniform Resource Identifier
 
628
 * @ret rc              Return status code
 
629
 */
 
630
static int nfs_open ( struct interface *xfer, struct uri *uri ) {
 
631
        int                     rc;
 
632
        struct nfs_request      *nfs;
 
633
 
 
634
        nfs = zalloc ( sizeof ( *nfs ) );
 
635
        if ( ! nfs )
 
636
                return -ENOMEM;
 
637
 
 
638
        rc = nfs_parse_uri( nfs, uri );
 
639
        if ( rc != 0 )
 
640
                goto err_uri;
 
641
 
 
642
        rc = oncrpc_init_cred_sys ( &nfs->auth_sys );
 
643
        if ( rc != 0 )
 
644
                goto err_cred;
 
645
 
 
646
        ref_init ( &nfs->refcnt, nfs_free );
 
647
        intf_init ( &nfs->xfer, &nfs_xfer_desc, &nfs->refcnt );
 
648
        intf_init ( &nfs->pm_intf, &nfs_pm_desc, &nfs->refcnt );
 
649
        intf_init ( &nfs->mount_intf, &nfs_mount_desc, &nfs->refcnt );
 
650
        intf_init ( &nfs->nfs_intf, &nfs_desc, &nfs->refcnt );
 
651
 
 
652
        portmap_init_session ( &nfs->pm_session, &nfs->auth_sys.credential );
 
653
        mount_init_session ( &nfs->mount_session, &nfs->auth_sys.credential );
 
654
        nfs_init_session ( &nfs->nfs_session, &nfs->auth_sys.credential );
 
655
 
 
656
        DBGC ( nfs, "NFS_OPEN %p connecting to port mapper (%s:%d)...\n", nfs,
 
657
               nfs->hostname, PORTMAP_PORT );
 
658
 
 
659
        rc = nfs_connect ( &nfs->pm_intf, PORTMAP_PORT, nfs->hostname );
 
660
        if ( rc != 0 )
 
661
                goto err_connect;
 
662
 
 
663
        /* Attach to parent interface, mortalise self, and return */
 
664
        intf_plug_plug ( &nfs->xfer, xfer );
 
665
        ref_put ( &nfs->refcnt );
 
666
 
 
667
        return 0;
 
668
 
 
669
err_connect:
 
670
        free ( nfs->auth_sys.hostname );
 
671
err_cred:
 
672
        nfs_uri_free ( &nfs->uri );
 
673
        free ( nfs->hostname );
 
674
err_uri:
 
675
        free ( nfs );
 
676
        return rc;
 
677
}
 
678
 
 
679
/** NFS URI opener */
 
680
struct uri_opener nfs_uri_opener __uri_opener = {
 
681
        .scheme = "nfs",
 
682
        .open   = nfs_open,
 
683
};