Skip to content

Commit 99b4357

Browse files
rluboshenrikbrixandersen
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]>
1 parent 5f64a3a commit 99b4357

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
@@ -115,6 +115,7 @@ static enum test_case_no {
115115
TEST_CLIENT_FIN_ACK_WITH_DATA = 18,
116116
TEST_CLIENT_SEQ_VALIDATION = 19,
117117
TEST_SERVER_ACK_VALIDATION = 20,
118+
TEST_SERVER_FIN_ACK_AFTER_DATA = 21,
118119
} test_case_no;
119120

120121
static enum test_state t_state;
@@ -141,6 +142,7 @@ static void handle_syn_invalid_ack(sa_family_t af, struct tcphdr *th);
141142
static void handle_client_fin_ack_with_data_test(sa_family_t af, struct tcphdr *th);
142143
static void handle_client_seq_validation_test(sa_family_t af, struct tcphdr *th);
143144
static void handle_server_ack_validation_test(struct net_pkt *pkt);
145+
static void handle_server_fin_ack_after_data_test(sa_family_t af, struct tcphdr *th);
144146

145147
static void verify_flags(struct tcphdr *th, uint8_t flags,
146148
const char *fun, int line)
@@ -493,6 +495,9 @@ static int tester_send(const struct device *dev, struct net_pkt *pkt)
493495
case TEST_SERVER_ACK_VALIDATION:
494496
handle_server_ack_validation_test(pkt);
495497
break;
498+
case TEST_SERVER_FIN_ACK_AFTER_DATA:
499+
handle_server_fin_ack_after_data_test(net_pkt_family(pkt), &th);
500+
break;
496501
default:
497502
zassert_true(false, "Undefined test case");
498503
}
@@ -3001,4 +3006,204 @@ ZTEST(net_tcp, test_server_ack_validation)
30013006
net_context_put(accepted_ctx);
30023007
}
30033008

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

0 commit comments

Comments
 (0)