1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

gnrc_tcp: fix data race on fsm status

This commit is contained in:
Simon Brummer 2021-04-04 17:31:42 +02:00
parent e8cc3c6194
commit 458cfb9994
4 changed files with 52 additions and 16 deletions

View File

@ -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);
}

View File

@ -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) ||

View File

@ -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;
}

View File

@ -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