Skip to content

Commit c82a387

Browse files
rluboscvinayak
authored andcommitted
[nrf fromtree] tests: net: tcp: Add test case verifying FIN with data processing
Verify, that when TCP stack received FIN packet containing data bytes, the data is provided to the application and respective seq/ack counters are updated respectively. Signed-off-by: Robert Lubos <[email protected]> (cherry picked from commit b1adbbe)
1 parent ab47d8a commit c82a387

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

tests/net/tcp/src/main.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static void handle_client_closing_test(sa_family_t af, struct tcphdr *th);
129129
static void handle_data_fin1_test(sa_family_t af, struct tcphdr *th);
130130
static void handle_data_during_fin1_test(sa_family_t af, struct tcphdr *th);
131131
static void handle_server_recv_out_of_order(struct net_pkt *pkt);
132+
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th);
132133

133134
static void verify_flags(struct tcphdr *th, uint8_t flags,
134135
const char *fun, int line)
@@ -430,6 +431,11 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
430431
case 11:
431432
handle_data_during_fin1_test(net_pkt_family(pkt), &th);
432433
break;
434+
435+
case 18:
436+
handle_client_fin_ack_with_data_test(net_pkt_family(pkt), &th);
437+
break;
438+
433439
default:
434440
zassert_true(false, "Undefined test case");
435441
}
@@ -1811,4 +1817,191 @@ ZTEST(net_tcp, test_server_out_of_order_data)
18111817
test_server_timeout_out_of_order_data();
18121818
}
18131819

