Ver código fonte

Updated TFTP and PXE UDP API code to use not-yet-implemented data-xfer

UDP API.
tags/v0.9.3
Michael Brown 17 anos atrás
pai
commit
01b4bde8a0
4 arquivos alterados com 468 adições e 401 exclusões
  1. 1
    64
      src/include/gpxe/tftp.h
  2. 5
    4
      src/interface/pxe/pxe_tftp.c
  3. 84
    87
      src/interface/pxe/pxe_udp.c
  4. 378
    246
      src/net/udp/tftp.c

+ 1
- 64
src/include/gpxe/tftp.h Ver arquivo

@@ -78,71 +78,8 @@ union tftp_any {
78 78
 	struct tftp_ack		ack;
79 79
 	struct tftp_error	error;
80 80
 	struct tftp_oack	oack;
81
-};	
82
-
83
-/**
84
- * A TFTP session
85
- *
86
- * This data structure holds the state for an ongoing TFTP transfer.
87
- */
88
-struct tftp_session {
89
-	/** URI being fetched */
90
-	struct uri *uri;
91
-	/** Data buffer to fill */
92
-	struct buffer *buffer;
93
-	/** Asynchronous operation */
94
-	struct async async;
95
-
96
-	/** Requested data block size
97
-	 *
98
-	 * This is the "blksize" option requested from the TFTP
99
-	 * server.  It may or may not be honoured.
100
-	 */
101
-	unsigned int request_blksize;
102
-
103
-	/** Data block size
104
-	 *
105
-	 * This is the "blksize" option negotiated with the TFTP
106
-	 * server.  (If the TFTP server does not support TFTP options,
107
-	 * this will default to 512).
108
-	 */
109
-	unsigned int blksize;
110
-	/** File size
111
-	 *
112
-	 * This is the value returned in the "tsize" option from the
113
-	 * TFTP server.  If the TFTP server does not support the
114
-	 * "tsize" option, this value will be zero.
115
-	 */
116
-	unsigned long tsize;
117
-
118
-	/**
119
-	 * Transfer ID
120
-	 *
121
-	 * This is the transfer ID allocated by the server, used as
122
-	 * the server UDP port for all packets except the initial read
123
-	 * request.
124
-	 */
125
-	uint16_t tid;
126
-	/** Session state
127
-	 *
128
-	 * This is the block number to be used in the next ACK sent
129
-	 * back to the server, i.e. the number of the last received
130
-	 * data block.  The value zero indicates that the last
131
-	 * received block was an OACK (i.e. that the next ACK will
132
-	 * contain a block number of zero), and any value less than
133
-	 * zero indicates that the connection has not yet been opened
134
-	 * (i.e. that no blocks have yet been received).
135
-	 */
136
-	int state;
137
-	/** UDP connection */
138
-	struct udp_connection udp;
139
-	/** Retransmission timer */
140
-	struct retry_timer timer;
141 81
 };
142 82
 
143
-/* Function prototypes */
144
-
145
-extern int tftp_get ( struct uri *uri, struct buffer *buffer,
146
-		      struct async *parent );
83
+extern void tftp_set_request_blksize ( unsigned int blksize );
147 84
 
148 85
 #endif /* _GPXE_TFTP_H */

+ 5
- 4
src/interface/pxe/pxe_tftp.c Ver arquivo

@@ -71,10 +71,11 @@ static void pxe_tftp_build_uri ( char uri_string[PXE_URI_LEN],
71 71
 		port = htons ( TFTP_PORT );
72 72
 	if ( ! blksize )
73 73
 		blksize = TFTP_MAX_BLKSIZE;
74
-	snprintf ( uri_string, sizeof ( uri_string ),
75
-		   "tftp://%s:%d%s%s?blksize=%d", inet_ntoa ( address ),
76
-		   ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ),
77
-		   filename, blksize );
74
+	tftp_set_request_blksize ( blksize );
75
+
76
+	snprintf ( uri_string, sizeof ( uri_string ), "tftp://%s:%d%s%s",
77
+		   inet_ntoa ( address ), ntohs ( port ),
78
+		   ( ( filename[0] == '/' ) ? "" : "/" ), filename );
78 79
 }
79 80
 
80 81
 /**

+ 84
- 87
src/interface/pxe/pxe_udp.c Ver arquivo

@@ -6,6 +6,7 @@
6 6
 
7 7
 #include <string.h>
8 8
 #include <byteswap.h>
9
+#include <gpxe/xfer.h>
9 10
 #include <gpxe/udp.h>
10 11
 #include <gpxe/uaccess.h>
11 12
 #include <gpxe/process.h>
@@ -31,85 +32,63 @@
31 32
 
32 33
 /** A PXE UDP connection */
33 34
 struct pxe_udp_connection {
34
-	/** Etherboot UDP connection */
35
-	struct udp_connection udp;
35
+	/** Data transfer interface to UDP stack */
36
+	struct xfer_interface xfer;
36 37
 	/** "Connection is open" flag */
37 38
 	int open;
38
-	/** Current pxenv_udp_read() operation, if any */
39
+	/** Local address */
40
+	struct sockaddr_in local;
41
+	/** Current PXENV_UDP_READ parameter block */
39 42
 	struct s_PXENV_UDP_READ *pxenv_udp_read;
40
-	/** Current pxenv_udp_write() operation, if any */
41
-	struct s_PXENV_UDP_WRITE *pxenv_udp_write;
42 43
 };
43 44
 
