net: Fix task block when devif_send fails.

When a task needs to send data, a callback is allocated and the
transmission is happening in a worker task through devif_send.
Synchronization between the two tasks (sender & worker) is
achieved by a semaphore.

If devif_send fails, this semaphore was never posted, leaving
the sending task blocked indefinitely. This commit fixes this
by checking the return code of netif_send, and posting this
semaphore in case of failure.

Polling then stops, and execution is resumed on the sending
task.
This commit is contained in:
Fotis Panagiotopoulos 2023-05-30 00:26:19 +03:00 committed by Xiang Xiao
parent 5606e77ee0
commit 3c54d82d81
8 changed files with 74 additions and 45 deletions

View File

@ -106,11 +106,13 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
{
/* Copy the packet data into the device packet buffer and send it */
devif_send(dev, pstate->snd_buffer, pstate->snd_buflen, 0);
int ret = devif_send(dev, pstate->snd_buffer,
pstate->snd_buflen, 0);
dev->d_len = dev->d_sndlen;
if (dev->d_sndlen == 0)
if (ret <= 0)
{
return flags;
pstate->snd_sent = ret;
goto end_wait;
}
pstate->snd_sent = pstate->snd_buflen;
@ -122,6 +124,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
}
}
end_wait:
/* Don't allow any further call backs. */
pstate->snd_cb->flags = 0;

View File

@ -432,31 +432,40 @@ uint16_t devif_conn_event(FAR struct net_driver_s *dev, uint16_t flags,
uint16_t devif_dev_event(FAR struct net_driver_s *dev, uint16_t flags);
/****************************************************************************
* Send data on the current connection.
* Name: devif_send
*
* This function is used to send out a single segment of TCP data. Only
* socket logic that have been invoked by the lower level for event
* processing can send data.
* Description:
* Send data on the current connection.
*
* The amount of data that actually is sent out after a call to this
* function is determined by the maximum amount of data TCP allows. The
* network will automatically crop the data so that only the appropriate
* amount of data is sent. The mss field of the TCP connection structure
* can be used to determine the amount of data that actually will be sent.
* This function is used to send out a single segment of TCP data. Only
* socket logic that have been invoked by the lower level for event
* processing can send data.
*
* The amount of data that actually is sent out after a call to this
* function is determined by the maximum amount of data TCP allows. The
* network will automatically crop the data so that only the appropriate
* amount of data is sent. The mss field of the TCP connection structure
* can be used to determine the amount of data that actually will be sent.
*
* Note: This function does not guarantee that the sent data will
* arrive at the destination. If the data is lost in the network, the
* TCP socket layer will be invoked with the TCP_REXMIT flag set. The
* socket layer will then have to resend the data using this function.
*
* data A pointer to the data which is to be sent.
* Input Parameters:
* dev - The network device state structure associated with the network
* device that initiated the callback event.
* buf - A pointer to the data which is to be sent.
* len - The maximum amount of data bytes to be sent.
* offset - Offset of data in buffer.
*
* len The maximum amount of data bytes to be sent.
* Returned Value:
* The amount of data sent, or negated ERRNO in case of failure.
*
****************************************************************************/
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset);
int devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset);
/****************************************************************************
* Name: devif_iob_send
@ -475,9 +484,9 @@ void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
#ifdef CONFIG_MM_IOB
struct iob_s;
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
unsigned int len, unsigned int offset,
unsigned int target_offset);
int devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
unsigned int len, unsigned int offset,
unsigned int target_offset);
#endif
/****************************************************************************

View File

@ -53,9 +53,9 @@
*
****************************************************************************/
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
unsigned int len, unsigned int offset,
unsigned int target_offset)
int devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
unsigned int len, unsigned int offset,
unsigned int target_offset)
{
int ret;
@ -105,10 +105,11 @@ void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
lib_dumpbuffer("devif_iob_send", dev->d_appdata, len);
#endif
return;
return dev->d_sndlen;
errout:
nerr("ERROR: devif_iob_send error: %d\n", ret);
return ret;
}
#endif /* CONFIG_MM_IOB */

