|
|
@@ -816,6 +816,185 @@ START_TEST(test_tcp_rto_tracking)
|
|
|
}
|
|
|
END_TEST
|
|
|
|
|
|
+START_TEST(test_tcp_rto_timeout)
|
|
|
+{
|
|
|
+ struct netif netif;
|
|
|
+ struct test_tcp_txcounters txcounters;
|
|
|
+ struct test_tcp_counters counters;
|
|
|
+ struct tcp_pcb *pcb, *cur;
|
|
|
+ err_t err;
|
|
|
+ u16_t i;
|
|
|
+ LWIP_UNUSED_ARG(_i);
|
|
|
+
|
|
|
+ /* Setup data for a single segment */
|
|
|
+ for (i = 0; i < TCP_MSS; i++) {
|
|
|
+ tx_data[i] = (u8_t)i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* initialize local vars */
|
|
|
+ test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
|
|
|
+ memset(&counters, 0, sizeof(counters));
|
|
|
+
|
|
|
+ /* create and initialize the pcb */
|
|
|
+ tcp_ticks = SEQNO1 - ISS;
|
|
|
+ pcb = test_tcp_new_counters_pcb(&counters);
|
|
|
+ EXPECT_RET(pcb != NULL);
|
|
|
+ tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
|
|
|
+ pcb->mss = TCP_MSS;
|
|
|
+ pcb->cwnd = TCP_MSS;
|
|
|
+
|
|
|
+ /* send our segment */
|
|
|
+ err = tcp_write(pcb, &tx_data[0], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
|
|
+ EXPECT_RET(err == ERR_OK);
|
|
|
+ err = tcp_output(pcb);
|
|
|
+ EXPECT(txcounters.num_tx_calls == 1);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == 1 * (TCP_MSS + 40U));
|
|
|
+ memset(&txcounters, 0, sizeof(txcounters));
|
|
|
+
|
|
|
+ /* ensure no errors have been recorded */
|
|
|
+ EXPECT(counters.err_calls == 0);
|
|
|
+ EXPECT(counters.last_err == ERR_OK);
|
|
|
+
|
|
|
+ /* Force us into retransmisson timeout */
|
|
|
+ while (!(pcb->flags & TF_RTO)) {
|
|
|
+ test_tcp_tmr();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check first rexmit */
|
|
|
+ EXPECT(pcb->nrtx == 1);
|
|
|
+ EXPECT(txcounters.num_tx_calls == 1);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == 1 * (TCP_MSS + 40U));
|
|
|
+
|
|
|
+ /* still no error expected */
|
|
|
+ EXPECT(counters.err_calls == 0);
|
|
|
+ EXPECT(counters.last_err == ERR_OK);
|
|
|
+
|
|
|
+ /* keep running the timer till we hit our maximum RTO */
|
|
|
+ while (counters.last_err == ERR_OK) {
|
|
|
+ test_tcp_tmr();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check number of retransmissions */
|
|
|
+ EXPECT(txcounters.num_tx_calls == TCP_MAXRTX);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == TCP_MAXRTX * (TCP_MSS + 40U));
|
|
|
+
|
|
|
+ /* check the connection (pcb) has been aborted */
|
|
|
+ EXPECT(counters.err_calls == 1);
|
|
|
+ EXPECT(counters.last_err == ERR_ABRT);
|
|
|
+ /* check our pcb is no longer active */
|
|
|
+ for (cur = tcp_active_pcbs; cur != NULL; cur = cur->next) {
|
|
|
+ EXPECT(cur != pcb);
|
|
|
+ }
|
|
|
+ EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
|
|
|
+}
|
|
|
+END_TEST
|
|
|
+
|
|
|
+START_TEST(test_tcp_zwp_timeout)
|
|
|
+{
|
|
|
+ struct netif netif;
|
|
|
+ struct test_tcp_txcounters txcounters;
|
|
|
+ struct test_tcp_counters counters;
|
|
|
+ struct tcp_pcb *pcb, *cur;
|
|
|
+ struct pbuf* p;
|
|
|
+ err_t err;
|
|
|
+ u16_t i;
|
|
|
+ LWIP_UNUSED_ARG(_i);
|
|
|
+
|
|
|
+ /* Setup data for two segments */
|
|
|
+ for (i = 0; i < 2*TCP_MSS; i++) {
|
|
|
+ tx_data[i] = (u8_t)i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* initialize local vars */
|
|
|
+ test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask);
|
|
|
+ memset(&counters, 0, sizeof(counters));
|
|
|
+
|
|
|
+ /* create and initialize the pcb */
|
|
|
+ tcp_ticks = SEQNO1 - ISS;
|
|
|
+ pcb = test_tcp_new_counters_pcb(&counters);
|
|
|
+ EXPECT_RET(pcb != NULL);
|
|
|
+ tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT);
|
|
|
+ pcb->mss = TCP_MSS;
|
|
|
+ pcb->cwnd = TCP_MSS;
|
|
|
+
|
|
|
+ /* send first segment */
|
|
|
+ err = tcp_write(pcb, &tx_data[0], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
|
|
+ EXPECT(err == ERR_OK);
|
|
|
+ err = tcp_output(pcb);
|
|
|
+ EXPECT(err == ERR_OK);
|
|
|
+
|
|
|
+ /* verify segment is in-flight */
|
|
|
+ EXPECT(pcb->unsent == NULL);
|
|
|
+ check_seqnos(pcb->unacked, 1, seqnos);
|
|
|
+ EXPECT(txcounters.num_tx_calls == 1);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == 1 * (TCP_MSS + 40U));
|
|
|
+ memset(&txcounters, 0, sizeof(txcounters));
|
|
|
+
|
|
|
+ /* ACK the segment and close the TX window */
|
|
|
+ p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK, 0);
|
|
|
+ test_tcp_input(p, &netif);
|
|
|
+ EXPECT(pcb->unacked == NULL);
|
|
|
+ EXPECT(pcb->unsent == NULL);
|
|
|
+ EXPECT(pcb->persist_backoff == 1);
|
|
|
+ EXPECT(pcb->snd_wnd == 0);
|
|
|
+
|
|
|
+ /* send second segment, should be buffered */
|
|
|
+ err = tcp_write(pcb, &tx_data[TCP_MSS], TCP_MSS, TCP_WRITE_FLAG_COPY);
|
|
|
+ EXPECT(err == ERR_OK);
|
|
|
+ err = tcp_output(pcb);
|
|
|
+ EXPECT(err == ERR_OK);
|
|
|
+
|
|
|
+ /* ensure it is buffered */
|
|
|
+ EXPECT(pcb->unacked == NULL);
|
|
|
+ check_seqnos(pcb->unsent, 1, &seqnos[1]);
|
|
|
+ EXPECT(txcounters.num_tx_calls == 0);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == 0);
|
|
|
+
|
|
|
+ /* ensure no errors have been recorded */
|
|
|
+ EXPECT(counters.err_calls == 0);
|
|
|
+ EXPECT(counters.last_err == ERR_OK);
|
|
|
+
|
|
|
+ /* run timer till first probe */
|
|
|
+ EXPECT(pcb->persist_probe == 0);
|
|
|
+ while (pcb->persist_probe == 0) {
|
|
|
+ test_tcp_tmr();
|
|
|
+ }
|
|
|
+ EXPECT(txcounters.num_tx_calls == 1);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == (1 + 40U));
|
|
|
+ memset(&txcounters, 0, sizeof(txcounters));
|
|
|
+
|
|
|
+ /* respond to probe with remote's current SEQ, ACK, and zero-window */
|
|
|
+ p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, 0, TCP_ACK, 0);
|
|
|
+ test_tcp_input(p, &netif);
|
|
|
+ /* ensure zero-window is still active, but probe count reset */
|
|
|
+ EXPECT(pcb->persist_backoff > 1);
|
|
|
+ EXPECT(pcb->persist_probe == 0);
|
|
|
+ EXPECT(pcb->snd_wnd == 0);
|
|
|
+
|
|
|
+ /* ensure no errors have been recorded */
|
|
|
+ EXPECT(counters.err_calls == 0);
|
|
|
+ EXPECT(counters.last_err == ERR_OK);
|
|
|
+
|
|
|
+ /* now run the timer till we hit our maximum probe count */
|
|
|
+ while (counters.last_err == ERR_OK) {
|
|
|
+ test_tcp_tmr();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check maximum number of 1 byte probes were sent */
|
|
|
+ EXPECT(txcounters.num_tx_calls == TCP_MAXRTX);
|
|
|
+ EXPECT(txcounters.num_tx_bytes == TCP_MAXRTX * (1 + 40U));
|
|
|
+
|
|
|
+ /* check the connection (pcb) has been aborted */
|
|
|
+ EXPECT(counters.err_calls == 1);
|
|
|
+ EXPECT(counters.last_err == ERR_ABRT);
|
|
|
+ /* check our pcb is no longer active */
|
|
|
+ for (cur = tcp_active_pcbs; cur != NULL; cur = cur->next) {
|
|
|
+ EXPECT(cur != pcb);
|
|
|
+ }
|
|
|
+ EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
|
|
|
+}
|
|
|
+END_TEST
|
|
|
+
|
|
|
/** Create the suite including all tests for this module */
|
|
|
Suite *
|
|
|
tcp_suite(void)
|
|
|
@@ -829,7 +1008,9 @@ tcp_suite(void)
|
|
|
TESTFUNC(test_tcp_rto_rexmit_wraparound),
|
|
|
TESTFUNC(test_tcp_tx_full_window_lost_from_unacked),
|
|
|
TESTFUNC(test_tcp_tx_full_window_lost_from_unsent),
|
|
|
- TESTFUNC(test_tcp_rto_tracking)
|
|
|
+ TESTFUNC(test_tcp_rto_tracking),
|
|
|
+ TESTFUNC(test_tcp_rto_timeout),
|
|
|
+ TESTFUNC(test_tcp_zwp_timeout)
|
|
|
};
|
|
|
return create_suite("TCP", tests, sizeof(tests)/sizeof(testfunc), tcp_setup, tcp_teardown);
|
|
|
}
|