ReactOS 0.4.15-dev-7842-g558ab78
test_tcp.c File Reference
#include "test_tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/stats.h"
#include "tcp_helper.h"
Include dependency graph for test_tcp.c:

Go to the source code of this file.

Macros

#define SEQNO1   (0xFFFFFF00 - TCP_MSS)
 
#define ISS   6510
 
#define SEQNO1   (0xFFFFFF00 - TCP_MSS)
 
#define ISS   6510
 

Functions

static void test_tcp_tmr (void)
 
static void tcp_setup (void)
 
static void tcp_teardown (void)
 
 START_TEST (test_tcp_new_abort)
 
END_TEST START_TEST (test_tcp_recv_inseq)
 
END_TEST START_TEST (test_tcp_fast_retx_recover)
 
static void check_seqnos (struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected)
 
 START_TEST (test_tcp_fast_rexmit_wraparound)
 
END_TEST START_TEST (test_tcp_rto_rexmit_wraparound)
 
static END_TEST void test_tcp_tx_full_window_lost (u8_t zero_window_probe_from_unsent)
 
 START_TEST (test_tcp_tx_full_window_lost_from_unsent)
 
END_TEST START_TEST (test_tcp_tx_full_window_lost_from_unacked)
 
END_TEST Suite * tcp_suite (void)
 

Variables

static u8_t test_tcp_timer
 
static END_TEST u8_t tx_data [TCP_WND *2]
 

Macro Definition Documentation

◆ ISS [1/2]

#define ISS   6510

◆ ISS [2/2]

#define ISS   6510

◆ SEQNO1 [1/2]

#define SEQNO1   (0xFFFFFF00 - TCP_MSS)

◆ SEQNO1 [2/2]

#define SEQNO1   (0xFFFFFF00 - TCP_MSS)

Function Documentation

◆ check_seqnos()

static void check_seqnos ( struct tcp_seg *  segs,
int  num_expected,
u32_t seqnos_expected 
)
static

Definition at line 296 of file test_tcp.c.

297{
298 struct tcp_seg *s = segs;
299 int i;
300 for (i = 0; i < num_expected; i++, s = s->next) {
301 EXPECT_RET(s != NULL);
302 EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i]));
303 }
304 EXPECT(s == NULL);
305}
#define NULL
Definition: types.h:112
GLdouble s
Definition: gl.h:2039
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define EXPECT(x)
Definition: lwip_check.h:11
#define EXPECT_RET(x)
Definition: lwip_check.h:12
#define htonl(x)
Definition: module.h:214

Referenced by START_TEST().

◆ START_TEST() [1/7]

END_TEST START_TEST ( test_tcp_fast_retx_recover  )

Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. At the end, send more data.

Definition at line 123 of file test_tcp.c.

