diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-09-20 09:33:40 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-09-20 09:33:40 +0200 |
commit | 9a06f93b71e339741ac6078a0246e11e789aa784 (patch) | |
tree | 48312aa7a5c42c174f1c6b94f7bcd6e9a83d15d3 | |
parent | 9d182f906d2d97316b151851039ffb33bb4e79e0 (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.c | 15 | ||||
-rw-r--r-- | sys/src/cmd/ip/tftpd.c | 3 | ||||
-rw-r--r-- | 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; } } |