From b570e123128f3fafa583bae186fd61429dcb49a7 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@meshlink.io>
Date: Wed, 10 Dec 2014 11:11:09 +0100
Subject: [PATCH] Handle retransmissions in CLOSE_WAIT, CLOSING and LAST_ACK
 states.

---
 utcp.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/utcp.c b/utcp.c
index f062319..e8755ed 100644
--- a/utcp.c
+++ b/utcp.c
@@ -465,11 +465,8 @@ static void retransmit(struct utcp_connection *c) {
 	pkt->hdr.dst = c->dst;
 
 	switch(c->state) {
-		case LISTEN:
-			// TODO: this should not happen
-			break;
-
 		case SYN_SENT:
+			// Send our SYN again
 			pkt->hdr.seq = c->snd.iss;
 			pkt->hdr.ack = 0;
 			pkt->hdr.wnd = c->rcv.wnd;
@@ -479,6 +476,7 @@ static void retransmit(struct utcp_connection *c) {
 			break;
 
 		case SYN_RECEIVED:
+			// Send SYNACK again
 			pkt->hdr.seq = c->snd.nxt;
 			pkt->hdr.ack = c->rcv.nxt;
 			pkt->hdr.ctl = SYN | ACK;
@@ -488,28 +486,34 @@ static void retransmit(struct utcp_connection *c) {
 
 		case ESTABLISHED:
 		case FIN_WAIT_1:
+		case CLOSE_WAIT:
+		case CLOSING:
+		case LAST_ACK:
+			// Send unacked data again.
 			pkt->hdr.seq = c->snd.una;
 			pkt->hdr.ack = c->rcv.nxt;
 			pkt->hdr.ctl = ACK;
-			uint32_t len = seqdiff(c->snd.nxt, c->snd.una);
-			if(c->state == FIN_WAIT_1)
-				len--;
+			uint32_t len = seqdiff(c->snd.last, c->snd.una);
 			if(len > utcp->mtu)
 				len = utcp->mtu;
-			else {
-				if(c->state == FIN_WAIT_1)
-					pkt->hdr.ctl |= FIN;
+			if(fin_wanted(c, c->snd.una + len)) {
+				len--;
+				pkt->hdr.ctl |= FIN;
 			}
 			buffer_copy(&c->sndbuf, pkt->data, 0, len);
 			print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len);
 			utcp->send(utcp, pkt, sizeof pkt->hdr + len);
 			break;
 
-		default:
-			// TODO: implement
+		case CLOSED:
+		case LISTEN:
+		case TIME_WAIT:
+		case FIN_WAIT_2:
+			// We shouldn't need to retransmit anything in this state.
 #ifdef UTCP_DEBUG
 			abort();
 #endif
+			timerclear(&c->rtrx_timeout);
 			break;
 	}
 
-- 
2.39.5