Skip to content

Commit ec83e9c

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 8d7d156 commit ec83e9c

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

tests/net/tcp/src/main.c

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ static void handle_server_recv_out_of_order(struct net_pkt *pkt);
134134
static void handle_server_rst_on_closed_port(sa_family_t af, struct tcphdr *th);
135135
static void handle_server_rst_on_listening_port(sa_family_t af, struct tcphdr *th);
136136
static void handle_syn_invalid_ack(sa_family_t af, struct tcphdr *th);
137+
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th);
137138

138139
static void verify_flags(struct tcphdr *th, uint8_t flags,
139140
const char *fun, int line)
@@ -469,6 +470,10 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
469470
handle_syn_invalid_ack(net_pkt_family(pkt), &th);
470471
break;
471472

473+
case 18:
474+
handle_client_fin_ack_with_data_test(net_pkt_family(pkt), &th);
475+
break;
476+
472477
default:
473478
zassert_true(false, "Undefined test case");
474479
}
@@ -2127,4 +2132,191 @@ ZTEST(net_tcp, test_client_rst_on_unexpected_ack_on_syn)
21272132
test_sem_take(K_MSEC(100), __LINE__);
21282133
}
21292134

2135+
#define TEST_FIN_DATA "test_data"
2136+
2137+
static enum fin_data_variant {
2138+
FIN_DATA_FIN,
2139+
FIN_DATA_FIN_ACK,
2140+
FIN_DATA_FIN_ACK_PSH,
2141+
} test_fin_data_variant;
2142+
2143+
static struct k_work_delayable test_fin_data_work;
2144+
2145+
/* In this test we check that FIN packet containing data is handled correctly
2146+
* by the TCP stack.
2147+
*/
2148+
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th)
2149+
{
2150+
static uint16_t peer_port;
2151+
struct net_pkt *reply;
2152+
uint8_t flags = 0;
2153+
2154+
switch (t_state) {
2155+
case T_SYN:
2156+
test_verify_flags(th, SYN);
2157+
device_initial_seq = ntohl(th->th_seq);
2158+
seq = 0U;
2159+
ack = ntohl(th->th_seq) + 1U;
2160+
peer_port = th->th_sport;
2161+
reply = prepare_syn_ack_packet(af, htons(MY_PORT), peer_port);
2162+
seq++;
2163+
t_state = T_SYN_ACK;
2164+
break;
2165+
case T_SYN_ACK:
2166+
test_verify_flags(th, ACK);
2167+
t_state = T_DATA;
2168+
2169+
/* FIN packet with DATA needs to be rescheduled for later - if
2170+
* we send it here, the net_context_recv() won't have a chance
2171+
* to execute, hence no callback will be registered and data
2172+
* will be dropped.
2173+
*/
2174+
k_work_reschedule(&test_fin_data_work, K_MSEC(1));
2175+
return;
2176+
case T_DATA:
2177+
switch (test_fin_data_variant) {
2178+
case FIN_DATA_FIN:
2179+
flags = FIN;
2180+
t_state = T_FIN;
2181+
break;
2182+
case FIN_DATA_FIN_ACK:
2183+
flags = FIN | ACK;
2184+
t_state = T_FIN_ACK;
2185+
break;
2186+
case FIN_DATA_FIN_ACK_PSH:
2187+
flags = FIN | ACK | PSH;
2188+
t_state = T_FIN_ACK;
2189+
break;
2190+
}
2191+
2192+
reply = tester_prepare_tcp_pkt(af, htons(MY_PORT), peer_port,
2193+
flags, TEST_FIN_DATA,
2194+
strlen(TEST_FIN_DATA));
2195+
seq += strlen(TEST_FIN_DATA) + 1;
2196+
2197+
break;
2198+
case T_FIN:
2199+
test_verify_flags(th, ACK);
2200+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN, got %d",
2201+
get_rel_seq(th));
2202+
zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN, got %d",
2203+
ntohl(th->th_ack));
2204+
2205+
t_state = T_CLOSING;
2206+
return;
2207+
case T_FIN_ACK:
2208+
test_verify_flags(th, FIN | ACK);
2209+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_FIN_ACK, got %d",
2210+
get_rel_seq(th));
2211+
zassert_equal(ntohl(th->th_ack), seq, "Unexpected ACK in T_FIN_ACK, got %d",
2212+
ntohl(th->th_ack));
2213+
2214+
ack++;
2215+
reply = prepare_ack_packet(af, htons(MY_PORT), peer_port);
2216+
t_state = T_SYN;
2217+
break;
2218+
2219+
case T_CLOSING:
2220+
test_verify_flags(th, FIN);
2221+
zassert_equal(get_rel_seq(th), 1, "Unexpected SEQ number in T_CLOSING, got %d",
2222+
get_rel_seq(th));
2223+
2224+
ack++;
2225+
reply = prepare_ack_packet(af, htons(MY_PORT), peer_port);
2226+
t_state = T_SYN;
2227+
break;
2228+
2229+
default:
2230+
zassert_true(false, "%s unexpected state", __func__);
2231+
return;
2232+
}
2233+
2234+
zassert_ok(net_recv_data(net_iface, reply), "%s failed", __func__);
2235+
}
2236+
2237+
2238+
static void test_fin_data_handler(struct k_work *work)
2239+
{
2240+
ARG_UNUSED(work);
2241+
2242+
handle_client_fin_ack_with_data_test(AF_INET, NULL);
2243+
}
2244+
2245+
static void test_fin_ack_data_recv_cb(struct net_context *context,
2246+
struct net_pkt *pkt,
2247+
union net_ip_header *ip_hdr,
2248+
union net_proto_header *proto_hdr,
2249+
int status,
2250+
void *user_data)
2251+
{
2252+
if (status) {
2253+
zassert_true(false, "failed to recv the data");
2254+
}
2255+
2256+
if (pkt) {
2257+
uint8_t buf[sizeof(TEST_FIN_DATA)] = { 0 };
2258+
int data_len = net_pkt_remaining_data(pkt);
2259+
2260+
zassert_equal(data_len, strlen(TEST_FIN_DATA),
2261+
"Invalid packet length, %d", data_len);
2262+
zassert_ok(net_pkt_read(pkt, buf, data_len));
2263+
zassert_mem_equal(buf, TEST_FIN_DATA, data_len);
2264+
2265+
net_pkt_unref(pkt);
2266+
}
2267+
2268+
test_sem_give();
2269+
}
2270+
2271+
/* Test case scenario IPv4
2272+
* expect SYN,
2273+
* send SYN ACK,
2274+
* expect ACK,
2275+
* send FIN/FIN,ACK/FIN,ACK,PSH with Data,
2276+
* expect FIN/FIN,ACK/ACK,
2277+
* send ACK
2278+
* any failures cause test case to fail.
2279+
*/
2280+
ZTEST(net_tcp, test_client_fin_ack_with_data)
2281+
{
2282+
struct net_context *ctx;
2283+
2284+
test_case_no = 18;
2285+
2286+
k_work_init_delayable(&test_fin_data_work, test_fin_data_handler);
2287+
2288+
for (enum fin_data_variant variant = FIN_DATA_FIN;
2289+
variant <= FIN_DATA_FIN_ACK_PSH; variant++) {
2290+
test_fin_data_variant = variant;
2291+
t_state = T_SYN;
2292+
seq = ack = 0;
2293+
2294+
zassert_ok(net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx),
2295+
"Failed to get net_context");
2296+
2297+
net_context_ref(ctx);
2298+
2299+
zassert_ok(net_context_connect(ctx, (struct sockaddr *)&peer_addr_s,
2300+
sizeof(struct sockaddr_in), NULL,
2301+
K_MSEC(1000), NULL),
2302+
"Failed to connect to peer");
2303+
zassert_ok(net_context_recv(ctx, test_fin_ack_data_recv_cb,
2304+
K_NO_WAIT, NULL),
2305+
"Failed to recv data from peer");
2306+
2307+
/* Take sem twice, one for data packet, second for conn close
2308+
* (NULL net_pkt).
2309+
*/
2310+
test_sem_take(K_MSEC(100), __LINE__);
2311+
test_sem_take(K_MSEC(100), __LINE__);
2312+
2313+
net_context_put(ctx);
2314+
2315+
/* Connection is in TIME_WAIT state, context will be released
2316+
* after K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY), so wait for it.
2317+
*/
2318+
k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY));
2319+
}
2320+
}
2321+
21302322
ZTEST_SUITE(net_tcp, NULL, presetup, NULL, NULL, NULL);

0 commit comments

Comments
 (0)