Hello,
I've got some troubles with ENET driver on LPC54628J512. When on a network under a VLAN, on reception of a MTU-size packet from another VLAN, We got a freeze of the device
1 - Context
The network setup is represented on the following diagram

2 - Problem
Problem occurs on reception of a MTU-Sized packet, or first fragment of fragmented packet (In our case this is a ≃2000 sized payload packet from KDEConnect client software). If the packet is sent directly on the device VLAN (192.168.16.255), there is no problem. But when the device comes from another VLAN (192.168.11.255), and then re-emmited by the Main-switch to other VLANs, it produces the freeze.
3 - Analysis
After activating LWIP_ASSERT, we got an assert in ethernetif_rx_frame_to_pbufs()
buffer = rxFrame->rxBuffArray[i].buffer; // corrupted
bufferLength = rxFrame->rxBuffArray[i].length; // corrupted
len += bufferLength;
/* Find pbuf wrapper for the actually read byte buffer */
idx = ((rx_buffer_t *)(((uint8_t *)buffer) - ETH_PAD_SIZE)) - ethernetif->RxDataBuff;
LWIP_ASSERT("Buffer returned by ENET_GetRxFrame() doesn't match any RX buffer descriptor",
((idx >= 0) && (idx < ENET_RXBUFF_NUM)));
- idx = 1953659110
- bufferLenght = 65535 (or -1)
At this point, we see that data from rxFrame is very invalid data. So let analyse values in ENET_GetRxFrame(), which fill this structure.
Here is the result (simplified code):
/* Get the valid frame */
index = 0;
do
{
rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
/* Calculate the buffer and frame length. */
if ((rxDesc->rdes3 & ENET_RXDESCRIP_WR_LD_MASK) != 0U)
{
isLastBuff = true;
rxFrame->totLen = (uint16_t)(rxDesc->rdes3 & ENET_RXDESCRIP_WR_PACKETLEN_MASK);
if (rxFrame->totLen - offset > (uint16_t)rxBdRing->rxBuffSizeAlign)
{
buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
if (handle->doubleBuffEnable)
{
buff2Len = rxFrame->totLen - offset - (uint16_t)rxBdRing->rxBuffSizeAlign - ENET_FCS_LEN;
}
}
else
{
buff1Len = rxFrame->totLen - offset - ENET_FCS_LEN;
}
rxFrame->totLen -= ENET_FCS_LEN;
}
else
{
if (!handle->doubleBuffEnable)
{
buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
offset += buff1Len;
}
else
{
buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
buff2Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
offset += buff1Len + buff2Len;
}
}
// <-- Check data here (assert on invalid buff1Len)
/* Allocate new buffer to replace the buffer taken by application */
if (!isDrop)
{
/* Get the frame data information into Rx frame structure. */
/* Give new buffer from application to BD */
}
else
{
/* Drop frame if there's no new buffer memory */
}
} while (!isLastBuff);
- buff1Len = 65534 (or -2)
- rxDesc->rdes3 & ENET_RXDESCRIP_WR_LD_MASK = 1522
- rxFrame->totLen = 1518
- offset = 1520
Knowing that the max buffer size is aligned(1518) = 1520, the frame length reported by the rxDescriptor is 2 over this value. This could be the cause of a data overflow...
4 - Faulty packet
The incriminated packet is a fragmented packet that is sent from another VLAN and retransmitted by the main switch.
A same packet sent directly from the device VLAN or from another VLAN doesn't result in the same effect, but when analysing the packets with wireshark, there are exactly the same from MAC layer header to payload data (except source and timestamps of course).
I found that when a VLAN controller send a packet, it add some additionnal informations in the IP Layer header. See https://en.wikipedia.org/wiki/IEEE_802.1Q. It represent 4 additional bytes, that could put the 1518 lenght packet to 1522. These data are generally not displayed in wireshark, because most network interfaces process these data themselves and remove them from packet. That also the case of some more "intelligent" switches, that make the problem disapear under them.
On linux, you can do some tricks to stop removing these packets, and tadam ! here they are on wireshark

5 - Need more info about ENET driver alternative
In my program I use fsl_enet.c/.h from drivers/lpc_enet/ folder in NXP MCUXPresso SDk Core. I'm currently using v2.12.0, but I also tried with latest version on github.
I see there is another implementation for ENET, under drivers/enet/. Has I understand, it's a mor generic implementation, but it also supports more Networking features (such as VLAN) for more advanced CPUS such as iMX series.
I wasn't able to compile with the enet/ driver, because I'm missing some definitions which are only available for iMX plateforms. Is there a chance I could use this driver for LPC546 ?

I hope someone would be able to help me handling this bug or migrating to the other variation of the driver.
Thanks,
Lucas