Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto,
!net_if_is_ip_offloaded(net_if_get_default()) &&
proto == IPPROTO_TCP) {
/* Free the TCP context that we allocated earlier */
net_tcp_put(&contexts[i]);
net_tcp_put(&contexts[i], false);
}

return ret;
Expand Down Expand Up @@ -735,7 +735,7 @@ int net_context_put(struct net_context *context)
context->send_cb = NULL;

/* net_tcp_put() will handle decrementing refcount on stack's behalf */
net_tcp_put(context);
net_tcp_put(context, false);

/* Decrement refcount on user app's behalf */
net_context_unref(context);
Expand Down
2 changes: 2 additions & 0 deletions subsys/net/ip/net_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL);
#include "net_private.h"
#include "ipv4.h"
#include "ipv6.h"
#include "tcp_internal.h"

#include "net_stats.h"

Expand Down Expand Up @@ -5761,6 +5762,7 @@ static void notify_iface_up(struct net_if *iface)

static void notify_iface_down(struct net_if *iface)
{
net_tcp_close_all_for_iface(iface);
net_if_flag_clear(iface, NET_IF_RUNNING);
net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface);
net_virtual_disable(iface);
Expand Down
77 changes: 58 additions & 19 deletions subsys/net/ip/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3137,7 +3137,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
* the TCP context and put the connection into
* active close (TCP_FIN_WAIT_1).
*/
net_tcp_put(conn->context);
net_tcp_put(conn->context, false);
break;
}

Expand Down Expand Up @@ -3690,7 +3690,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
}

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

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

/* How long to wait until all the data has been sent?
*/
k_work_reschedule_for_queue(&tcp_work_q,
&conn->send_data_timer,
K_MSEC(TCP_RTO_MS));
if (force_close) {
k_work_cancel_delayable(&conn->send_data_timer);

keep_alive_timer_stop(conn);
tcp_conn_close(conn, -ENETRESET);
} else {
/* How long to wait until all the data has been sent?
*/
k_work_reschedule_for_queue(&tcp_work_q,
&conn->send_data_timer,
K_MSEC(TCP_RTO_MS));
}

} else {
NET_DBG("[%p] TCP connection in %s close, "
"not disposing yet (waiting %dms)",
conn, "active", tcp_max_timeout_ms);
k_work_reschedule_for_queue(&tcp_work_q,
&conn->fin_timer,
FIN_TIMEOUT);
if (force_close) {
NET_DBG("[%p] TCP connection in %s close, "
"disposing immediately",
conn, "forced");

tcp_out(conn, FIN | ACK);
conn_seq(conn, + 1);
tcp_setup_retransmission(conn);
keep_alive_timer_stop(conn);
tcp_conn_close(conn, -ENETRESET);
} else {
NET_DBG("[%p] TCP connection in %s close, "
"not disposing yet (waiting %dms)",
conn, "active", tcp_max_timeout_ms);
k_work_reschedule_for_queue(&tcp_work_q,
&conn->fin_timer,
FIN_TIMEOUT);

tcp_out(conn, FIN | ACK);
conn_seq(conn, + 1);
tcp_setup_retransmission(conn);

conn_state(conn, TCP_FIN_WAIT_1);
conn_state(conn, TCP_FIN_WAIT_1);

keep_alive_timer_stop(conn);
keep_alive_timer_stop(conn);
}
}
} else if (conn->in_connect) {
conn->in_connect = false;
Expand Down Expand Up @@ -4411,7 +4428,7 @@ enum net_verdict tp_input(struct net_conn *net_conn,
if (is("CLOSE2", tp->op)) {
struct tcp *conn =
(void *)sys_slist_peek_head(&tcp_conns);
net_tcp_put(conn->context);
net_tcp_put(conn->context, false);
}
if (is("RECV", tp->op)) {
#define HEXSTR_SIZE 64
Expand Down Expand Up @@ -4734,6 +4751,28 @@ struct k_sem *net_tcp_conn_sem_get(struct net_context *context)
return &conn->connect_sem;
}

static void close_tcp_conn(struct tcp *conn, void *user_data)
{
struct net_if *iface = user_data;
struct net_context *context = conn->context;

if (!net_context_is_used(context)) {
return;
}

if (net_context_get_iface(context) != iface) {
return;
}

/* net_tcp_put() will handle decrementing refcount on stack's behalf */
net_tcp_put(context, true);
}

void net_tcp_close_all_for_iface(struct net_if *iface)
{
net_tcp_foreach(close_tcp_conn, iface);
}

void net_tcp_init(void)
{
int i;
Expand Down
26 changes: 24 additions & 2 deletions subsys/net/ip/tcp_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,19 @@ static inline int net_tcp_update_recv_wnd(struct net_context *context,
* @brief Close and delete the TCP connection for the net_context
*
* @param context Network context
* @param force_close If true, close the connection immediately. This is
* used e.g., when network interface goes down and we cannot wait for proper
* connection close procedure as we cannot send any packets anymore.
*
* @return 0 on success, < 0 on error
*/
#if defined(CONFIG_NET_NATIVE_TCP)
int net_tcp_put(struct net_context *context);
int net_tcp_put(struct net_context *context, bool force_close);
#else
static inline int net_tcp_put(struct net_context *context)
static inline int net_tcp_put(struct net_context *context, bool force_close)
{
ARG_UNUSED(context);
ARG_UNUSED(force_close);

return -EPROTONOSUPPORT;
}
Expand Down Expand Up @@ -490,6 +494,24 @@ static inline void net_tcp_conn_accepted(struct net_context *child_ctx)
}
#endif

/**
* @brief Close and unref all TCP context bound to an network interface.
*
* @details This releases all the TCP contexts that are bound to a specific
* network interface. It is not possible to send or receive data via those
* contexts after this call.
*
* @param iface The network interface to use to find out the bound contexts.
*/
#if defined(CONFIG_NET_NATIVE_TCP)
void net_tcp_close_all_for_iface(struct net_if *iface);
#else
static inline void net_tcp_close_all_for_iface(struct net_if *iface)
{
ARG_UNUSED(iface);
}
#endif

#ifdef __cplusplus
}
#endif
Expand Down