Skip to content

Commit ab47d8a

Browse files
rluboscvinayak
authored andcommitted
[nrf fromtree] net: tcp: Fix FIN with data handling
In case FIN packet included data bytes, Zephyr would ignore the data. It wasn't passed to the application, and it wasn't considered when bumping the ACK counter. This ended out in connection timing out, instead of being properly terminated. Fix this, by refactoring FIN processing in TCP_ESTABLISHED state. Instead of handling FIN/FIN,ACK/FIN,ACK,PSH cases separately, have a common handler when FIN flag is present, and when ACK flag is present along with FIN. When FIN is present, take any potentially incoming data into account. Signed-off-by: Robert Lubos <[email protected]> (cherry picked from commit a0f0e55)
1 parent 44cfceb commit ab47d8a

File tree

1 file changed

+23
-25
lines changed

1 file changed

+23
-25
lines changed

subsys/net/ip/tcp.c

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,28 +2545,9 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
25452545
break;
25462546
case TCP_ESTABLISHED:
25472547
/* full-close */
2548-
if (th && FL(&fl, ==, (FIN | ACK), th_seq(th) == conn->ack)) {
2549-
if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) {
2550-
uint32_t len_acked = th_ack(th) - conn->seq;
2548+
if (th && FL(&fl, &, FIN, th_seq(th) == conn->ack)) {
2549+
bool acked = false;
25512550

2552-
conn_seq(conn, + len_acked);
2553-
}
2554-
2555-
conn_ack(conn, + 1);
2556-
tcp_out(conn, FIN | ACK);
2557-
conn_seq(conn, + 1);
2558-
next = TCP_LAST_ACK;
2559-
verdict = NET_OK;
2560-
tcp_setup_last_ack_timer(conn);
2561-
break;
2562-
} else if (th && FL(&fl, ==, FIN, th_seq(th) == conn->ack)) {
2563-
conn_ack(conn, + 1);
2564-
tcp_out(conn, ACK);
2565-
next = TCP_CLOSE_WAIT;
2566-
verdict = NET_OK;
2567-
break;
2568-
} else if (th && FL(&fl, ==, (FIN | ACK | PSH),
2569-
th_seq(th) == conn->ack)) {
25702551
if (len) {
25712552
verdict = tcp_data_get(conn, pkt, &len);
25722553
if (verdict == NET_OK) {
@@ -2578,10 +2559,27 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
25782559
}
25792560

25802561
conn_ack(conn, + len + 1);
2581-
tcp_out(conn, FIN | ACK);
2582-
conn_seq(conn, + 1);
2583-
next = TCP_LAST_ACK;
2584-
tcp_setup_last_ack_timer(conn);
2562+
2563+
if (FL(&fl, &, ACK)) {
2564+
acked = true;
2565+
2566+
if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) {
2567+
uint32_t len_acked = th_ack(th) - conn->seq;
2568+
2569+
conn_seq(conn, + len_acked);
2570+
}
2571+
}
2572+
2573+
if (acked) {
2574+
tcp_out(conn, FIN | ACK);
2575+
conn_seq(conn, + 1);
2576+
tcp_setup_last_ack_timer(conn);
2577+
next = TCP_LAST_ACK;
2578+
} else {
2579+
tcp_out(conn, ACK);
2580+
next = TCP_CLOSE_WAIT;
2581+
}
2582+
25852583
break;
25862584
}
25872585

0 commit comments

Comments
 (0)