Browse Source

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

UDP API.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
01b4bde8a0
4 changed files with 468 additions and 401 deletions
  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 View File

78
 	struct tftp_ack		ack;
78
 	struct tftp_ack		ack;
79
 	struct tftp_error	error;
79
 	struct tftp_error	error;
80
 	struct tftp_oack	oack;
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
 #endif /* _GPXE_TFTP_H */
85
 #endif /* _GPXE_TFTP_H */

+ 5
- 4
src/interface/pxe/pxe_tftp.c View File

71
 		port = htons ( TFTP_PORT );
71
 		port = htons ( TFTP_PORT );
72
 	if ( ! blksize )
72
 	if ( ! blksize )
73
 		blksize = TFTP_MAX_BLKSIZE;
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 View File

6
 
6
 
7
 #include <string.h>
7
 #include <string.h>
8
 #include <byteswap.h>
8
 #include <byteswap.h>
9
+#include <gpxe/xfer.h>
9
 #include <gpxe/udp.h>
10
 #include <gpxe/udp.h>
10
 #include <gpxe/uaccess.h>
11
 #include <gpxe/uaccess.h>
11
 #include <gpxe/process.h>
12
 #include <gpxe/process.h>
31
 
32
 
32
 /** A PXE UDP connection */
33
 /** A PXE UDP connection */
33
 struct pxe_udp_connection {
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
 	/** "Connection is open" flag */
37
 	/** "Connection is open" flag */
37
 	int open;
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
 	struct s_PXENV_UDP_READ *pxenv_udp_read;
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
  * Receive PXE UDP data
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
  * Receives a packet as part of the current pxenv_udp_read()
53
  * Receives a packet as part of the current pxenv_udp_read()
85
  * operation.
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
 	struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
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
 	userptr_t buffer;
64
 	userptr_t buffer;
65
+	size_t len;
66
+	int rc = 0;
95
 
67
 
96
 	if ( ! pxenv_udp_read ) {
68
 	if ( ! pxenv_udp_read ) {
97
 		DBG ( "PXE discarded UDP packet\n" );
69
 		DBG ( "PXE discarded UDP packet\n" );
98
-		return -ENOBUFS;
70
+		rc = -ENOBUFS;
71
+		goto done;
99
 	}
72
 	}
100
 
73
 
101
 	/* Copy packet to buffer and record length */
74
 	/* Copy packet to buffer and record length */
102
 	buffer = real_to_user ( pxenv_udp_read->buffer.segment,
75
 	buffer = real_to_user ( pxenv_udp_read->buffer.segment,
103
 				pxenv_udp_read->buffer.offset );
76
 				pxenv_udp_read->buffer.offset );
77
+	len = iob_len ( iobuf );
104
 	if ( len > pxenv_udp_read->buffer_size )
78
 	if ( len > pxenv_udp_read->buffer_size )
105
 		len = pxenv_udp_read->buffer_size;
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
 	pxenv_udp_read->buffer_size = len;
81
 	pxenv_udp_read->buffer_size = len;
108
 
82
 
109
 	/* Fill in source/dest information */
83
 	/* Fill in source/dest information */
84
+	assert ( meta );
85
+	sin_src = ( struct sockaddr_in * ) meta->src;
86
+	assert ( sin_src );
110
 	assert ( sin_src->sin_family == AF_INET );
87
 	assert ( sin_src->sin_family == AF_INET );
111
 	pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
88
 	pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
112
 	pxenv_udp_read->s_port = sin_src->sin_port;
89
 	pxenv_udp_read->s_port = sin_src->sin_port;
90
+	sin_dest = ( struct sockaddr_in * ) meta->dest;
91
+	assert ( sin_dest );
113
 	assert ( sin_dest->sin_family == AF_INET );
92
 	assert ( sin_dest->sin_family == AF_INET );
114
 	pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
93
 	pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
115
 	pxenv_udp_read->d_port = sin_dest->sin_port;
94
 	pxenv_udp_read->d_port = sin_dest->sin_port;
117
 	/* Mark as received */
96
 	/* Mark as received */
118
 	pxe_udp->pxenv_udp_read = NULL;
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
 /** The PXE UDP connection */
115
 /** The PXE UDP connection */
130
 static struct pxe_udp_connection pxe_udp = {
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
  *
169
  *
175
  */
170
  */
176
 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
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
 	DBG ( "PXENV_UDP_OPEN" );
173
 	DBG ( "PXENV_UDP_OPEN" );
180
 
174
 
184
 		return PXENV_EXIT_FAILURE;
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
 	pxe_udp.open = 1;
186
 	pxe_udp.open = 1;
199
 
187
 
200
 	pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
188
 	pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
232
 	}
220
 	}
