Browse Source

[nfs] Add support for NFS protocol

Tested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Marin Hannache <git@mareo.fr>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Marin Hannache 11 years ago
parent
commit
30de9e8300

+ 1
- 1
src/Makefile View File

@@ -61,7 +61,7 @@ ZLIB_DIR	:= /usr
61 61
 SRCDIRS		:=
62 62
 SRCDIRS		+= libgcc
63 63
 SRCDIRS		+= core
64
-SRCDIRS		+= net net/tcp net/udp net/infiniband net/80211
64
+SRCDIRS		+= net net/oncrpc net/tcp net/udp net/infiniband net/80211
65 65
 SRCDIRS		+= image
66 66
 SRCDIRS		+= drivers/bus
67 67
 SRCDIRS		+= drivers/net

+ 3
- 0
src/config/config.c View File

@@ -129,6 +129,9 @@ REQUIRE_OBJECT ( https );
129 129
 #ifdef DOWNLOAD_PROTO_FTP
130 130
 REQUIRE_OBJECT ( ftp );
131 131
 #endif
132
+#ifdef DOWNLOAD_PROTO_NFS
133
+REQUIRE_OBJECT ( nfs_open );
134
+#endif
132 135
 #ifdef DOWNLOAD_PROTO_SLAM
133 136
 REQUIRE_OBJECT ( slam );
134 137
 #endif

+ 1
- 0
src/config/general.h View File

@@ -59,6 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
59 59
 #undef	DOWNLOAD_PROTO_HTTPS	/* Secure Hypertext Transfer Protocol */
60 60
 #undef	DOWNLOAD_PROTO_FTP	/* File Transfer Protocol */
61 61
 #undef	DOWNLOAD_PROTO_SLAM	/* Scalable Local Area Multicast */
62
+#undef	DOWNLOAD_PROTO_NFS	/* Network File System Protocol */
62 63
 
63 64
 /*
64 65
  * SAN boot protocols

+ 2
- 0
src/include/big_bswap.h View File

@@ -1,6 +1,8 @@
1 1
 #ifndef ETHERBOOT_BIG_BSWAP_H
2 2
 #define ETHERBOOT_BIG_BSWAP_H
3 3
 
4
+#define htonll(x)	(x)
5
+#define ntohll(x)	(x)
4 6
 #define ntohl(x) 	(x)
5 7
 #define htonl(x) 	(x)
6 8
 #define ntohs(x) 	(x)

+ 12
- 0
src/include/ipxe/dhcp.h View File

@@ -450,6 +450,18 @@ struct dhcp_netdev_desc {
450 450
  */
451 451
 #define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 )
452 452
 
453
+/** User ID
454
+ *
455
+ * This will be used as the user id for AUTH_SYS based authentication in NFS.
456
+ */
457
+#define DHCP_EB_UID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc2 )
458
+
459
+/** Group ID
460
+ *
461
+ * This will be used as the group id for AUTH_SYS based authentication in NFS.
462
+ */
463
+#define DHCP_EB_GID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc3 )
464
+
453 465
 /** iPXE version number */
454 466
 #define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb )
455 467
 

+ 6
- 0
src/include/ipxe/errfile.h View File

@@ -208,6 +208,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
208 208
 #define ERRFILE_fcoe			( ERRFILE_NET | 0x002e0000 )
209 209
 #define ERRFILE_fcns			( ERRFILE_NET | 0x002f0000 )
210 210
 #define ERRFILE_vlan			( ERRFILE_NET | 0x00300000 )
211
+#define ERRFILE_oncrpc			( ERRFILE_NET | 0x00310000 )
212
+#define ERRFILE_portmap			( ERRFILE_NET | 0x00320000 )
213
+#define ERRFILE_nfs			( ERRFILE_NET | 0x00330000 )
214
+#define ERRFILE_nfs_open		( ERRFILE_NET | 0x00340000 )
215
+#define ERRFILE_mount			( ERRFILE_NET | 0x00350000 )
216
+#define ERRFILE_oncrpc_iob		( ERRFILE_NET | 0x00360000 )
211 217
 
212 218
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
213 219
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 1
- 0
src/include/ipxe/features.h View File

@@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
54 54
 #define DHCP_EB_FEATURE_VLAN		0x26 /**< VLAN support */
55 55
 #define DHCP_EB_FEATURE_MENU		0x27 /**< Menu support */
56 56
 #define DHCP_EB_FEATURE_SDI		0x28 /**< SDI image support */
57
+#define DHCP_EB_FEATURE_NFS		0x29 /**< NFS protocol */
57 58
 
58 59
 /** @} */
59 60
 

+ 76
- 0
src/include/ipxe/mount.h View File

@@ -0,0 +1,76 @@
1
+#ifndef _IPXE_MOUNT_H
2
+#define _IPXE_MOUNT_H
3
+
4
+#include <ipxe/nfs.h>
5
+
6
+/** @file
7
+ *
8
+ * NFS MOUNT protocol.
9
+ *
10
+ */
11
+
12
+FILE_LICENCE ( GPL2_OR_LATER );
13
+
14
+/** NFS MOUNT protocol number */
15
+#define ONCRPC_MOUNT 100005
16
+/** NFS MOUNT protocol version */
17
+#define MOUNT_VERS   3
18
+
19
+
20
+/** No error */
21
+#define MNT3_OK                 0
22
+/** Not owner */
23
+#define MNT3ERR_PERM            1
24
+/** No such file or directory */
25
+#define MNT3ERR_NOENT           2
26
+/** I/O error */
27
+#define MNT3ERR_IO              5
28
+/** Permission denied */
29
+#define MNT3ERR_ACCES           13
30
+/** Not a directory */
31
+#define MNT3ERR_NOTDIR          20
32
+/** Invalid argument */
33
+#define MNT3ERR_INVAL           22
34
+/** Filename too long */
35
+#define MNT3ERR_NAMETOOLONG     63
36
+/** Operation not supported */
37
+#define MNT3ERR_NOTSUPP         10004
38
+/** A failure on the server */
39
+#define MNT3ERR_SERVERFAULT     10006
40
+
41
+
42
+/**
43
+ * A MOUNT MNT reply
44
+ *
45
+ */
46
+struct mount_mnt_reply {
47
+	/** Reply status */
48
+	uint32_t        status;
49
+	/** Root file handle */
50
+	struct nfs_fh   fh;
51
+};
52
+
53
+/**
54
+ * Prepare an ONC RPC session to be used as a MOUNT session
55
+ *
56
+ * @v session           ONC RPC session
57
+ * @v credential        ONC RPC credential
58
+ *
59
+ * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you
60
+ * don't want a particular scheme to be used.
61
+ */
62
+static inline void mount_init_session ( struct oncrpc_session *session,
63
+                                        struct oncrpc_cred *credential ) {
64
+	oncrpc_init_session ( session, credential, &oncrpc_auth_none,
65
+	                      ONCRPC_MOUNT, MOUNT_VERS );
66
+}
67
+
68
+int mount_mnt ( struct interface *intf, struct oncrpc_session *session,
69
+                const char *mountpoint );
70
+int mount_umnt ( struct interface *intf, struct oncrpc_session *session,
71
+                 const char *mountpoint );
72
+
73
+int mount_get_mnt_reply ( struct mount_mnt_reply *mnt_reply,
74
+                          struct oncrpc_reply *reply );
75
+
76
+#endif /* _IPXE_MOUNT_H */

