shithub: riscv

Download patch

ref: 9a06f93b71e339741ac6078a0246e11e789aa784
parent: 9d182f906d2d97316b151851039ffb33bb4e79e0
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Thu Sep 20 05:33:40 EDT 2012

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).

--- a/sys/src/boot/pc/pxe.c
+++ b/sys/src/boot/pc/pxe.c
@@ -249,16 +249,21 @@
 		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 @@
 	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))
--- a/sys/src/cmd/ip/tftpd.c
+++ b/sys/src/cmd/ip/tftpd.c
@@ -340,9 +340,6 @@
 	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);
--- a/sys/src/cmd/ip/tftpfs.c
+++ b/sys/src/cmd/ip/tftpfs.c
@@ -147,7 +147,7 @@
 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 @@
 
 	notify(catch);
 
+	seq = 1;
 	last = 0;
 	while(!last){
 		alarm(5000);
@@ -218,33 +219,36 @@
 			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;
 		}
--