summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-09-20 09:33:40 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-09-20 09:33:40 +0200
commit9a06f93b71e339741ac6078a0246e11e789aa784 (patch)
tree48312aa7a5c42c174f1c6b94f7bcd6e9a83d15d3
parent9d182f906d2d97316b151851039ffb33bb4e79e0 (diff)
tftp: prevent it from hanging if ack packets get lost
send ACK reply for duplicate data packets in case our ack response got lost. make sure packets are in sequence and ignore out of oder packets (except the ones we'v already acked).
-rw-r--r--sys/src/boot/pc/pxe.c15
-rw-r--r--sys/src/cmd/ip/tftpd.c3
-rw-r--r--sys/src/cmd/ip/tftpfs.c52
3 files changed, 38 insertions, 32 deletions
diff --git a/sys/src/boot/pc/pxe.c b/sys/src/boot/pc/pxe.c
index 97ee259cb..9f6d74b29 100644
--- a/sys/src/boot/pc/pxe.c
+++ b/sys/src/boot/pc/pxe.c
@@ -249,16 +249,21 @@ read(void *f, void *data, int len)
switch(nhgets(t->pkt)){
case Tftp_DATA:
seq = nhgets(t->pkt+2);
- if(seq <= t->seq){
- putc('@');
+ if(seq > t->seq){
+ putc('?');
continue;
}
hnputs(t->pkt, Tftp_ACK);
while(udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt))
putc('!');
- t->seq = seq;
+ if(seq < t->seq){
+ putc('@');
+ continue;
+ }
+ t->seq = seq+1;
+ n -= 4;
t->rp = t->pkt + 4;
- t->ep = t->pkt + n;
+ t->ep = t->rp + n;
t->eof = n < Segsize;
break;
case Tftp_ERROR:
@@ -300,7 +305,7 @@ tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip)
t->sport = xport++;
t->dport = 0;
t->rp = t->ep = 0;
- t->seq = -1;
+ t->seq = 1;
t->eof = 0;
t->nul = 0;
if(r = udpopen(t->sip))
diff --git a/sys/src/cmd/ip/tftpd.c b/sys/src/cmd/ip/tftpd.c
index 9b543a29e..355e98340 100644
--- a/sys/src/cmd/ip/tftpd.c
+++ b/sys/src/cmd/ip/tftpd.c
@@ -340,9 +340,6 @@ options(int fd, char *buf, int bufsz, char *file, ushort oper, char *p, int dlen
if (nopts == 0)
return 0; /* no options actually seen */
- if (bp + 3 >= ep)
- return -1;
-
if (write(fd, buf, bp - buf) < bp - buf) {
syslog(dbg, flog, "tftpd network write error on oack to %s: %r",
raddr);
diff --git a/sys/src/cmd/ip/tftpfs.c b/sys/src/cmd/ip/tftpfs.c
index 2e48d6cb4..55d8f496d 100644
--- a/sys/src/cmd/ip/tftpfs.c
+++ b/sys/src/cmd/ip/tftpfs.c
@@ -147,7 +147,7 @@ filereq(uchar *buf, char *path)
static void
download(void *aux)
{
- int fd, cfd, last, block, n, ndata;
+ int fd, cfd, last, block, seq, n, ndata;
char *err, adir[40];
uchar *data;
Channel *c;
@@ -197,6 +197,7 @@ download(void *aux)
notify(catch);
+ seq = 1;
last = 0;
while(!last){
alarm(5000);
@@ -218,34 +219,37 @@ download(void *aux)
if(n < 4)
continue;
block = nhgets(msg.buf+2);
- if((n -= 4) > 0){
- data = erealloc9p(data, ndata + n);
- memcpy(data + ndata, msg.buf+4, n);
- ndata += n;
-
-rloop: /* hanlde read request while downloading */
- if((r != nil) && (r->ifcall.type == Tread) && (r->ifcall.offset < ndata)){
- readbuf(r, data, ndata);
- respond(r, nil);
- r = nil;
- }
- if((r == nil) && (nbrecv(c, &r) == 1)){
- if(r == nil){
- chanfree(c);
- c = nil;
- goto out;
- }
- goto rloop;
- }
- }
- if(n < Segsize)
- last = 1;
+ if(block > seq)
+ continue;
hnputs(msg.buf, Tftp_ACK);
- hnputs(msg.buf+2, block);
if(write(fd, &msg, sizeof(Udphdr) + 4) < 0){
err = "send acknowledge: %r";
goto out;
}
+ if(block < seq)
+ continue;
+ seq = block+1;
+ n -= 4;
+ if(n < Segsize)
+ last = 1;
+ data = erealloc9p(data, ndata + n);
+ memcpy(data + ndata, msg.buf+4, n);
+ ndata += n;
+
+ rloop: /* hanlde read request while downloading */
+ if((r != nil) && (r->ifcall.type == Tread) && (r->ifcall.offset < ndata)){
+ readbuf(r, data, ndata);
+ respond(r, nil);
+ r = nil;
+ }
+ if((r == nil) && (nbrecv(c, &r) == 1)){
+ if(r == nil){
+ chanfree(c);
+ c = nil;
+ goto out;
+ }
+ goto rloop;
+ }
break;
}
}