233
 
221
 
234
 	/* Close UDP connection */
222
 	/* Close UDP connection */
235
-	udp_close ( &pxe_udp.udp );
223
+	udp_close_promisc ( &pxe_udp.xfer );
236
 	pxe_udp.open = 0;
224
 	pxe_udp.open = 0;
237
 
225
 
238
 	pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
226
 	pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
281
  *
269
  *
282
  */
270
  */
283
 PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
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
 	int rc;
280
 	int rc;
289
 
281
 
290
 	DBG ( "PXENV_UDP_WRITE" );
282
 	DBG ( "PXENV_UDP_WRITE" );
297
 
289
 
298
 	/* Construct destination socket address */
290
 	/* Construct destination socket address */
299
 	memset ( &dest, 0, sizeof ( dest ) );
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
 	/* Set local (source) port.  PXE spec says source port is 2069
296
 	/* Set local (source) port.  PXE spec says source port is 2069
306
 	 * if not specified.  Really, this ought to be set at UDP open
297
 	 * if not specified.  Really, this ought to be set at UDP open
307
 	 * time but hey, we didn't design this API.
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
 	/* FIXME: we ignore the gateway specified, since we're
304
 	/* FIXME: we ignore the gateway specified, since we're
314
 	 * confident of being able to do our own routing.  We should
305
 	 * confident of being able to do our own routing.  We should
315
 	 * probably allow for multiple gateways.
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
 	DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
320
 	DBG ( " %04x:%04x+%x %d->%s:%d", pxenv_udp_write->buffer.segment,
319
 	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
321
 	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
320
 	      ntohs ( pxenv_udp_write->src_port ),
322
 	      ntohs ( pxenv_udp_write->src_port ),
321
-	      inet_ntoa ( dest.sin.sin_addr ),
323
+	      inet_ntoa ( dest.sin_addr ),
322
 	      ntohs ( pxenv_udp_write->dst_port ) );
324
 	      ntohs ( pxenv_udp_write->dst_port ) );
323
 	
325
 	
324
 	/* Transmit packet */
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
 		return PXENV_EXIT_FAILURE;
330
 		return PXENV_EXIT_FAILURE;
331
 	}
331
 	}
332
 
332
 
389
 		return PXENV_EXIT_FAILURE;
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
 	/* Try receiving a packet */
392
 	/* Try receiving a packet */
396
 	pxe_udp.pxenv_udp_read = pxenv_udp_read;
393
 	pxe_udp.pxenv_udp_read = pxenv_udp_read;
397
 	step();
394
 	step();

+ 378
- 246
src/net/udp/tftp.c View File

24
 #include <byteswap.h>
24
 #include <byteswap.h>
25
 #include <errno.h>
25
 #include <errno.h>
26
 #include <assert.h>
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
 #include <gpxe/uri.h>
30
 #include <gpxe/uri.h>
31
+#include <gpxe/tftp.h>
30
 
32
 
31
 /** @file
33
 /** @file
32
  *
34
  *
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
  * @v tftp		TFTP connection
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
  * @v tftp		TFTP connection
143
  * @v tftp		TFTP connection
105
- * @v name		Option name
106
- * @v value		Option value
107
  * @ret rc		Return status code
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
  * @v tftp		TFTP connection
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
  * @v tftp		TFTP connection
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
 	start_timer ( &tftp->timer );
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
  * @v fail		Failure indicator
226
  * @v fail		Failure indicator
164
  */
227
  */
165
 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
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
 	if ( fail ) {
232
 	if ( fail ) {
170
 		tftp_done ( tftp, -ETIMEDOUT );
233
 		tftp_done ( tftp, -ETIMEDOUT );
179
  * @v tftp		TFTP connection
242
  * @v tftp		TFTP connection
180
  * @v block		Block number
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
 	/* Stop the retry timer */
247
 	/* Stop the retry timer */
185
 	stop_timer ( &tftp->timer );
248
 	stop_timer ( &tftp->timer );
192
 }
255
 }
193
 
256
 
