FreeRTOS+UDP

Hello, I’m trying to use the UDP/IP stack after it has successfully initialized and gotten an IP address via DHCP. However, I notice that I cannot send UDP packets from the FreeRTOS target to the host PC until after I “ping” the FreeRTOS target from the PC host. Once I send a “ping” from the PC host to the FreeRTOS target, the FreeRTOS target begins sending UDP packets. The FreeRTOS target is acting like the first ping it receives causes it to perform arp and initialize its table. Any thoughts on what I may have missed in initializing the UDP/IP stack? Thank you, Ray

FreeRTOS+UDP

It does sound like an ARP is not being sent, or is being sent but then the reply is not being received correctly. Once the incoming ping has been received the ARP cache will already be populated so the ARP is no longer required. I think it would be expected for at least one UDP message to be converted to an ARP, but hopefully the reply will then be received. Can you log this scenario using wireshark to see if trying to send the UDP data is generating an outgoing ARP…and if so, if the ARP reply also appears on the network. Regards.

FreeRTOS+UDP

The ARP request is never being sent – I verified that with Wireshark. I even tried to force an ARP before I start sending UDP packets by removing “static” from the “prvOutputARPRequest()” declaration and sending it manually after giving plenty of time for the DHCP to complete. I verified the DHCP was complete well before my “forced” ARP and I saw it work once, but didn’t capture the ouotput with Wireshark. Repeated attempts all failed. In stepping through the code It is difficult to see what is happening as it is hard to view the contents of the network buffer descriptor. This one has me scratching my head… Ray

FreeRTOS+UDP

After debugging further, I assume the issue is with the formation of the outgoing Ethernet frames. To interface the UDP/IP stack to the RM46x Eternet driver requires tranforming an “xNetworkBufferDescriptort” into the structure the device driver uses – a “pbufstruct”. The Ethernet device driver expects a fully formed Ethernet frame referenced in the “pbuf_struct”. Of course the frame can span more than one “pbufstruct”, but the Ethernet frame must be fully formed. The documentation for the “xNetworkBufferDescriptort” is not complete enough for me to figure out how to make sure the Ethernet frame is fully formed properly. Do you have a reference I can consult for details? I assumed (maybe incorrectly) that the “*pucEthernetBuffer” in the “xNetworkBufferDescriptor_t” referenced a “transmit ready” Ethernet frame. Is that a good assumption? Ray

FreeRTOS+UDP

By the time the buffer gets to the driver, that is correct. Depending on how the driver is implemented you can either point the DMA at the buffer, or copy the buffer into a buffer used by the DMA. I think you said once the ARP table had the necessary entry the UDP buffer did make it onto the network – so if the packet is not getting onto the network before the ARP table has the entry it would seem to be something specific to the outgoing ARP. You should be able to put a break point in the prvOutputARPRequest() function (implemented in FreeRTOSUDPIP.c) and then see the ARP request being generated and follow its progress to the network driver. Regards.

FreeRTOS+UDP