44
-static inline struct pxe_udp_connection *
45
-udp_to_pxe ( struct udp_connection *conn ) {
46
-	return container_of ( conn, struct pxe_udp_connection, udp );
47
-}
48
-
49
-/**
50
- * Send PXE UDP data
51
- *
52
- * @v conn			UDP connection
53
- * @v data			Temporary data buffer
54
- * @v len			Size of temporary data buffer
55
- * @ret rc			Return status code
56
- *
57
- * Sends the packet belonging to the current pxenv_udp_write()
58
- * operation.
59
- */
60
-static int pxe_udp_senddata ( struct udp_connection *conn, void *data,
61
-			      size_t len ) {
62
-	struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
63
-	struct s_PXENV_UDP_WRITE *pxenv_udp_write = pxe_udp->pxenv_udp_write;
64
-	userptr_t buffer;
65
-
66
-	/* Transmit packet */
67
-	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
68
-				pxenv_udp_write->buffer.offset );
69
-	if ( len > pxenv_udp_write->buffer_size )
70
-		len = pxenv_udp_write->buffer_size;
71
-	copy_from_user ( data, buffer, 0, len );
72
-	return udp_send ( conn, data, len );
73
-}
74
-
75 45
 /**
76 46
  * Receive PXE UDP data
77 47
  *
78
- * @v conn			UDP connection
79
- * @v data			Received data
80
- * @v len			Length of received data
81
- * @v st_src			Source address
82
- * @v st_dest			Destination address
48
+ * @v xfer			Data transfer interface
49
+ * @v iobuf			I/O buffer
50
+ * @v meta			Data transfer metadata
51
+ * @ret rc			Return status code
83 52
  *
84 53
  * Receives a packet as part of the current pxenv_udp_read()
85 54
  * operation.
86 55
  */
87
-static int pxe_udp_newdata ( struct udp_connection *conn, void *data,
88
-			     size_t len, struct sockaddr_tcpip *st_src,
89
-			     struct sockaddr_tcpip *st_dest ) {
90
-	struct pxe_udp_connection *pxe_udp = udp_to_pxe ( conn );
56
+static int pxe_udp_deliver_iob ( struct xfer_interface *xfer,
57
+				 struct io_buffer *iobuf,
58
+				 struct xfer_metadata *meta ) {
59
+	struct pxe_udp_connection *pxe_udp = 
60
+		container_of ( xfer, struct pxe_udp_connection, xfer );
91 61
 	struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
92
-	struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
93
-	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
62
+	struct sockaddr_in *sin_src;
63
+	struct sockaddr_in *sin_dest;
94 64
 	userptr_t buffer;
65
+	size_t len;
66
+	int rc = 0;
95 67
 
96 68
 	if ( ! pxenv_udp_read ) {
97 69
 		DBG ( "PXE discarded UDP packet\n" );
98
-		return -ENOBUFS;
70
+		rc = -ENOBUFS;
71
+		goto done;
99 72
 	}
100 73
 
101 74
 	/* Copy packet to buffer and record length */
102 75
 	buffer = real_to_user ( pxenv_udp_read->buffer.segment,
103 76
 				pxenv_udp_read->buffer.offset );
77
+	len = iob_len ( iobuf );
104 78
 	if ( len > pxenv_udp_read->buffer_size )
105 79
 		len = pxenv_udp_read->buffer_size;
106
-	copy_to_user ( buffer, 0, data, len );
80
+	copy_to_user ( buffer, 0, iobuf->data, len );
107 81
 	pxenv_udp_read->buffer_size = len;
108 82
 
109 83
 	/* Fill in source/dest information */
84
+	assert ( meta );
85
+	sin_src = ( struct sockaddr_in * ) meta->src;
86
+	assert ( sin_src );
110 87
 	assert ( sin_src->sin_family == AF_INET );
111 88
 	pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
112 89
 	pxenv_udp_read->s_port = sin_src->sin_port;
90
+	sin_dest = ( struct sockaddr_in * ) meta->dest;
91
+	assert ( sin_dest );
113 92
 	assert ( sin_dest->sin_family == AF_INET );
114 93
 	pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
115 94
 	pxenv_udp_read->d_port = sin_dest->sin_port;
@@ -117,18 +96,34 @@ static int pxe_udp_newdata ( struct udp_connection *conn, void *data,
117 96
 	/* Mark as received */
118 97
 	pxe_udp->pxenv_udp_read = NULL;
119 98
 
120
-	return 0;
99
+ done:
100
+	free_iob ( iobuf );
101
+	return rc;
121 102
 }
122 103
 
123
-/** PXE UDP operations */
124
-static struct udp_operations pxe_udp_operations = {
125
-	.senddata = pxe_udp_senddata,
126
-	.newdata = pxe_udp_newdata,
104
+/** PXE UDP data transfer interface operations */
105
+static struct xfer_interface_operations pxe_udp_xfer_operations = {
106
+	.close		= ignore_xfer_close,
107
+	.vredirect	= ignore_xfer_vredirect,
108
+	.request	= ignore_xfer_request,
109
+	.seek		= ignore_xfer_seek,
110
+	.alloc_iob	= default_xfer_alloc_iob,
111
+	.deliver_iob	= pxe_udp_deliver_iob,
112
+	.deliver_raw	= xfer_deliver_as_iob,
127 113
 };
128 114
 
129 115
 /** The PXE UDP connection */
130 116
 static struct pxe_udp_connection pxe_udp = {
131
-	.udp.udp_op = &pxe_udp_operations,
117
+	.xfer = {
118
+		.intf = {
119
+			.dest = &null_xfer.intf,
120
+			.refcnt = NULL,
121
+		},
122
+		.op = &pxe_udp_xfer_operations,
123
+	},
124
+	.local = {
125
+		.sin_family = AF_INET,
126
+	},
132 127
 };
133 128
 
134 129
 /**
@@ -174,7 +169,6 @@ static struct pxe_udp_connection pxe_udp = {
174 169
  *
175 170
  */
176 171
 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
177
-	struct in_addr new_ip = { .s_addr = pxenv_udp_open->src_ip };
178 172
 
179 173
 	DBG ( "PXENV_UDP_OPEN" );
180 174
 
@@ -184,17 +178,11 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
184 178
 		return PXENV_EXIT_FAILURE;
185 179
 	}
186 180
 
187
-	/* Set IP address if specified */
188
-	if ( new_ip.s_addr ) {
189
-		/* FIXME: actually do something here */
190
-		DBG ( " with new IP address %s", inet_ntoa ( new_ip ) );
191
-	}
181
+	/* Record source IP address */
182
+	pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
192 183
 
193
-	/* Open UDP connection */
194
-	if ( udp_open ( &pxe_udp.udp, 0 ) != 0 ) {
195
-		pxenv_udp_open->Status = PXENV_STATUS_OUT_OF_RESOURCES;
196
-		return PXENV_EXIT_FAILURE;
197
-	}
184
+	/* Open promiscuous UDP connection */
185
+	udp_open_promisc ( &pxe_udp.xfer );
198 186
 	pxe_udp.open = 1;
199 187
 
200 188
 	pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
@@ -232,7 +220,7 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
232 220
 	}
233 221
 
234 222
 	/* Close UDP connection */
235
-	udp_close ( &pxe_udp.udp );
223
+	udp_close_promisc ( &pxe_udp.xfer );
236 224
 	pxe_udp.open = 0;
237 225
 
238 226
 	pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
@@ -281,10 +269,14 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
281 269
  *
282 270
  */
283 271
 PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
284
-	union {
285
-		struct sockaddr_in sin;
286
-		struct sockaddr_tcpip st;
287
-	} dest;
272
+	struct sockaddr_in dest;
273
+	struct xfer_metadata meta = {
274
+		.src = ( struct sockaddr * ) &pxe_udp.local,
275
+		.dest = ( struct sockaddr * ) &dest,
276
+	};
277
+	size_t len;
278
+	struct io_buffer *iobuf;
279
+	userptr_t buffer;
288 280
 	int rc;
289 281
 
290 282
 	DBG ( "PXENV_UDP_WRITE" );
@@ -297,36 +289,44 @@ PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
297 289
 
298 290
 	/* Construct destination socket address */
299 291
 	memset ( &dest, 0, sizeof ( dest ) );
300
-	dest.sin.sin_family = AF_INET;
301
-	dest.sin.sin_addr.s_addr = pxenv_udp_write->ip;
302
-	dest.sin.sin_port = pxenv_udp_write->dst_port;
303
-	udp_connect ( &pxe_udp.udp, &dest.st );
292
+	dest.sin_family = AF_INET;
293
+	dest.sin_addr.s_addr = pxenv_udp_write->ip;
294
+	dest.sin_port = pxenv_udp_write->dst_port;
304 295
 
305 296
 	/* Set local (source) port.  PXE spec says source port is 2069
306 297
 	 * if not specified.  Really, this ought to be set at UDP open
307 298
 	 * time but hey, we didn't design this API.
308 299
 	 */
309
-	if ( ! pxenv_udp_write->src_port )
310
-		pxenv_udp_write->src_port = htons ( 2069 );
311
-	udp_bind ( &pxe_udp.udp, pxenv_udp_write->src_port );
300
+	pxe_udp.local.sin_port = pxenv_udp_write->src_port;
301
+	if ( ! pxe_udp.local.sin_port )
302
+		pxe_udp.local.sin_port = htons ( 2069 );
312 303
 
313 304
 	/* FIXME: we ignore the gateway specified, since we're
314 305
 	 * confident of being able to do our own routing.  We should
315 306
 	 * probably allow for multiple gateways.
316 307
 	 */
317 308
 
309
+	/* Allocate and fill data buffer */
310
+	len = pxenv_udp_write->buffer_size;
311
+	iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
312
+	if ( ! iobuf ) {
313
+		pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
314
+		return PXENV_EXIT_FAILURE;
315
+	}
316
+	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
317
+				pxenv_udp_write->buffer.offset );
318
+	copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
319
+
318 320
 	DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
