diff --git a/mongoose.c b/mongoose.c index 55c4bf07..85d2ad38 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4836,10 +4836,16 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { uint32_t rem_ip; memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); if (pkt->tcp->flags & TH_FIN) { + uint8_t flags = TH_ACK; + if (mg_ntohl(pkt->tcp->seq) != s->ack) { + MG_VERBOSE(("ignoring FIN, SEQ != ACK: %x %x", mg_ntohl(pkt->tcp->seq), s->ack)); + tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + return; + } // If we initiated the closure, we reply with ACK upon receiving FIN // If we didn't initiate it, we reply with FIN as part of the normal TCP // closure process - uint8_t flags = TH_ACK; s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); s->fin_rcvd = true; if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { diff --git a/src/net_builtin.c b/src/net_builtin.c index f82cedf4..d6f5c72d 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -688,10 +688,16 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { uint32_t rem_ip; memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); if (pkt->tcp->flags & TH_FIN) { + uint8_t flags = TH_ACK; + if (mg_ntohl(pkt->tcp->seq) != s->ack) { + MG_VERBOSE(("ignoring FIN, SEQ != ACK: %x %x", mg_ntohl(pkt->tcp->seq), s->ack)); + tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + return; + } // If we initiated the closure, we reply with ACK upon receiving FIN // If we didn't initiate it, we reply with FIN as part of the normal TCP // closure process - uint8_t flags = TH_ACK; s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1); s->fin_rcvd = true; if (c->is_draining && s->ttype == MIP_TTYPE_FIN) { diff --git a/test/mip_test.c b/test/mip_test.c index 56f02936..32ca2d77 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -120,7 +120,7 @@ static bool if_poll(struct mg_tcpip_if *ifp, bool s1) { static size_t if_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; - if (!driver_data->len) return 0; + if (driver_data->len == 0) return 0; if (len > driver_data->len) len = driver_data->len; memcpy(buf, driver_data->buf, len); driver_data->len = 0; // cleaning up the buffer @@ -142,10 +142,10 @@ static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq, t.ack = mg_htonl(ack); t.off = 5 << 4; memcpy(s_driver_data.buf, e, sizeof(*e)); + ip->len = mg_htons((uint16_t)(sizeof(*ip) + sizeof(struct tcp) + payload_len)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(struct tcp)); - s_driver_data.len = - sizeof(*e) + sizeof(*ip) + sizeof(struct tcp) + payload_len; + memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(t)); + s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(t) + payload_len; } static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp, @@ -199,13 +199,10 @@ static void test_retransmit(void) { // setting the IP header memset(&ip, 0, sizeof(ip)); ip.ver = 4 << 4, ip.proto = 6; - ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); init_tcp_handshake(&e, &ip, t, &mgr); // packet with seq_no = 1001 - ip.len = - mg_htons(sizeof(struct ip) + sizeof(struct tcp) + /* TCP Payload */ 2); create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 2); mg_mgr_poll(&mgr, 0); while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); @@ -253,6 +250,39 @@ static void test_retransmit(void) { ASSERT((t->flags == TH_ACK)); ASSERT((t->ack == mg_htonl(1005))); // OK + // packet with seq_no = 1005 got delayed, send FIN with seq_no = 1007 + create_tcp_pkt(&e, &ip, 1007, 1, TH_FIN, 0); + mg_mgr_poll(&mgr, 0); + start = mg_millis(); + while (!received_response(&s_driver_data)) { + mg_mgr_poll(&mgr, 0); + now = mg_millis() - start; + if (now > 2 * MIP_TCP_ACK_MS) + ASSERT(0); // response should have been received by now + } + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == TH_ACK)); + ASSERT((t->ack == mg_htonl(1005))); // dup ACK + + // retransmitting packet with seq_no = 1005 + create_tcp_pkt(&e, &ip, 1005, 1, TH_PUSH | TH_ACK, 2); + mg_mgr_poll(&mgr, 0); + while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == TH_ACK)); + ASSERT((t->ack == mg_htonl(1007))); // OK + + // retransmitting FIN packet with seq_no = 1007 + create_tcp_pkt(&e, &ip, 1007, 1, TH_FIN | TH_ACK, 0); + mg_mgr_poll(&mgr, 0); + while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == (TH_FIN | TH_ACK))); // check we respond with FIN ACK + ASSERT((t->ack == mg_htonl(1008))); // OK + s_driver_data.len = 0; mg_mgr_free(&mgr); } @@ -285,12 +315,10 @@ static void test_frag_recv_path(void) { // setting the IP header memset(&ip, 0, sizeof(ip)); ip.ver = 0x45, ip.proto = 6; - ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); init_tcp_handshake(&e, &ip, t, &mgr); // send fragmented TCP packet - ip.len = mg_htons(sizeof(struct ip) + sizeof(struct tcp) + 1000); ip.frag |= IP_MORE_FRAGS_MSK; // setting More Fragments bit to 1 create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1000); s_sent_fragment = 1; // "enable" fn