+ 157
- 0
src/include/ipxe/nfs.h View File

@@ -0,0 +1,157 @@
1
+#ifndef _IPXE_NFS_H
2
+#define _IPXE_NFS_H
3
+
4
+#include <stdint.h>
5
+#include <ipxe/oncrpc.h>
6
+
7
+/** @file
8
+ *
9
+ * Network File System protocol.
10
+ *
11
+ */
12
+
13
+FILE_LICENCE ( GPL2_OR_LATER );
14
+
15
+/** NFS protocol number */
16
+#define ONCRPC_NFS 100003
17
+
18
+/** NFS protocol version */
19
+#define NFS_VERS   3
20
+
21
+/** No error*/
22
+#define NFS3_OK             0
23
+/** Not owner */
24
+#define NFS3ERR_PERM        1
25
+/** No such file or directory */
26
+#define NFS3ERR_NOENT       2
27
+/** I/O error */
28
+#define NFS3ERR_IO          5
29
+/** No such device or address */
30
+#define NFS3ERR_NXIO        6
31
+/** Permission denied */
32
+#define NFS3ERR_ACCES       13
33
+/** The file specified already exists */
34
+#define NFS3ERR_EXIST       17
35
+/**  Attempt to do a cross-device hard link */
36
+#define NFS3ERR_XDEV        18
37
+/** No such device */
38
+#define NFS3ERR_NODEV       19
39
+/** Not a directory */
40
+#define NFS3ERR_NOTDIR      20
41
+ /**Is a directory */
42
+#define NFS3ERR_ISDIR       21
43
+/** Invalid argument */
44
+#define NFS3ERR_INVAL       22
45
+/** Filename too long */
46
+#define NFS3ERR_NAMETOOLONG 63
47
+/** Invalid file handle */
48
+#define NFS3ERR_STALE       70
49
+/** Too many levels of remote in path */
50
+#define NFS3ERR_REMOTE      71
51
+/** Illegal NFS file handle */
52
+#define NFS3ERR_BADHANDLE   10001
53
+/**  READDIR or READDIRPLUS cookie is stale */
54
+#define NFS3ERR_BAD_COOKIE  10003
55
+/** Operation not supported */
56
+#define NFS3ERR_NOTSUPP     10004
57
+/** Buffer or request is too small */
58
+#define NFS3ERR_TOOSMALL    10005
59
+/** An error occurred on the server which does not map to any  of the legal NFS
60
+ * version 3 protocol error values */
61
+#define NFS3ERR_SERVERFAULT 10006
62
+/** The server initiated the request, but was not able to complete it in a
63
+ * timely fashion */
64
+#define NFS3ERR_JUKEBOX     10008
65
+
66
+enum nfs_attr_type {
67
+	NFS_ATTR_SYMLINK = 5,
68
+};
69
+
70
+/**
71
+ * A NFS file handle
72
+ *
73
+ */
74
+struct nfs_fh {
75
+	uint8_t               fh[64];
76
+	size_t                size;
77
+};
78
+
79
+/**
80
+ * A NFS LOOKUP reply
81
+ *
82
+ */
83
+struct nfs_lookup_reply {
84
+	/** Reply status */
85
+	uint32_t             status;
86
+	/** Entity type */
87
+	enum nfs_attr_type   ent_type;
88
+	/** File handle */
89
+	struct nfs_fh        fh;
90
+};
91
+
92
+/**
93
+ * A NFS READLINK reply
94
+ *
95
+ */
96
+struct nfs_readlink_reply {
97
+	/** Reply status */
98
+	uint32_t             status;
99
+	/** File path length */
100
+	uint32_t             path_len;
101
+	/** File path */
102
+	char                 *path;
103
+};
104
+
105
+
106
+/**
107
+ * A NFS READ reply
108
+ *
109
+ */
110
+struct nfs_read_reply {
111
+	/** Reply status */
112
+	uint32_t             status;
113
+	/** File size */
114
+	uint64_t             filesize;
115
+	/** Bytes read */
116
+	uint32_t             count;
117
+	/** End-of-File indicator */
118
+	uint32_t             eof;
119
+	/** Data length */
120
+	uint32_t             data_len;
121
+	/** Data read */
122
+	void                 *data;
123
+};
124
+
125
+size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh );
126
+size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh );
127
+
128
+/**
129
+ * Prepare an ONC RPC session to be used as a NFS session
130
+ *
131
+ * @v session           ONC RPC session
132
+ * @v credential        ONC RPC credential
133
+ *
134
+ * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you
135
+ * don't want a particular scheme to be used.
136
+ */
137
+static inline void nfs_init_session ( struct oncrpc_session *session,
138
+                                      struct oncrpc_cred *credential ) {
139
+	oncrpc_init_session ( session, credential, &oncrpc_auth_none,
140
+	                      ONCRPC_NFS, NFS_VERS );
141
+}
142
+
143
+int nfs_lookup ( struct interface *intf, struct oncrpc_session *session,
144
+                 const struct nfs_fh *fh, const char *filename );
145
+int nfs_readlink ( struct interface *intf, struct oncrpc_session *session,
146
+                   const struct nfs_fh *fh );
147
+int nfs_read ( struct interface *intf, struct oncrpc_session *session,
148
+               const struct nfs_fh *fh, uint64_t offset, uint32_t count );
149
+
150
+int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply,
151
+                           struct oncrpc_reply *reply );
152
+int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply,
153
+                             struct oncrpc_reply *reply );
154
+int nfs_get_read_reply ( struct nfs_read_reply *read_reply,
155
+                         struct oncrpc_reply *reply );
156
+
157
+#endif /* _IPXE_NFS_H */