319 321
 	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
320 322
 	      ntohs ( pxenv_udp_write->src_port ),
321
-	      inet_ntoa ( dest.sin.sin_addr ),
323
+	      inet_ntoa ( dest.sin_addr ),
322 324
 	      ntohs ( pxenv_udp_write->dst_port ) );
323 325
 	
324 326
 	/* Transmit packet */
325
-	pxe_udp.pxenv_udp_write = pxenv_udp_write;
326
-	rc = udp_senddata ( &pxe_udp.udp );
327
-	pxe_udp.pxenv_udp_write = NULL;
328
-	if ( rc != 0 ) {
329
-		pxenv_udp_write->Status = PXENV_STATUS_UNDI_TRANSMIT_ERROR;
327
+	if ( ( rc = xfer_deliver_iob_meta ( &pxe_udp.xfer, iobuf,
328
+					    &meta ) ) != 0 ) {
329
+		pxenv_udp_write->Status = PXENV_STATUS ( rc );
330 330
 		return PXENV_EXIT_FAILURE;
331 331
 	}
332 332
 
@@ -389,9 +389,6 @@ PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
389 389
 		return PXENV_EXIT_FAILURE;
390 390
 	}
391 391
 
392
-	/* Bind promiscuously; we will do our own filtering */
393
-	udp_bind_promisc ( &pxe_udp.udp );
394
-
395 392
 	/* Try receiving a packet */
396 393
 	pxe_udp.pxenv_udp_read = pxenv_udp_read;
397 394
 	step();

+ 378
- 246
src/net/udp/tftp.c Ver arquivo

@@ -24,9 +24,11 @@
24 24
 #include <byteswap.h>
25 25
 #include <errno.h>
26 26
 #include <assert.h>
27
-#include <gpxe/async.h>
28
-#include <gpxe/tftp.h>
27
+#include <gpxe/refcnt.h>
28
+#include <gpxe/xfer.h>
29
+#include <gpxe/open.h>
29 30
 #include <gpxe/uri.h>
31
+#include <gpxe/tftp.h>
30 32
 
31 33
 /** @file
32 34
  *
@@ -34,126 +36,187 @@
34 36
  *
35 37
  */
36 38
 
