Skip to content

Commit 8d7d156

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

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
@@ -2719,28 +2719,9 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
27192719
break;
27202720
case TCP_ESTABLISHED:
27212721
/* full-close */
2722-
if (th && FL(&fl, ==, (FIN | ACK), th_seq(th) == conn->ack)) {
2723-
if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) {
2724-
uint32_t len_acked = th_ack(th) - conn->seq;
2722+
if (th && FL(&fl, &, FIN, th_seq(th) == conn->ack)) {
2723+
bool acked = false;
27252724

2726-
conn_seq(conn, + len_acked);
2727-
}
2728-
2729-
conn_ack(conn, + 1);
2730-
tcp_out(conn, FIN | ACK);
2731-
conn_seq(conn, + 1);
2732-
next = TCP_LAST_ACK;
2733-
verdict = NET_OK;
2734-
tcp_setup_last_ack_timer(conn);
2735-
break;
2736-
} else if (th && FL(&fl, ==, FIN, th_seq(th) == conn->ack)) {
2737-
conn_ack(conn, + 1);
2738-
tcp_out(conn, ACK);
2739-
next = TCP_CLOSE_WAIT;
2740-
verdict = NET_OK;
2741-
break;
2742-
} else if (th && FL(&fl, ==, (FIN | ACK | PSH),
2743-
th_seq(th) == conn->ack)) {
27442725
if (len) {
27452726
verdict = tcp_data_get(conn, pkt, &len);
27462727
if (verdict == NET_OK) {
@@ -2752,10 +2733,27 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
27522733
}
27532734

27542735
conn_ack(conn, + len + 1);
2755-
tcp_out(conn, FIN | ACK);
2756-
conn_seq(conn, + 1);
2757-
next = TCP_LAST_ACK;
2758-
tcp_setup_last_ack_timer(conn);
2736+
2737+
if (FL(&fl, &, ACK)) {
2738+
acked = true;
2739+
2740+
if (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0) {
2741+
uint32_t len_acked = th_ack(th) - conn->seq;
2742+
2743+
conn_seq(conn, + len_acked);
2744+
}
2745+
}
2746+
2747+
if (acked) {
2748+
tcp_out(conn, FIN | ACK);
2749+
conn_seq(conn, + 1);
2750+
tcp_setup_last_ack_timer(conn);
2751+
next = TCP_LAST_ACK;
2752+
} else {
2753+
tcp_out(conn, ACK);
2754+
next = TCP_CLOSE_WAIT;
2755+
}
2756+
27592757
break;
27602758
}
27612759

0 commit comments

Comments
 (0)