+ 12
- 0
src/include/ipxe/nfs_open.h View File

@@ -0,0 +1,12 @@
1
+#ifndef _IPXE_NFS_OPEN_H
2
+#define _IPXE_NFS_OPEN_H
3
+
4
+/** @file
5
+ *
6
+ * Network File System protocol.
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#endif /* _IPXE_NFS_OPEN_H */

+ 128
- 0
src/include/ipxe/oncrpc.h View File

@@ -0,0 +1,128 @@
1
+#ifndef _IPXE_ONCRPC_H
2
+#define _IPXE_ONCRPC_H
3
+
4
+#include <stdint.h>
5
+#include <ipxe/interface.h>
6
+#include <ipxe/iobuf.h>
7
+
8
+/** @file
9
+ *
10
+ * SUN ONC RPC protocol.
11
+ *
12
+ */
13
+
14
+FILE_LICENCE ( GPL2_OR_LATER );
15
+
16
+/** ONC RCP Version */
17
+#define ONCRPC_VERS 2
18
+
19
+/** ONC RPC Null Authentication */
20
+#define ONCRPC_AUTH_NONE 0
21
+
22
+/** ONC RPC System Authentication (also called UNIX Authentication) */
23
+#define ONCRPC_AUTH_SYS  1
24
+
25
+/** Size of an ONC RPC header */
26
+#define ONCRPC_HEADER_SIZE ( 11 * sizeof ( uint32_t ) )
27
+
28
+#define ONCRPC_FIELD( type, value ) { oncrpc_ ## type, { .type = value } }
29
+#define ONCRPC_SUBFIELD( type, args... ) \
30
+	{ oncrpc_ ## type, { .type = { args } } }
31
+
32
+#define ONCRPC_FIELD_END { oncrpc_none, { } }
33
+
34
+/** Enusure that size is a multiple of four */
35
+#define oncrpc_align( size ) ( ( (size) + 3 ) & ~3 )
36
+
37
+/**
38
+ * Calculate the length of a string, including padding bytes.
39
+ *
40
+ * @v str               String
41
+ * @ret size            Length of the padded string
42
+ */
43
+#define oncrpc_strlen( str ) ( oncrpc_align ( strlen ( str ) ) + \
44
+                               sizeof ( uint32_t ) )
45
+
46
+struct oncrpc_cred {
47
+	uint32_t               flavor;
48
+	uint32_t               length;
49
+};
50
+
51
+struct oncrpc_cred_sys {
52
+	struct oncrpc_cred     credential;
53
+	uint32_t               stamp;
54
+	char                   *hostname;
55
+	uint32_t               uid;
56
+	uint32_t               gid;
57
+	uint32_t               aux_gid_len;
58
+	uint32_t               aux_gid[16];
59
+};
60
+
61
+struct oncrpc_reply
62
+{
63
+	struct oncrpc_cred      *verifier;
64
+	uint32_t                rpc_id;
65
+	uint32_t                reply_state;
66
+	uint32_t                accept_state;
67
+	uint32_t                frame_size;
68
+	struct io_buffer        *data;
69
+};
70
+
71
+struct oncrpc_session {
72
+	struct oncrpc_reply     pending_reply;
73
+	struct oncrpc_cred      *credential;
74
+	struct oncrpc_cred      *verifier;
75
+	uint32_t                rpc_id;
76
+	uint32_t                prog_name;
77
+	uint32_t                prog_vers;
78
+};
79
+
80
+enum oncrpc_field_type {
81
+	oncrpc_none = 0,
82
+	oncrpc_int32,
83
+	oncrpc_int64,
84
+	oncrpc_str,
85
+	oncrpc_array,
86
+	oncrpc_intarray,
87
+	oncrpc_cred,
88
+};
89
+
90
+union oncrpc_field_value {
91
+	struct {
92
+		size_t           length;
93
+		const void       *ptr;
94
+	}                        array;
95
+
96
+	struct {
97
+		size_t           length;
98
+		const uint32_t   *ptr;
99
+	}                        intarray;
100
+
101
+	int64_t                  int64;
102
+	int32_t                  int32;
103
+	const char               *str;
104
+	const struct oncrpc_cred *cred;
105
+};
106
+
107
+struct oncrpc_field {
108
+	enum oncrpc_field_type       type;
109
+	union oncrpc_field_value     value;
110
+};
111
+
112
+extern struct oncrpc_cred oncrpc_auth_none;
113
+
114
+int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys );
115
+void oncrpc_init_session ( struct oncrpc_session *session,
116
+                           struct oncrpc_cred *credential,
117
+                           struct oncrpc_cred *verifier, uint32_t prog_name,
118
+                           uint32_t prog_vers );
119
+
120
+int oncrpc_call ( struct interface *intf, struct oncrpc_session *session,
121
+                  uint32_t proc_name, const struct oncrpc_field fields[] );
122
+
123
+size_t oncrpc_compute_size ( const struct oncrpc_field fields[] );
124
+
125
+int oncrpc_get_reply ( struct oncrpc_session *session,
126
+                       struct oncrpc_reply *reply, struct io_buffer *io_buf );
127
+
128
+#endif /* _IPXE_ONCRPC_H */

+ 102
- 0
src/include/ipxe/oncrpc_iob.h View File