124{
125 struct netif netif;
126 struct test_tcp_txcounters txcounters;
128 struct tcp_pcb* pcb;
129 struct pbuf* p;
130 char data1[] = { 1, 2, 3, 4};
131 char data2[] = { 5, 6, 7, 8};
132 char data3[] = { 9, 10, 11, 12};
133 char data4[] = {13, 14, 15, 16};
134 char data5[] = {17, 18, 19, 20};
135 char data6[] = {21, 22, 23, 24};
136 ip_addr_t remote_ip, local_ip, netmask;
137 u16_t remote_port = 0x100, local_port = 0x101;
138 err_t err;
139 LWIP_UNUSED_ARG(_i);
140
141 /* initialize local vars */
142 IP4_ADDR(&local_ip, 192, 168, 1, 1);
143 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
144 IP4_ADDR(&netmask, 255, 255, 255, 0);
145 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
146 memset(&counters, 0, sizeof(counters));
147
148 /* create and initialize the pcb */
150 EXPECT_RET(pcb != NULL);
151 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
152 pcb->mss = TCP_MSS;
153 /* disable initial congestion window (we don't send a SYN here...) */
154 pcb->cwnd = pcb->snd_wnd;
155
156 /* send data1 */
157 err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY);
159 err = tcp_output(pcb);
161 EXPECT_RET(txcounters.num_tx_calls == 1);
162 EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
163 memset(&txcounters, 0, sizeof(txcounters));
164 /* "recv" ACK for data1 */
165 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK);
166 EXPECT_RET(p != NULL);
168 EXPECT_RET(txcounters.num_tx_calls == 0);
169 EXPECT_RET(pcb->unacked == NULL);
170 /* send data2 */
171 err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY);
173 err = tcp_output(pcb);
175 EXPECT_RET(txcounters.num_tx_calls == 1);
176 EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
177 memset(&txcounters, 0, sizeof(txcounters));
178 /* duplicate ACK for data1 (data2 is lost) */
179 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
180 EXPECT_RET(p != NULL);
182 EXPECT_RET(txcounters.num_tx_calls == 0);
183 EXPECT_RET(pcb->dupacks == 1);
184 /* send data3 */
185 err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY);
187 err = tcp_output(pcb);
189 /* nagle enabled, no tx calls */
190 EXPECT_RET(txcounters.num_tx_calls == 0);
191 EXPECT_RET(txcounters.num_tx_bytes == 0);
192 memset(&txcounters, 0, sizeof(txcounters));
193 /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */
194 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
195 EXPECT_RET(p != NULL);
197 EXPECT_RET(txcounters.num_tx_calls == 0);
198 EXPECT_RET(pcb->dupacks == 2);
199 /* queue data4, don't send it (unsent-oversize is != 0) */
200 err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY);
202 /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */
203 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
204 EXPECT_RET(p != NULL);
206 /*EXPECT_RET(txcounters.num_tx_calls == 1);*/
207 EXPECT_RET(pcb->dupacks == 3);
208 memset(&txcounters, 0, sizeof(txcounters));
209 /* TODO: check expected data?*/
210
211 /* send data5, not output yet */
212 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
214 /*err = tcp_output(pcb);
215 EXPECT_RET(err == ERR_OK);*/
216 EXPECT_RET(txcounters.num_tx_calls == 0);
217 EXPECT_RET(txcounters.num_tx_bytes == 0);
218 memset(&txcounters, 0, sizeof(txcounters));
219 {
220 int i = 0;
221 do
222 {
223 err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY);
224 i++;
225 }while(err == ERR_OK);
227 }
228 err = tcp_output(pcb);
230 /*EXPECT_RET(txcounters.num_tx_calls == 0);
231 EXPECT_RET(txcounters.num_tx_bytes == 0);*/
232 memset(&txcounters, 0, sizeof(txcounters));
233
234 /* send even more data */
235 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
237 err = tcp_output(pcb);
239 /* ...and even more data */
240 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
242 err = tcp_output(pcb);
244 /* ...and even more data */
245 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
247 err = tcp_output(pcb);
249 /* ...and even more data */
250 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
252 err = tcp_output(pcb);
254
255 /* send ACKs for data2 and data3 */
256 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK);
257 EXPECT_RET(p != NULL);
259 /*EXPECT_RET(txcounters.num_tx_calls == 0);*/
260
261 /* ...and even more data */
262 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
264 err = tcp_output(pcb);
266 /* ...and even more data */
267 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
269 err = tcp_output(pcb);
271
272#if 0
273 /* create expected segment */
274 p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
275 EXPECT_RET(p != NULL);
276 if (p != NULL) {
277 /* pass the segment to tcp_input */
279 /* check if counters are as expected */
280 EXPECT_RET(counters.close_calls == 0);
281 EXPECT_RET(counters.recv_calls == 1);
282 EXPECT_RET(counters.recved_bytes == data_len);
283 EXPECT_RET(counters.err_calls == 0);
284 }
285#endif
286 /* make sure the pcb is freed */
287 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
288 tcp_abort(pcb);
289 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
290}
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:73
static const char data4[]
Definition: db.c:2904
static const WCHAR data3[]
Definition: db.c:2900
static const WCHAR data5[]
Definition: db.c:2906
static const WCHAR data6[]
Definition: db.c:2924
unsigned short u16_t
Definition: cc.h:24
#define ERR_OK
Definition: err.h:52
s8_t err_t
Definition: err.h:47
GLint GLint GLsizei GLuint * counters
Definition: glext.h:11114
GLfloat GLfloat p
Definition: glext.h:8902
#define TCP_MSS
Definition: lwipopts.h:65
#define IP4_ADDR(ipaddr, a, b, c, d)
Definition: ip_addr.h:139
typedefPACK_STRUCT_END struct ip_addr ip_addr_t
Definition: ip_addr.h:64
#define err(...)
#define memset(x, y, z)
Definition: compat.h:39
Definition: tftpd.h:126
Definition: tftpd.h:138
Definition: ip.h:116
Definition: netif.h:136
Definition: pbuf.h:79
void test_tcp_input(struct pbuf *p, struct netif *inp)
Definition: tcp_helper.c:238
struct pbuf * tcp_create_rx_segment(struct tcp_pcb *pcb, void *data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags)
Definition: tcp_helper.c:118
struct tcp_pcb * test_tcp_new_counters_pcb(struct test_tcp_counters *counters)
Definition: tcp_helper.c:223
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, ip_addr_t *ip_addr, ip_addr_t *netmask)
Definition: tcp_helper.c:276
static __inline void tcp_set_state(struct sock *sk, int state)
Definition: tcpcore.h:3256

