|
@@ -24,6 +24,9 @@
|
24
|
24
|
|
25
|
25
|
#include "pxe.h"
|
26
|
26
|
|
|
27
|
+static int pxe_tftp_read_block ( unsigned char *data, unsigned int block,
|
|
28
|
+ unsigned int len, int eof );
|
|
29
|
+
|
27
|
30
|
/**
|
28
|
31
|
* TFTP OPEN
|
29
|
32
|
*
|
|
@@ -74,6 +77,10 @@
|
74
|
77
|
* relevant @ref pxe_note_tftp "implementation note" for Etherboot's
|
75
|
78
|
* solution to this problem.
|
76
|
79
|
*
|
|
80
|
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
|
81
|
+ * value before calling this function in protected mode. You cannot
|
|
82
|
+ * call this function with a 32-bit stack segment. (See the relevant
|
|
83
|
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
|
77
|
84
|
*
|
78
|
85
|
* @note If you pass in a value less than 512 for
|
79
|
86
|
* s_PXENV_TFTP_OPEN::PacketSize, Etherboot will attempt to negotiate
|
|
@@ -89,7 +96,15 @@
|
89
|
96
|
* achieved without the existence of an API call %pxenv_tftp_write()
|
90
|
97
|
* is not made clear.
|
91
|
98
|
*
|
92
|
|
- * Status: working
|
|
99
|
+ * @note Despite the existence of the numerous statements within the
|
|
100
|
+ * PXE specification of the form "...if a TFTP/MTFTP or UDP connection
|
|
101
|
+ * is active...", you cannot use pxenv_tftp_open() and
|
|
102
|
+ * pxenv_tftp_read() to read a file via MTFTP; only via plain old
|
|
103
|
+ * TFTP. If you want to use MTFTP, use pxenv_tftp_read_file()
|
|
104
|
+ * instead. Astute readers will note that, since
|
|
105
|
+ * pxenv_tftp_read_file() is an atomic operation from the point of
|
|
106
|
+ * view of the PXE API, it is conceptually impossible to issue any
|
|
107
|
+ * other PXE API call "if an MTFTP connection is active".
|
93
|
108
|
*/
|
94
|
109
|
PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
|
95
|
110
|
struct sockaddr_in tftp_server;
|
|
@@ -134,9 +149,26 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
|
134
|
149
|
return PXENV_EXIT_SUCCESS;
|
135
|
150
|
}
|
136
|
151
|
|
137
|
|
-/* PXENV_TFTP_CLOSE
|
|
152
|
+/**
|
|
153
|
+ * TFTP CLOSE
|
|
154
|
+ *
|
|
155
|
+ * @v tftp_close Pointer to a struct s_PXENV_TFTP_CLOSE
|
|
156
|
+ * @ret #PXENV_EXIT_SUCCESS File was closed successfully
|
|
157
|
+ * @ret #PXENV_EXIT_FAILURE File was not closed
|
|
158
|
+ * @ret s_PXENV_TFTP_CLOSE::Status PXE status code
|
|
159
|
+ * @err None -
|
|
160
|
+ *
|
|
161
|
+ * Close a connection previously opened with pxenv_tftp_open(). You
|
|
162
|
+ * must have previously opened a connection with pxenv_tftp_open().
|
138
|
163
|
*
|
139
|
|
- * Status: working
|
|
164
|
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
|
165
|
+ * value before calling this function in protected mode. You cannot
|
|
166
|
+ * call this function with a 32-bit stack segment. (See the relevant
|
|
167
|
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
|
|
168
|
+ *
|
|
169
|
+ * @note Since TFTP runs over UDP, which is a connectionless protocol,
|
|
170
|
+ * the concept of closing a file is somewhat meaningless. This call
|
|
171
|
+ * is a no-op for Etherboot.
|
140
|
172
|
*/
|
141
|
173
|
PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
|
142
|
174
|
DBG ( "PXENV_TFTP_CLOSE" );
|
|
@@ -145,9 +177,71 @@ PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
|
145
|
177
|
return PXENV_EXIT_SUCCESS;
|
146
|
178
|
}
|
147
|
179
|
|
148
|
|
-/* PXENV_TFTP_READ
|
|
180
|
+/**
|
|
181
|
+ * TFTP READ
|
|
182
|
+ *
|
|
183
|
+ * @v tftp_read Pointer to a struct s_PXENV_TFTP_READ
|
|
184
|
+ * @v s_PXENV_TFTP_READ::Buffer Address of data buffer
|
|
185
|
+ * @ret #PXENV_EXIT_SUCCESS Data was read successfully
|
|
186
|
+ * @ret #PXENV_EXIT_FAILURE Data was not read
|
|
187
|
+ * @ret s_PXENV_TFTP_READ::Status PXE status code
|
|
188
|
+ * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number
|
|
189
|
+ * @ret s_PXENV_TFTP_READ::BufferSize Length of data written into buffer
|
|
190
|
+ *
|
|
191
|
+ * Reads a single packet from a connection previously opened with
|
|
192
|
+ * pxenv_tftp_open() into the data buffer pointed to by
|
|
193
|
+ * s_PXENV_TFTP_READ::Buffer. You must have previously opened a
|
|
194
|
+ * connection with pxenv_tftp_open(). The data written into
|
|
195
|
+ * s_PXENV_TFTP_READ::Buffer is just the file data; the various
|
|
196
|
+ * network headers have already been removed.
|
149
|
197
|
*
|
150
|
|
- * Status: working
|
|
198
|
+ * The buffer must be large enough to contain a packet of the size
|
|
199
|
+ * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the
|
|
200
|
+ * pxenv_tftp_open() call. It is worth noting that the PXE
|
|
201
|
+ * specification does @b not require the caller to fill in
|
|
202
|
+ * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so
|
|
203
|
+ * the PXE stack is free to ignore whatever value the caller might
|
|
204
|
+ * place there and just assume that the buffer is large enough. That
|
|
205
|
+ * said, it may be worth the caller always filling in
|
|
206
|
+ * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that
|
|
207
|
+ * mistake it for an input parameter.
|
|
208
|
+ *
|
|
209
|
+ * The length of the TFTP data packet will be returned via
|
|
210
|
+ * s_PXENV_TFTP_READ::BufferSize. If this length is less than the
|
|
211
|
+ * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to
|
|
212
|
+ * pxenv_tftp_open(), this indicates that the block is the last block
|
|
213
|
+ * in the file. Note that zero is a valid length for
|
|
214
|
+ * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of
|
|
215
|
+ * the file is a multiple of the blksize.
|
|
216
|
+ *
|
|
217
|
+ * The PXE specification doesn't actually state that calls to
|
|
218
|
+ * pxenv_tftp_read() will return the data packets in strict sequential
|
|
219
|
+ * order, though most PXE stacks will probably do so. The sequence
|
|
220
|
+ * number of the packet will be returned in
|
|
221
|
+ * s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has
|
|
222
|
+ * a sequence number of one, not zero.
|
|
223
|
+ *
|
|
224
|
+ * To guard against flawed PXE stacks, the caller should probably set
|
|
225
|
+ * s_PXENV_TFTP_READ::PacketNumber to one less than the expected
|
|
226
|
+ * returned value (i.e. set it to zero for the first call to
|
|
227
|
+ * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ
|
|
228
|
+ * parameter block for subsequent calls without modifying
|
|
229
|
+ * s_PXENV_TFTP_READ::PacketNumber between calls). The caller should
|
|
230
|
+ * also guard against potential problems caused by flawed
|
|
231
|
+ * implementations returning the occasional duplicate packet, by
|
|
232
|
+ * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber
|
|
233
|
+ * is as expected (i.e. one greater than that returned from the
|
|
234
|
+ * previous call to pxenv_tftp_read()).
|
|
235
|
+ *
|
|
236
|
+ * Nothing in the PXE specification indicates when the TFTP
|
|
237
|
+ * acknowledgement packets will be sent back to the server. See the
|
|
238
|
+ * relevant @ref pxe_note_tftp "implementation note" for details on
|
|
239
|
+ * when Etherboot chooses to send these packets.
|
|
240
|
+ *
|
|
241
|
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
|
242
|
+ * value before calling this function in protected mode. You cannot
|
|
243
|
+ * call this function with a 32-bit stack segment. (See the relevant
|
|
244
|
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
|
151
|
245
|
*/
|
152
|
246
|
PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
|
153
|
247
|
struct tftpblk_info_t block;
|
|
@@ -180,23 +274,97 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
|
180
|
274
|
return PXENV_EXIT_SUCCESS;
|
181
|
275
|
}
|
182
|
276
|
|
183
|
|
-/* PXENV_TFTP_READ_FILE
|
|
277
|
+/**
|
|
278
|
+ * TFTP/MTFTP read file
|
|
279
|
+ *
|
|
280
|
+ * @v tftp_read_file Pointer to a struct s_PXENV_TFTP_READ_FILE
|
|
281
|
+ * @v s_PXENV_TFTP_READ_FILE::FileName File name
|
|
282
|
+ * @v s_PXENV_TFTP_READ_FILE::BufferSize Size of the receive buffer
|
|
283
|
+ * @v s_PXENV_TFTP_READ_FILE::Buffer Address of the receive buffer
|
|
284
|
+ * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress TFTP server IP address
|
|
285
|
+ * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress Relay agent IP address
|
|
286
|
+ * @v s_PXENV_TFTP_READ_FILE::McastIPAddress File's multicast IP address
|
|
287
|
+ * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort Client multicast UDP port
|
|
288
|
+ * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort Server multicast UDP port
|
|
289
|
+ * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut Time to wait for first packet
|
|
290
|
+ * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay MTFTP inactivity timeout
|
|
291
|
+ * @ret #PXENV_EXIT_SUCCESS File downloaded successfully
|
|
292
|
+ * @ret #PXENV_EXIT_FAILURE File not downloaded
|
|
293
|
+ * @ret s_PXENV_TFTP_READ_FILE::Status PXE status code
|
|
294
|
+ * @ret s_PXENV_TFTP_READ_FILE::BufferSize Length of downloaded file
|
|
295
|
+ *
|
|
296
|
+ * Downloads an entire file via either TFTP or MTFTP into the buffer
|
|
297
|
+ * pointed to by s_PXENV_TFTP_READ_FILE::Buffer.
|
|
298
|
+ *
|
|
299
|
+ * The PXE specification does not make it clear how the caller
|
|
300
|
+ * requests that MTFTP be used rather than TFTP (or vice versa). One
|
|
301
|
+ * reasonable guess is that setting
|
|
302
|
+ * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP
|
|
303
|
+ * to be used instead of MTFTP, though it is conceivable that some PXE
|
|
304
|
+ * stacks would interpret that as "use the DHCP-provided multicast IP
|
|
305
|
+ * address" instead. Some PXE stacks will not implement MTFTP at all,
|
|
306
|
+ * and will always use TFTP.
|
|
307
|
+ *
|
|
308
|
+ * It is not specified whether or not
|
|
309
|
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server
|
|
310
|
+ * port for TFTP (rather than MTFTP) downloads. Callers should assume
|
|
311
|
+ * that the only way to access a TFTP server on a non-standard port is
|
|
312
|
+ * to use pxenv_tftp_open() and pxenv_tftp_read().
|
|
313
|
+ *
|
|
314
|
+ * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP
|
|
315
|
+ * routing will take place. See the relevant
|
|
316
|
+ * @ref pxe_routing "implementation note" for more details.
|
|
317
|
+ *
|
|
318
|
+ * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an
|
|
319
|
+ * #ADDR32_t type, i.e. nominally a flat physical address. Some PXE
|
|
320
|
+ * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real
|
|
321
|
+ * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above
|
|
322
|
+ * 1MB. This means that PXE stacks must be prepared to write to areas
|
|
323
|
+ * outside base memory. Exactly how this is to be achieved is not
|
|
324
|
+ * specified, though using INT 15,87 is as close to a standard method
|
|
325
|
+ * as any, and should probably be used. Switching to protected-mode
|
|
326
|
+ * in order to access high memory will fail if pxenv_tftp_read_file()
|
|
327
|
+ * is called in V86 mode; it is reasonably to expect that a V86
|
|
328
|
+ * monitor would intercept the relatively well-defined INT 15,87 if it
|
|
329
|
+ * wants the PXE stack to be able to write to high memory.
|
|
330
|
+ *
|
|
331
|
+ * Things get even more interesting if pxenv_tftp_read_file() is
|
|
332
|
+ * called in protected mode, because there is then absolutely no way
|
|
333
|
+ * for the PXE stack to write to an absolute physical address. You
|
|
334
|
+ * can't even get around the problem by creating a special "access
|
|
335
|
+ * everything" segment in the s_PXE data structure, because the
|
|
336
|
+ * #SEGDESC_t descriptors are limited to 64kB in size.
|
|
337
|
+ *
|
|
338
|
+ * Previous versions of the PXE specification (e.g. WfM 1.1a) provide
|
|
339
|
+ * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to
|
|
340
|
+ * work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE
|
|
341
|
+ * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into
|
|
342
|
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and
|
|
343
|
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a
|
|
344
|
+ * protected-mode segment:offset address for the data buffer. This
|
|
345
|
+ * API call is no longer present in version 2.1 of the PXE
|
|
346
|
+ * specification.
|
|
347
|
+ *
|
|
348
|
+ * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer
|
|
349
|
+ * is an offset relative to the caller's data segment, when
|
|
350
|
+ * pxenv_tftp_read_file() is called in protected mode.
|
|
351
|
+ *
|
|
352
|
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
|
353
|
+ * value before calling this function in protected mode. You cannot
|
|
354
|
+ * call this function with a 32-bit stack segment. (See the relevant
|
|
355
|
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
|
|
356
|
+ *
|
|
357
|
+ * @note Microsoft's NTLDR assumes that the filename passed in via
|
|
358
|
+ * s_PXENV_TFTP_READ_FILE::FileName will be stored in the "file" field
|
|
359
|
+ * of the stored DHCPACK packet, whence it will be returned via any
|
|
360
|
+ * subsequent calls to pxenv_get_cached_info(). Though this is
|
|
361
|
+ * essentially a bug in the Intel PXE implementation (not, for once,
|
|
362
|
+ * in the specification!), it is a bug that Microsoft relies upon, and
|
|
363
|
+ * so we implement this bug-for-bug compatibility by overwriting the
|
|
364
|
+ * filename stored DHCPACK packet with the filename passed in
|
|
365
|
+ * s_PXENV_TFTP_READ_FILE::FileName.
|
184
|
366
|
*
|
185
|
|
- * Status: working
|
186
|
367
|
*/
|
187
|
|
-
|
188
|
|
-int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused,
|
189
|
|
- unsigned int len, int eof ) {
|
190
|
|
- if ( pxe_stack->readfile.buffer ) {
|
191
|
|
- if ( pxe_stack->readfile.offset + len >=
|
192
|
|
- pxe_stack->readfile.bufferlen ) return -1;
|
193
|
|
- memcpy ( pxe_stack->readfile.buffer +
|
194
|
|
- pxe_stack->readfile.offset, data, len );
|
195
|
|
- }
|
196
|
|
- pxe_stack->readfile.offset += len;
|
197
|
|
- return eof ? 0 : 1;
|
198
|
|
-}
|
199
|
|
-
|
200
|
368
|
PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
|
201
|
369
|
*tftp_read_file ) {
|
202
|
370
|
struct sockaddr_in tftp_server;
|
|
@@ -233,11 +401,60 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
|
233
|
401
|
return PXENV_EXIT_SUCCESS;
|
234
|
402
|
}
|
235
|
403
|
|
236
|
|
-/* PXENV_TFTP_GET_FSIZE
|
|
404
|
+static int pxe_tftp_read_block ( unsigned char *data,
|
|
405
|
+ unsigned int block __unused,
|
|
406
|
+ unsigned int len, int eof ) {
|
|
407
|
+ if ( pxe_stack->readfile.buffer ) {
|
|
408
|
+ if ( pxe_stack->readfile.offset + len >=
|
|
409
|
+ pxe_stack->readfile.bufferlen ) return -1;
|
|
410
|
+ memcpy ( pxe_stack->readfile.buffer +
|
|
411
|
+ pxe_stack->readfile.offset, data, len );
|
|
412
|
+ }
|
|
413
|
+ pxe_stack->readfile.offset += len;
|
|
414
|
+ return eof ? 0 : 1;
|
|
415
|
+}
|
|
416
|
+
|
|
417
|
+/**
|
|
418
|
+ * TFTP GET FILE SIZE
|
|
419
|
+ *
|
|
420
|
+ * @v tftp_get_fsize Pointer to a struct s_PXENV_TFTP_GET_FSIZE
|
|
421
|
+ * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress TFTP server IP address
|
|
422
|
+ * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress Relay agent IP address
|
|
423
|
+ * @v s_PXENV_TFTP_GET_FSIZE::FileName File name
|
|
424
|
+ * @ret #PXENV_EXIT_SUCCESS File size was determined successfully
|
|
425
|
+ * @ret #PXENV_EXIT_FAILURE File size was not determined
|
|
426
|
+ * @ret s_PXENV_TFTP_GET_FSIZE::Status PXE status code
|
|
427
|
+ * @ret s_PXENV_TFTP_GET_FSIZE::FileSize File size
|
237
|
428
|
*
|
238
|
|
- * Status: working, though ugly (we actually read the whole file,
|
239
|
|
- * because it's too ugly to make Etherboot request the tsize option
|
240
|
|
- * and hand it to us).
|
|
429
|
+ * Determine the size of a file on a TFTP server. This uses the
|
|
430
|
+ * "tsize" TFTP option, and so will not work with a TFTP server that
|
|
431
|
+ * does not support TFTP options, or that does not support the "tsize"
|
|
432
|
+ * option.
|
|
433
|
+ *
|
|
434
|
+ * The PXE specification states that this API call will @b not open a
|
|
435
|
+ * TFTP connection for subsequent use with pxenv_tftp_read(). (This
|
|
436
|
+ * is somewhat daft, since the only way to obtain the file size via
|
|
437
|
+ * the "tsize" option involves issuing a TFTP open request, but that's
|
|
438
|
+ * life.)
|
|
439
|
+ *
|
|
440
|
+ * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP
|
|
441
|
+ * connection is open.
|
|
442
|
+ *
|
|
443
|
+ * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP
|
|
444
|
+ * routing will take place. See the relevant
|
|
445
|
+ * @ref pxe_routing "implementation note" for more details.
|
|
446
|
+ *
|
|
447
|
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
|
|
448
|
+ * value before calling this function in protected mode. You cannot
|
|
449
|
+ * call this function with a 32-bit stack segment. (See the relevant
|
|
450
|
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
|
|
451
|
+ *
|
|
452
|
+ * @note There is no way to specify the TFTP server port with this API
|
|
453
|
+ * call. Though you can open a file using a non-standard TFTP server
|
|
454
|
+ * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially,
|
|
455
|
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of
|
|
456
|
+ * a file from a TFTP server listening on the standard TFTP port.
|
|
457
|
+ * "Consistency" is not a word in Intel's vocabulary.
|
241
|
458
|
*/
|
242
|
459
|
PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
|
243
|
460
|
*tftp_get_fsize ) {
|