FreeRTOS+UDP

gmgrpl wrote on Tuesday, March 24, 2015:

I’ve not had any luck in tracking down the problem. Could it be that the packet is smaller than the minimum size and the EMAC is discarding it? According to my snooping around on the Internet, an Ethernet packet must have at least 46 bytes of user data so that when combined with the 14 bytes of Ethernet header and the 4 bytes of FCS gives a total of 64 bytes.

My DHCP broadcast packet is well above the 64 byte minimum and works well. The broadcast ARP has only 28 bytes of user data - should I try padding it with 16 additional bytes?

Thanks for your help,

Ray

gmgrpl wrote on Wednesday, March 25, 2015:

OK, I finally solved the issue. The broadcast ARP packet must be at least 60 bytes in length. You can see in the attached PCAP file the broadcast went out correctly and was responded to correctly. The UDP/IP stack behaved as I expected it to. I also looked at broadcast ARP packets coming from other entities on my network and they are all formed the same.

I have some cleanup and/or refactoring to do, but I think I’ll be ready to post in a few days depending on how much time I have to spend on this.

Thanks for all your help,

Ray

rtel wrote on Wednesday, March 25, 2015:

Hi Ray, thanks for this information, I will have a look at this and
compare it to the full TCP stack and report back what I find here.

Regards.

rtel wrote on Wednesday, March 25, 2015:

I have looked at the behaviour of both the +UDP stack and +TCP stack and found it to be identical. The generated ARP frame is 42 bytes long, which is technically too small. I have to say that, of all the architectures we have run these stacks on, we have never known this to actually cause a problem before. That said, it is out of spec, and should be corrected.

Looking at the RM46 user manual I note the DMA uses 64-byte reads and writes, so that is probably why the RM64 is not happy with smaller packets.

How did you pad your packet out to 64-bytes? By which I mean, at what point in the code did you add more to the packet?

Regards.

gmgrpl wrote on Wednesday, March 25, 2015:

I simply added a uint8_t byte array of size 18 in the xARP_HEADER struct in FreeRTOS_IP_Private.h

And I corrected the xDefaultPartARPPacketHeader array in FreeRTOS_UDP_IP.c

struct __attribute__((__packed__)) xARP_HEADER
{
    uint16_t      usHardwareType;
    uint16_t      usProtocolType;
    uint8_t       ucHardwareAddressLength;
    uint8_t       ucProtocolAddressLength;
    uint16_t      usOperation;
    xMACAddress_t xSenderHardwareAddress;
    uint32_t      ulSenderProtocolAddress;
    xMACAddress_t xTargetHardwareAddress;
    uint32_t      ulTargetProtocolAddress;
    uint8_t       padding[18];
};
typedef struct xARP_HEADER xARPHeader_t;