◆ START_TEST() [2/7]

START_TEST ( test_tcp_fast_rexmit_wraparound  )

Send data with sequence numbers that wrap around the u32_t range. Then, provoke fast retransmission by duplicate ACKs and check that all segment lists are still properly sorted.

Definition at line 310 of file test_tcp.c.

311{
312 struct netif netif;
313 struct test_tcp_txcounters txcounters;
315 struct tcp_pcb* pcb;
316 struct pbuf* p;
317 ip_addr_t remote_ip, local_ip, netmask;
318 u16_t remote_port = 0x100, local_port = 0x101;
319 err_t err;
320#define SEQNO1 (0xFFFFFF00 - TCP_MSS)
321#define ISS 6510
322 u16_t i, sent_total = 0;
323 u32_t seqnos[] = {
324 SEQNO1,
325 SEQNO1 + (1 * TCP_MSS),
326 SEQNO1 + (2 * TCP_MSS),
327 SEQNO1 + (3 * TCP_MSS),
328 SEQNO1 + (4 * TCP_MSS),
329 SEQNO1 + (5 * TCP_MSS)};
330 LWIP_UNUSED_ARG(_i);
331
332 for (i = 0; i < sizeof(tx_data); i++) {
333 tx_data[i] = (u8_t)i;
334 }
335
336 /* initialize local vars */
337 IP4_ADDR(&local_ip, 192, 168, 1, 1);
338 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
339 IP4_ADDR(&netmask, 255, 255, 255, 0);
340 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
341 memset(&counters, 0, sizeof(counters));
342
343 /* create and initialize the pcb */
344 tcp_ticks = SEQNO1 - ISS;
346 EXPECT_RET(pcb != NULL);
347 EXPECT(pcb->lastack == SEQNO1);
348 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
349 pcb->mss = TCP_MSS;
350 /* disable initial congestion window (we don't send a SYN here...) */
351 pcb->cwnd = 2*TCP_MSS;
352
353 /* send 6 mss-sized segments */
354 for (i = 0; i < 6; i++) {
355 err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
357 sent_total += TCP_MSS;
358 }
359 check_seqnos(pcb->unsent, 6, seqnos);
360 EXPECT(pcb->unacked == NULL);
361 err = tcp_output(pcb);
362 EXPECT(txcounters.num_tx_calls == 2);
363 EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
364 memset(&txcounters, 0, sizeof(txcounters));
365
366 check_seqnos(pcb->unacked, 2, seqnos);
367 check_seqnos(pcb->unsent, 4, &seqnos[2]);
368
369 /* ACK the first segment */
370 p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK);
372 /* ensure this didn't trigger a retransmission */
373 EXPECT(txcounters.num_tx_calls == 1);
374 EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
375 memset(&txcounters, 0, sizeof(txcounters));
376 check_seqnos(pcb->unacked, 2, &seqnos[1]);
377 check_seqnos(pcb->unsent, 3, &seqnos[3]);
378
379 /* 3 dupacks */
380 EXPECT(pcb->dupacks == 0);
381 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
383 EXPECT(txcounters.num_tx_calls == 0);
384 EXPECT(pcb->dupacks == 1);
385 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
387 EXPECT(txcounters.num_tx_calls == 0);
388 EXPECT(pcb->dupacks == 2);
389 /* 3rd dupack -> fast rexmit */
390 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
392 EXPECT(pcb->dupacks == 3);
393 EXPECT(txcounters.num_tx_calls == 4);
394 memset(&txcounters, 0, sizeof(txcounters));
395 EXPECT(pcb->unsent == NULL);
396 check_seqnos(pcb->unacked, 5, &seqnos[1]);
397
398 /* make sure the pcb is freed */
399 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
400 tcp_abort(pcb);
401 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
402}
unsigned long u32_t
Definition: cc.h:25
unsigned char u8_t
Definition: cc.h:23
static END_TEST u8_t tx_data[TCP_WND *2]
Definition: test_tcp.c:293
static void check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected)
Definition: test_tcp.c:296
#define SEQNO1
#define ISS

