Skip to content

Commit 1f5c285

Browse files
jukkarcfriedt
authored andcommitted
net: tcp: Allow immediate connection tear down
If the network interface goes down, then we do not have any time to tear down TCP connection gracefully because there is no more a connection to send data to. In this case the TCP connection is forcefully closed without going into FIN_WAIT_1 state. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent a0eb093 commit 1f5c285

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

subsys/net/ip/net_context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto,
650650
!net_if_is_ip_offloaded(net_if_get_default()) &&
651651
proto == IPPROTO_TCP) {
652652
/* Free the TCP context that we allocated earlier */
653-
net_tcp_put(&contexts[i]);
653+
net_tcp_put(&contexts[i], false);
654654
}
655655

656656
return ret;
@@ -735,7 +735,7 @@ int net_context_put(struct net_context *context)
735735
context->send_cb = NULL;
736736

737737
/* net_tcp_put() will handle decrementing refcount on stack's behalf */
738-
net_tcp_put(context);
738+
net_tcp_put(context, false);
739739

740740
/* Decrement refcount on user app's behalf */
741741
net_context_unref(context);

subsys/net/ip/tcp.c

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,7 +3137,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
31373137
* the TCP context and put the connection into
31383138
* active close (TCP_FIN_WAIT_1).
31393139
*/
3140-
net_tcp_put(conn->context);
3140+
net_tcp_put(conn->context, false);
31413141
break;
31423142
}
31433143

@@ -3690,7 +3690,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
36903690
}
36913691

36923692
/* Active connection close: send FIN and go to FIN_WAIT_1 state */
3693-
int net_tcp_put(struct net_context *context)
3693+
int net_tcp_put(struct net_context *context, bool force_close)
36943694
{
36953695
struct tcp *conn = context->tcp;
36963696

@@ -3713,26 +3713,43 @@ int net_tcp_put(struct net_context *context)
37133713
conn->send_data_total);
37143714
conn->in_close = true;
37153715

3716-
/* How long to wait until all the data has been sent?
3717-
*/
3718-
k_work_reschedule_for_queue(&tcp_work_q,
3719-
&conn->send_data_timer,
3720-
K_MSEC(TCP_RTO_MS));
3716+
if (force_close) {
3717+
k_work_cancel_delayable(&conn->send_data_timer);
3718+
3719+
keep_alive_timer_stop(conn);
3720+
tcp_conn_close(conn, -ENETRESET);
3721+
} else {
3722+
/* How long to wait until all the data has been sent?
3723+
*/
3724+
k_work_reschedule_for_queue(&tcp_work_q,
3725+
&conn->send_data_timer,
3726+
K_MSEC(TCP_RTO_MS));
3727+
}
3728+
37213729
} else {
3722-
NET_DBG("[%p] TCP connection in %s close, "
3723-
"not disposing yet (waiting %dms)",
3724-
conn, "active", tcp_max_timeout_ms);
3725-
k_work_reschedule_for_queue(&tcp_work_q,
3726-
&conn->fin_timer,
3727-
FIN_TIMEOUT);
3730+
if (force_close) {
3731+
NET_DBG("[%p] TCP connection in %s close, "
3732+
"disposing immediately",
3733+
conn, "forced");
37283734

3729-
tcp_out(conn, FIN | ACK);
3730-
conn_seq(conn, + 1);
3731-
tcp_setup_retransmission(conn);
3735+
keep_alive_timer_stop(conn);
3736+
tcp_conn_close(conn, -ENETRESET);
3737+
} else {
3738+
NET_DBG("[%p] TCP connection in %s close, "
3739+
"not disposing yet (waiting %dms)",
3740+
conn, "active", tcp_max_timeout_ms);
3741+
k_work_reschedule_for_queue(&tcp_work_q,
3742+
&conn->fin_timer,
3743+
FIN_TIMEOUT);
3744+
3745+
tcp_out(conn, FIN | ACK);
3746+
conn_seq(conn, + 1);
3747+
tcp_setup_retransmission(conn);
37323748

3733-
conn_state(conn, TCP_FIN_WAIT_1);
3749+
conn_state(conn, TCP_FIN_WAIT_1);
37343750

3735-
keep_alive_timer_stop(conn);
3751+
keep_alive_timer_stop(conn);
3752+
}
37363753
}
37373754
} else if (conn->in_connect) {
37383755
conn->in_connect = false;
@@ -4411,7 +4428,7 @@ enum net_verdict tp_input(struct net_conn *net_conn,
44114428
if (is("CLOSE2", tp->op)) {
44124429
struct tcp *conn =
44134430
(void *)sys_slist_peek_head(&tcp_conns);
4414-
net_tcp_put(conn->context);
4431+
net_tcp_put(conn->context, false);
44154432
}
44164433
if (is("RECV", tp->op)) {
44174434
#define HEXSTR_SIZE 64

subsys/net/ip/tcp_internal.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,19 @@ static inline int net_tcp_update_recv_wnd(struct net_context *context,
354354
* @brief Close and delete the TCP connection for the net_context
355355
*
356356
* @param context Network context
357+
* @param force_close If true, close the connection immediately. This is
358+
* used e.g., when network interface goes down and we cannot wait for proper
359+
* connection close procedure as we cannot send any packets anymore.
357360
*
358361
* @return 0 on success, < 0 on error
359362
*/
360363
#if defined(CONFIG_NET_NATIVE_TCP)
361-
int net_tcp_put(struct net_context *context);
364+
int net_tcp_put(struct net_context *context, bool force_close);
362365
#else
363-
static inline int net_tcp_put(struct net_context *context)
366+
static inline int net_tcp_put(struct net_context *context, bool force_close)
364367
{
365368
ARG_UNUSED(context);
369+
ARG_UNUSED(force_close);
366370

367371
return -EPROTONOSUPPORT;
368372
}

0 commit comments

Comments
 (0)