I’m attaching a PDF document showing the capture of a “ping reply” on Wireshark from my FreeRTOS target – it is a correctly formed packet. I also show a memory buffer dump of a broadcast ARP request coming from the same FreeRTOS target. I captured the buffer before it went to the hardware because I didn’t see it using Wireshark (I was filtering on the MAC and IP addresses of the FreeRTOS target and the development PC host. The broadcast ARP packet is not formed correctly. Do you have any suggestions of what to do next? The version of FreeRTOS+UDP file (FreeRTOSUDPIP.c) is V1.04 Thanks for your help Ray

FreeRTOS+UDP

A quick investigation reveals there may be an issue with packing structures when using the TI v5.x compiler. First, the compiler manual shows a slightly different syntax for the packing attribute. It shows ” _ _ attribute _ _ (( _ _ packed _ _ ))” rather than ” _ _ attribute _ _ ( (packed) )” as in the “packstructend.h” header file. Second, the directive is placed after the keyword “struct” and before the “label/tag” (I never remember which is the correct designation) rather than at the end of the structure. Finally, it might be that pointing to a structure not correctly aligned in memory (or a pointer embedded in a packed struct that is not correctly aligned) may cause undetermined behavior. Also, I can’t find any proof (other than disassembling the code) that using memcpy with a “void * ” doesn’t cause the compiler to generate “word” copy instructions rather than byte copy instructions. That’s what the output buffer seems to show. I don’t know if changing the cast to a “uint8_t * ” will work. Even if it does, will this be “legal” C code? I won’t be able to get back on this until later this week (probably late Friday) – I’m tied up in meetings for two days starting tomorrow. 🙁 Thanks for your help, Ray

FreeRTOS+UDP

First, the compiler manual shows a slightly different syntax
I don’t think the slight syntax change will make a difference, but you can test this easily enough by taking a sizeof( whateverstructispacket_ ) in your code, and comparing it to the expected value. I had a feeling there was a configASSERT() statement in the code somewhere that would be triggered if the structure packing was not working – but it might have been taken out as it could have resulted in “condition is always false” compiler warnings.
Second, the directive is placed after the keyword
Same comment, compilers are normally flexible on this, but you can try moving it to see if it changes the value returned by sizeof() when you count the bytes in the structure.
doesn’t cause the compiler to generate “word” copy instructions
Most library implementations will be written to use byte copies until alignment is achieved, then switch to wider copies for speed, then end up using byte copies again to catch the last few bytes if necessary. I very much doubt, but can’t say for certain, that this would be the cause of a problem. If it was the cause I would suggest it was a bug in the implementation within the library.
Finally, it might be that pointing to a structure not correctly aligned in memory (or
pointer embedded in a packed struct that is not correctly aligned) may cause undetermined behavior.
That could be a possibility – stepping through the code from where the arp is first generated should show you where this goes wrong, if it does. Regards.

FreeRTOS+UDP

I had the same feeling about the “packed” directive – sure enough it didn’t make a difference. I don’t have time to test it this morning, but my next step is to explicitly cast the source and destination locations to ” uint8_t * “. I’ll let you know what I learn. Thanks for all your help, Ray

FreeRTOS+UDP

OK, I tried changing ” ( void * ) ” to ” ( uint8_t * ) ” in all the memcpy calls and it had no effect at all (as you suspected). The message buffer looked exactly the same. I guess I’ll have to walk through the code that builds the broadcast ARP request message to see if I can find the issue. Ray

FreeRTOS+UDP

Hi Ray, If you are using gcc, you might want to look-up the compiler option “-fno-builtin-memcpy” and see what it does. Alignment: in the PDF you’re showing a memory dump:
FFFFFFFF 0800FFFF 6CA603EE 01000608
08000604 00010008 ee03a66c ac1f231e
At what physical starts the first ‘0xFFFFFFFF’ ? If it starts at a 32-bit aligned address it looks a bit strange. Normally there is this define:
#define ipconfigPACKET_FILLER_SIZE   2
which causes all network packets to get an alignment at 32-bit + 2 bytes:
....FFFF FFFF0800 FFFF6CA6 03EE0100
06080800 06040001 0008ee03 a66cac1f
Can you confirm that ipconfigPACKET_FILLER_SIZE is defined as ‘2’ ? Did you record the ARP message in Wireshark? If so, please post a PCAP with as much data as possible. Is your netmask ‘255.255.0.0’ on every host? Regards.

FreeRTOS+UDP

I’m not sure ipconfigPACKETFILLERSIZE is in the +UDP code, as it is in the +TCP code, I will have to check the code to be sure. Regards.

FreeRTOS+UDP

Hi, I finally got around to being able to spend some more time troubleshooting this problem. I captured the ARP request output buffer before transmission in code composer studio and displayed it in unsigned byte style so that it is easier to verify. Here is what I grabbed: FF FF FF FF FF FF 00 08 EE 03 A6 6C 08 06 00 01 08 00 06 04 00 01 00 08 EE 03 A6 6C C0 A8 01 8B 00 00 00 00 00 00 C0 A8 01 B7 The source (FreeRTOS) MAC is: 00 08 EE 03 A6 6C The source (FreeRTOS) IP is: C0 A8 01 8B (192.168.1.139 assigned successfully using DHCP) The destination (desktop PC) IP is: C0 A8 01 B7 (192.168.1.183) The packet is 42 bytes long and looks correct to me – without any padding or CRC. I’m careful to delay the task transmitting UDP datagrams until a delay long enough for an IP to be assigned by DHCP). The hardware won’t transmit the ARP request packet. I didn’t see anything happen while sniffing with Wireshark so I can’t post a PCAP. I’m using 255.255.255.0 for my netmask everywhere. The packet is in a buffer created by the call to pxNetworkBufferGet() at physical address 0x0800A1B8 – a 32 bit address boundary. I assume the hardware requires that boundary for the DMA to work properly (some DMA engines require a 32 byte boundary address). As I traced through the packet creation up to transmission, I noticed the pointer to the buffer containing the packet is simply passed to the hardware for DMA transfer. I found no definition for ipconfigPACKETFILLERSIZE in the FreeRTOS+UDP source code anywhere. Do you think the RFC requires padding for ARP packet? I’m going to attempt to research that. I create a socket and transmit 5 floating point numbers (total of 20 bytes of payload) and I can receive them at the host once I ping the FreeRTOS target to get the host’s MAC address in the target’s ARP table. Would you like a PCAP of a standard UDP datagram transmitted from the FreeRTOS target? Thank you for all your help. Ray

FreeRTOS+UDP