◆ START_TEST() [3/7]

START_TEST ( test_tcp_new_abort  )

Call tcp_new() and tcp_abort() and test memp stats

Definition at line 56 of file test_tcp.c.

57{
58 struct tcp_pcb* pcb;
60
61 fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
62
63 pcb = tcp_new();
64 fail_unless(pcb != NULL);
65 if (pcb != NULL) {
66 fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
67 tcp_abort(pcb);
68 fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
69 }
70}

◆ START_TEST() [4/7]

END_TEST START_TEST ( test_tcp_recv_inseq  )

Create an ESTABLISHED pcb and check if receive callback is called

Definition at line 74 of file test_tcp.c.

75{
77 struct tcp_pcb* pcb;
78 struct pbuf* p;
79 char data[] = {1, 2, 3, 4};
80 ip_addr_t remote_ip, local_ip;
81 u16_t data_len;
82 u16_t remote_port = 0x100, local_port = 0x101;
83 struct netif netif;
85
86 /* initialize local vars */
87 memset(&netif, 0, sizeof(netif));
88 IP4_ADDR(&local_ip, 192, 168, 1, 1);
89 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
90 data_len = sizeof(data);
91 /* initialize counter struct */
92 memset(&counters, 0, sizeof(counters));
93 counters.expected_data_len = data_len;
94 counters.expected_data = data;
95
96 /* create and initialize the pcb */
98 EXPECT_RET(pcb != NULL);
99 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
100
101 /* create a segment */
102 p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
103 EXPECT(p != NULL);
104 if (p != NULL) {
105 /* pass the segment to tcp_input */
107 /* check if counters are as expected */
108 EXPECT(counters.close_calls == 0);
109 EXPECT(counters.recv_calls == 1);
110 EXPECT(counters.recved_bytes == data_len);
111 EXPECT(counters.err_calls == 0);
112 }
113
114 /* make sure the pcb is freed */
115 EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
116 tcp_abort(pcb);
117 EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
118}
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950

◆ START_TEST() [5/7]

END_TEST START_TEST ( test_tcp_rto_rexmit_wraparound  )