194
 /**
257
 /**
195
- * Transmit RRQ
258
+ * Process TFTP "blksize" option
196
  *
259
  *
197
  * @v tftp		TFTP connection
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
  * @ret rc		Return status code
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
  * @v len		Length of temporary data buffer
353
  * @v len		Length of temporary data buffer
234
  * @ret rc		Return status code
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
 	struct tftp_oack *oack = buf;
357
 	struct tftp_oack *oack = buf;
238
 	char *end = buf + len;
358
 	char *end = buf + len;
239
 	char *name;
359
 	char *name;
276
  * Receive DATA
396
  * Receive DATA
277
  *
397
  *
278
  * @v tftp		TFTP connection
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
  * @ret rc		Return status code
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
 	unsigned int block;
407
 	unsigned int block;
286
-	size_t data_offset;
287
 	size_t data_len;
408
 	size_t data_len;
288
 	int rc;
409
 	int rc;
289
 
410
 
290
 	/* Sanity check */
411
 	/* Sanity check */
291
-	if ( len < sizeof ( *data ) ) {
412
+	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
292
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
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
 		return -EINVAL;
416
 		return -EINVAL;
295
 	}
417
 	}
296
 
418
 
297
-	/* Fill data buffer */
419
+	/* Extract data */
298
 	block = ntohs ( data->block );
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
 		       tftp, strerror ( rc ) );
427
 		       tftp, strerror ( rc ) );
305
 		tftp_done ( tftp, rc );
428
 		tftp_done ( tftp, rc );
306
 		return rc;
429
 		return rc;
316
 	return 0;
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
  * Receive ERROR
450
  * Receive ERROR
340
  * @v len		Length of temporary data buffer
454
  * @v len		Length of temporary data buffer
341
  * @ret rc		Return status code
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
 	struct tftp_error *error = buf;
458
 	struct tftp_error *error = buf;
345
 	unsigned int err;
459
 	unsigned int err;
346
 	int rc = 0;
460
 	int rc = 0;
362
 	if ( ! rc )
476
 	if ( ! rc )
363
 		rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
477
 		rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
364
 
478
 
365
-	/* Close TFTP session */
479
+	/* Close TFTP request */
366
 	tftp_done ( tftp, rc );
480
 	tftp_done ( tftp, rc );
367
 
481
 
368
 	return 0;
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
  * Receive new data
486
  * Receive new data
393
  *
487
  *
397
  * @v st_src		Partially-filled source address
491
  * @v st_src		Partially-filled source address
398
  * @v st_dest		Partially-filled destination address
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
 	if ( len < sizeof ( *common ) ) {
505
 	if ( len < sizeof ( *common ) ) {
408
 		DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
506
 		DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
409
 		       tftp, len );
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
 	/* Filter by TID.  Set TID on first response received */
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
 		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
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
 	switch ( common->opcode ) {
535
 	switch ( common->opcode ) {
437
 	case htons ( TFTP_OACK ):
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
 	case htons ( TFTP_DATA ):
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
 	case htons ( TFTP_ERROR ):
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
 	default:
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
  * Initiate TFTP download
612
  * Initiate TFTP download
475
  *
613
  *
614
+ * @v xfer		Data transfer interface
476
  * @v uri		Uniform Resource Identifier
615
  * @v uri		Uniform Resource Identifier
477
- * @v buffer		Buffer into which to download file
478
- * @v parent		Parent asynchronous operation
479
  * @ret rc		Return status code
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
 	int rc;
621
 	int rc;
484
 
622
 
485
 	/* Sanity checks */
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
 	/* Allocate and populate TFTP structure */
629
 	/* Allocate and populate TFTP structure */
492
 	tftp = malloc ( sizeof ( *tftp ) );
630
 	tftp = malloc ( sizeof ( *tftp ) );
493
-	if ( ! tftp ) {
494
-		rc = -ENOMEM;
495
-		goto err;
496
-	}
631
+	if ( ! tftp )
632
+		return -ENOMEM;
497
 	memset ( tftp, 0, sizeof ( *tftp ) );
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
 	tftp->state = -1;
638
 	tftp->state = -1;
504
-	tftp->udp.udp_op = &tftp_udp_operations;
505
 	tftp->timer.expired = tftp_timer_expired;
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
 		goto err;
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
 	return 0;
655
 	return 0;
531
 
656
 
532
  err:
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
 	       tftp, strerror ( rc ) );
659
 	       tftp, strerror ( rc ) );
535
-	free ( tftp );
660
+	tftp_done ( tftp, rc );
661
+	ref_put ( &tftp->refcnt );
536
 	return rc;
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
+};

Loading…
Cancel
Save