From 9a06f93b71e339741ac6078a0246e11e789aa784 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 20 Sep 2012 09:33:40 +0200 Subject: [PATCH] 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). --- sys/src/boot/pc/pxe.c | 15 ++++++++---- sys/src/cmd/ip/tftpd.c | 3 --- sys/src/cmd/ip/tftpfs.c | 52 ++++++++++++++++++++++------------------- 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; } }