summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2005-04-30 16:46:49 +0200
committerMichael Brown2005-04-30 16:46:49 +0200
commit167c26c92b3c831c96b3fe4514cd7bd75507c229 (patch)
tree9e7e72360eef1c48b009b481df3f46de713c6868
parenttftp moved to separate file. (diff)
downloadipxe-167c26c92b3c831c96b3fe4514cd7bd75507c229.tar.gz
ipxe-167c26c92b3c831c96b3fe4514cd7bd75507c229.tar.xz
ipxe-167c26c92b3c831c96b3fe4514cd7bd75507c229.zip
tftp functions moved to proto/tftp.c
-rw-r--r--src/core/nic.c160
-rw-r--r--src/proto/tftp.c174
2 files changed, 177 insertions, 157 deletions
diff --git a/src/core/nic.c b/src/core/nic.c
index 4d492e78a..35dbd1db4 100644
--- a/src/core/nic.c
+++ b/src/core/nic.c
@@ -342,7 +342,7 @@ int download_url ( char *url,
unparse_url ( &url_info );
/* Call protocol's method to download the file */
- return proto->load ( url, &server, process );
+ return proto->load ( url, &server, url_info.file, process );
error_out:
unparse_url ( &url_info );
@@ -659,161 +659,6 @@ void rx_qdrain(void)
}
#ifdef DOWNLOAD_PROTO_TFTP
-/**************************************************************************
-TFTP - Download extended BOOTP data, or kernel image
-**************************************************************************/
-static int await_tftp(int ival, void *ptr __unused,
- unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp,
- struct tcphdr *tcp __unused)
-{
- if (!udp) {
- return 0;
- }
- if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
- return 0;
- if (ntohs(udp->dest) != ival)
- return 0;
- return 1;
-}
-
-int tftp ( const char *name,
- int (*fnc)(unsigned char *, unsigned int, unsigned int, int) )
-{
- struct tftpreq_info_t request_data =
- { name, TFTP_PORT, TFTP_MAX_PACKET };
- struct tftpreq_info_t *request = &request_data;
- struct tftpblk_info_t block;
- int rc;
-
- while ( tftp_block ( request, &block ) ) {
- request = NULL; /* Send request only once */
- rc = fnc ( block.data, block.block, block.len, block.eof );
- if ( rc <= 0 ) return (rc);
- if ( block.eof ) {
- /* fnc should not have returned */
- printf ( "TFTP download complete, but\n" );
- return (0);
- }
- }
- return (0);
-}
-
-int tftp_block ( struct tftpreq_info_t *request, struct tftpblk_info_t *block )
-{
- static unsigned short lport = 2000; /* local port */
- static unsigned short rport = TFTP_PORT; /* remote port */
- struct tftp_t *rcvd = NULL;
- static struct tftpreq_t xmit;
- static unsigned short xmitlen = 0;
- static unsigned short blockidx = 0; /* Last block received */
- static unsigned short retry = 0; /* Retry attempts on last block */
- static int blksize = 0;
- unsigned short recvlen = 0;
-
- /* If this is a new request (i.e. if name is set), fill in
- * transmit block with RRQ and send it.
- */
- if ( request ) {
- rx_qdrain(); /* Flush receive queue */
- xmit.opcode = htons(TFTP_RRQ);
- xmitlen = (void*)&xmit.u.rrq - (void*)&xmit +
- sprintf((char*)xmit.u.rrq, "%s%coctet%cblksize%c%d",
- request->name, 0, 0, 0, request->blksize)
- + 1; /* null terminator */
- blockidx = 0; /* Reset counters */
- retry = 0;
- blksize = TFTP_DEFAULTSIZE_PACKET;
- lport++; /* Use new local port */
- rport = request->port;
- if ( !udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, lport,
- rport, xmitlen, &xmit) )
- return (0);
- }
- /* Exit if no transfer in progress */
- if ( !blksize ) return (0);
- /* Loop to wait until we get a packet we're interested in */
- block->data = NULL; /* Used as flag */
- while ( block->data == NULL ) {
- long timeout = rfc2131_sleep_interval ( blockidx ? TFTP_REXMT :
- TIMEOUT, retry );
- if ( !await_reply(await_tftp, lport, NULL, timeout) ) {
- /* No packet received */
- if ( retry++ > MAX_TFTP_RETRIES ) break;
- /* Retransmit last packet */
- if ( !blockidx ) lport++; /* New lport if new RRQ */
- if ( !udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit) )
- return (0);
- continue; /* Back to waiting for packet */
- }
- /* Packet has been received */
- rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
- recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
- - sizeof(rcvd->opcode);
- rport = ntohs(rcvd->udp.src);
- retry = 0; /* Reset retry counter */
- switch ( htons(rcvd->opcode) ) {
- case TFTP_ERROR : {
- printf ( "TFTP error %d (%s)\n",
- ntohs(rcvd->u.err.errcode),
- rcvd->u.err.errmsg );
- return (0); /* abort */
- }
- case TFTP_OACK : {
- const char *p = rcvd->u.oack.data;
- const char *e = p + recvlen - 10; /* "blksize\0\d\0" */
-
- *((char*)(p+recvlen-1)) = '\0'; /* Force final 0 */
- if ( blockidx || !request ) break; /* Too late */
- if ( recvlen <= TFTP_MAX_PACKET ) /* sanity */ {
- /* Check for blksize option honoured */
- while ( p < e ) {
- if ( strcasecmp("blksize",p) == 0 &&
- p[7] == '\0' ) {
- blksize = strtoul(p+8,&p,10);
- p++; /* skip null */
- }
- while ( *(p++) ) {};
- }
- }
- if ( blksize < TFTP_DEFAULTSIZE_PACKET || blksize > request->blksize ) {
- /* Incorrect blksize - error and abort */
- xmit.opcode = htons(TFTP_ERROR);
- xmit.u.err.errcode = 8;
- xmitlen = (void*)&xmit.u.err.errmsg
- - (void*)&xmit
- + sprintf((char*)xmit.u.err.errmsg,
- "RFC1782 error")
- + 1;
- udp_transmit(
- arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit);
- return (0);
- }
- } break;
- case TFTP_DATA :
- if ( ntohs(rcvd->u.data.block) != ( blockidx + 1 ) )
- break; /* Re-ACK last block sent */
- if ( recvlen > ( blksize+sizeof(rcvd->u.data.block) ) )
- break; /* Too large; ignore */
- block->data = rcvd->u.data.download;
- block->block = ++blockidx;
- block->len = recvlen - sizeof(rcvd->u.data.block);
- block->eof = ( (unsigned short)block->len < blksize );
- /* If EOF, zero blksize to indicate transfer done */
- if ( block->eof ) blksize = 0;
- break;
- default: break; /* Do nothing */
- }
- /* Send ACK */
- xmit.opcode = htons(TFTP_ACK);
- xmit.u.ack.block = htons(blockidx);
- xmitlen = TFTP_MIN_PACKET;
- udp_transmit ( arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit );
- }
- return ( block->data ? 1 : 0 );
-}
#endif /* DOWNLOAD_PROTO_TFTP */
#ifdef RARP_NOT_BOOTP
@@ -1778,7 +1623,8 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
memcpy(fname, extpath+2, TAG_LEN(extpath));
fname[(int)TAG_LEN(extpath)] = '\0';
printf("Loading BOOTP-extension file: %s\n",fname);
- tftp(fname, decode_rfc1533);
+#warning "BOOTP extension files are broken"
+ /* tftp(fname, decode_rfc1533); */
}
return 1; /* proceed with next block */
}
diff --git a/src/proto/tftp.c b/src/proto/tftp.c
new file mode 100644
index 000000000..9c0e55638
--- /dev/null
+++ b/src/proto/tftp.c
@@ -0,0 +1,174 @@
+#include "etherboot.h"
+#include "in.h"
+#include "nic.h"
+#include "proto.h"
+#include "tftp.h"
+
+/* Utility function for tftp_block() */
+static int await_tftp ( int ival, void *ptr __unused,
+ unsigned short ptype __unused, struct iphdr *ip,
+ struct udphdr *udp, struct tcphdr *tcp __unused ) {
+ if ( ! udp ) {
+ return 0;
+ }
+ if ( arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr )
+ return 0;
+ if ( ntohs ( udp->dest ) != ival )
+ return 0;
+ return 1;
+}
+
+/*
+ * Download a single block via TFTP. This function is non-static so
+ * that pxe_export.c can call it.
+ *
+ */
+int tftp_block ( struct tftpreq_info_t *request,
+ struct tftpblk_info_t *block ) {
+ static struct sockaddr_in server;
+ static unsigned short lport = 2000; /* local port */
+ struct tftp_t *rcvd = NULL;
+ static struct tftpreq_t xmit;
+ static unsigned short xmitlen = 0;
+ static unsigned short blockidx = 0; /* Last block received */
+ static unsigned short retry = 0; /* Retry attempts on last block */
+ static int blksize = 0;
+ unsigned short recvlen = 0;
+
+ /* If this is a new request (i.e. if name is set), fill in
+ * transmit block with RRQ and send it.
+ */
+ if ( request ) {
+ rx_qdrain(); /* Flush receive queue */
+ xmit.opcode = htons(TFTP_RRQ);
+ xmitlen = (void*)&xmit.u.rrq - (void*)&xmit +
+ sprintf((char*)xmit.u.rrq, "%s%coctet%cblksize%c%d",
+ request->name, 0, 0, 0, request->blksize)
+ + 1; /* null terminator */
+ blockidx = 0; /* Reset counters */
+ retry = 0;
+ blksize = TFTP_DEFAULTSIZE_PACKET;
+ lport++; /* Use new local port */
+ server = *(request->server);
+ if ( ! server.sin_port )
+ server.sin_port = TFTP_PORT;
+ if ( !udp_transmit(server.sin_addr.s_addr, lport,
+ server.sin_port, xmitlen, &xmit) )
+ return (0);
+ }
+ /* Exit if no transfer in progress */
+ if ( !blksize ) return (0);
+ /* Loop to wait until we get a packet we're interested in */
+ block->data = NULL; /* Used as flag */
+ while ( block->data == NULL ) {
+ long timeout = rfc2131_sleep_interval ( blockidx ? TFTP_REXMT :
+ TIMEOUT, retry );
+ if ( !await_reply(await_tftp, lport, NULL, timeout) ) {
+ /* No packet received */
+ if ( retry++ > MAX_TFTP_RETRIES ) break;
+ /* Retransmit last packet */
+ if ( !blockidx ) lport++; /* New lport if new RRQ */
+ if ( !udp_transmit(server.sin_addr.s_addr, lport,
+ server.sin_port, xmitlen, &xmit) )
+ return (0);
+ continue; /* Back to waiting for packet */
+ }
+ /* Packet has been received */
+ rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
+ recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
+ - sizeof(rcvd->opcode);
+ server.sin_port = ntohs(rcvd->udp.src);
+ retry = 0; /* Reset retry counter */
+ switch ( htons(rcvd->opcode) ) {
+ case TFTP_ERROR : {
+ printf ( "TFTP error %d (%s)\n",
+ ntohs(rcvd->u.err.errcode),
+ rcvd->u.err.errmsg );
+ return (0); /* abort */
+ }
+ case TFTP_OACK : {
+ const char *p = rcvd->u.oack.data;
+ const char *e = p + recvlen - 10; /* "blksize\0\d\0" */
+
+ *((char*)(p+recvlen-1)) = '\0'; /* Force final 0 */
+ if ( blockidx || !request ) break; /* Too late */
+ if ( recvlen <= TFTP_MAX_PACKET ) /* sanity */ {
+ /* Check for blksize option honoured */
+ while ( p < e ) {
+ if ( strcasecmp("blksize",p) == 0 &&
+ p[7] == '\0' ) {
+ blksize = strtoul(p+8,&p,10);
+ p++; /* skip null */
+ }
+ while ( *(p++) ) {};
+ }
+ }
+ if ( blksize < TFTP_DEFAULTSIZE_PACKET ||
+ blksize > request->blksize ) {
+ /* Incorrect blksize - error and abort */
+ xmit.opcode = htons(TFTP_ERROR);
+ xmit.u.err.errcode = 8;
+ xmitlen = (void*)&xmit.u.err.errmsg
+ - (void*)&xmit
+ + sprintf((char*)xmit.u.err.errmsg,
+ "RFC1782 error")
+ + 1;
+ udp_transmit(server.sin_addr.s_addr, lport,
+ server.sin_port, xmitlen, &xmit);
+ return (0);
+ }
+ } break;
+ case TFTP_DATA :
+ if ( ntohs(rcvd->u.data.block) != ( blockidx + 1 ) )
+ break; /* Re-ACK last block sent */
+ if ( recvlen > ( blksize+sizeof(rcvd->u.data.block) ) )
+ break; /* Too large; ignore */
+ block->data = rcvd->u.data.download;
+ block->block = ++blockidx;
+ block->len = recvlen - sizeof(rcvd->u.data.block);
+ block->eof = ( (unsigned short)block->len < blksize );
+ /* If EOF, zero blksize to indicate transfer done */
+ if ( block->eof ) blksize = 0;
+ break;
+ default: break; /* Do nothing */
+ }
+ /* Send ACK */
+ xmit.opcode = htons(TFTP_ACK);
+ xmit.u.ack.block = htons(blockidx);
+ xmitlen = TFTP_MIN_PACKET;
+ udp_transmit ( server.sin_addr.s_addr, lport, server.sin_port,
+ xmitlen, &xmit );
+ }
+ return ( block->data ? 1 : 0 );
+}
+
+/*
+ * Download a file via TFTP
+ *
+ */
+int tftp ( char *url __unused,
+ struct sockaddr_in *server,
+ char *file,
+ int ( * process ) ( unsigned char *data,
+ unsigned int blocknum,
+ unsigned int len, int eof ) ) {
+ struct tftpreq_info_t request_data = {
+ .server = server,
+ .name = file,
+ .blksize = TFTP_MAX_PACKET,
+ };
+ struct tftpreq_info_t *request = &request_data;
+ struct tftpblk_info_t block;
+ int rc;
+
+ while ( tftp_block ( request, &block ) ) {
+ request = NULL; /* Send request only once */
+ rc = process ( block.data, block.block, block.len, block.eof );
+ if ( rc <= 0 ) return ( rc );
+ }
+ return 0;
+}
+
+struct protocol tftp_protocol __default_protocol = {
+ "tftp", tftp
+};