aboutsummaryrefslogtreecommitdiffstats
path: root/com32/sysdump/be_tftp.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-02-07 15:14:21 -0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-07 15:14:21 -0800
commit88f5f9b480f036ef9da9cf9deb41935c9ad9743c (patch)
treed4aae48e5a3f2b8d618ca5675c87f852d744ac46 /com32/sysdump/be_tftp.c
parent257adb86a34db443100d9e18891ce98f2518333f (diff)
downloadsyslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.tar.gz
syslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.tar.xz
syslinux.git-88f5f9b480f036ef9da9cf9deb41935c9ad9743c.zip
sysdump: change to a two-phase generate/output model, buffer in memory
Instead of outputting data as it is generated, buffer it all in memory and then output it all at once. This not only gives us exact size and so on before we start, but turns out to be faster at least for TFTP. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'com32/sysdump/be_tftp.c')
-rw-r--r--com32/sysdump/be_tftp.c82
1 files changed, 46 insertions, 36 deletions
diff --git a/com32/sysdump/be_tftp.c b/com32/sysdump/be_tftp.c
index e9a98873..79642385 100644
--- a/com32/sysdump/be_tftp.c
+++ b/com32/sysdump/be_tftp.c
@@ -18,9 +18,16 @@ enum tftp_opcode {
TFTP_ERROR = 5,
};
-static uint16_t local_port = 0x4000;
+struct tftp_state {
+ uint32_t my_ip;
+ uint32_t srv_ip;
+ uint16_t my_port;
+ uint16_t srv_port;
+ uint16_t seq;
+};
-static int send_ack_packet(struct backend *be, const void *pkt, size_t len)
+static int send_ack_packet(struct tftp_state *tftp,
+ const void *pkt, size_t len)
{
com32sys_t ireg, oreg;
t_PXENV_UDP_WRITE *uw = __com32.cs_bounce;
@@ -38,9 +45,9 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len)
for (timeout = timeouts ; *timeout ; timeout++) {
memset(uw, 0, sizeof uw);
memcpy(uw+1, pkt, len);
- uw->ip = be->tftp.srv_ip;
- uw->src_port = be->tftp.my_port;
- uw->dst_port = be->tftp.srv_port ? be->tftp.srv_port : htons(69);
+ uw->ip = tftp->srv_ip;
+ uw->src_port = tftp->my_port;
+ uw->dst_port = tftp->srv_port ? tftp->srv_port : htons(69);
uw->buffer_size = len;
uw->buffer = FAR_PTR(uw+1);
@@ -54,10 +61,10 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len)
do {
memset(ur, 0, sizeof ur);
- ur->src_ip = be->tftp.srv_ip;
- ur->dest_ip = be->tftp.my_ip;
- ur->s_port = be->tftp.srv_port;
- ur->d_port = be->tftp.my_port;
+ ur->src_ip = tftp->srv_ip;
+ ur->dest_ip = tftp->my_ip;
+ ur->s_port = tftp->srv_port;
+ ur->d_port = tftp->my_port;
ur->buffer_size = __com32.cs_bounce_size - sizeof *ur;
ur->buffer = FAR_PTR(ur+1);
@@ -68,13 +75,13 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len)
if (!(oreg.eflags.l & EFLAGS_CF) &&
ur->status == PXENV_STATUS_SUCCESS &&
- be->tftp.srv_ip == ur->src_ip &&
- (be->tftp.srv_port == 0 ||
- be->tftp.srv_port == ur->s_port)) {
+ tftp->srv_ip == ur->src_ip &&
+ (tftp->srv_port == 0 ||
+ tftp->srv_port == ur->s_port)) {
uint16_t *xb = (uint16_t *)(ur+1);
if (ntohs(xb[0]) == TFTP_ACK &&
- ntohs(xb[1]) == be->tftp.seq) {
- be->tftp.srv_port = ur->s_port;
+ ntohs(xb[1]) == tftp->seq) {
+ tftp->srv_port = ur->s_port;
return 0; /* All good! */
} else if (ntohs(xb[1]) == TFTP_ERROR) {
return -1; /* All bad! */
@@ -86,47 +93,50 @@ static int send_ack_packet(struct backend *be, const void *pkt, size_t len)
return -1; /* No success... */
}
-static int be_tftp_open(struct backend *be, const char *argv[], size_t len)
+static int be_tftp_write(struct backend *be)
{
+ static uint16_t local_port = 0x4000;
+ struct tftp_state tftp;
char buffer[512+4+6];
int nlen;
const union syslinux_derivative_info *sdi =
syslinux_derivative_info();
+ const char *data = be->outbuf;
+ size_t len = be->zbytes;
+ size_t chunk;
- (void)len;
-
- be->tftp.my_ip = sdi->pxe.myip;
- be->tftp.my_port = htons(local_port++);
- be->tftp.srv_ip = pxe_dns(argv[1]);
- be->tftp.srv_port = 0;
- be->tftp.seq = 0;
+ tftp.my_ip = sdi->pxe.myip;
+ tftp.my_port = htons(local_port++);
+ tftp.srv_ip = pxe_dns(be->argv[1]);
+ tftp.srv_port = 0;
+ tftp.seq = 0;
buffer[0] = 0;
buffer[1] = TFTP_WRQ;
- nlen = strlcpy(buffer+2, argv[0], 512);
+ nlen = strlcpy(buffer+2, be->argv[0], 512);
memcpy(buffer+3+nlen, "octet", 6);
- return send_ack_packet(be, buffer, 2+nlen+1+6);
-}
+ if (send_ack_packet(&tftp, buffer, 2+nlen+1+6))
+ return -1;
-static int be_tftp_write(struct backend *be, const char *buf, size_t len)
-{
- char buffer[512+4];
+ do {
+ chunk = len >= 512 ? 512 : len;
- buffer[0] = 0;
- buffer[1] = TFTP_DATA;
- *((uint16_t *)(buffer+2)) = htons(++be->tftp.seq);
- memcpy(buffer+4, buf, len);
+ buffer[1] = TFTP_DATA;
+ *((uint16_t *)(buffer+2)) = htons(++tftp.seq);
+ memcpy(buffer+4, data, chunk);
+ data += chunk;
+
+ if (send_ack_packet(&tftp, buffer, chunk+4))
+ return -1;
+ } while (chunk == 512);
- return send_ack_packet(be, buffer, len+4);
+ return 0;
}
struct backend be_tftp = {
.name = "tftp",
.helpmsg = "filename tftp_server",
.minargs = 2,
- .blocksize = 512,
- .flags = 0,
- .open = be_tftp_open,
.write = be_tftp_write,
};