FreeRTOS+UDP

gmgrpl wrote on Monday, March 16, 2015:

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

rtel wrote on Tuesday, March 17, 2015:

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.

gmgrpl wrote on Tuesday, March 17, 2015:

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

gmgrpl wrote on Tuesday, March 17, 2015:

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 “xNetworkBufferDescriptor_t” into the structure the device driver uses - a “pbuf_struct”. The Ethernet device driver expects a fully formed Ethernet frame referenced in the “pbuf_struct”.

Of course the frame can span more than one “pbuf_struct”, but the Ethernet frame must be fully formed. The documentation for the “xNetworkBufferDescriptor_t” 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

rtel wrote on Tuesday, March 17, 2015:

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
FreeRTOS_UDP_IP.c) and then see the ARP request being generated and
follow its progress to the network driver.

Regards.

gmgrpl wrote on Wednesday, March 18, 2015:

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 (FreeRTOS_UDP_IP.c) is V1.04

Thanks for your help
Ray

gmgrpl wrote on Wednesday, March 18, 2015:

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 “pack_struct_end.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. :frowning:

Thanks for your help,

Ray

rtel wrote on Wednesday, March 18, 2015:

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( whatever_struct_is_packet ) 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.

gmgrpl wrote on Wednesday, March 18, 2015:

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

gmgrpl wrote on Wednesday, March 18, 2015:

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

heinbali01 wrote on Thursday, March 19, 2015:

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.

rtel wrote on Thursday, March 19, 2015:

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

Regards.

gmgrpl wrote on Saturday, March 21, 2015:

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 ipconfigPACKET_FILLER_SIZE 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

rtel wrote on Saturday, March 21, 2015:

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.

gmgrpl wrote on Saturday, March 21, 2015:

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

rtel wrote on Sunday, March 22, 2015:

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).

gmgrpl wrote on Sunday, March 22, 2015:

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

gmgrpl wrote on Monday, March 23, 2015:

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

andymcc0 wrote on Tuesday, March 24, 2015:

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

gmgrpl wrote on Tuesday, March 24, 2015:

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