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:
parent
5606e77ee0
commit
3c54d82d81
@ -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 */
|
/* 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;
|
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;
|
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. */
|
/* Don't allow any further call backs. */
|
||||||
|
|
||||||
pstate->snd_cb->flags = 0;
|
pstate->snd_cb->flags = 0;
|
||||||
|
@ -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);
|
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
|
* Description:
|
||||||
* socket logic that have been invoked by the lower level for event
|
* Send data on the current connection.
|
||||||
* processing can send data.
|
|
||||||
*
|
*
|
||||||
* The amount of data that actually is sent out after a call to this
|
* This function is used to send out a single segment of TCP data. Only
|
||||||
* function is determined by the maximum amount of data TCP allows. The
|
* socket logic that have been invoked by the lower level for event
|
||||||
* network will automatically crop the data so that only the appropriate
|
* processing can send data.
|
||||||
* 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.
|
* 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
|
* Note: This function does not guarantee that the sent data will
|
||||||
* arrive at the destination. If the data is lost in the network, the
|
* 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
|
* 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.
|
* 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 devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
|
||||||
int len, unsigned int offset);
|
int len, unsigned int offset);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: devif_iob_send
|
* 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
|
#ifdef CONFIG_MM_IOB
|
||||||
struct iob_s;
|
struct iob_s;
|
||||||
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
|
int devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
|
||||||
unsigned int len, unsigned int offset,
|
unsigned int len, unsigned int offset,
|
||||||
unsigned int target_offset);
|
unsigned int target_offset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -53,9 +53,9 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
|
int devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
|
||||||
unsigned int len, unsigned int offset,
|
unsigned int len, unsigned int offset,
|
||||||
unsigned int target_offset)
|
unsigned int target_offset)
|
||||||
{
|
{
|
||||||
int ret;
|
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);
|
lib_dumpbuffer("devif_iob_send", dev->d_appdata, len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return;
|
return dev->d_sndlen;
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
nerr("ERROR: devif_iob_send error: %d\n", ret);
|
nerr("ERROR: devif_iob_send error: %d\n", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_MM_IOB */
|
#endif /* CONFIG_MM_IOB */
|
||||||
|
@ -66,8 +66,8 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
|
int devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
|
||||||
int len, unsigned int offset)
|
int len, unsigned int offset)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -113,8 +113,9 @@ void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
|
|||||||
|
|
||||||
dev->d_sndlen = len;
|
dev->d_sndlen = len;
|
||||||
|
|
||||||
return;
|
return dev->d_sndlen;
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
nerr("ERROR: devif_send error: %d\n", ret);
|
nerr("ERROR: devif_send error: %d\n", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
/* 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,
|
||||||
if (dev->d_sndlen == 0)
|
pstate->snd_buflen, 0);
|
||||||
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
return flags;
|
pstate->snd_sent = ret;
|
||||||
|
goto end_wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
pstate->snd_sent = pstate->snd_buflen;
|
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);
|
IFF_SET_NOARP(dev->d_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end_wait:
|
||||||
|
|
||||||
/* Don't allow any further call backs. */
|
/* Don't allow any further call backs. */
|
||||||
|
|
||||||
pstate->snd_cb->flags = 0;
|
pstate->snd_cb->flags = 0;
|
||||||
|
@ -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 *entry;
|
||||||
FAR sq_entry_t *next;
|
FAR sq_entry_t *next;
|
||||||
size_t sndlen;
|
size_t sndlen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* According to RFC 6298 (5.4), retransmit the earliest segment
|
/* According to RFC 6298 (5.4), retransmit the earliest segment
|
||||||
* that has not been acknowledged by the TCP receiver.
|
* 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));
|
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb));
|
||||||
|
|
||||||
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
|
ret = devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
|
||||||
0, tcpip_hdrsize(conn));
|
0, tcpip_hdrsize(conn));
|
||||||
if (dev->d_sndlen == 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
return flags;
|
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))
|
if (TCP_SEQ_LT(seq, snd_wnd_edge))
|
||||||
{
|
{
|
||||||
uint32_t remaining_snd_wnd;
|
uint32_t remaining_snd_wnd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
||||||
if (sndlen > conn->mss)
|
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).
|
* won't actually happen until the polling cycle completes).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
|
ret = devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
|
||||||
TCP_WBSENT(wrb), tcpip_hdrsize(conn));
|
TCP_WBSENT(wrb), tcpip_hdrsize(conn));
|
||||||
if (dev->d_sndlen == 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
{
|
{
|
||||||
FAR struct send_s *pstate = pvpriv;
|
FAR struct send_s *pstate = pvpriv;
|
||||||
FAR struct tcp_conn_s *conn;
|
FAR struct tcp_conn_s *conn;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(pstate != NULL);
|
DEBUGASSERT(pstate != NULL);
|
||||||
|
|
||||||
@ -283,8 +284,12 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
* happen until the polling cycle completes).
|
* happen until the polling cycle completes).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
devif_send(dev, &pstate->snd_buffer[pstate->snd_acked],
|
ret = devif_send(dev, &pstate->snd_buffer[pstate->snd_acked],
|
||||||
sndlen, tcpip_hdrsize(conn));
|
sndlen, tcpip_hdrsize(conn));
|
||||||
|
if (ret <= 0)
|
||||||
|
{
|
||||||
|
goto end_wait;
|
||||||
|
}
|
||||||
|
|
||||||
/* Continue waiting */
|
/* Continue waiting */
|
||||||
|
|
||||||
@ -365,11 +370,11 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
* happen until the polling cycle completes).
|
* happen until the polling cycle completes).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
devif_send(dev, &pstate->snd_buffer[pstate->snd_sent],
|
ret = devif_send(dev, &pstate->snd_buffer[pstate->snd_sent],
|
||||||
sndlen, tcpip_hdrsize(conn));
|
sndlen, tcpip_hdrsize(conn));
|
||||||
if (dev->d_sndlen == 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
return flags;
|
goto end_wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the amount of data sent (but not necessarily ACKed) */
|
/* Update the amount of data sent (but not necessarily ACKed) */
|
||||||
|
@ -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 */
|
/* Copy the user data into d_appdata and send it */
|
||||||
|
|
||||||
devif_send(dev, pstate->st_buffer,
|
int ret = devif_send(dev, pstate->st_buffer, pstate->st_buflen,
|
||||||
pstate->st_buflen, udpip_hdrsize(pstate->st_conn));
|
udpip_hdrsize(pstate->st_conn));
|
||||||
if (dev->d_sndlen == 0)
|
if (ret <= 0)
|
||||||
{
|
{
|
||||||
return flags;
|
pstate->st_sndlen = ret;
|
||||||
|
goto end_wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NEED_IPDOMAIN_SUPPORT
|
#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;
|
pstate->st_sndlen = pstate->st_buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end_wait:
|
||||||
|
|
||||||
/* Don't allow any further call backs. */
|
/* Don't allow any further call backs. */
|
||||||
|
|
||||||
pstate->st_cb->flags = 0;
|
pstate->st_cb->flags = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user