static const uint8_t xDefaultPartARPPacketHeader[] =
{
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  /* Ethernet destination address. */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Ethernet source address. */
    0x08, 0x06,                          /* Ethernet frame type (ipARP_TYPE). */
    0x00, 0x01,                          /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
    0x08, 0x00,                          /* usProtocolType. */
    ipMAC_ADDRESS_LENGTH_BYTES,          /* ucHardwareAddressLength. */
    ipIP_ADDRESS_LENGTH_BYTES,           /* ucProtocolAddressLength. */
    0x00, 0x01,                          /* usOperation (ipARP_REQUEST). */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* xSenderHardwareAddress. */
    0x00, 0x00, 0x00, 0x00,              /* ulSenderProtocolAddress */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* xTargetHardwareAddress. */
    0x00, 0x00, 0x00, 0x00,              /* ulTargetProtocolAddress. */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18 bytes of pad */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

Ray

gmgrpl wrote on Wednesday, March 25, 2015:

By the way, you’ll note that the 18 byte pad extends the packet out to 60 bytes, but I think the FCS adds the additional 4 bytes. I think I first added 22 bytes, but then it seemed like something was expecting a 4 byte CRC. That’s when I looked at other devices and noted their ARP broadcast messages were 60 bytes, so I did the same and it worked. You know the old saying, “when it sarts working, stop fixing it” :slight_smile:

Ray

heinbali01 wrote on Thursday, March 26, 2015:

Hi Ray,

By the way, you’ll note that the 18 byte pad extends the packet out to 60 bytes,
but I think the FCS (Frame Check Sequence) adds the additional 4 bytes.

Some MACB says that in automatic FCS mode, it will also add padding (if necessary). I guess that in a manual FCS mode, the user has to add both as:

<packet> <FCS> <padding>
   42   +  4   +  18       = 64 bytes minimum

so I did the same and it worked. You know the old saying,
“when it starts working, stop fixing it” :slight_smile:

… but still it would be nice if all small packets get a proper padding when needed. Couldn’t you find any setting for this in your MAC? Which MCU were you using?

Regards

gmgrpl wrote on Friday, March 27, 2015:

Hein,

That’s a fair statement. I’m using a TI RM46852ZWTT HDK. I didn’t write the device driver - it’s generated by TI’s HALCoGen. I looked at the technical reference manual for the RM46, but there is nothing about being able to set a configurable feature to automatically pad out frames having less than 46 data bytes in them. They discuss the format for an Ethernet frame and point out that 46 data bytes is the minimum, but that’s it.

The TI reference manual doesn’t say who provided the IP for EMAC - them or a third party, so there is no other place to reference. I did note that the default EMAC address TI offers belongs to Logic Product Development. I assume they really did provide the IP otherwise I’m not sure why TI would use their MAC address.

I assume the pad would have to be added in the case a packet is fragmented - does the stack do that or does the MAC do it in hardware?

Ray

heinbali01 wrote on Sunday, March 29, 2015:

Hi Ray,

I assume the pad would have to be added in the case a packet is
fragmented - does the stack do that or does the MAC do it in hardware?

Yes, every packet on the wire has to have a minimum length of 64 bytes.
Support for Fragmentation is discontinued in FreeRTOS+TCP. It adds a lot of complexity and it has a small advantage only.

I’ve been reading in the RM46x tech ref (‘SPNU514A’, September 2013).
It says that the CRC insertion can be switched off (PASSCRC flag).
In many places there are texts about the minimum packet length:

"The padding is required to make up the frame to a minimum of 64 bytes".

But I’m afraid that you are right, the EMAC will NOT add the required padding, in stead the user is responsible. That’s a pity, because for the EMAC it is much easier to add padding.

The above means that the library should get this option of adding padding bytes. There are 3 message types (and maybe more) that may need padding. They all have a minimum size of 28 bytes:

ARP reply   : 28 byte (or more)
ICMP echo   : 28 byte (if length = 0)
UDP message : 28 byte (if there is no payload)

The minimum frame has 64 bytes.

Minus 4 bytes FCS = 60
Minus 14 bytes Ethernet header = 46

and that is also the number you (and the tech ref) mentioned, 46 bytes.

The code below is tested in FreeRTOS+TCP :

#define    ipconfigETHERNET_MINIMUM_PACKET_BYTES        60

void vReturnEthernetFrame( xNetworkBufferDescriptor_t *
    const pxNetworkBuffer,
    BaseType_t xReleaseAfterSend )
{
xEthernetHeader_t *pxEthernetHeader;

    #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
    {
        if( pxNetworkBuffer->xDataLength <
            ipconfigETHERNET_MINIMUM_PACKET_BYTES )
        {
        BaseType_t xIndex;

            FreeRTOS_debug_printf( (
                "vReturnEthernetFrame: length %d < %d\n",
                pxNetworkBuffer->xDataLength,
                ipconfigETHERNET_MINIMUM_PACKET_BYTES ) );
            /* Clearing the padding bytes is essential. */
            for( xIndex = pxNetworkBuffer->xDataLength;
                 xIndex < ipconfigETHERNET_MINIMUM_PACKET_BYTES;
                 xIndex++ )
            {
                pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0;
            }
            pxNetworkBuffer->xDataLength =
                ipconfigETHERNET_MINIMUM_PACKET_BYTES;
        }
    }
    #endif
    ...

We must be careful when ‘BufferAllocation_2.c’ is being used. One can not just increase ‘xDataLength’, because ‘pucEthernetBuffer’ may turn out to be too small.

For FreeRTOS+TCP, I would like to modify ‘BufferAllocation_2.c’ and set the minimum size at 60 bytes:

#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
    #if( MINIMAL_BUFFER_SIZE < ipconfigETHERNET_MINIMUM_PACKET_BYTES )
        #undef MINIMAL_BUFFER_SIZE
        #define MINIMAL_BUFFER_SIZE ipconfigETHERNET_MINIMUM_PACKET_BYTES
    #endif
#endif

Regards,
Hein