@@ -0,0 +1,102 @@
1
+#ifndef _IPXE_ONCRPC_IOB_H
2
+#define _IPXE_ONCRPC_IOB_H
3
+
4
+#include <stdint.h>
5
+#include <string.h>
6
+#include <ipxe/iobuf.h>
7
+#include <ipxe/refcnt.h>
8
+#include <ipxe/oncrpc.h>
9
+
10
+/** @file
11
+ *
12
+ * SUN ONC RPC protocol.
13
+ *
14
+ */
15
+
16
+FILE_LICENCE ( GPL2_OR_LATER );
17
+
18
+/**
19
+ * Add a string to the end of an I/O buffer
20
+ *
21
+ * @v io_buf            I/O buffer
22
+ * @v val               String
23
+ * @ret size            Size of the data written
24
+ */
25
+#define oncrpc_iob_add_string( buf, str ) \
26
+( { \
27
+	const char * _str = (str); \
28
+	oncrpc_iob_add_array ( (buf), strlen ( _str ), _str ); \
29
+} )
30
+
31
+/**
32
+ * Get a 32 bits integer from the beginning of an I/O buffer
33
+ *
34
+ * @v buf               I/O buffer
35
+ * @ret int             Integer
36
+ */
37
+
38
+#define oncrpc_iob_get_int( buf ) \
39
+( { \
40
+	uint32_t *_val; \
41
+	_val = (buf)->data; \
42
+	iob_pull ( (buf), sizeof ( uint32_t ) ); \
43
+	ntohl ( *_val ); \
44
+} )
45
+
46
+/**
47
+ * Get a 64 bits integer from the beginning of an I/O buffer
48
+ *
49
+ * @v buf               I/O buffer
50
+ * @ret int             Integer
51
+ */
52
+#define oncrpc_iob_get_int64( buf ) \
53
+( { \
54
+	uint64_t *_val; \
55
+	_val = (buf)->data; \
56
+	iob_pull ( (buf), sizeof ( uint64_t ) ); \
57
+	ntohll ( *_val ); \
58
+} )
59
+
60
+
61
+size_t oncrpc_iob_add_fields ( struct io_buffer *io_buf,
62
+                               const struct oncrpc_field fields[] );
63
+
64
+size_t oncrpc_iob_add_array ( struct io_buffer *io_buf, size_t length,
65
+                              const void *data );
66
+
67
+size_t oncrpc_iob_add_intarray ( struct io_buffer *io_buf, size_t length,
68
+                                 const uint32_t *array );
69
+
70
+size_t oncrpc_iob_add_cred ( struct io_buffer *io_buf,
71
+                             const struct oncrpc_cred *cred );
72
+
73
+size_t oncrpc_iob_get_cred ( struct io_buffer *io_buf,
74
+                             struct oncrpc_cred *cred );
75
+
76
+/**
77
+ * Add a 32 bits integer to the end of an I/O buffer
78
+ *
79
+ * @v io_buf            I/O buffer
80
+ * @v val               Integer
81
+ * @ret size            Size of the data written
82
+ */
83
+static inline size_t oncrpc_iob_add_int ( struct io_buffer *io_buf,
84
+                                          uint32_t val ) {
85
+	* ( uint32_t * ) iob_put ( io_buf, sizeof ( val ) ) = htonl ( val );
86
+	return ( sizeof ( val) );
87
+}
88
+
89
+/**
90
+ * Add a 64 bits integer to the end of an I/O buffer
91
+ *
92
+ * @v io_buf            I/O buffer
93
+ * @v val               Integer
94
+ * @ret size            Size of the data written
95
+ */
96
+static inline size_t oncrpc_iob_add_int64 ( struct io_buffer *io_buf,
97
+                                            uint64_t val ) {
98
+	* ( uint64_t * ) iob_put ( io_buf, sizeof ( val ) ) = htonll ( val );
99
+	return ( sizeof ( val) );
100
+}
101
+
102
+#endif /* _IPXE_ONCRPC_IOB_H */

+ 63
- 0
src/include/ipxe/portmap.h View File

@@ -0,0 +1,63 @@
1
+#ifndef _IPXE_PORTMAP_H
2
+#define _IPXE_PORTMAP_H
3
+
4
+#include <stdint.h>
5
+#include <ipxe/oncrpc.h>
6
+
7
+/** @file
8
+ *
9
+ * SUN ONC RPC protocol.
10
+ *
11
+ */
12
+
13
+FILE_LICENCE ( GPL2_OR_LATER );
14
+
15
+/** PORTMAP default port */
16
+#define PORTMAP_PORT   111
17
+
18
+/** PORTMAP protocol number */
19
+#define ONCRPC_PORTMAP 100000
20
+
21
+/** PORTMAP version */
22
+#define PORTMAP_VERS   2
23
+
24
+
25
+/** TCP protocol number */
26
+#define PORTMAP_PROTO_TCP 6
27
+/** UDB protocol number */
28
+#define PORTMAP_PROTO_UDP 17
29
+
30
+
31
+/**
32
+ * A PORTMAP GETPORT reply
33
+ *
34
+ */
35
+struct portmap_getport_reply {
36
+	/** Port returned */
37
+	uint32_t        port;
38
+};
39
+
40
+
41
+/**
42
+ * Prepare an ONC RPC session to be used as a PORTMAP session
43
+ *
44
+ * @v session           ONC RPC session
45
+ * @v credential        ONC RPC credential
46
+ *
47
+ * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you
48
+ * don't want a particular scheme to be used.
49
+ */
50
+static inline void portmap_init_session ( struct oncrpc_session *session,
51
+                                          struct oncrpc_cred *credential) {
52
+	oncrpc_init_session ( session, credential, &oncrpc_auth_none,
53
+	                      ONCRPC_PORTMAP, PORTMAP_VERS );
54
+}
55
+
56
+
57
+int portmap_getport ( struct interface *intf, struct oncrpc_session *session,
58
+                      uint32_t prog, uint32_t vers, uint32_t proto );
59
+int portmap_get_getport_reply ( struct portmap_getport_reply *getport_reply,
60
+                                struct oncrpc_reply *reply );
61
+
62
+
63
+#endif /* _IPXE_PORTMAP_H */

+ 14
- 4
src/include/ipxe/uri.h View File

