Skip to content

Commit 51e1f38

Browse files
rlubosdkalowsk
authored andcommitted
tests: net: tcp: Add test for FIN,ACK received after final data
Add a test case for a scenario where the final data sent by one peer is acknowledged in the FIN,ACK response from the other peer. Verify that the acknowledgment is handled correctly, and a consecutive sequence number sent by the TCP stack in such case is set correctly. This complements the other existing test for FIN packet handling, which verified that data received in a FIN packet is handled correctly. With those tests in place it should be safer to update any logic related to FIN packet handling. Signed-off-by: Robert Lubos <[email protected]> (cherry picked from commit 99b4357)
1 parent 87b0639 commit 51e1f38

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

tests/net/tcp/src/main.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ static enum test_case_no {
116116
TEST_CLIENT_FIN_ACK_WITH_DATA = 18,
117117
TEST_CLIENT_SEQ_VALIDATION = 19,
118118
TEST_SERVER_ACK_VALIDATION = 20,
119+
TEST_SERVER_FIN_ACK_AFTER_DATA = 21,
119120
} test_case_no;
120121

121122
static enum test_state t_state;
@@ -142,6 +143,7 @@ static void handle_syn_invalid_ack(sa_family_t af, struct tcphdr *th);
142143
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th);
143144
static void handle_client_seq_validation_test(sa_family_t af, struct tcphdr *th);
144145
static void handle_server_ack_validation_test(struct net_pkt *pkt);
146+
static void handle_server_fin_ack_after_data_test(sa_family_t af, struct tcphdr *th);
145147

146148
static void verify_flags(struct tcphdr *th, uint8_t flags,
147149
const char *fun, int line)
@@ -494,6 +496,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
494496
case TEST_SERVER_ACK_VALIDATION:
495497
handle_server_ack_validation_test(pkt);
496498
break;
499+
case TEST_SERVER_FIN_ACK_AFTER_DATA:
500+
handle_server_fin_ack_after_data_test(net_pkt_family(pkt), &th);
501+
break;
497502
default:
498503
zassert_true(false, "Undefined test case");
499504
}
@@ -3002,4 +3007,204 @@ ZTEST(net_tcp, test_server_ack_validation)
30023007
net_context_put(accepted_ctx);
30033008
}
30043009

