ReactOS 0.4.15-dev-6656-gbbb33a6
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 300 of file test_tcp.c.

301{
302 struct tcp_seg *s = segs;
303 int i;
304 for (i = 0; i < num_expected; i++, s = s->next) {
305 EXPECT_RET(s != NULL);
306 EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i]));
307 }
308 EXPECT(s == NULL);
309}
#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 127 of file test_tcp.c.

128{
129 struct netif netif;
130 struct test_tcp_txcounters txcounters;
132 struct tcp_pcb* pcb;
133 struct pbuf* p;
134 char data1[] = { 1, 2, 3, 4};
135 char data2[] = { 5, 6, 7, 8};
136 char data3[] = { 9, 10, 11, 12};
137 char data4[] = {13, 14, 15, 16};
138 char data5[] = {17, 18, 19, 20};
139 char data6[] = {21, 22, 23, 24};
140 ip_addr_t remote_ip, local_ip, netmask;
141 u16_t remote_port = 0x100, local_port = 0x101;
142 err_t err;
143 LWIP_UNUSED_ARG(_i);
144
145 /* initialize local vars */
146 IP4_ADDR(&local_ip, 192, 168, 1, 1);
147 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
148 IP4_ADDR(&netmask, 255, 255, 255, 0);
149 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
150 memset(&counters, 0, sizeof(counters));
151
152 /* create and initialize the pcb */
154 EXPECT_RET(pcb != NULL);
155 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
156 pcb->mss = TCP_MSS;
157 /* disable initial congestion window (we don't send a SYN here...) */
158 pcb->cwnd = pcb->snd_wnd;
159
160 /* send data1 */
161 err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY);
163 err = tcp_output(pcb);
165 EXPECT_RET(txcounters.num_tx_calls == 1);
166 EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
167 memset(&txcounters, 0, sizeof(txcounters));
168 /* "recv" ACK for data1 */
169 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK);
170 EXPECT_RET(p != NULL);
172 EXPECT_RET(txcounters.num_tx_calls == 0);
173 EXPECT_RET(pcb->unacked == NULL);
174 /* send data2 */
175 err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY);
177 err = tcp_output(pcb);
179 EXPECT_RET(txcounters.num_tx_calls == 1);
180 EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr));
181 memset(&txcounters, 0, sizeof(txcounters));
182 /* duplicate ACK for data1 (data2 is lost) */
183 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
184 EXPECT_RET(p != NULL);
186 EXPECT_RET(txcounters.num_tx_calls == 0);
187 EXPECT_RET(pcb->dupacks == 1);
188 /* send data3 */
189 err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY);
191 err = tcp_output(pcb);
193 /* nagle enabled, no tx calls */
194 EXPECT_RET(txcounters.num_tx_calls == 0);
195 EXPECT_RET(txcounters.num_tx_bytes == 0);
196 memset(&txcounters, 0, sizeof(txcounters));
197 /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */
198 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
199 EXPECT_RET(p != NULL);
201 EXPECT_RET(txcounters.num_tx_calls == 0);
202 EXPECT_RET(pcb->dupacks == 2);
203 /* queue data4, don't send it (unsent-oversize is != 0) */
204 err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY);
206 /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */
207 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK);
208 EXPECT_RET(p != NULL);
210 /*EXPECT_RET(txcounters.num_tx_calls == 1);*/
211 EXPECT_RET(pcb->dupacks == 3);
212 memset(&txcounters, 0, sizeof(txcounters));
213 /* TODO: check expected data?*/
214
215 /* send data5, not output yet */
216 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
218 /*err = tcp_output(pcb);
219 EXPECT_RET(err == ERR_OK);*/
220 EXPECT_RET(txcounters.num_tx_calls == 0);
221 EXPECT_RET(txcounters.num_tx_bytes == 0);
222 memset(&txcounters, 0, sizeof(txcounters));
223 {
224 int i = 0;
225 do
226 {
227 err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY);
228 i++;
229 }while(err == ERR_OK);
231 }
232 err = tcp_output(pcb);
234 /*EXPECT_RET(txcounters.num_tx_calls == 0);
235 EXPECT_RET(txcounters.num_tx_bytes == 0);*/
236 memset(&txcounters, 0, sizeof(txcounters));
237
238 /* send even more data */
239 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
241 err = tcp_output(pcb);
243 /* ...and even more data */
244 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
246 err = tcp_output(pcb);
248 /* ...and even more data */
249 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
251 err = tcp_output(pcb);
253 /* ...and even more data */
254 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
256 err = tcp_output(pcb);
258
259 /* send ACKs for data2 and data3 */
260 p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK);
261 EXPECT_RET(p != NULL);
263 /*EXPECT_RET(txcounters.num_tx_calls == 0);*/
264
265 /* ...and even more data */
266 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
268 err = tcp_output(pcb);
270 /* ...and even more data */
271 err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY);
273 err = tcp_output(pcb);
275
276#if 0
277 /* create expected segment */
278 p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
279 EXPECT_RET(p != NULL);
280 if (p != NULL) {
281 /* pass the segment to tcp_input */
283 /* check if counters are as expected */
284 EXPECT_RET(counters.close_calls == 0);
285 EXPECT_RET(counters.recv_calls == 1);
286 EXPECT_RET(counters.recved_bytes == data_len);
287 EXPECT_RET(counters.err_calls == 0);
288 }
289#endif
290 /* make sure the pcb is freed */
291 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
292 tcp_abort(pcb);
293 EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
294}
#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 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 TCP_MSS
Definition: opt.h:956
#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:283
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 314 of file test_tcp.c.

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

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

◆ 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 75 of file test_tcp.c.

76{
78 struct tcp_pcb* pcb;
79 struct pbuf* p;
80 char data[] = {1, 2, 3, 4};
81 ip_addr_t remote_ip, local_ip, netmask;
82 u16_t data_len;
83 u16_t remote_port = 0x100, local_port = 0x101;
84 struct netif netif;
85 struct test_tcp_txcounters txcounters;
87
88 /* initialize local vars */
89 memset(&netif, 0, sizeof(netif));
90 IP4_ADDR(&local_ip, 192, 168, 1, 1);
91 IP4_ADDR(&remote_ip, 192, 168, 1, 2);
92 IP4_ADDR(&netmask, 255, 255, 255, 0);
93 test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask);
94 data_len = sizeof(data);
95 /* initialize counter struct */
96 memset(&counters, 0, sizeof(counters));
97 counters.expected_data_len = data_len;
98 counters.expected_data = data;
99
100 /* create and initialize the pcb */
102 EXPECT_RET(pcb != NULL);
103 tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
104
105 /* create a segment */
106 p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0);
107 EXPECT(p != NULL);
108 if (p != NULL) {
109 /* pass the segment to tcp_input */
111 /* check if counters are as expected */
112 EXPECT(counters.close_calls == 0);
113 EXPECT(counters.recv_calls == 1);
114 EXPECT(counters.recved_bytes == data_len);
115 EXPECT(counters.err_calls == 0);
116 }
117
118 /* make sure the pcb is freed */
119 EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
120 tcp_abort(pcb);
121 EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
122}
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 412 of file test_tcp.c.

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

651{
652 LWIP_UNUSED_ARG(_i);
654}
static END_TEST void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent)
Definition: test_tcp.c:501

◆ START_TEST() [7/7]

START_TEST ( test_tcp_tx_full_window_lost_from_unsent  )

Definition at line 643 of file test_tcp.c.

644{
645 LWIP_UNUSED_ARG(_i);
647}

◆ 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 659 of file test_tcp.c.

660{
661 TFun tests[] = {
662 test_tcp_new_abort,
663 test_tcp_recv_inseq,
664 test_tcp_fast_retx_recover,
665 test_tcp_fast_rexmit_wraparound,
666 test_tcp_rto_rexmit_wraparound,
667 test_tcp_tx_full_window_lost_from_unacked,
668 test_tcp_tx_full_window_lost_from_unsent
669 };
670 return create_suite("TCP", tests, sizeof(tests)/sizeof(TFun), tcp_setup, tcp_teardown);
671}
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{
51}
struct netif * netif_list
Definition: netif.c:75
struct netif * netif_default
Definition: netif.c:76

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 501 of file test_tcp.c.

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

Referenced by START_TEST(), and test_tcp_tx_full_window_lost().