@@ -109,17 +109,27 @@ enum {
109 109
  * Note that this is a separate concept from a URI with an absolute
110 110
  * path.
111 111
  */
112
-static inline int uri_is_absolute ( struct uri *uri ) {
112
+static inline int uri_is_absolute ( const struct uri *uri ) {
113 113
 	return ( uri->scheme != NULL );
114 114
 }
115 115
 
116
+/**
117
+ * URI has an opaque part
118
+ *
119
+ * @v uri			URI
120
+ * @ret has_opaque		URI has an opaque part
121
+ */
122
+static inline int uri_has_opaque ( const struct uri *uri ) {
123
+	return ( uri->opaque && ( uri->opaque[0] != '\0' ) );
124
+
125
+}
116 126
 /**
117 127
  * URI has a path
118 128
  *
119 129
  * @v uri			URI
120 130
  * @ret has_path		URI has a path
121 131
  */
122
-static inline int uri_has_path ( struct uri *uri ) {
132
+static inline int uri_has_path ( const struct uri *uri ) {
123 133
 	return ( uri->path && ( uri->path[0] != '\0' ) );
124 134
 }
125 135
 
@@ -133,7 +143,7 @@ static inline int uri_has_path ( struct uri *uri ) {
133 143
  * concept from an absolute URI.  Note also that a URI may not have a
134 144
  * path at all.
135 145
  */
136
-static inline int uri_has_absolute_path ( struct uri *uri ) {
146
+static inline int uri_has_absolute_path ( const struct uri *uri ) {
137 147
 	return ( uri->path && ( uri->path[0] == '/' ) );
138 148
 }
139 149
 
@@ -147,7 +157,7 @@ static inline int uri_has_absolute_path ( struct uri *uri ) {
147 157
  * this is a separate concept from a relative URI.  Note also that a
148 158
  * URI may not have a path at all.
149 159
  */
150
-static inline int uri_has_relative_path ( struct uri *uri ) {
160
+static inline int uri_has_relative_path ( const struct uri *uri ) {
151 161
 	return ( uri->path && ( uri->path[0] != '/' ) );
152 162
 }
153 163
 

+ 2
- 0
src/include/little_bswap.h View File

@@ -3,6 +3,8 @@
3 3
 
4 4
 FILE_LICENCE ( GPL2_OR_LATER );
5 5
 
6
+#define htonll(x)	__bswap_64(x)
7
+#define ntohll(x)	__bswap_64(x)
6 8
 #define ntohl(x)	__bswap_32(x)
7 9
 #define htonl(x) 	__bswap_32(x)
8 10
 #define ntohs(x) 	__bswap_16(x)

+ 119
- 0
src/net/oncrpc/mount.c View File

@@ -0,0 +1,119 @@
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/oncrpc.h>
33
+#include <ipxe/oncrpc_iob.h>
34
+#include <ipxe/nfs.h>
35
+#include <ipxe/mount.h>
36
+
37
+/** @file
38
+ *
39
+ * NFS MOUNT protocol
40
+ *
41
+ */
42
+
43
+/** MNT procedure number */
44
+#define MOUNT_MNT       1
45
+/** UMNT procedure number */
46
+#define MOUNT_UMNT      3
47
+
48
+/**
49
+ * Send a MNT request
50
+ *
51
+ * @v intf              Interface to send the request on
52
+ * @v session           ONC RPC session
53
+ * @v mountpoinrt       The path of the directory to mount.
54
+ * @ret rc              Return status code
55
+ */
56
+int mount_mnt ( struct interface *intf, struct oncrpc_session *session,
57
+                const char *mountpoint ) {
58
+	struct oncrpc_field fields[] = {
59
+		ONCRPC_FIELD ( str, mountpoint ),
60
+		ONCRPC_FIELD_END,
61
+	};
62
+
63
+	return oncrpc_call ( intf, session, MOUNT_MNT, fields );
64
+}
65
+
66
+/**
67
+ * Send a UMNT request
68
+ *
69
+ * @v intf              Interface to send the request on
70
+ * @v session           ONC RPC session
71
+ * @v mountpoinrt       The path of the directory to unmount.
72
+ * @ret rc              Return status code
73
+ */
74
+int mount_umnt ( struct interface *intf, struct oncrpc_session *session,
75
+                 const char *mountpoint ) {
76
+	struct oncrpc_field fields[] = {
77
+		ONCRPC_FIELD ( str, mountpoint ),
78
+		ONCRPC_FIELD_END,
79
+	};
80
+
81
+	return oncrpc_call ( intf, session, MOUNT_UMNT, fields );
82
+}
83
+
84
+/**
85
+ * Parse an MNT reply
86
+ *
87
+ * @v mnt_reply         A structure where the data will be saved
88
+ * @v reply             The ONC RPC reply to get data from
89
+ * @ret rc              Return status code
90
+ */
91
+int mount_get_mnt_reply ( struct mount_mnt_reply *mnt_reply,
92
+                          struct oncrpc_reply *reply ) {
93
+	if (  ! mnt_reply || ! reply )
94
+		return -EINVAL;
95
+
96
+	mnt_reply->status = oncrpc_iob_get_int ( reply->data );
97
+
98
+	switch ( mnt_reply->status )
99
+	{
100
+	case MNT3_OK:
101
+		break;
102
+	case MNT3ERR_NOENT:
103
+		return -ENOENT;
104
+	case MNT3ERR_IO:
105
+		return -EIO;
106
+	case MNT3ERR_ACCES:
107
+		return -EACCES;
108
+	case MNT3ERR_NOTDIR:
109
+		return -ENOTDIR;
110
+	case MNT3ERR_NAMETOOLONG:
111
+		return -ENAMETOOLONG;
112
+	default:
113
+		return -EPROTO;
114
+	}
115
+
116
+	nfs_iob_get_fh ( reply->data, &mnt_reply->fh );
117
+
118
+	return 0;
119
+}

+ 288
- 0
src/net/oncrpc/nfs.c View File

@@ -0,0 +1,288 @@
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
+

+ 711
- 0
src/net/oncrpc/nfs_open.c View File

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

+ 200
- 0
src/net/oncrpc/oncrpc_iob.c View File

@@ -0,0 +1,200 @@
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 <byteswap.h>
27
+#include <ipxe/socket.h>
28
+#include <ipxe/tcpip.h>
29
+#include <ipxe/in.h>
30
+#include <ipxe/iobuf.h>
31
+#include <ipxe/xfer.h>
32
+#include <ipxe/open.h>
33
+#include <ipxe/uri.h>
34
+#include <ipxe/features.h>
35
+#include <ipxe/oncrpc.h>
36
+#include <ipxe/oncrpc_iob.h>
37
+
38
+/** @file
39
+ *
40
+ * SUN ONC RPC protocol
41
+ *
42
+ */
43
+
44
+size_t oncrpc_iob_add_fields ( struct io_buffer *io_buf,
45
+                               const struct oncrpc_field fields[] ) {
46
+	size_t i;
47
+	size_t s = 0;
48
+
49
+	struct oncrpc_field f;
50
+
51
+	if ( ! io_buf )
52
+		return 0;
53
+
54
+	for ( i = 0; fields[i].type != oncrpc_none; i++ ) {
55
+		f = fields[i];
56
+		switch ( f.type ) {
57
+		case oncrpc_int32:
58
+			s += oncrpc_iob_add_int ( io_buf, f.value.int32 );
59
+			break;
60
+
61
+		case oncrpc_int64:
62
+			s += oncrpc_iob_add_int64 ( io_buf, f.value.int64 );
63
+			break;
64
+
65
+		case oncrpc_str:
66
+			s += oncrpc_iob_add_string ( io_buf, f.value.str );
67
+			break;
68
+
69
+		case oncrpc_array:
70
+			s += oncrpc_iob_add_array ( io_buf,
71
+			                            f.value.array.length,
72
+			                            f.value.array.ptr );
73
+			break;
74
+
75
+		case oncrpc_intarray:
76
+			s += oncrpc_iob_add_intarray ( io_buf,
77
+			                               f.value.intarray.length,
78
+			                               f.value.intarray.ptr );
79
+			break;
80
+
81
+		case oncrpc_cred:
82
+			s += oncrpc_iob_add_cred ( io_buf, f.value.cred);
83
+			break;
84
+
85
+		default:
86
+			return s;
87
+		}
88
+	}
89
+
90
+	return s;
91
+}
92
+
93
+/**
94
+ * Add an array of bytes to the end of an I/O buffer
95
+ *
96
+ * @v io_buf            I/O buffer
97
+ * @v val               String
98
+ * @ret size            Size of the data written
99
+ *
100
+ * In the ONC RPC protocol, every data is four byte paded, we add padding when
101
+ * necessary by using oncrpc_align()
102
+ */
103
+size_t oncrpc_iob_add_array ( struct io_buffer *io_buf, size_t length,
104
+                              const void *data ) {
105
+	size_t padding = oncrpc_align ( length ) - length;
106
+
107
+	oncrpc_iob_add_int ( io_buf, length );
108
+	memcpy ( iob_put ( io_buf, length ), data, length );
109
+	memset ( iob_put ( io_buf, padding ), 0, padding );
110
+
111
+	return length + padding + sizeof ( uint32_t );
112
+}
113
+
114
+/**
115
+ * Add an int array to the end of an I/O buffer
116
+ *
117
+ * @v io_buf            I/O buffer
118
+ * @v length            Length od the array
119
+ * @v val               Int array
120
+ * @ret size            Size of the data written
121
+ */
122
+size_t oncrpc_iob_add_intarray ( struct io_buffer *io_buf, size_t length,
123
+                                 const uint32_t *array ) {
124
+	size_t                  i;
125
+
126
+	oncrpc_iob_add_int ( io_buf, length );
127
+
128
+	for ( i = 0; i < length; ++i )
129
+		oncrpc_iob_add_int ( io_buf, array[i] );
130
+
131
+	return ( ( length + 1 ) * sizeof ( uint32_t ) );
132
+}
133
+
134
+/**
135
+ * Add credential information to the end of an I/O buffer
136
+ *
137
+ * @v io_buf            I/O buffer
138
+ * @v cred              Credential information
139
+ * @ret size            Size of the data written
140
+ */
141
+size_t oncrpc_iob_add_cred ( struct io_buffer *io_buf,
142
+                             const struct oncrpc_cred *cred ) {
143
+	struct oncrpc_cred_sys  *syscred;
144
+	size_t                  s;
145
+
146
+	struct oncrpc_field credfields[] = {
147
+		ONCRPC_FIELD ( int32, cred->flavor ),
148
+		ONCRPC_FIELD ( int32, cred->length ),
149
+		ONCRPC_FIELD_END,
150
+	};
151
+
152
+	if ( ! io_buf || ! cred )
153
+		return 0;
154
+
155
+	s  = oncrpc_iob_add_fields ( io_buf, credfields);
156
+
157
+	switch ( cred->flavor ) {
158
+	case ONCRPC_AUTH_NONE:
159
+		break;
160
+
161
+	case ONCRPC_AUTH_SYS:
162
+		syscred = container_of ( cred, struct oncrpc_cred_sys,
163
+		                         credential );
164
+
165
+		struct oncrpc_field syscredfields[] = {
166
+			ONCRPC_FIELD ( int32, syscred->stamp ),
167
+			ONCRPC_FIELD ( str, syscred->hostname ),
168
+			ONCRPC_FIELD ( int32, syscred->uid ),
169
+			ONCRPC_FIELD ( int32, syscred->gid ),
170
+			ONCRPC_SUBFIELD ( intarray, syscred->aux_gid_len,
171
+			                  syscred->aux_gid ),
172
+			ONCRPC_FIELD_END,
173
+		};
174
+
175
+		s += oncrpc_iob_add_fields ( io_buf, syscredfields );
176
+		break;
177
+	}
178
+
179
+	return s;
180
+}
181
+
182
+/**
183
+ * Get credential information from the beginning of an I/O buffer
184
+ *
185
+ * @v io_buf            I/O buffer
186
+ * @v cred              Struct where the information will be saved
187
+ * @ret size            Size of the data read
188
+ */
189
+size_t oncrpc_iob_get_cred ( struct io_buffer *io_buf,
190
+                             struct oncrpc_cred *cred ) {
191
+	if ( cred == NULL )
192
+		return * ( uint32_t * ) io_buf->data;
193
+
194
+	cred->flavor = oncrpc_iob_get_int ( io_buf );
195
+	cred->length = oncrpc_iob_get_int ( io_buf );
196
+
197
+	iob_pull ( io_buf, cred->length );
198
+
199
+	return ( 2 * sizeof ( uint32_t ) + cred->length );
200
+}

+ 90
- 0
src/net/oncrpc/portmap.c View File

@@ -0,0 +1,90 @@
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 <byteswap.h>
27
+#include <ipxe/socket.h>
28
+#include <ipxe/tcpip.h>
29
+#include <ipxe/in.h>
30
+#include <ipxe/iobuf.h>
31
+#include <ipxe/xfer.h>
32
+#include <ipxe/open.h>
33
+#include <ipxe/uri.h>
34
+#include <ipxe/features.h>
35
+#include <ipxe/timer.h>
36
+#include <ipxe/oncrpc.h>
37
+#include <ipxe/oncrpc_iob.h>
38
+#include <ipxe/portmap.h>
39
+
40
+/** @file
41
+ *
42
+ * PORTMAPPER protocol.
43
+ *
44
+ */
45
+
46
+/** PORTMAP GETPORT procedure. */
47
+#define PORTMAP_GETPORT 3
48
+
49
+/**
50
+ * Send a GETPORT request
51
+ *
52
+ * @v intf              Interface to send the request on
53
+ * @v session           ONC RPC session
54
+ * @v prog              ONC RPC program number
55
+ * @v vers              ONC RPC rogram version number
56
+ * @v proto             Protocol (TCP or UDP)
57
+ * @ret rc              Return status code
58
+ */
59
+int portmap_getport ( struct interface *intf, struct oncrpc_session *session,
60
+                      uint32_t prog, uint32_t vers, uint32_t proto ) {
61
+	struct oncrpc_field fields[] = {
62
+		ONCRPC_FIELD ( int32, prog ),
63
+		ONCRPC_FIELD ( int32, vers ),
64
+		ONCRPC_FIELD ( int32, proto ),
65
+		ONCRPC_FIELD ( int32, 0 ), /* The port field is only meaningful
66
+		                              in GETPORT reply */
67
+		ONCRPC_FIELD_END,
68
+	};
69
+
70
+	return oncrpc_call ( intf, session, PORTMAP_GETPORT, fields );
71
+}
72
+
73
+/**
74
+ * Parse a GETPORT reply
75
+ *
76
+ * @v getport_reply     A structure where the data will be saved
77
+ * @v reply             The ONC RPC reply to get data from
78
+ * @ret rc              Return status code
79
+ */
80
+int portmap_get_getport_reply ( struct portmap_getport_reply *getport_reply,
81
+                                struct oncrpc_reply *reply ) {
82
+	if ( ! getport_reply || ! reply )
83
+		return -EINVAL;
84
+
85
+	getport_reply->port = oncrpc_iob_get_int ( reply->data );
86
+	if ( getport_reply == 0 || getport_reply->port >= 65536 )
87
+		return -EINVAL;
88
+
89
+	return 0;
90
+}

+ 250
- 0
src/net/tcp/oncrpc.c View File

@@ -0,0 +1,250 @@
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 <byteswap.h>
27
+#include <ipxe/socket.h>
28
+#include <ipxe/tcpip.h>
29
+#include <ipxe/in.h>
30
+#include <ipxe/iobuf.h>
31
+#include <ipxe/dhcp.h>
32
+#include <ipxe/xfer.h>
33
+#include <ipxe/open.h>
34
+#include <ipxe/uri.h>
35
+#include <ipxe/features.h>
36
+#include <ipxe/oncrpc.h>
37
+#include <ipxe/oncrpc_iob.h>
38
+#include <ipxe/init.h>
39
+#include <ipxe/settings.h>
40
+#include <config/general.h>
41
+
42
+/** @file
43
+ *
44
+ * SUN ONC RPC protocol
45
+ *
46
+ */
47
+
48
+/** Set most significant bit to 1. */
49
+#define SET_LAST_FRAME( x ) ( (x) | 1 << 31 )
50
+#define GET_FRAME_SIZE( x ) ( (x) & ~( 1 << 31 ) )
51
+
52
+#define ONCRPC_CALL     0
53
+#define ONCRPC_REPLY    1
54
+
55
+/** AUTH NONE authentication flavor */
56
+struct oncrpc_cred oncrpc_auth_none = {
57
+	.flavor = ONCRPC_AUTH_NONE,
58
+	.length = 0
59
+};
60
+
61
+struct setting uid_setting __setting ( SETTING_AUTH ) = {
62
+	.name        = "uid",
63
+	.description = "User ID",
64
+	.tag         = DHCP_EB_UID,
65
+	.type        = &setting_type_uint32
66
+};
67
+
68
+struct setting gid_setting __setting ( SETTING_AUTH ) = {
69
+	.name        = "gid",
70
+	.description = "Group ID",
71
+	.tag         = DHCP_EB_GID,
72
+	.type        = &setting_type_uint32
73
+};
74
+
75
+/**
76
+ * Initialize an ONC RPC AUTH SYS credential structure
77
+ *
78
+ * @v auth_sys          The structure to initialize
79
+ *
80
+ * The hostname field is filled with the value of the hostname setting, if the
81
+ * hostname setting is empty, PRODUCT_SHORT_NAME (usually "iPXE") is used
82
+ * instead.
83
+ */
84
+int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ) {
85
+	if ( ! auth_sys )
86
+		return -EINVAL;
87
+
88
+	fetch_string_setting_copy ( NULL, &hostname_setting,
89
+	                            &auth_sys->hostname );
90
+	if ( ! auth_sys->hostname )
91
+		if ( ! ( auth_sys->hostname = strdup ( PRODUCT_SHORT_NAME ) ) )
92
+			return -ENOMEM;
93
+
94
+	auth_sys->uid         = fetch_uintz_setting ( NULL, &uid_setting );
95
+	auth_sys->gid         = fetch_uintz_setting ( NULL, &uid_setting );
96
+	auth_sys->aux_gid_len = 0;
97
+	auth_sys->stamp       = 0;
98
+
99
+	auth_sys->credential.flavor = ONCRPC_AUTH_SYS;
100
+	auth_sys->credential.length = 16 +
101
+	                              oncrpc_strlen ( auth_sys->hostname );
102
+
103
+	return 0;
104
+}
105
+
106
+/**
107
+ * Prepare an ONC RPC session structure to be used by the ONC RPC layer
108
+ *
109
+ * @v session           ONC RPC session
110
+ * @v credential        Credential structure pointer
111
+ * @v verifier          Verifier structure pointer
112
+ * @v prog_name         ONC RPC program number
113
+ * @v prog_vers         ONC RPC program version number
114
+ */
115
+void oncrpc_init_session ( struct oncrpc_session *session,
116
+                           struct oncrpc_cred *credential,
117
+                           struct oncrpc_cred *verifier, uint32_t prog_name,
118
+                           uint32_t prog_vers ) {
119
+	if ( ! session )
120
+		return;
121
+
122
+	session->rpc_id     = rand();
123
+	session->credential = credential;
124
+	session->verifier   = verifier;
125
+	session->prog_name  = prog_name;
126
+	session->prog_vers  = prog_vers;
127
+}
128
+
129
+int oncrpc_call ( struct interface *intf, struct oncrpc_session *session,
130
+                  uint32_t proc_name, const struct oncrpc_field fields[] ) {
131
+	int              rc;
132
+	size_t           frame_size;
133
+	struct io_buffer *io_buf;
134
+
135
+	if ( ! session )
136
+		return -EINVAL;
137
+
138
+	struct oncrpc_field header[] = {
139
+		ONCRPC_FIELD ( int32, 0 ),
140
+		ONCRPC_FIELD ( int32, ++session->rpc_id ),
141
+		ONCRPC_FIELD ( int32, ONCRPC_CALL ),
142
+		ONCRPC_FIELD ( int32, ONCRPC_VERS ),
143
+		ONCRPC_FIELD ( int32, session->prog_name ),
144
+		ONCRPC_FIELD ( int32, session->prog_vers ),
145
+		ONCRPC_FIELD ( int32, proc_name ),
146
+		ONCRPC_FIELD ( cred, session->credential ),
147
+		ONCRPC_FIELD ( cred, session->verifier ),
148
+		ONCRPC_FIELD_END,
149
+	};
150
+
151
+	frame_size  = oncrpc_compute_size ( header );
152
+	frame_size += oncrpc_compute_size ( fields );
153
+
154
+	io_buf = alloc_iob ( frame_size );
155
+	if ( ! io_buf )
156
+		return -ENOBUFS;
157
+
158
+	header[0].value.int32 = SET_LAST_FRAME ( frame_size -
159
+	                                         sizeof ( uint32_t ) );
160
+
161
+	oncrpc_iob_add_fields ( io_buf, header );
162
+	oncrpc_iob_add_fields ( io_buf, fields );
163
+
164
+	rc = xfer_deliver_iob ( intf, io_buf );
165
+	if ( rc != 0 )
166
+		free_iob ( io_buf );
167
+
168
+	return rc;
169
+}
170
+
171
+size_t oncrpc_compute_size ( const struct oncrpc_field fields[] ) {
172
+
173
+	size_t i;
174
+	size_t size = 0;
175
+
176
+	for ( i = 0; fields[i].type != oncrpc_none; i++ ) {
177
+		switch ( fields[i].type ) {
178
+		case oncrpc_int32:
179
+			size += sizeof ( uint32_t );
180
+			break;
181
+
182
+		case oncrpc_int64:
183
+			size += sizeof ( uint64_t );
184
+			break;
185
+
186
+		case oncrpc_str:
187
+			size += oncrpc_strlen ( fields[i].value.str );
188
+			break;
189
+
190
+		case oncrpc_array:
191
+			size += oncrpc_align ( fields[i].value.array.length );
192
+			size += sizeof ( uint32_t );
193
+			break;
194
+
195
+		case oncrpc_intarray:
196
+			size += sizeof ( uint32_t ) *
197
+				fields[i].value.intarray.length;
198
+			size += sizeof ( uint32_t );
199
+			break;
200
+
201
+		case oncrpc_cred:
202
+			size += fields[i].value.cred->length;
203
+			size += 2 * sizeof ( uint32_t );
204
+			break;
205
+
206
+		default:
207
+			return size;
208
+		}
209
+	}
210
+
211
+	return size;
212
+}
213
+
214
+/**
215
+ * Parse an I/O buffer to extract a ONC RPC REPLY
216
+ * @v session	        ONC RPC session
217
+ * @v reply             Reply structure where data will be saved
218
+ * @v io_buf            I/O buffer
219
+ */
220
+int oncrpc_get_reply ( struct oncrpc_session *session __unused,
221
+                       struct oncrpc_reply *reply, struct io_buffer *io_buf ) {
222
+	if ( ! reply || ! io_buf )
223
+		return -EINVAL;
224
+
225
+	reply->frame_size = GET_FRAME_SIZE ( oncrpc_iob_get_int ( io_buf ) );
226
+	reply->rpc_id     = oncrpc_iob_get_int ( io_buf );
227
+
228
+	/* iPXE has no support for handling ONC RPC call */
229
+	if ( oncrpc_iob_get_int ( io_buf ) != ONCRPC_REPLY )
230
+		return -ENOSYS;
231
+
232
+	reply->reply_state = oncrpc_iob_get_int ( io_buf );
233
+
234
+	if ( reply->reply_state == 0 )
235
+	{
236
+		/* verifier.flavor */
237
+		oncrpc_iob_get_int ( io_buf );
238
+		/* verifier.length */
239
+		iob_pull ( io_buf, oncrpc_iob_get_int ( io_buf ));
240
+
241
+		/* We don't use the verifier in iPXE, let it be an empty
242
+		   verifier. */
243
+		reply->verifier = &oncrpc_auth_none;
244
+	}
245
+
246
+	reply->accept_state = oncrpc_iob_get_int ( io_buf );
247
+	reply->data         = io_buf;
248
+
249
+	return 0;
250
+}

Loading…
Cancel
Save