37
-/** A TFTP option */
38
-struct tftp_option {
39
-	/** Option name */
40
-	const char *name;
41
-	/** Option processor
39
+/**
40
+ * A TFTP request
41
+ *
42
+ * This data structure holds the state for an ongoing TFTP transfer.
43
+ */
44
+struct tftp_request {
45
+	/** Reference count */
46
+	struct refcnt refcnt;
47
+	/** Data transfer interface */
48
+	struct xfer_interface xfer;
49
+
50
+	/** URI being fetched */
51
+	struct uri *uri;
52
+	/** Transport layer interface */
53
+	struct xfer_interface socket;
54
+
55
+	/** Data block size
42 56
 	 *
43
-	 * @v tftp	TFTP connection
44
-	 * @v value	Option value
45
-	 * @ret rc	Return status code
57
+	 * This is the "blksize" option negotiated with the TFTP
58
+	 * server.  (If the TFTP server does not support TFTP options,
59
+	 * this will default to 512).
60
+	 */
61
+	unsigned int blksize;
62
+	/** File size
63
+	 *
64
+	 * This is the value returned in the "tsize" option from the
65
+	 * TFTP server.  If the TFTP server does not support the
66
+	 * "tsize" option, this value will be zero.
67
+	 */
68
+	unsigned long tsize;
69
+
70
+	/** Request state
71
+	 *
72
+	 * This is the block number to be used in the next ACK sent
73
+	 * back to the server, i.e. the number of the last received
74
+	 * data block.  The value zero indicates that the last
75
+	 * received block was an OACK (i.e. that the next ACK will
76
+	 * contain a block number of zero), and any value less than
77
+	 * zero indicates that the connection has not yet been opened
78
+	 * (i.e. that no blocks have yet been received).
79
+	 */
80
+	int state;
81
+	/** Peer address
82
+	 *
83
+	 * The peer address is determined by the first response
84
+	 * received to the TFTP RRQ.
46 85
 	 */
47
-	int ( * process ) ( struct tftp_session *tftp, const char *value );
86
+	struct sockaddr_tcpip peer;
87
+	/** Retransmission timer */
88
+	struct retry_timer timer;
48 89
 };
49 90
 
50 91
 /**
51
- * Process TFTP "blksize" option
92
+ * Free TFTP request
52 93
  *
53
- * @v tftp		TFTP connection
54
- * @v value		Option value
55
- * @ret rc		Return status code
94
+ * @v refcnt		Reference counter
56 95
  */
57
-static int tftp_process_blksize ( struct tftp_session *tftp,
58
-				  const char *value ) {
59
-	char *end;
60
-
61
-	tftp->blksize = strtoul ( value, &end, 10 );
62
-	if ( *end ) {
63
-		DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
64
-		       tftp, value );
65
-		return -EINVAL;
66
-	}
67
-	DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
96
+static void tftp_free ( struct refcnt *refcnt ) {
97
+	struct tftp_request *tftp =
98
+		container_of ( refcnt, struct tftp_request, refcnt );
68 99
 
69
-	return 0;
100
+	uri_put ( tftp->uri );
101
+	free ( tftp );
70 102
 }
71 103
 
72 104
 /**
73
- * Process TFTP "tsize" option
105
+ * Mark TFTP request as complete
74 106
  *
75 107
  * @v tftp		TFTP connection
76
- * @v value		Option value
77
- * @ret rc		Return status code
108
+ * @v rc		Return status code
78 109
  */
79
-static int tftp_process_tsize ( struct tftp_session *tftp,
80
-				const char *value ) {
81
-	char *end;
110
+static void tftp_done ( struct tftp_request *tftp, int rc ) {
82 111
 
83
-	tftp->tsize = strtoul ( value, &end, 10 );
84
-	if ( *end ) {
85
-		DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
86
-		       tftp, value );
87
-		return -EINVAL;
88
-	}
89
-	DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
112
+	/* Stop the retry timer */
113
+	stop_timer ( &tftp->timer );
90 114
 
91
-	return 0;
115
+	/* Close all data transfer interfaces */
116
+	xfer_nullify ( &tftp->socket );
117
+	xfer_close ( &tftp->socket, rc );
118
+	xfer_nullify ( &tftp->xfer );
119
+	xfer_close ( &tftp->xfer, rc );
92 120
 }
93 121
 
94
-/** Recognised TFTP options */
95
-static struct tftp_option tftp_options[] = {
96
-	{ "blksize", tftp_process_blksize },
97
-	{ "tsize", tftp_process_tsize },
98
-	{ NULL, NULL }
99
-};
122
+/**
123
+ * TFTP requested blocksize
124
+ *
125
+ * This is treated as a global configuration parameter.
126
+ */
127
+static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
100 128
 
101 129
 /**
102
- * Process TFTP option
130
+ * Set TFTP request blocksize
131
+ *
132
+ * @v blksize		Requested block size
133
+ */
134
+void tftp_set_request_blksize ( unsigned int blksize ) {
135
+	if ( blksize < TFTP_DEFAULT_BLKSIZE )
136
+		blksize = TFTP_DEFAULT_BLKSIZE;
137
+	tftp_request_blksize = blksize;
138
+}
139
+
140
+/**
141
+ * Transmit RRQ
103 142
  *
104 143
  * @v tftp		TFTP connection
105
- * @v name		Option name
106
- * @v value		Option value
107 144
  * @ret rc		Return status code
108 145
  */
109
-static int tftp_process_option ( struct tftp_session *tftp,
110
-				 const char *name, const char *value ) {
111
-	struct tftp_option *option;
112
-
113
-	for ( option = tftp_options ; option->name ; option++ ) {
114
-		if ( strcasecmp ( name, option->name ) == 0 )
115
-			return option->process ( tftp, value );
116
-	}
117
-
118
-	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
119
-	       tftp, name, value );
146
+static int tftp_send_rrq ( struct tftp_request *tftp ) {
147
+	struct tftp_rrq *rrq;
148
+	const char *path = tftp->uri->path;
149
+	size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
150
+		       + 5 + 1 /* "octet" + NUL */
151
+		       + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
152
+		       + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ );
153
+	struct io_buffer *iobuf;
154
+
155
+	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
156
+
157
+	/* Allocate buffer */
158
+	iobuf = xfer_alloc_iob ( &tftp->socket, len );
159
+	if ( ! iobuf )
160
+		return -ENOMEM;
161
+
162
+	/* Build request */
163
+	rrq = iob_put ( iobuf, sizeof ( *rrq ) );
164
+	rrq->opcode = htons ( TFTP_RRQ );
165
+	iob_put ( iobuf,
166
+		  snprintf ( iobuf->data, iob_tailroom ( iobuf ),
167
+			     "%s%coctet%cblksize%c%d%ctsize%c0", path, 0,
168
+			     0, 0, tftp_request_blksize, 0, 0 ) + 1 );
120 169
 
121
-	return -EINVAL;
170
+	/* RRQ always goes to the address specified in the initial
171
+	 * xfer_open() call
172
+	 */
173
+	return xfer_deliver_iob ( &tftp->socket, iobuf );
122 174
 }