3010+
#define TEST_FIN_ACK_AFTER_DATA_REQ "request"
3011+
#define TEST_FIN_ACK_AFTER_DATA_RSP "test data response"
3012+
3013+
/* In this test we check that FIN,ACK packet acknowledging latest data is
3014+
* handled correctly by the TCP stack.
3015+
*/
3016+
static void handle_server_fin_ack_after_data_test(sa_family_t af, struct tcphdr *th)
3017+
{
3018+
struct net_pkt *reply = NULL;
3019+
3020+
zassert_false(th == NULL && t_state != T_SYN,
3021+
"NULL pkt only expected in T_SYN state");
3022+
3023+
switch (t_state) {
3024+
case T_SYN:
3025+
reply = prepare_syn_packet(af, htons(MY_PORT), htons(PEER_PORT));
3026+
seq++;
3027+
t_state = T_SYN_ACK;
3028+
break;
3029+
case T_SYN_ACK:
3030+
test_verify_flags(th, SYN | ACK);
3031+
zassert_equal(ntohl(th->th_ack), seq,
3032+
"Unexpected ACK in T_SYN_ACK, got %d, expected %d",
3033+
ntohl(th->th_ack), seq);
3034+
device_initial_seq = ntohl(th->th_seq);
3035+
ack = ntohl(th->th_seq) + 1U;
3036+
t_state = T_DATA_ACK;
3037+
3038+
/* Dummy "request" packet */
3039+
reply = prepare_data_packet(af, htons(MY_PORT), htons(PEER_PORT),
3040+
TEST_FIN_ACK_AFTER_DATA_REQ,
3041+
sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1);
3042+
seq += sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1;
3043+
break;
3044+
case T_DATA_ACK:
3045+
test_verify_flags(th, ACK);
3046+
t_state = T_DATA;
3047+
zassert_equal(ntohl(th->th_seq), ack,
3048+
"Unexpected SEQ in T_DATA_ACK, got %d, expected %d",
3049+
get_rel_seq(th), ack);
3050+
zassert_equal(ntohl(th->th_ack), seq,
3051+
"Unexpected ACK in T_DATA_ACK, got %d, expected %d",
3052+
ntohl(th->th_ack), seq);
3053+
break;
3054+
case T_DATA:
3055+
test_verify_flags(th, PSH | ACK);
3056+
zassert_equal(ntohl(th->th_seq), ack,
3057+
"Unexpected SEQ in T_DATA, got %d, expected %d",
3058+
get_rel_seq(th), ack);
3059+
zassert_equal(ntohl(th->th_ack), seq,
3060+
"Unexpected ACK in T_DATA, got %d, expected %d",
3061+
ntohl(th->th_ack), seq);
3062+
ack += sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1;
3063+
t_state = T_FIN_ACK;
3064+
3065+
reply = prepare_fin_ack_packet(af, htons(MY_PORT), htons(PEER_PORT));
3066+
seq++;
3067+
break;
3068+
case T_FIN_ACK:
3069+
test_verify_flags(th, FIN | ACK);
3070+
zassert_equal(ntohl(th->th_seq), ack,
3071+
"Unexpected SEQ in T_FIN_ACK, got %d, expected %d",
3072+
get_rel_seq(th), ack);
3073+
zassert_equal(ntohl(th->th_ack), seq,
3074+
"Unexpected ACK in T_FIN_ACK, got %d, expected %d",
3075+
ntohl(th->th_ack), seq);
3076+
3077+
ack++;
3078+
t_state = T_CLOSING;
3079+
3080+
reply = prepare_ack_packet(af, htons(MY_PORT), htons(PEER_PORT));
3081+
seq++;
3082+
break;
3083+
case T_CLOSING:
3084+
zassert_true(false, "Should not receive anything after final ACK");
3085+
break;
3086+
default:
3087+
zassert_true(false, "%s unexpected state", __func__);
3088+
return;
3089+
}
3090+
3091+
if (reply != NULL) {
3092+
zassert_ok(net_recv_data(net_iface, reply), "%s failed", __func__);
3093+
}
3094+
}
3095+
3096+
/* Receive callback to be installed in the accept handler */
3097+
static void test_fin_ack_after_data_recv_cb(struct net_context *context,
3098+
struct net_pkt *pkt,
3099+
union net_ip_header *ip_hdr,
3100+
union net_proto_header *proto_hdr,
3101+
int status,
3102+
void *user_data)
3103+
{
3104+
zassert_ok(status, "failed to recv the data");
3105+
3106+
if (pkt != NULL) {
3107+
uint8_t buf[sizeof(TEST_FIN_ACK_AFTER_DATA_REQ)] = { 0 };
3108+
int data_len = net_pkt_remaining_data(pkt);
3109+
3110+
zassert_equal(data_len, sizeof(TEST_FIN_ACK_AFTER_DATA_REQ) - 1,
3111+
"Invalid packet length, %d", data_len);
3112+
zassert_ok(net_pkt_read(pkt, buf, data_len));
3113+
zassert_mem_equal(buf, TEST_FIN_ACK_AFTER_DATA_REQ, data_len);
3114+
3115+
net_pkt_unref(pkt);
3116+
}
3117+
3118+
test_sem_give();
3119+
}
3120+
3121+
static void test_fin_ack_after_data_accept_cb(struct net_context *ctx,
3122+
struct sockaddr *addr,
3123+
socklen_t addrlen,
3124+
int status,
3125+
void *user_data)
3126+
{
3127+
int ret;
3128+
3129+
zassert_ok(status, "failed to accept the conn");
3130+
3131+
/* set callback on newly created context */
3132+
accepted_ctx = ctx;
3133+
ret = net_context_recv(ctx, test_fin_ack_after_data_recv_cb,
3134+
K_NO_WAIT, NULL);
3135+
zassert_ok(ret, "Failed to recv data from peer");
3136+
3137+
/* Ref the context on the app behalf. */
3138+
net_context_ref(ctx);
3139+
}
3140+
3141+
/* Verify that the TCP stack replies with a valid FIN,ACK after the peer
3142+
* acknowledges the latest data in the FIN packet.
3143+
* Test case scenario IPv4
3144+
* send SYN,
3145+
* expect SYN ACK,
3146+
* send ACK with Data,
3147+
* expect ACK,
3148+
* expect Data,
3149+
* send FIN,ACK
3150+
* expect FIN,ACK
3151+
* send ACK
3152+
* any failures cause test case to fail.
3153+
*/
3154+
ZTEST(net_tcp, test_server_fin_ack_after_data)
3155+
{
3156+
struct net_context *ctx;
3157+
int ret;
3158+
3159+
test_case_no = TEST_SERVER_FIN_ACK_AFTER_DATA;
3160+
3161+
t_state = T_SYN;
3162+
seq = ack = 0;
3163+
3164+
ret = net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP, &ctx);
3165+
zassert_ok(ret, "Failed to get net_context");
3166+
3167+
net_context_ref(ctx);
3168+
3169+
ret = net_context_bind(ctx, (struct sockaddr *)&my_addr_s,
3170+
sizeof(struct sockaddr_in));
3171+
zassert_ok(ret, "Failed to bind net_context");
3172+
3173+
/* Put context into listening mode and install accept cb */
3174+
ret = net_context_listen(ctx, 1);
3175+
zassert_ok(ret, "Failed to listen on net_context");
3176+
3177+
ret = net_context_accept(ctx, test_fin_ack_after_data_accept_cb,
3178+
K_NO_WAIT, NULL);
3179+
zassert_ok(ret, "Failed to set accept on net_context");
3180+
3181+
/* Trigger the peer to send SYN */
3182+
handle_server_fin_ack_after_data_test(AF_INET, NULL);
3183+
3184+
/* test_fin_ack_after_data_recv_cb will release the semaphore after
3185+
* dummy request is read.
3186+
*/
3187+
test_sem_take(K_MSEC(100), __LINE__);
3188+
3189+
/* Send dummy "response" */
3190+
ret = net_context_send(accepted_ctx, TEST_FIN_ACK_AFTER_DATA_RSP,
3191+
sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1, NULL,
3192+
K_NO_WAIT, NULL);
3193+
zassert_equal(ret, sizeof(TEST_FIN_ACK_AFTER_DATA_RSP) - 1,
3194+
"Failed to send data to peer %d", ret);
3195+
3196+
/* test_fin_ack_after_data_recv_cb will release the semaphore after
3197+
* the connection is marked closed.
3198+
*/
3199+
test_sem_take(K_MSEC(100), __LINE__);
3200+
3201+
net_context_put(ctx);
3202+
net_context_put(accepted_ctx);
3203+
3204+
/* Connection is in TIME_WAIT state, context will be released
3205+
* after K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY), so wait for it.
3206+
*/
3207+
k_sleep(K_MSEC(CONFIG_NET_TCP_TIME_WAIT_DELAY));
3208+
}
3209+
30053210
ZTEST_SUITE(net_tcp, NULL, presetup, NULL, NULL, NULL);

0 commit comments

Comments
 (0)