Send data with sequence numbers that wrap around the u32_t range. Then, provoke RTO retransmission and check that all segment lists are still properly sorted.

Definition at line 408 of file test_tcp.c.

409{
410 struct netif netif;
411 struct test_tcp_txcounters txcounters;
413 struct tcp_pcb* pcb;
414 ip_addr_t remote_ip, local_ip, netmask;
415 u16_t remote_port = 0x100, local_port = 0x101;
416 err_t err;
417#define SEQNO1 (0xFFFFFF00 - TCP_MSS)
418#define ISS 6510
419 u16_t i, sent_total = 0;
420 u32_t seqnos[] = {
421 SEQNO1,
422 SEQNO1 + (1 * TCP_MSS),
423 SEQNO1 + (2 * TCP_MSS),
424 SEQNO1 + (3 * TCP_MSS),
425 SEQNO1 + (4 * TCP_MSS),
426 SEQNO1 + (5 * TCP_MSS)};
427 LWIP_UNUSED_ARG(_i);
428
429 for (i = 0; i < sizeof(tx_data); i++) {
430 tx_data[i] = (u8_t)i;
431 }
432
433 /* initialize local vars */
434 IP4_ADDR(&local_ip, 192, 168, 1, 1);
435 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
436 IP4_ADDR(&netmask, 255, 255, 255, 0);
437 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
438 memset(&counters, 0, sizeof(counters));
439
440 /* create and initialize the pcb */
441 tcp_ticks = 0;
442 tcp_ticks = 0 - tcp_next_iss();
443 tcp_ticks = SEQNO1 - tcp_next_iss();
445 EXPECT_RET(pcb != NULL);
446 EXPECT(pcb->lastack == SEQNO1);
447 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
448 pcb->mss = TCP_MSS;
449 /* disable initial congestion window (we don't send a SYN here...) */
450 pcb->cwnd = 2*TCP_MSS;
451
452 /* send 6 mss-sized segments */
453 for (i = 0; i < 6; i++) {
454 err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
456 sent_total += TCP_MSS;
457 }
458 check_seqnos(pcb->unsent, 6, seqnos);
459 EXPECT(pcb->unacked == NULL);
460 err = tcp_output(pcb);
461 EXPECT(txcounters.num_tx_calls == 2);
462 EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U));
463 memset(&txcounters, 0, sizeof(txcounters));
464
465 check_seqnos(pcb->unacked, 2, seqnos);
466 check_seqnos(pcb->unsent, 4, &seqnos[2]);
467
468 /* call the tcp timer some times */
469 for (i = 0; i < 10; i++) {
470 test_tcp_tmr();
471 EXPECT(txcounters.num_tx_calls == 0);
472 }
473 /* 11th call to tcp_tmr: RTO rexmit fires */
474 test_tcp_tmr();
475 EXPECT(txcounters.num_tx_calls == 1);
476 check_seqnos(pcb->unacked, 1, seqnos);
477 check_seqnos(pcb->unsent, 5, &seqnos[1]);
478
479 /* fake greater cwnd */
480 pcb->cwnd = pcb->snd_wnd;
481 /* send more data */
482 err = tcp_output(pcb);
483 EXPECT(err == ERR_OK);
484 /* check queues are sorted */
485 EXPECT(pcb->unsent == NULL);
486 check_seqnos(pcb->unacked, 6, seqnos);
487
488 /* make sure the pcb is freed */
489 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
490 tcp_abort(pcb);
491 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
492}
static void test_tcp_tmr(void)
Definition: test_tcp.c:22

◆ START_TEST() [6/7]

END_TEST START_TEST ( test_tcp_tx_full_window_lost_from_unacked  )

Definition at line 646 of file test_tcp.c.

647{
648 LWIP_UNUSED_ARG(_i);
650}
static END_TEST void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent)
Definition: test_tcp.c:497

◆ START_TEST() [7/7]

START_TEST ( test_tcp_tx_full_window_lost_from_unsent  )