123 175
 
124
-/** Translation between TFTP errors and internal error numbers */
125
-static const uint8_t tftp_errors[] = {
126
-	[TFTP_ERR_FILE_NOT_FOUND]	= PXENV_STATUS_TFTP_FILE_NOT_FOUND,
127
-	[TFTP_ERR_ACCESS_DENIED]	= PXENV_STATUS_TFTP_ACCESS_VIOLATION,
128
-	[TFTP_ERR_ILLEGAL_OP]		= PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
129
-};
130
-
131 176
 /**
132
- * Mark TFTP session as complete
177
+ * Transmit ACK
133 178
  *
134 179
  * @v tftp		TFTP connection
135
- * @v rc		Return status code
180
+ * @ret rc		Return status code
136 181
  */
137
-static void tftp_done ( struct tftp_session *tftp, int rc ) {
182
+static int tftp_send_ack ( struct tftp_request *tftp ) {
183
+	struct tftp_ack *ack;
184
+	struct io_buffer *iobuf;
185
+	struct xfer_metadata meta = {
186
+		.dest = ( struct sockaddr * ) &tftp->peer,
187
+	};
138 188
 
139
-	/* Stop the retry timer */
140
-	stop_timer ( &tftp->timer );
189
+	/* Allocate buffer */
190
+	iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
191
+	if ( ! iobuf )
192
+		return -ENOMEM;
141 193
 
142
-	/* Close UDP connection */
143
-	udp_close ( &tftp->udp );
194
+	/* Build ACK */
195
+	ack = iob_put ( iobuf, sizeof ( *ack ) );
196
+	ack->opcode = htons ( TFTP_ACK );
197
+	ack->block = htons ( tftp->state );
144 198
 
145
-	/* Mark async operation as complete */
146
-	async_done ( &tftp->async, rc );
199
+	/* ACK always goes to the peer recorded from the RRQ response */
200
+	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
147 201
 }
148 202
 
149 203
 /**
150
- * Send next packet in TFTP session
204
+ * Transmit data
151 205
  *
152 206
  * @v tftp		TFTP connection
207
+ * @ret rc		Return status code
153 208
  */
154
-static void tftp_send_packet ( struct tftp_session *tftp ) {
209
+static int tftp_send_packet ( struct tftp_request *tftp ) {
210
+
211
+	/* Start retransmission timer */
155 212
 	start_timer ( &tftp->timer );
156
-	udp_senddata ( &tftp->udp );
213
+
214
+	/* Send RRQ or ACK as appropriate */
215
+	if ( tftp->state < 0 ) {
216
+		return tftp_send_rrq ( tftp );
217
+	} else {
218
+		return tftp_send_ack ( tftp );
219
+	}
157 220
 }
158 221
 
159 222
 /**
@@ -163,8 +226,8 @@ static void tftp_send_packet ( struct tftp_session *tftp ) {
163 226
  * @v fail		Failure indicator
164 227
  */
165 228
 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
166
-	struct tftp_session *tftp =
167
-		container_of ( timer, struct tftp_session, timer );
229
+	struct tftp_request *tftp =
230
+		container_of ( timer, struct tftp_request, timer );
168 231
 
169 232
 	if ( fail ) {
170 233
 		tftp_done ( tftp, -ETIMEDOUT );
@@ -179,7 +242,7 @@ static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
179 242
  * @v tftp		TFTP connection
180 243
  * @v block		Block number
181 244
  */
182
-static void tftp_received ( struct tftp_session *tftp, unsigned int block ) {
245
+static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
183 246
 
184 247
 	/* Stop the retry timer */
185 248
 	stop_timer ( &tftp->timer );
@@ -192,37 +255,94 @@ static void tftp_received ( struct tftp_session *tftp, unsigned int block ) {
192 255
 }
193 256
 
194 257
 /**
195
- * Transmit RRQ
258
+ * Process TFTP "blksize" option
196 259
  *
197 260
  * @v tftp		TFTP connection
198
- * @v buf		Temporary data buffer
199
- * @v len		Length of temporary data buffer
261
+ * @v value		Option value
200 262
  * @ret rc		Return status code
201 263
  */
202
-static int tftp_send_rrq ( struct tftp_session *tftp, void *buf, size_t len ) {
203
-	struct tftp_rrq *rrq = buf;
204
-	void *data;
205
-	void *end;
206
-
207
-	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->uri->path );
208
-
209
-	data = rrq->data;
210
-	end = ( buf + len );
211
-	if ( data > end )
212
-		goto overflow;
213
-	data += ( snprintf ( data, ( end - data ),
214
-			     "%s%coctet%cblksize%c%d%ctsize%c0",
215
-			     tftp->uri->path, 0, 0, 0,
216
-			     tftp->request_blksize, 0, 0 ) + 1 );
217
-	if ( data > end )
218
-		goto overflow;
219
-	rrq->opcode = htons ( TFTP_RRQ );
264
+static int tftp_process_blksize ( struct tftp_request *tftp,
265
+				  const char *value ) {
266
+	char *end;
267
+
268
+	tftp->blksize = strtoul ( value, &end, 10 );
269
+	if ( *end ) {
270
+		DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
271
+		       tftp, value );
272
+		return -EINVAL;
273
+	}
274
+	DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
275
+
276
+	return 0;
277
+}
278
+
279
+/**
280
+ * Process TFTP "tsize" option
281
+ *
282
+ * @v tftp		TFTP connection
283
+ * @v value		Option value
284
+ * @ret rc		Return status code
285
+ */
286
+static int tftp_process_tsize ( struct tftp_request *tftp,
287
+				const char *value ) {
288
+	char *end;
220 289
 
221
-	return udp_send ( &tftp->udp, buf, ( data - buf ) );
290
+	tftp->tsize = strtoul ( value, &end, 10 );
291
+	if ( *end ) {
292
+		DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
293
+		       tftp, value );
294
+		return -EINVAL;
295
+	}
296
+	DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
222 297
 
223
- overflow:
224
-	DBGC ( tftp, "TFTP %p RRQ out of space\n", tftp );
225
-	return -ENOBUFS;
298
+	/* Notify recipient of file size */
299
+	xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
300
+	xfer_seek ( &tftp->xfer, 0, SEEK_SET );
301
+
302
+	return 0;
303
+}
304
+
305
+/** A TFTP option */
306
+struct tftp_option {
307
+	/** Option name */
308
+	const char *name;
309
+	/** Option processor
310
+	 *
311
+	 * @v tftp	TFTP connection
312
+	 * @v value	Option value
313
+	 * @ret rc	Return status code
314
+	 */
315
+	int ( * process ) ( struct tftp_request *tftp, const char *value );
316
+};
317
+
318
+/** Recognised TFTP options */
319
+static struct tftp_option tftp_options[] = {
320
+	{ "blksize", tftp_process_blksize },
321
+	{ "tsize", tftp_process_tsize },
322
+	{ NULL, NULL }
323
+};
324
+
325
+/**
326
+ * Process TFTP option
327
+ *
328
+ * @v tftp		TFTP connection
329
+ * @v name		Option name
330
+ * @v value		Option value
331
+ * @ret rc		Return status code
332
+ */
333
+static int tftp_process_option ( struct tftp_request *tftp,
334
+				 const char *name, const char *value ) {
335
+	struct tftp_option *option;
336
+
337
+	for ( option = tftp_options ; option->name ; option++ ) {
338
+		if ( strcasecmp ( name, option->name ) == 0 )
339
+			return option->process ( tftp, value );
340
+	}
341
+
342
+	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
343
+	       tftp, name, value );
344
+
345
+	return -EINVAL;
226 346
 }
227 347
 
228 348
 /**
@@ -233,7 +353,7 @@ static int tftp_send_rrq ( struct tftp_session *tftp, void *buf, size_t len ) {
233 353
  * @v len		Length of temporary data buffer
234 354
  * @ret rc		Return status code
235 355
  */
236
-static int tftp_rx_oack ( struct tftp_session *tftp, void *buf, size_t len ) {
356
+static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
237 357
 	struct tftp_oack *oack = buf;
238 358
 	char *end = buf + len;
239 359
 	char *name;
@@ -276,31 +396,34 @@ static int tftp_rx_oack ( struct tftp_session *tftp, void *buf, size_t len ) {
276 396
  * Receive DATA
277 397
  *
278 398
  * @v tftp		TFTP connection
279
- * @v buf		Temporary data buffer
280
- * @v len		Length of temporary data buffer
399
+ * @v iobuf		I/O buffer
281 400
  * @ret rc		Return status code
401
+ *
402
+ * Takes ownership of I/O buffer.
282 403
  */
283
-static int tftp_rx_data ( struct tftp_session *tftp, void *buf, size_t len ) {
284
-	struct tftp_data *data = buf;
404
+static int tftp_rx_data ( struct tftp_request *tftp,
405
+			  struct io_buffer *iobuf ) {
406
+	struct tftp_data *data = iobuf->data;
285 407
 	unsigned int block;
286
-	size_t data_offset;
287 408
 	size_t data_len;
288 409
 	int rc;
289 410
 
290 411
 	/* Sanity check */
291
-	if ( len < sizeof ( *data ) ) {
412
+	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
292 413
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
293
-		       "length %d\n", tftp, len );
414
+		       "length %d\n", tftp, iob_len ( iobuf ) );
415
+		free_iob ( iobuf );
294 416
 		return -EINVAL;
295 417
 	}
296 418
 
297
-	/* Fill data buffer */
419
+	/* Extract data */
298 420
 	block = ntohs ( data->block );
299
-	data_offset = ( ( block - 1 ) * tftp->blksize );
300
-	data_len = ( len - offsetof ( typeof ( *data ), data ) );
301
-	if ( ( rc = fill_buffer ( tftp->buffer, data->data, data_offset,
302
-				  data_len ) ) != 0 ) {
303
-		DBGC ( tftp, "TFTP %p could not fill data buffer: %s\n",
421
+	iob_pull ( iobuf, sizeof ( *data ) );
422
+	data_len = iob_len ( iobuf );
423
+
424
+	/* Deliver data */
425
+	if ( ( rc = xfer_deliver_iob ( &tftp->xfer, iobuf ) ) != 0 ) {
426
+		DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
304 427
 		       tftp, strerror ( rc ) );
305 428
 		tftp_done ( tftp, rc );
306 429
 		return rc;
@@ -316,21 +439,12 @@ static int tftp_rx_data ( struct tftp_session *tftp, void *buf, size_t len ) {
316 439
 	return 0;
317 440
 }
318 441
 
319
-/**
320
- * Transmit ACK
321
- *
322
- * @v tftp		TFTP connection
323
- * @v buf		Temporary data buffer
324
- * @v len		Length of temporary data buffer
325
- * @ret rc		Return status code
326
- */
327
-static int tftp_send_ack ( struct tftp_session *tftp ) {
328
-	struct tftp_ack ack;
329
-
330
-	ack.opcode = htons ( TFTP_ACK );
331
-	ack.block = htons ( tftp->state );
332
-	return udp_send ( &tftp->udp, &ack, sizeof ( ack ) );
333
-}
442
+/** Translation between TFTP errors and internal error numbers */
443
+static const uint8_t tftp_errors[] = {
444
+	[TFTP_ERR_FILE_NOT_FOUND]	= PXENV_STATUS_TFTP_FILE_NOT_FOUND,
445
+	[TFTP_ERR_ACCESS_DENIED]	= PXENV_STATUS_TFTP_ACCESS_VIOLATION,
446
+	[TFTP_ERR_ILLEGAL_OP]		= PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
447
+};
334 448
 
335 449
 /**
336 450
  * Receive ERROR
@@ -340,7 +454,7 @@ static int tftp_send_ack ( struct tftp_session *tftp ) {
340 454
  * @v len		Length of temporary data buffer
341 455
  * @ret rc		Return status code
342 456
  */
343
-static int tftp_rx_error ( struct tftp_session *tftp, void *buf, size_t len ) {
457
+static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
344 458
 	struct tftp_error *error = buf;
345 459
 	unsigned int err;
346 460
 	int rc = 0;
@@ -362,32 +476,12 @@ static int tftp_rx_error ( struct tftp_session *tftp, void *buf, size_t len ) {
362 476
 	if ( ! rc )
363 477
 		rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
364 478
 
365
-	/* Close TFTP session */
479
+	/* Close TFTP request */
366 480
 	tftp_done ( tftp, rc );
367 481
 
368 482
 	return 0;
369 483
 }
370 484
 
371
-/**
372
- * Transmit data
373
- *
374
- * @v conn		UDP connection
375
- * @v buf		Temporary data buffer
376
- * @v len		Length of temporary data buffer
377
- * @ret rc		Return status code
378
- */
379
-static int tftp_senddata ( struct udp_connection *conn,
380
-			   void *buf, size_t len ) {
381
-	struct tftp_session *tftp = 
382
-		container_of ( conn, struct tftp_session, udp );
383
-
384
-	if ( tftp->state < 0 ) {
385
-		return tftp_send_rrq ( tftp, buf, len );
386
-	} else {
387
-		return tftp_send_ack ( tftp );
388
-	}
389
-}
390
-
391 485
 /**
392 486
  * Receive new data
393 487
  *
@@ -397,141 +491,179 @@ static int tftp_senddata ( struct udp_connection *conn,
397 491
  * @v st_src		Partially-filled source address
398 492
  * @v st_dest		Partially-filled destination address
399 493
  */
400
-static int tftp_newdata ( struct udp_connection *conn, void *data, size_t len,
401
-			  struct sockaddr_tcpip *st_src __unused,
402
-			  struct sockaddr_tcpip *st_dest __unused ) {
403
-	struct tftp_session *tftp = 
404
-		container_of ( conn, struct tftp_session, udp );
405
-	struct tftp_common *common = data;
494
+static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
495
+				     struct io_buffer *iobuf,
496
+				     struct xfer_metadata *meta ) {
497
+	struct tftp_request *tftp =
498
+		container_of ( socket, struct tftp_request, socket );
499
+	struct sockaddr_tcpip *st_src;
500
+	struct tftp_common *common = iobuf->data;
501
+	size_t len = iob_len ( iobuf );
502
+	int rc = -EINVAL;
406 503
 	
504
+	/* Sanity checks */
407 505
 	if ( len < sizeof ( *common ) ) {
408 506
 		DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
409 507
 		       tftp, len );
410
-		return -EINVAL;
508
+		goto done;
509
+	}
510
+	if ( ! meta ) {
511
+		DBGC ( tftp, "TFTP %p received packet without metadata\n",
512
+		       tftp );
513
+		goto done;
514
+	}
515
+	if ( ! meta->src ) {
516
+		DBGC ( tftp, "TFTP %p received packet without source port\n",
517
+		       tftp );
518
+		goto done;
411 519
 	}
412 520
 
413 521
 	/* Filter by TID.  Set TID on first response received */
414
-	if ( tftp->tid ) {
415
-		if ( tftp->tid != st_src->st_port ) {
416
-			DBGC ( tftp, "TFTP %p received packet from wrong port "
417
-			       "(got %d, wanted %d)\n", tftp,
418
-			       ntohs ( st_src->st_port ), ntohs ( tftp->tid ));
419
-			return -EINVAL;
420
-		}
421
-	} else {
422
-		tftp->tid = st_src->st_port;
522
+	st_src = ( struct sockaddr_tcpip * ) meta->src;
523
+	if ( tftp->state < 0 ) {
524
+		memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
423 525
 		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
424
-		       ntohs ( tftp->tid ) );
425
-		udp_connect_port ( &tftp->udp, tftp->tid );
426
-	}
427
-
428
-	/* Filter by source address */
429
-	if ( memcmp ( st_src, udp_peer ( &tftp->udp ),
430
-		      sizeof ( *st_src ) ) != 0 ) {
431
-		DBGC ( tftp, "TFTP %p received packet from foreign source\n",
432
-		       tftp );
433
-		return -EINVAL;
526
+		       ntohs ( tftp->peer.st_port ) );
527
+	} else if ( memcmp ( &tftp->peer, st_src,
528
+			     sizeof ( tftp->peer ) ) != 0 ) {
529
+		DBGC ( tftp, "TFTP %p received packet from wrong source (got "
530
+		       "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
531
+		       ntohs ( tftp->peer.st_port ) );
532
+		goto done;
434 533
 	}
435 534
 
436 535
 	switch ( common->opcode ) {
437 536
 	case htons ( TFTP_OACK ):
438
-		return tftp_rx_oack ( tftp, data, len );
537
+		rc = tftp_rx_oack ( tftp, iobuf->data, len );
538
+		break;
439 539
 	case htons ( TFTP_DATA ):
440
-		return tftp_rx_data ( tftp, data, len );
540
+		rc = tftp_rx_data ( tftp, iobuf );
541
+		iobuf = NULL;
542
+		break;
441 543
 	case htons ( TFTP_ERROR ):
442
-		return tftp_rx_error ( tftp, data, len );
544
+		rc = tftp_rx_error ( tftp, iobuf->data, len );
545
+		break;
443 546
 	default:
444
-		DBGC ( tftp, "TFTP %p received strange packet type %d\n", tftp,
445
-		       ntohs ( common->opcode ) );
446
-		return -EINVAL;
547
+		DBGC ( tftp, "TFTP %p received strange packet type %d\n",
548
+		       tftp, ntohs ( common->opcode ) );
549
+		break;
447 550
 	};
551
+
552
+ done:
553
+	free_iob ( iobuf );
554
+	return rc;
448 555
 }
449 556
 
450
-/** TFTP UDP operations */
451
-static struct udp_operations tftp_udp_operations = {
452
-	.senddata = tftp_senddata,
453
-	.newdata = tftp_newdata,
454
-};
557
+/**
558
+ * TFTP connection closed by network stack
559
+ *
560
+ * @v socket		Transport layer interface
561
+ * @v rc		Reason for close
562
+ */
563
+static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
564
+	struct tftp_request *tftp =
565
+		container_of ( socket, struct tftp_request, socket );
566
+
567
+	DBGC ( tftp, "TFTP %p socket closed: %s\n",
568
+	       tftp, strerror ( rc ) );
455 569
 
570
+	tftp_done ( tftp, rc );
571
+}
572
+
573
+/** TFTP socket operations */
574
+static struct xfer_interface_operations tftp_socket_operations = {
575
+	.close		= tftp_socket_close,
576
+	.vredirect	= xfer_vopen,
577
+	.request	= ignore_xfer_request,
578
+	.seek		= ignore_xfer_seek,
579
+	.alloc_iob	= default_xfer_alloc_iob,
580
+	.deliver_iob	= tftp_socket_deliver_iob,
581
+	.deliver_raw	= xfer_deliver_as_iob,
582
+};
583
+ 
456 584
 /**
457
- * Reap asynchronous operation
585
+ * Close TFTP data transfer interface
458 586
  *
459
- * @v async		Asynchronous operation
587
+ * @v xfer		Data transfer interface
588
+ * @v rc		Reason for close
460 589
  */
461
-static void tftp_reap ( struct async *async ) {
462
-	struct tftp_session *tftp =
463
-		container_of ( async, struct tftp_session, async );
590
+static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
591
+	struct tftp_request *tftp =
592
+		container_of ( xfer, struct tftp_request, xfer );
464 593
 
465
-	free ( tftp );
594
+	DBGC ( tftp, "TFTP %p interface closed: %s\n",
595
+	       tftp, strerror ( rc ) );
596
+
597
+	tftp_done ( tftp, rc );
466 598
 }
467 599
 
468
-/** TFTP asynchronous operations */
469
-static struct async_operations tftp_async_operations = {
470
-	.reap = tftp_reap,
600
+/** TFTP data transfer interface operations */
601
+static struct xfer_interface_operations tftp_xfer_operations = {
602
+	.close		= tftp_xfer_close,
603
+	.vredirect	= ignore_xfer_vredirect,
604
+	.request	= ignore_xfer_request,
605
+	.seek		= ignore_xfer_seek,
606
+	.alloc_iob	= default_xfer_alloc_iob,
607
+	.deliver_iob	= xfer_deliver_as_raw,
608
+	.deliver_raw	= ignore_xfer_deliver_raw,
471 609
 };
472 610
 
473 611
 /**
474 612
  * Initiate TFTP download
475 613
  *
614
+ * @v xfer		Data transfer interface
476 615
  * @v uri		Uniform Resource Identifier
477
- * @v buffer		Buffer into which to download file
478
- * @v parent		Parent asynchronous operation
479 616
  * @ret rc		Return status code
480 617
  */
481
-int tftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
482
-	struct tftp_session *tftp = NULL;
618
+int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
619
+	struct tftp_request *tftp;
620
+	struct sockaddr_tcpip server;
483 621
 	int rc;
484 622
 
485 623
 	/* Sanity checks */
486
-	if ( ! uri->path ) {
487
-		rc = -EINVAL;
488
-		goto err;
489
-	}
624
+	if ( ! uri->host )
625
+		return -EINVAL;
626
+	if ( ! uri->path )
627
+		return -EINVAL;
490 628
 
491 629
 	/* Allocate and populate TFTP structure */
492 630
 	tftp = malloc ( sizeof ( *tftp ) );
493
-	if ( ! tftp ) {
494
-		rc = -ENOMEM;
495
-		goto err;
496
-	}
631
+	if ( ! tftp )
632
+		return -ENOMEM;
497 633
 	memset ( tftp, 0, sizeof ( *tftp ) );
498
-	tftp->uri = uri;
499
-	tftp->buffer = buffer;
500
-	if ( ! tftp->request_blksize )
501
-		tftp->request_blksize = TFTP_MAX_BLKSIZE;
502
-	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
634
+	tftp->refcnt.free = tftp_free;
635
+	xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
636
+	tftp->uri = uri_get ( uri );
637
+	xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
503 638
 	tftp->state = -1;
504
-	tftp->udp.udp_op = &tftp_udp_operations;
505 639
 	tftp->timer.expired = tftp_timer_expired;
506 640
 
507
-
508
-#warning "Quick name resolution hack"
509
-	union {
510
-		struct sockaddr_tcpip st;
511
-		struct sockaddr_in sin;
512
-	} server;
513
-	server.sin.sin_port = htons ( TFTP_PORT );
514
-	server.sin.sin_family = AF_INET;
515
-	if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
516
-		rc = -EINVAL;
517
-		goto err;
518
-	}
519
-	udp_connect ( &tftp->udp, &server.st );
520
-
521
-
522
-	/* Open UDP connection */
523
-	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 )
641
+	/* Open socket */
642
+	memset ( &server, 0, sizeof ( server ) );
643
+	server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
644
+	if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
645
+					     ( struct sockaddr * ) &server,
646
+					     uri->host, NULL ) ) != 0 )
524 647
 		goto err;
525 648
 
526
-	/* Transmit initial RRQ */
527
-	tftp_send_packet ( tftp );
649
+	/* Start timer to initiate RRQ */
650
+	start_timer ( &tftp->timer );
528 651
 
529
-	async_init ( &tftp->async, &tftp_async_operations, parent );
652
+	/* Attach to parent interface, mortalise self, and return */
653
+	xfer_plug_plug ( &tftp->xfer, xfer );
654
+	ref_put ( &tftp->refcnt );
530 655
 	return 0;
531 656
 
532 657
  err:
533
-	DBGC ( tftp, "TFTP %p could not create session: %s\n",
658
+	DBGC ( tftp, "TFTP %p could not create request: %s\n",
534 659
 	       tftp, strerror ( rc ) );
535
-	free ( tftp );
660
+	tftp_done ( tftp, rc );
661
+	ref_put ( &tftp->refcnt );
536 662
 	return rc;
537 663
 }
664
+
665
+/** TFTP URI opener */
666
+struct uri_opener tftp_uri_opener __uri_opener = {
667
+	.scheme	= "tftp",
668
+	.open	= tftp_open,
669
+};

Carregando…
Cancelar
Salvar