Hi – thanks for the detail. I’m a bit stuck as to what to suggest to be honest as everything looks ok. I don’t think a PCAP of the data after the ping will help, as it is the lack of outgoing ARP that is the request. Knowing the packet looks ok, as is getting to the network driver is a big help. Could it be that the DMA is just in a state whereby it doesn’t recognise it has something to send? Or that it’s configured not to send a broadcast packet? Sorry if I asked this already – but are you connected directly between the target and host, or are you going through a router or switch? If not connected directly could you try connecting directly – which may mean you need a point to point (crossover) Ethernet cable – although many development boards have jacks on them that will automatically switch. Regards.

FreeRTOS+UDP

You may have a point about the EMAC device driver being configured not to send a broadcast packet – I’ll check on that. Poking around the web I seem to have found that a broadcast ARP is supposed to have a 10 byte pad and a 32 bit CRC (as opposed to a 16 bit checksum). The 10 byte pad seems arbitrary, but what about the CRC? Ray

FreeRTOS+UDP

If you are talking about the Ethernet CRC, rather than the UDP checksum, then that should be added by the hardware (at least, that would be normal).

FreeRTOS+UDP

I couldn’t find anything in the EMAC configuration about transmitting a broadcast ARP. I posted a question on TI’s forum – I’m waiting for a response. Right now I know a correctly formed ARP broadcast packet is sent to the EMAC hardware and I see no evidence that the packet is transmitted. Ray

FreeRTOS+UDP

I haven’t heard back from TI yet, but in the meantime I connected the PC host and the FreeRTOS target (the TI RM46x HDK) in a point-to-point Ethernet network. I noticed the exact same behavior. That is, using Wireshark I see no broadcast ARP sent from the FreeRTOS target. When I ping the FreeRTOS target from the host, I see the UDP packet transmission start. The packet memory buffer capture I posted two days ago appears to be formatted correctly. I also realized that the initial DHCP message the FreeRTOS target transmits is a broadcast message as well. Unless TI tells me otherwise, I have to assume something is wrong with the packet causing the hardware to not transmit it. I can’t find anywhere whether a broadcast ARP should have a 2 byte checksum. I also can’t find any documentation as to whether the FreeRTOS target EMAC expects a 2 byte checksum. I traced a UDP packet and found that it does include a 2 byte checksum. I plan to trace a DHCP broadcast packet to determine if it includes a 2 byte checksum. I’m running out of ideas of things to look at. Can you think of anything I’ve missed or anything I should investigate? Ray

FreeRTOS+UDP

Hi Ray, I had problems with DHCP broadcast on my work network, take a look at: https://sourceforge.net/p/freertos/discussion/382005/thread/5591a1a9/?limit=25&page=1#89e3 it might help you. Cheers, Andy

FreeRTOS+UDP

Thanks for the input Andy. I don’t think I’m having the same problem you had. DHCP works OK for me. I can’t, however, get a broadcast ARP to transmit. I verified my buffers are on 8 byte boundaries when passed to the EMAC hardware and there are no flags in an ARP header as in the DHCP message structure. I’m at a loss as to why the EMAC refuses to transmit the broadcast ARP. If I ping the target from my PC the target’s ARP table gets updated and I can correctly transmit UDP data via a socket. I just can’t get the target to automatically update its ARP table since the broadcast ARP doesn’t transmit. Ray

FreeRTOS+UDP

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

FreeRTOS+UDP

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

FreeRTOS+UDP

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.

FreeRTOS+UDP

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.

FreeRTOS+UDP

I simply added a uint8t byte array of size 18 in the xARPHEADER struct in FreeRTOSIPPrivate.h And I corrected the xDefaultPartARPPacketHeader array in FreeRTOSUDPIP.c ~~~~~~~~~~~~~~~~~~~~~~~ struct attribute((packed)) xARPHEADER { uint16t usHardwareType; uint16t usProtocolType; uint8t ucHardwareAddressLength; uint8t ucProtocolAddressLength; uint16t usOperation; xMACAddresst xSenderHardwareAddress; uint32t ulSenderProtocolAddress; xMACAddresst xTargetHardwareAddress; uint32t ulTargetProtocolAddress; uint8t padding[18]; }; typedef struct xARPHEADER xARPHeader_t; static const uint8t xDefaultPartARPPacketHeader[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */ 0x08, 0x06, /* Ethernet frame type (ipARPTYPE). / 0x00, 0x01, / usHardwareType (ipARPHARDWARETYPEETHERNET). */ 0x08, 0x00, /* usProtocolType. */ ipMACADDRESSLENGTHBYTES, /* 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

FreeRTOS+UDP

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” 🙂 Ray

FreeRTOS+UDP

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” 🙂
.. 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

FreeRTOS+UDP

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

FreeRTOS+UDP

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 ipconfigETHERNETMINIMUMPACKET_BYTES 60

void vReturnEthernetFrame( xNetworkBufferDescriptort * const pxNetworkBuffer, BaseTypet 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 < %dn",
            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( ipconfigETHERNETMINIMUMPACKET_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