Definition at line 639 of file test_tcp.c.

640{
641 LWIP_UNUSED_ARG(_i);
643}

◆ tcp_setup()

static void tcp_setup ( void  )
static

Definition at line 33 of file test_tcp.c.

34{
35 /* reset iss to default (6510) */
36 tcp_ticks = 0;
37 tcp_ticks = 0 - (tcp_next_iss() - 6510);
38 tcp_next_iss();
39 tcp_ticks = 0;
40
43}
void tcp_remove_all(void)
Definition: tcp_helper.c:28
static u8_t test_tcp_timer
Definition: test_tcp.c:18

Referenced by tcp_suite().

◆ tcp_suite()

END_TEST Suite * tcp_suite ( void  )

Create the suite including all tests for this module

Definition at line 655 of file test_tcp.c.

656{
657 TFun tests[] = {
658 test_tcp_new_abort,
659 test_tcp_recv_inseq,
660 test_tcp_fast_retx_recover,
661 test_tcp_fast_rexmit_wraparound,
662 test_tcp_rto_rexmit_wraparound,
663 test_tcp_tx_full_window_lost_from_unacked,
664 test_tcp_tx_full_window_lost_from_unsent
665 };
666 return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown);
667}
static Suite * create_suite(const char *name, TFun *tests, size_t num_tests, SFun setup, SFun teardown)
Definition: lwip_check.h:20
static struct test_info tests[]
static void tcp_teardown(void)
Definition: test_tcp.c:46
static void tcp_setup(void)
Definition: test_tcp.c:33

Referenced by main().

◆ tcp_teardown()

static void tcp_teardown ( void  )
static

Definition at line 46 of file test_tcp.c.

47{
50}
struct netif * netif_list
Definition: netif.c:75

Referenced by tcp_suite().

◆ test_tcp_tmr()

static void test_tcp_tmr ( void  )
static

Definition at line 22 of file test_tcp.c.

23{
24 tcp_fasttmr();
25 if (++test_tcp_timer & 1) {
26 tcp_slowtmr();
27 }
28}

Referenced by START_TEST(), and test_tcp_tx_full_window_lost().

◆ test_tcp_tx_full_window_lost()

static END_TEST void test_tcp_tx_full_window_lost ( u8_t  zero_window_probe_from_unsent)
static

Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. At the end, send more data.

Definition at line 497 of file test_tcp.c.