View File

@ -66,8 +66,8 @@
*
****************************************************************************/
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset)
int devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset)
{
int ret;
@ -113,8 +113,9 @@ void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
dev->d_sndlen = len;
return;
return dev->d_sndlen;
errout:
nerr("ERROR: devif_send error: %d\n", ret);
return ret;
}

View File

@ -105,10 +105,12 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
{
/* Copy the packet data into the device packet buffer and send it */
devif_send(dev, pstate->snd_buffer, pstate->snd_buflen, 0);
if (dev->d_sndlen == 0)
int ret = devif_send(dev, pstate->snd_buffer,
pstate->snd_buflen, 0);
if (ret <= 0)
{
return flags;
pstate->snd_sent = ret;
goto end_wait;
}
pstate->snd_sent = pstate->snd_buflen;
@ -120,6 +122,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
IFF_SET_NOARP(dev->d_flags);
}
end_wait:
/* Don't allow any further call backs. */
pstate->snd_cb->flags = 0;

View File

@ -695,6 +695,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
FAR sq_entry_t *entry;
FAR sq_entry_t *next;
size_t sndlen;
int ret;
/* According to RFC 6298 (5.4), retransmit the earliest segment
* that has not been acknowledged by the TCP receiver.
@ -742,9 +743,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb));
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
0, tcpip_hdrsize(conn));
if (dev->d_sndlen == 0)
ret = devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
0, tcpip_hdrsize(conn));
if (ret <= 0)
{
return flags;
}
@ -1005,6 +1006,7 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
if (TCP_SEQ_LT(seq, snd_wnd_edge))
{
uint32_t remaining_snd_wnd;
int ret;
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
if (sndlen > conn->mss)
@ -1048,9 +1050,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* won't actually happen until the polling cycle completes).
*/
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
TCP_WBSENT(wrb), tcpip_hdrsize(conn));
if (dev->d_sndlen == 0)
ret = devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
TCP_WBSENT(wrb), tcpip_hdrsize(conn));
if (ret <= 0)
{
return flags;
}

View File

@ -126,6 +126,7 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
{
FAR struct send_s *pstate = pvpriv;
FAR struct tcp_conn_s *conn;
int ret;
DEBUGASSERT(pstate != NULL);
@ -283,8 +284,12 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
* happen until the polling cycle completes).
*/
devif_send(dev, &pstate->snd_buffer[pstate->snd_acked],
sndlen, tcpip_hdrsize(conn));
ret = devif_send(dev, &pstate->snd_buffer[pstate->snd_acked],
sndlen, tcpip_hdrsize(conn));
if (ret <= 0)
{
goto end_wait;
}
/* Continue waiting */
@ -365,11 +370,11 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
* happen until the polling cycle completes).
*/
devif_send(dev, &pstate->snd_buffer[pstate->snd_sent],
sndlen, tcpip_hdrsize(conn));
if (dev->d_sndlen == 0)
ret = devif_send(dev, &pstate->snd_buffer[pstate->snd_sent],
sndlen, tcpip_hdrsize(conn));
if (ret <= 0)
{
return flags;
goto end_wait;
}
/* Update the amount of data sent (but not necessarily ACKed) */

View File

@ -194,11 +194,12 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
{
/* Copy the user data into d_appdata and send it */
devif_send(dev, pstate->st_buffer,
pstate->st_buflen, udpip_hdrsize(pstate->st_conn));
if (dev->d_sndlen == 0)
int ret = devif_send(dev, pstate->st_buffer, pstate->st_buflen,
udpip_hdrsize(pstate->st_conn));
if (ret <= 0)
{
return flags;
pstate->st_sndlen = ret;
goto end_wait;
}
#ifdef NEED_IPDOMAIN_SUPPORT
@ -214,6 +215,8 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
pstate->st_sndlen = pstate->st_buflen;
}
end_wait:
/* Don't allow any further call backs. */
pstate->st_cb->flags = 0;