net: tcp: Make sure ACK timer is not run if cancelled
We must not let ACK timer to run if we have already cancelled it. So keep track that the timer is cancelled and refuse to run it if it was indeed cancelled. The reason why the timer might be run in this case is because the timer might be scheduled to be triggered after which one cannot cancel it. Change-Id: I1c8b8cee72bc7a644e02db154d9d009b8d98ade2 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
137e4e7256
commit
1bf14853aa
2 changed files with 23 additions and 5 deletions
|
@ -1173,11 +1173,21 @@ int net_context_connect(struct net_context *context,
|
|||
|
||||
#define ACK_TIMEOUT MSEC_PER_SEC
|
||||
|
||||
static void ack_timer_cancel(struct net_tcp *tcp)
|
||||
{
|
||||
tcp->ack_timer_cancelled = true;
|
||||
k_delayed_work_cancel(&tcp->ack_timer);
|
||||
}
|
||||
|
||||
static void ack_timeout(struct k_work *work)
|
||||
{
|
||||
/* This means that we did not receive ACK response in time. */
|
||||
struct net_tcp *tcp = CONTAINER_OF(work, struct net_tcp, ack_timer);
|
||||
|
||||
if (tcp->ack_timer_cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_DBG("Did not receive ACK in %dms", ACK_TIMEOUT);
|
||||
|
||||
send_reset(tcp->context, &tcp->context->remote);
|
||||
|
@ -1281,10 +1291,13 @@ NET_CONN_CB(tcp_syn_rcvd)
|
|||
* if the SYN is sent more than once. So we need to cancel
|
||||
* any pending timers.
|
||||
*/
|
||||
k_delayed_work_cancel(&tcp->ack_timer);
|
||||
ack_timer_cancel(tcp);
|
||||
|
||||
k_delayed_work_init(&tcp->ack_timer, ack_timeout);
|
||||
k_delayed_work_submit(&tcp->ack_timer, ACK_TIMEOUT);
|
||||
|
||||
tcp->ack_timer_cancelled = false;
|
||||
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1305,7 @@ NET_CONN_CB(tcp_syn_rcvd)
|
|||
* If we receive RST, we go back to LISTEN state.
|
||||
*/
|
||||
if (NET_TCP_FLAGS(pkt) == NET_TCP_RST) {
|
||||
k_delayed_work_cancel(&tcp->ack_timer);
|
||||
ack_timer_cancel(tcp);
|
||||
|
||||
net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
|
||||
|
||||
|
@ -1316,7 +1329,7 @@ NET_CONN_CB(tcp_syn_rcvd)
|
|||
* So if we are not in SYN_RCVD state, then it is an error.
|
||||
*/
|
||||
if (net_tcp_get_state(tcp) != NET_TCP_SYN_RCVD) {
|
||||
k_delayed_work_cancel(&tcp->ack_timer);
|
||||
ack_timer_cancel(tcp);
|
||||
NET_DBG("Not in SYN_RCVD state, sending RST");
|
||||
goto reset;
|
||||
}
|
||||
|
@ -1438,7 +1451,7 @@ NET_CONN_CB(tcp_syn_rcvd)
|
|||
net_tcp_change_state(new_context->tcp, NET_TCP_ESTABLISHED);
|
||||
net_context_set_state(new_context, NET_CONTEXT_CONNECTED);
|
||||
|
||||
k_delayed_work_cancel(&tcp->ack_timer);
|
||||
ack_timer_cancel(tcp);
|
||||
|
||||
context->tcp->accept_cb(new_context,
|
||||
&new_context->remote,
|
||||
|
|
|
@ -134,8 +134,13 @@ struct net_tcp {
|
|||
uint32_t fin_sent : 1;
|
||||
/* An inbound FIN packet has been received */
|
||||
uint32_t fin_rcvd : 1;
|
||||
/* Tells if ack timer has been already cancelled. It might happen
|
||||
* that the timer is executed even if it is cancelled, this is because
|
||||
* of various timing issues when timer is scheduled to run.
|
||||
*/
|
||||
uint32_t ack_timer_cancelled : 1;
|
||||
/** Remaining bits in this uint32_t */
|
||||
uint32_t _padding : 12;
|
||||
uint32_t _padding : 11;
|
||||
|
||||
/** Accept callback to be called when the connection has been
|
||||
* established.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue