mirror of https://github.com/ARMmbed/mbed-os.git
lwip - Fixed memory leak in k64f cyclic-buffer overflow
This was actually several bugs colluding together. 1. Confusion on the buffer-semaphore paradigm used led to misuse of the tx semaphore and potential for odd behaviour. 2. Equality tests on tx_consume_index and tx_produce_index did not handle overflow correctly. This would allow tx_consume_index to catch up to tx_produce_index and trick the k64f_rx_reclaim function into forgetting about a whole buffer of pbufs. 3. On top of all of that, the ENET_BUFFDESCRIPTOR_TX_READ_MASK was not correctly read immediately after being set due to either a compiler optimization or hardware delays. This caused k64f_low_level_output to eagerly overrun existing buff-descriptors before they had been completely sent. Adopting the counting-semaphore paradigm for 1 avoided this concern. As pointed out by @infinnovation, the overflow only occurs in the rare case that the 120MHz CPU can actually generate packets faster than the ENET hardware can transmit on a 100Mbps link.pull/3135/head
parent
d7c02a13b1
commit
2fd15f4f44
|
@ -102,24 +102,22 @@ static void update_read_buffer(uint8_t *buf)
|
|||
*/
|
||||
static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet)
|
||||
{
|
||||
uint8_t i = 0 ;
|
||||
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&k64f_enet->TXLockMutex);
|
||||
|
||||
i = k64f_enet->tx_consume_index;
|
||||
// Traverse all descriptors, looking for the ones modified by the uDMA
|
||||
while((i != k64f_enet->tx_produce_index) && (!(g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))) {
|
||||
pbuf_free(tx_buff[i]);
|
||||
while((k64f_enet->tx_consume_index != k64f_enet->tx_produce_index) &&
|
||||
(!(g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))) {
|
||||
pbuf_free(tx_buff[k64f_enet->tx_consume_index % ENET_TX_RING_LEN]);
|
||||
if (g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK)
|
||||
g_handle.txBdDirty = g_handle.txBdBase;
|
||||
else
|
||||
g_handle.txBdDirty++;
|
||||
|
||||
i = (i + 1) % ENET_TX_RING_LEN;
|
||||
k64f_enet->tx_consume_index += 1;
|
||||
osSemaphoreRelease(k64f_enet->xTXDCountSem.id);
|
||||
}
|
||||
|
||||
k64f_enet->tx_consume_index = i;
|
||||
/* Restore access */
|
||||
sys_mutex_unlock(&k64f_enet->TXLockMutex);
|
||||
}
|
||||
|
@ -526,15 +524,14 @@ static err_t k64f_low_level_output(struct netif *netif, struct pbuf *p)
|
|||
|
||||
/* Wait until a descriptor is available for the transfer. */
|
||||
/* THIS WILL BLOCK UNTIL THERE ARE A DESCRIPTOR AVAILABLE */
|
||||
while (g_handle.txBdCurrent->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)
|
||||
osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
|
||||
osSemaphoreWait(k64f_enet->xTXDCountSem.id, osWaitForever);
|
||||
|
||||
/* Get exclusive access */
|
||||
sys_mutex_lock(&k64f_enet->TXLockMutex);
|
||||
|
||||
/* Save the buffer so that it can be freed when transmit is done */
|
||||
tx_buff[k64f_enet->tx_produce_index] = temp_pbuf;
|
||||
k64f_enet->tx_produce_index = (k64f_enet->tx_produce_index + 1) % ENET_TX_RING_LEN;
|
||||
tx_buff[k64f_enet->tx_produce_index % ENET_TX_RING_LEN] = temp_pbuf;
|
||||
k64f_enet->tx_produce_index += 1;
|
||||
|
||||
/* Setup transfers */
|
||||
g_handle.txBdCurrent->buffer = psend;
|
||||
|
|
Loading…
Reference in New Issue