498{
499 struct netif netif;
500 struct test_tcp_txcounters txcounters;
502 struct tcp_pcb* pcb;
503 struct pbuf *p;
504 ip_addr_t remote_ip, local_ip, netmask;
505 u16_t remote_port = 0x100, local_port = 0x101;
506 err_t err;
507 u16_t sent_total, i;
508 u8_t expected = 0xFE;
509
510 for (i = 0; i < sizeof(tx_data); i++) {
511 u8_t d = (u8_t)i;
512 if (d == 0xFE) {
513 d = 0xF0;
514 }
515 tx_data[i] = d;
516 }
517 if (zero_window_probe_from_unsent) {
519 } else {
520 tx_data[0] = expected;
521 }
522
523 /* initialize local vars */
524 IP4_ADDR(&local_ip, 192, 168, 1, 1);
525 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
526 IP4_ADDR(&netmask, 255, 255, 255, 0);
527 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
528 memset(&counters, 0, sizeof(counters));
529 memset(&txcounters, 0, sizeof(txcounters));
530
531 /* create and initialize the pcb */
533 EXPECT_RET(pcb != NULL);
534 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
535 pcb->mss = TCP_MSS;
536 /* disable initial congestion window (we don't send a SYN here...) */
537 pcb->cwnd = pcb->snd_wnd;
538
539 /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */
540 sent_total = 0;
541 if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) {
542 u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS;
543 err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY);
545 err = tcp_output(pcb);
547 EXPECT(txcounters.num_tx_calls == 1);
548 EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U);
549 memset(&txcounters, 0, sizeof(txcounters));
550 sent_total += initial_data_len;
551 }
552 for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) {
553 err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
555 err = tcp_output(pcb);
557 EXPECT(txcounters.num_tx_calls == 1);
558 EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
559 memset(&txcounters, 0, sizeof(txcounters));
560 }
561 EXPECT(sent_total == (TCP_WND - TCP_MSS));
562
563 /* now ACK the packet before the first */
564 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
566 /* ensure this didn't trigger a retransmission */
567 EXPECT(txcounters.num_tx_calls == 0);
568 EXPECT(txcounters.num_tx_bytes == 0);
569
570 EXPECT(pcb->persist_backoff == 0);
571 /* send the last packet, now a complete window has been sent */
572 err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY);
573 sent_total += TCP_MSS;
575 err = tcp_output(pcb);
577 EXPECT(txcounters.num_tx_calls == 1);
578 EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U);
579 memset(&txcounters, 0, sizeof(txcounters));
580 EXPECT(pcb->persist_backoff == 0);
581
582 if (zero_window_probe_from_unsent) {
583 /* ACK all data but close the TX window */
584 p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0);
586 /* ensure this didn't trigger any transmission */
587 EXPECT(txcounters.num_tx_calls == 0);
588 EXPECT(txcounters.num_tx_bytes == 0);
589 EXPECT(pcb->persist_backoff == 1);
590 }
591
592 /* send one byte more (out of window) -> persist timer starts */
593 err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY);
595 err = tcp_output(pcb);
597 EXPECT(txcounters.num_tx_calls == 0);
598 EXPECT(txcounters.num_tx_bytes == 0);
599 memset(&txcounters, 0, sizeof(txcounters));
600 if (!zero_window_probe_from_unsent) {
601 /* no persist timer unless a zero window announcement has been received */
602 EXPECT(pcb->persist_backoff == 0);
603 } else {
604 EXPECT(pcb->persist_backoff == 1);
605
606 /* call tcp_timer some more times to let persist timer count up */
607 for (i = 0; i < 4; i++) {
608 test_tcp_tmr();
609 EXPECT(txcounters.num_tx_calls == 0);
610 EXPECT(txcounters.num_tx_bytes == 0);
611 }
612
613 /* this should trigger the zero-window-probe */
614 txcounters.copy_tx_packets = 1;
615 test_tcp_tmr();
616 txcounters.copy_tx_packets = 0;
617 EXPECT(txcounters.num_tx_calls == 1);
618 EXPECT(txcounters.num_tx_bytes == 1 + 40U);
619 EXPECT(txcounters.tx_packets != NULL);
620 if (txcounters.tx_packets != NULL) {
621 u8_t sent;
622 u16_t ret;
623 ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U);
624 EXPECT(ret == 1);
625 EXPECT(sent == expected);
626 }
627 if (txcounters.tx_packets != NULL) {
628 pbuf_free(txcounters.tx_packets);
629 txcounters.tx_packets = NULL;
630 }
631 }
632
633 /* make sure the pcb is freed */
634 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
635 tcp_abort(pcb);
636 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
637}
@ sent
Definition: SystemMenu.c:27
#define TCP_WND
Definition: lwipopts.h:67
#define d
Definition: ke_i.h:81
BOOL expected
Definition: store.c:2063
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:918
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:618
struct pbuf * tcp_create_rx_segment_wnd(struct tcp_pcb *pcb, void *data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
Definition: tcp_helper.c:130
int ret

Referenced by START_TEST().

Variable Documentation

◆ test_tcp_timer

u8_t test_tcp_timer
static

Definition at line 18 of file test_tcp.c.

Referenced by tcp_setup(), and test_tcp_tmr().

◆ tx_data

END_TEST u8_t tx_data[TCP_WND *2]
static

Definition at line 293 of file test_tcp.c.

Referenced by START_TEST(), and test_tcp_tx_full_window_lost().