* (i.e. that no blocks have yet been received).
*/
int state;
+ /** Requested data block size
+ *
+ * This is the "blksize" option requested from the TFTP
+ * server. It may or may not be honoured.
+ */
+ unsigned int request_blksize;
/** Data block size
*
* This is the "blksize" option negotiated with the TFTP
struct retry_timer timer;
};
+/* Function prototypes */
+
+extern struct async_operation * tftp_get ( struct tftp_session *tftp );
+
#endif /* _GPXE_TFTP_H */
end = ( buf + len );
if ( data > end )
goto overflow;
- data += snprintf ( data, ( end - data ),
- "%s%coctet%cblksize%c%d%ctsize%c0",
- tftp->filename, 0, 0, 0, tftp->blksize, 0, 0 ) + 1;
+ data += ( snprintf ( data, ( end - data ),
+ "%s%coctet%cblksize%c%d%ctsize%c0",
+ tftp->filename, 0, 0, 0,
+ tftp->request_blksize, 0, 0 ) + 1 );
if ( data > end )
goto overflow;
rrq->opcode = htons ( TFTP_RRQ );
tftp->timer.expired = tftp_timer_expired;
tftp->state = -1;
tftp->blksize = TFTP_DEFAULT_BLKSIZE;
+ if ( ! tftp->request_blksize )
+ tftp->request_blksize = TFTP_MAX_BLKSIZE;
/* Open UDP connection */
if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
return 0;
}
+static int test_dhcp_tftp ( char *tftpname ) {
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_tcpip st;
+ } target;
+
+ memset ( &target, 0, sizeof ( target ) );
+ target.sin.sin_family = AF_INET;
+ target.sin.sin_port = htons ( 69 );
+ find_global_dhcp_ipv4_option ( DHCP_EB_SIADDR,
+ &target.sin.sin_addr );
+
+ return test_tftp ( &target.st, tftpname );
+}
+
static int test_dhcp_boot ( struct net_device *netdev, char *filename ) {
if ( strncmp ( filename, "aoe:", 4 ) == 0 ) {
return test_dhcp_aoe_boot ( netdev, &filename[4] );
} else if ( strncmp ( filename, "hello:", 6 ) == 0 ) {
return test_dhcp_hello ( &filename[6] );
} else {
- printf ( "Don't know how to boot %s\n", filename );
- return -EPROTONOSUPPORT;
+ return test_dhcp_tftp ( filename );
}
}
--- /dev/null
+#include <stdint.h>
+#include <string.h>
+#include <console.h>
+#include <gpxe/udp.h>
+#include <gpxe/tftp.h>
+#include <gpxe/async.h>
+
+static void test_tftp_callback ( struct tftp_session *tftp __unused,
+ unsigned int block __unused,
+ void *data, size_t len ) {
+ unsigned int i;
+ char c;
+
+ for ( i = 0 ; i < len ; i++ ) {
+ c = * ( ( char * ) data + i );
+ if ( c == '\r' ) {
+ /* Print nothing */
+ } else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
+ putchar ( c );
+ } else {
+ putchar ( '.' );
+ }
+ }
+}
+
+int test_tftp ( struct sockaddr_tcpip *target, const char *filename ) {
+ struct tftp_session tftp;
+
+ memset ( &tftp, 0, sizeof ( tftp ) );
+ udp_connect ( &tftp.udp, target );
+ tftp.filename = filename;
+ tftp.callback = test_tftp_callback;
+
+ return async_wait ( tftp_get ( &tftp ) );
+}