Skip to content

Commit 693c666

Browse files
committed
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 <jukka.rissanen@nordicsemi.no>
1 parent 1f75fc1 commit 693c666

File tree

3 files changed

+43
-22
lines changed

3 files changed

+43
-22
lines changed

subsys/net/ip/net_context.c

Lines changed: 3 additions & 3 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);
@@ -777,7 +777,7 @@ int net_context_put_all(struct net_if *iface)
777777
contexts[i].send_cb = NULL;
778778

779779
/* net_tcp_put() will handle decrementing refcount on stack's behalf */
780-
net_tcp_put(&contexts[i]);
780+
net_tcp_put(&contexts[i], true);
781781

782782
/* Decrement refcount on user app's behalf */
783783
net_context_unref(&contexts[i]);

subsys/net/ip/tcp.c

Lines changed: 34 additions & 17 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

@@ -3715,24 +3715,41 @@ int net_tcp_put(struct net_context *context)
37153715

37163716
/* How long to wait until all the data has been sent?
37173717
*/
3718-
k_work_reschedule_for_queue(&tcp_work_q,
3719-
&conn->send_data_timer,
3720-
K_MSEC(TCP_RTO_MS));
3718+
if (!force_close) {
3719+
k_work_reschedule_for_queue(&tcp_work_q,
3720+
&conn->send_data_timer,
3721+
K_MSEC(TCP_RTO_MS));
3722+
} else {
3723+
k_work_cancel_delayable(&conn->send_data_timer);
3724+
3725+
keep_alive_timer_stop(conn);
3726+
tcp_conn_close(conn, -ENETRESET);
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+
"not disposing yet (waiting %dms)",
3733+
conn, "active", tcp_max_timeout_ms);
3734+
k_work_reschedule_for_queue(&tcp_work_q,
3735+
&conn->fin_timer,
3736+
FIN_TIMEOUT);
37283737

3729-
tcp_out(conn, FIN | ACK);
3730-
conn_seq(conn, + 1);
3731-
tcp_setup_retransmission(conn);
3738+
tcp_out(conn, FIN | ACK);
3739+
conn_seq(conn, + 1);
3740+
tcp_setup_retransmission(conn);
37323741

3733-
conn_state(conn, TCP_FIN_WAIT_1);
3742+
conn_state(conn, TCP_FIN_WAIT_1);
37343743

3735-
keep_alive_timer_stop(conn);
3744+
keep_alive_timer_stop(conn);
3745+
} else {
3746+
NET_DBG("[%p] TCP connection in %s close, "
3747+
"disposing immediately",
3748+
conn, "active");
3749+
3750+
keep_alive_timer_stop(conn);
3751+
tcp_conn_close(conn, -ENETRESET);
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)