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:
parent
e8cc3c6194
commit
458cfb9994
@ -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];
|
msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
|
||||||
mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE);
|
mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
_gnrc_tcp_fsm_state_t state = 0;
|
||||||
|
|
||||||
/* Lock the TCB for this function call */
|
/* Lock the TCB for this function call */
|
||||||
mutex_lock(&(tcb->function_lock));
|
mutex_lock(&(tcb->function_lock));
|
||||||
|
|
||||||
/* TCB is already connected: Return -EISCONN */
|
/* 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));
|
mutex_unlock(&(tcb->function_lock));
|
||||||
TCP_DEBUG_ERROR("-EISCONN: TCB already connected.");
|
TCP_DEBUG_ERROR("-EISCONN: TCB already connected.");
|
||||||
TCP_DEBUG_LEAVE;
|
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 */
|
/* Wait until a connection was established or closed */
|
||||||
while (ret >= 0 && tcb->state != FSM_STATE_CLOSED && tcb->state != FSM_STATE_ESTABLISHED &&
|
state = _gnrc_tcp_fsm_get_state(tcb);
|
||||||
tcb->state != FSM_STATE_CLOSE_WAIT) {
|
while (ret >= 0 && state != FSM_STATE_CLOSED && state != FSM_STATE_ESTABLISHED &&
|
||||||
|
state != FSM_STATE_CLOSE_WAIT) {
|
||||||
mbox_get(&mbox, &msg);
|
mbox_get(&mbox, &msg);
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case MSG_TYPE_NOTIFY_USER:
|
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
|
/* 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
|
* send SYN+ACK we received upon entering SYN_RCVD is never acknowledged
|
||||||
* by the peer. */
|
* 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);
|
_unsched_mbox(&tcb->event_misc);
|
||||||
_sched_connection_timeout(&tcb->event_misc, &mbox);
|
_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:
|
default:
|
||||||
TCP_DEBUG_ERROR("Received unexpected message.");
|
TCP_DEBUG_ERROR("Received unexpected message.");
|
||||||
}
|
}
|
||||||
|
state = _gnrc_tcp_fsm_get_state(tcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
_gnrc_tcp_fsm_set_mbox(tcb, NULL);
|
_gnrc_tcp_fsm_set_mbox(tcb, NULL);
|
||||||
_unsched_mbox(&tcb->event_misc);
|
_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.");
|
TCP_DEBUG_ERROR("-ECONNREFUSED: Connection refused by peer.");
|
||||||
ret = -ECONNREFUSED;
|
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;
|
uint32_t probe_timeout_duration_ms = 0;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
bool probing_mode = false;
|
bool probing_mode = false;
|
||||||
|
_gnrc_tcp_fsm_state_t state = 0;
|
||||||
|
|
||||||
/* Lock the TCB for this function call */
|
/* Lock the TCB for this function call */
|
||||||
mutex_lock(&(tcb->function_lock));
|
mutex_lock(&(tcb->function_lock));
|
||||||
|
|
||||||
/* Check if connection is in a valid state */
|
/* 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));
|
mutex_unlock(&(tcb->function_lock));
|
||||||
TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected.");
|
TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected.");
|
||||||
TCP_DEBUG_LEAVE;
|
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 */
|
/* Loop until something was sent and acked */
|
||||||
while (ret == 0 || tcb->pkt_retransmit != NULL) {
|
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 */
|
/* 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.");
|
TCP_DEBUG_ERROR("-ECONNRESET: Connection was reset by peer.");
|
||||||
ret = -ECONNRESET;
|
ret = -ECONNRESET;
|
||||||
break;
|
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);
|
mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE);
|
||||||
evtimer_mbox_event_t event_user_timeout;
|
evtimer_mbox_event_t event_user_timeout;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
|
_gnrc_tcp_fsm_state_t state = 0;
|
||||||
|
|
||||||
/* Lock the TCB for this function call */
|
/* Lock the TCB for this function call */
|
||||||
mutex_lock(&(tcb->function_lock));
|
mutex_lock(&(tcb->function_lock));
|
||||||
|
|
||||||
/* Check if connection is in a valid state */
|
/* Check if connection is in a valid state */
|
||||||
if (tcb->state != FSM_STATE_ESTABLISHED && tcb->state != FSM_STATE_FIN_WAIT_1 &&
|
state = _gnrc_tcp_fsm_get_state(tcb);
|
||||||
tcb->state != FSM_STATE_FIN_WAIT_2 && tcb->state != FSM_STATE_CLOSE_WAIT) {
|
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));
|
mutex_unlock(&(tcb->function_lock));
|
||||||
TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected.");
|
TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected.");
|
||||||
TCP_DEBUG_LEAVE;
|
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. */
|
/* 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. */
|
/* 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);
|
ret = _gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len);
|
||||||
mutex_unlock(&(tcb->function_lock));
|
mutex_unlock(&(tcb->function_lock));
|
||||||
TCP_DEBUG_LEAVE;
|
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 */
|
/* Processing loop */
|
||||||
while (ret == 0) {
|
while (ret == 0) {
|
||||||
/* Check if the connections state is closed. If so, a reset was received */
|
/* 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.");
|
TCP_DEBUG_ERROR("-ECONNRESET: Connection was reset by peer.");
|
||||||
ret = -ECONNRESET;
|
ret = -ECONNRESET;
|
||||||
break;
|
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);
|
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 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,12 +740,14 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb)
|
|||||||
msg_t msg;
|
msg_t msg;
|
||||||
msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
|
msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
|
||||||
mbox_t mbox = MBOX_INIT(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 */
|
/* Lock the TCB for this function call */
|
||||||
mutex_lock(&(tcb->function_lock));
|
mutex_lock(&(tcb->function_lock));
|
||||||
|
|
||||||
/* Return if connection is closed */
|
/* 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));
|
mutex_unlock(&(tcb->function_lock));
|
||||||
TCP_DEBUG_LEAVE;
|
TCP_DEBUG_LEAVE;
|
||||||
return;
|
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);
|
_gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_CLOSE, NULL, NULL, 0);
|
||||||
|
|
||||||
/* Loop until the connection has been closed */
|
/* 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);
|
mbox_get(&mbox, &msg);
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case MSG_TYPE_CONNECTION_TIMEOUT:
|
case MSG_TYPE_CONNECTION_TIMEOUT:
|
||||||
@ -764,6 +779,7 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb)
|
|||||||
default:
|
default:
|
||||||
TCP_DEBUG_ERROR("Received unexpected message.");
|
TCP_DEBUG_ERROR("Received unexpected message.");
|
||||||
}
|
}
|
||||||
|
state = _gnrc_tcp_fsm_get_state(tcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
@ -780,7 +796,7 @@ void gnrc_tcp_abort(gnrc_tcp_tcb_t *tcb)
|
|||||||
|
|
||||||
/* Lock the TCB for this function call */
|
/* Lock the TCB for this function call */
|
||||||
mutex_lock(&(tcb->function_lock));
|
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 */
|
/* Call FSM ABORT event */
|
||||||
_gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_ABORT, NULL, NULL, 0);
|
_gnrc_tcp_fsm(tcb, FSM_EVENT_CALL_ABORT, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,8 @@ static int _receive(gnrc_pktsnip_t *pkt)
|
|||||||
if (ip->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) {
|
if (ip->type == GNRC_NETTYPE_IPV6 && tcb->address_family == AF_INET6) {
|
||||||
/* If SYN is set, a connection is listening on that port ... */
|
/* If SYN is set, a connection is listening on that port ... */
|
||||||
ipv6_addr_t *tmp_addr = NULL;
|
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 */
|
/* ... and local addr is unspec or pre configured */
|
||||||
tmp_addr = &((ipv6_hdr_t *)ip->data)->dst;
|
tmp_addr = &((ipv6_hdr_t *)ip->data)->dst;
|
||||||
if (ipv6_addr_equal((ipv6_addr_t *) tcb->local_addr, (ipv6_addr_t *) tmp_addr) ||
|
if (ipv6_addr_equal((ipv6_addr_t *) tcb->local_addr, (ipv6_addr_t *) tmp_addr) ||
|
||||||
|
@ -971,3 +971,13 @@ void _gnrc_tcp_fsm_set_mbox(gnrc_tcp_tcb_t *tcb, mbox_t *mbox)
|
|||||||
mutex_unlock(&(tcb->fsm_lock));
|
mutex_unlock(&(tcb->fsm_lock));
|
||||||
TCP_DEBUG_LEAVE;
|
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;
|
||||||
|
}
|
||||||
|
@ -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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user