diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c index 495cfd77ef..40a4586d17 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c @@ -100,12 +100,14 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); int ret = 0; + _gnrc_tcp_fsm_state_t state = 0; /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); /* TCB is already connected: Return -EISCONN */ - if (tcb->state != FSM_STATE_CLOSED) { + state = _gnrc_tcp_fsm_get_state(tcb); + if (state != FSM_STATE_CLOSED) { mutex_unlock(&(tcb->function_lock)); TCP_DEBUG_ERROR("-EISCONN: TCB already connected."); TCP_DEBUG_LEAVE; @@ -177,8 +179,9 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, } /* Wait until a connection was established or closed */ - while (ret >= 0 && tcb->state != FSM_STATE_CLOSED && tcb->state != FSM_STATE_ESTABLISHED && - tcb->state != FSM_STATE_CLOSE_WAIT) { + state = _gnrc_tcp_fsm_get_state(tcb); + while (ret >= 0 && state != FSM_STATE_CLOSED && state != FSM_STATE_ESTABLISHED && + state != FSM_STATE_CLOSE_WAIT) { mbox_get(&mbox, &msg); switch (msg.type) { case MSG_TYPE_NOTIFY_USER: @@ -187,7 +190,8 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, /* Setup a timeout to be able to revert back to LISTEN state, in case the * send SYN+ACK we received upon entering SYN_RCVD is never acknowledged * by the peer. */ - if ((tcb->state == FSM_STATE_SYN_RCVD) && (tcb->status & STATUS_PASSIVE)) { + state = _gnrc_tcp_fsm_get_state(tcb); + if ((state == FSM_STATE_SYN_RCVD) && (tcb->status & STATUS_PASSIVE)) { _unsched_mbox(&tcb->event_misc); _sched_connection_timeout(&tcb->event_misc, &mbox); } @@ -214,12 +218,13 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, default: TCP_DEBUG_ERROR("Received unexpected message."); } + state = _gnrc_tcp_fsm_get_state(tcb); } /* Cleanup */ _gnrc_tcp_fsm_set_mbox(tcb, NULL); _unsched_mbox(&tcb->event_misc); - if (tcb->state == FSM_STATE_CLOSED && ret == 0) { + if (state == FSM_STATE_CLOSED && ret == 0) { TCP_DEBUG_ERROR("-ECONNREFUSED: Connection refused by peer."); ret = -ECONNREFUSED; } @@ -498,12 +503,14 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, uint32_t probe_timeout_duration_ms = 0; ssize_t ret = 0; bool probing_mode = false; + _gnrc_tcp_fsm_state_t state = 0; /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); /* Check if connection is in a valid state */ - if (tcb->state != FSM_STATE_ESTABLISHED && tcb->state != FSM_STATE_CLOSE_WAIT) { + state = _gnrc_tcp_fsm_get_state(tcb); + if (state != FSM_STATE_ESTABLISHED && state != FSM_STATE_CLOSE_WAIT) { mutex_unlock(&(tcb->function_lock)); TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected."); TCP_DEBUG_LEAVE; @@ -523,8 +530,10 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, /* Loop until something was sent and acked */ while (ret == 0 || tcb->pkt_retransmit != NULL) { + state = _gnrc_tcp_fsm_get_state(tcb); + /* Check if the connections state is closed. If so, a reset was received */ - if (tcb->state == FSM_STATE_CLOSED) { + if (state == FSM_STATE_CLOSED) { TCP_DEBUG_ERROR("-ECONNRESET: Connection was reset by peer."); ret = -ECONNRESET; break; @@ -621,13 +630,15 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); evtimer_mbox_event_t event_user_timeout; ssize_t ret = 0; + _gnrc_tcp_fsm_state_t state = 0; /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); /* Check if connection is in a valid state */ - if (tcb->state != FSM_STATE_ESTABLISHED && tcb->state != FSM_STATE_FIN_WAIT_1 && - tcb->state != FSM_STATE_FIN_WAIT_2 && tcb->state != FSM_STATE_CLOSE_WAIT) { + state = _gnrc_tcp_fsm_get_state(tcb); + if (state != FSM_STATE_ESTABLISHED && state != FSM_STATE_FIN_WAIT_1 && + state != FSM_STATE_FIN_WAIT_2 && state != FSM_STATE_CLOSE_WAIT) { mutex_unlock(&(tcb->function_lock)); TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected."); TCP_DEBUG_LEAVE; @@ -636,7 +647,7 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, /* If FIN was received (CLOSE_WAIT), no further data can be received. */ /* Copy received data into given buffer and return number of bytes. Can be zero. */ - if (tcb->state == FSM_STATE_CLOSE_WAIT) { + if (state == FSM_STATE_CLOSE_WAIT) { ret = _gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len); mutex_unlock(&(tcb->function_lock)); TCP_DEBUG_LEAVE; @@ -669,7 +680,8 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, /* Processing loop */ while (ret == 0) { /* Check if the connections state is closed. If so, a reset was received */ - if (tcb->state == FSM_STATE_CLOSED) { + state = _gnrc_tcp_fsm_get_state(tcb); + if (state == FSM_STATE_CLOSED) { TCP_DEBUG_ERROR("-ECONNRESET: Connection was reset by peer."); ret = -ECONNRESET; break; @@ -679,7 +691,7 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, ret = _gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len); /* If FIN was received (CLOSE_WAIT), no further data can be received. Leave event loop */ - if (tcb->state == FSM_STATE_CLOSE_WAIT) { + if (state == FSM_STATE_CLOSE_WAIT) { break; } @@ -728,12 +740,14 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) msg_t msg; msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); + _gnrc_tcp_fsm_state_t state = 0; /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); /* Return if connection is closed */ - if (tcb->state == FSM_STATE_CLOSED) { + state = _gnrc_tcp_fsm_get_state(tcb); + if (state == FSM_STATE_CLOSED) { mutex_unlock(&(tcb->function_lock)); TCP_DEBUG_LEAVE; return; @@ -749,7 +763,8 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) _gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_CLOSE, NULL, NULL, 0); /* Loop until the connection has been closed */ - while (tcb->state != FSM_STATE_CLOSED) { + state = _gnrc_tcp_fsm_get_state(tcb); + while (state != FSM_STATE_CLOSED) { mbox_get(&mbox, &msg); switch (msg.type) { case MSG_TYPE_CONNECTION_TIMEOUT: @@ -764,6 +779,7 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) default: TCP_DEBUG_ERROR("Received unexpected message."); } + state = _gnrc_tcp_fsm_get_state(tcb); } /* Cleanup */ @@ -780,7 +796,7 @@ void gnrc_tcp_abort(gnrc_tcp_tcb_t *tcb) /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); - if (tcb->state != FSM_STATE_CLOSED) { + if (_gnrc_tcp_fsm_get_state(tcb) != FSM_STATE_CLOSED) { /* Call FSM ABORT event */ _gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_ABORT, NULL, NULL, 0); } diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c index 9ea4b58d6d..d05a3ea400 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c @@ -217,7 +217,8 @@ static int _receive(gnrc_pktsnip_t *pkt) if (ip->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) { /* If SYN is set, a connection is listening on that port ... */ ipv6_addr_t *tmp_addr = NULL; - if (syn && tcb->local_port == dst && tcb->state == FSM_STATE_LISTEN) { + _gnrc_tcp_fsm_state_t state = _gnrc_tcp_fsm_get_state(tcb); + if (syn && tcb->local_port == dst && state == FSM_STATE_LISTEN) { /* ... and local addr is unspec or pre configured */ tmp_addr = &((ipv6_hdr_t *)ip->data)->dst; if (ipv6_addr_equal((ipv6_addr_t *) tcb->local_addr, (ipv6_addr_t *) tmp_addr) || diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c index 7e311da9bc..04a03f990f 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c @@ -971,3 +971,13 @@ void _gnrc_tcp_fsm_set_mbox(gnrc_tcp_tcb_t *tcb, mbox_t *mbox) mutex_unlock(&(tcb->fsm_lock)); TCP_DEBUG_LEAVE; } + +_gnrc_tcp_fsm_state_t _gnrc_tcp_fsm_get_state(gnrc_tcp_tcb_t *tcb) +{ + TCP_DEBUG_ENTER; + mutex_lock(&(tcb->fsm_lock)); + _gnrc_tcp_fsm_state_t res = tcb->state; + mutex_unlock(&(tcb->fsm_lock)); + TCP_DEBUG_LEAVE; + return res; +} diff --git a/sys/net/gnrc/transport_layer/tcp/include/gnrc_tcp_fsm.h b/sys/net/gnrc/transport_layer/tcp/include/gnrc_tcp_fsm.h index 6260264af6..4f8f928677 100644 --- a/sys/net/gnrc/transport_layer/tcp/include/gnrc_tcp_fsm.h +++ b/sys/net/gnrc/transport_layer/tcp/include/gnrc_tcp_fsm.h @@ -88,6 +88,15 @@ int _gnrc_tcp_fsm(gnrc_tcp_tcb_t *tcb, _gnrc_tcp_fsm_event_t event, */ void _gnrc_tcp_fsm_set_mbox(gnrc_tcp_tcb_t *tcb, mbox_t *mbox); +/** + * @brief Get latest FSM state from given TCB. + * + * @param[in] tcb TCB to get state from. + * + * @return Current TCB state. + */ +_gnrc_tcp_fsm_state_t _gnrc_tcp_fsm_get_state(gnrc_tcp_tcb_t *tcb); + #ifdef __cplusplus } #endif