1820+
#define TEST_FIN_DATA "test_data"
1821+
1822+
static enum fin_data_variant {
1823+
FIN_DATA_FIN,
1824+
FIN_DATA_FIN_ACK,
1825+
FIN_DATA_FIN_ACK_PSH,
1826+
} test_fin_data_variant;
1827+
1828+
static struct k_work_delayable test_fin_data_work;
1829+
1830+
/* In this test we check that FIN packet containing data is handled correctly
1831+
* by the TCP stack.
1832+
*/
1833+
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th)
1834+
{
1835+
static uint16_t peer_port;
1836+
struct net_pkt *reply;
1837+
uint8_t flags = 0;
1838+
1839+
switch (t_state) {
1840+
case T_SYN:
1841+
test_verify_flags(th, SYN);
1842+
device_initial_seq = ntohl(th->th_seq);
1843+
seq = 0U;
1844+
ack = ntohl(th->th_seq) + 1U;
1845+
peer_port = th->th_sport;
1846+
reply = prepare_syn_ack_packet(af, htons(MY_PORT), peer_port);
1847+
seq++;
1848+
t_state = T_SYN_ACK;
1849+
break;
1850+
case T_SYN_ACK:
1851+
test_verify_flags(th, ACK);
1852+
t_state = T_DATA;
1853+
1854+
/* FIN packet with DATA needs to be rescheduled for later - if
1855+
* we send it here, the net_context_recv() won't have a chance
1856+
* to execute, hence no callback will be registered and data
1857+
* will be dropped.
1858+
*/
1859+
k_work_reschedule(&test_fin_data_work, K_MSEC(1));
1860+
return;
1861+
case T_DATA:
1862+
switch (test_fin_data_variant) {
1863+
case FIN_DATA_FIN:
1864+
flags = FIN;
1865+
t_state = T_FIN;
1866+
break;
1867+
case FIN_DATA_FIN_ACK:
1868+
flags = FIN | ACK;
1869+
t_state = T_FIN_ACK;
1870+
break;
1871+
case FIN_DATA_FIN_ACK_PSH:
1872+
flags = FIN | ACK | PSH;
1873+
t_state = T_FIN_ACK;
1874+
break;
1875+
}
1876+
1877+
reply = tester_prepare_tcp_pkt(af, htons(MY_PORT), peer_port,
1878+
flags, TEST_FIN_DATA,
1879+
strlen(TEST_FIN_DATA));
1880+
seq += strlen(TEST_FIN_DATA) + 1;
1881+
1882+
break;
1883+
case T_FIN:
1884+
test_verify_flags(th, ACK);
1885+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN, got %d",
1886+
get_rel_seq(th));
1887+
zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN, got %d",
1888+
ntohl(th->th_ack));
1889+
1890+
t_state = T_CLOSING;
1891+
return;
1892+
case T_FIN_ACK:
1893+
test_verify_flags(th, FIN | ACK);
1894+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN_ACK, got %d",
1895+
get_rel_seq(th));
1896+
zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN_ACK, got %d",
1897+
ntohl(th->th_ack));
1898+
1899+
ack++;
1900+
reply = prepare_ack_packet(af, htons(MY_PORT), peer_port);
1901+
t_state = T_SYN;
1902+
break;
1903+
1904+
case T_CLOSING:
1905+
test_verify_flags(th, FIN);
1906+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_CLOSING, got %d",
1907+
get_rel_seq(th));
1908+
1909+
ack++;
1910+
reply = prepare_ack_packet(af, htons(MY_PORT), peer_port);
1911+
t_state = T_SYN;
1912+
break;
1913+
1914+
default:
1915+
zassert_true(false, "%s unexpected state", __func__);
1916+
return;
1917+
}
1918+
1919+
zassert_ok(net_recv_data(net_iface, reply), "%s failed", __func__);
1920+
}
1921+
1922+
1923+
static void test_fin_data_handler(struct k_work *work)
1924+
{
1925+
ARG_UNUSED(work);
1926+
1927+
handle_client_fin_ack_with_data_test(AF_INET, NULL);
1928+
}
1929+
1930+
static void test_fin_ack_data_recv_cb(struct net_context *context,
1931+
struct net_pkt *pkt,
1932+
union net_ip_header *ip_hdr,
1933+
union net_proto_header *proto_hdr,
1934+
int status,
1935+
void *user_data)
1936+
{
1937+
if (status) {
1938+
zassert_true(false, "failed to recv the data");
1939+
}
1940+
1941+
if (pkt) {
1942+
uint8_t buf[sizeof(TEST_FIN_DATA)] = { 0 };
1943+
int data_len = net_pkt_remaining_data(pkt);
1944+
1945+
zassert_equal(data_len, strlen(TEST_FIN_DATA),
1946+
"Invalid packet length, %d", data_len);
1947+
zassert_ok(net_pkt_read(pkt, buf, data_len));
1948+
zassert_mem_equal(buf, TEST_FIN_DATA, data_len);
1949+
1950+
net_pkt_unref(pkt);
1951+
}
1952+
1953+
test_sem_give();
1954+
}
1955+
1956+
/* Test case scenario IPv4
1957+
* expect SYN,
1958+
* send SYN ACK,
1959+
* expect ACK,
1960+
* send FIN/FIN,ACK/FIN,ACK,PSH with Data,
1961+
* expect FIN/FIN,ACK/ACK,
1962+
* send ACK
1963+
* any failures cause test case to fail.
1964+
*/
1965+
ZTEST(net_tcp, test_client_fin_ack_with_data)
1966+
{
1967+
struct net_context *ctx;
1968+
1969+
test_case_no = 18;
1970+
1971+
k_work_init_delayable(&test_fin_data_work, test_fin_data_handler);
1972+
1973+
for (enum fin_data_variant variant = FIN_DATA_FIN;
1974+
variant <= FIN_DATA_FIN_ACK_PSH; variant++) {
1975+
test_fin_data_variant = variant;
1976+
t_state = T_SYN;
1977+
seq = ack = 0;
1978+
1979+
zassert_ok(net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx),
1980+
"Failed to get net_context");
1981+
1982+
net_context_ref(ctx);
1983+
1984+
zassert_ok(net_context_connect(ctx, (struct sockaddr *)&peer_addr_s,
1985+
sizeof(struct sockaddr_in), NULL,
1986+
K_MSEC(1000), NULL),
1987+
"Failed to connect to peer");
1988+
zassert_ok(net_context_recv(ctx, test_fin_ack_data_recv_cb,
1989+
K_NO_WAIT, NULL),
1990+
"Failed to recv data from peer");
1991+
1992+
/* Take sem twice, one for data packet, second for conn close
1993+
* (NULL net_pkt).
1994+
*/
1995+
test_sem_take(K_MSEC(100), __LINE__);
1996+
test_sem_take(K_MSEC(100), __LINE__);
1997+
1998+
net_context_put(ctx);
1999+
2000+
/* Connection is in TIME_WAIT state, context will be released
2001+
* after K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY), so wait for it.
2002+
*/
2003+
k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY));
2004+
}
2005+
}
2006+
18142007
ZTEST_SUITE(net_tcp, NULL, presetup, NULL, NULL, NULL);

0 commit comments

Comments
 (0)