FreeRTOS+TCP minor bug-finds

andymcc0 wrote on Thursday, March 05, 2015:

Hi Hein,

In desperation, I had set my device to accept anything, but nothing was coming in. It didn’t help that I couldn’t see any BOOTP/DHCP messages with Wireshark. In the end I went step by step through a working lwip implementation, comparing it with the +TCP (the BOOTP/DHCP packets for this didn’t show up in Wireshark either).

I guess it has something to do with the way the network here is set up.

Would it be an idea to control the use of the dhcpBROADCAST flag with an ipcofigUSE_BLAHBLAH define, or alternatively build ‘fallover’ logic into the DHCP implementation?

Cheers,

andymcc0 wrote on Thursday, March 05, 2015:

I think I have found a possible bug in FreeRTOS_Sockets.c

In function FreeRTOS_recvfrom(),

if( pxSourceAddress != NULL )
{
	pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
	pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
}

occurs after the non zero copy option has called
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer )
I see no problem with moving it up to before the

if( ( ulFlags & FREERTOS_ZERO_COPY ) == 0 )

test

It is probable that the contents of pxNetworkBuffer->usPort and pxNetworkBuffer->ulIPAddress remain valid for long enough for the assignment to work as it is, but I wouldn’t want to rely on it.

Opinions?

heinbali01 wrote on Thursday, March 05, 2015:

Would it be an idea to control the use of the dhcpBROADCAST
flag with an ipcofigUSE_BLAHBLAH define, or alternatively
build ‘fallover’ logic into the DHCP implementation?

Yes sure that is possible.

I was thinking of :

#define ipconfigDHCP_USES_UNICAST       1

And maybe this can even become ‘1’ by default. I don’t think it will hurt any existing setup as unicast works better than broadcast.

I will respond to your other message later,

Thanks,
Hein

rtel wrote on Thursday, March 05, 2015:

Yes sure that is possible.

I was thinking of :

#define ipconfigDHCP_USES_UNICAST 1

Actually - I don’t think that is a suitable solution because the
firmware in a product would need to change depending on the network it
was plugged in to. Something more adaptive would be more robust -
either try uni cast first, then broadcast on the retry, then unicast on
the next retry, etc. Or alternative start by sending both a unicast and
a broadcast, if the DHCP server is not upset by such a thing.

Regards.

heinbali01 wrote on Thursday, March 05, 2015:

Hi Andy,

if( pxSourceAddress != NULL )
{
    pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
    pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
}

occurs after the non zero copy option has called

Well seen, thanks!

Opinions?

Yes: assign earlier, before deleting the buffers.

Regards.

andymcc0 wrote on Friday, March 06, 2015:

This may not be a bug, but I think it worth noting:

My PC is on a different sub-net to the IP address obtained by my development board. This makes it appear as a “remote” host when vARPRefreshCacheEntry() is called as part of processing a received UDP packet.

If ipconfigARP_STORES_REMOTE_ADDRESSES is 0 (in my case, it wasn’t even defined, so I have since added it to FreeRTOSIPConfig.h), then no entry is made in the ARP table. When it comes to replying there is an ARP cache miss, so the outgoing UDP packet is turned into an ARP request to the obtained gateway IP address. A short burst of these appear on the network then my application runs off into the weeds (which might be my failure to handle the problem in my UDP server task; I wasn’t able to catch exactly what happened).

If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, the ARP entry is made, and there are ‘happy bunnies’ all round.

I now have a working LPC4088_GCC version of the ‘FreeRTOS_Plus_TCP_and_CLI_Windows_Simulator’ demo. I have rewritten vTCPNetStat() to take a buffer pointer as a parameter, which it fills with the formatted output. The call from prvIPTask() now passes xReceivedEvent.pvData as the pointer and FreeRTOS_netstat() sets up the buffer and passes the pointer in the IPStackEvent struct to xSendEventStructToIPTask(). Why did I do this? So that the demo prvNetStatCommand() could return the data to the calling CLI client by calling xSendEventStructToIPTask() with the pcWriteBuffer as the .pvData member.

Everything is a bit messy at the moment, so it’s not quite ready for public consumption, but soon, soon. It will be good discipline for me to tidy up before moving on to Telnet, FTP, etc.

heinbali01 wrote on Friday, March 06, 2015:

Hi Andy,

Appreciate your feedback.

The classical idea about the netmask is: if an IP address is outside the netmask, it is a strange address and it is assumed to go through a router.

As you can read somewhere in the documentation, ipconfigARP_STORES_REMOTE_ADDRESSES was introduced to remember the MAC-address of all packets, also from devices that are outside the netmask (maybe from the Internet).
Modern networks can have many different routers / gateways, not just one.

Glad to hear that defining ipconfigARP_STORES_REMOTE_ADDRESSES = 1 helps to solve your problem.

Actually I thing we should solve the kind of problem you’re facing by adding routing rules.

Just curious: why isn’t your laptop on the same netmask as your embedded devices? Aren’t they both using the same DHCP server?

I have rewritten vTCPNetStat() to take a buffer pointer as a parameter

I’m sure Richard will like that too. It is much more in-line with the listings of tasks (uxTaskGetSystemState), that also works by providing a buffer and a buffer length.

All of my embedded projects have logging, and also the output of FreeRTOS_printf() will be added to that logging. The logging can be seen by making a telnet connection. Every logging-line is preceded by a time-stamp and a task number.

Here is an example of the ‘netstat’ command:

    321.682.673 [1]: netstat
    321.682.773 [5]: Prot Port IP-Remote       : Port  R/T Status       Alive  tmout Child
    321.682.905 [5]: TCP  8001 0.0.0.0         :    0 0/0 eTCP_LISTEN   317646      0 0/12
    321.683.041 [5]: TCP  8000 0.0.0.0         :    0 0/0 eTCP_LISTEN   317646      0 0/12
    321.683.122 [5]: TCP    21 0.0.0.0         :    0 0/0 eTCP_LISTEN   317647      0 3/12
    321.683.254 [5]: TCP  8021 0.0.0.0         :    0 0/0 eTCP_LISTEN   317646      0 0/12
    321.683.387 [5]: TCP  2402 192.168.2.3     : 2800 1/1 eESTABLISHED       1  20000
    321.683.515 [5]: TCP    23 0.0.0.0         :    0 0/0 eTCP_LISTEN   317642      0 0/3
    321.683.651 [5]: TCP    80 0.0.0.0         :    0 0/0 eTCP_LISTEN   317241      0 13/16
    321.683.783 [5]: TCP  8080 0.0.0.0         :    0 0/0 eTCP_LISTEN   317241      0 0/16
    321.683.917 [5]: TCP    80 192.168.2.3     : 2817 1/1 eESTABLISHED    3450  16532
    321.684.049 [5]: TCP    80 192.168.2.3     : 2820 1/1 eESTABLISHED    4108  15858
    321.684.124 [5]: TCP    21 192.168.2.3     : 2840 1/1 eESTABLISHED    5350  17058
    321.684.251 [5]: TCP    21 192.168.2.3     : 2845 1/1 eESTABLISHED    2654  19836
    321.684.384 [5]: TCP    21 192.168.2.3     : 2846 1/1 eESTABLISHED    2825  19664
    321.684.511 [5]: TCP    80 192.168.2.3     : 3017 1/1 eESTABLISHED    4232  15732
    321.684.639 [5]: TCP    80 192.168.2.3     : 3018 1/1 eESTABLISHED    3373  16611
    321.684.772 [5]: TCP    80 192.168.2.3     : 3019 1/1 eESTABLISHED    3369  16615
    321.684.898 [5]: TCP    80 192.168.2.3     : 3020 1/1 eESTABLISHED     142     62
    321.685.123 [5]: TCP    80 192.168.2.3     : 3037 1/1 eESTABLISHED     106     96
    321.685.250 [5]: TCP    80 192.168.2.3     : 3038 1/1 eESTABLISHED    3498  16585
    321.685.382 [5]: TCP    80 192.168.2.3     : 3039 1/1 eESTABLISHED    3593  16481
    321.685.510 [5]: TCP    80 192.168.2.3     : 3040 1/1 eESTABLISHED    4255  15904
    321.685.643 [5]: TCP    80 192.168.2.3     : 3041 1/1 eESTABLISHED    3428  16755
    321.685.771 [5]: TCP    80 192.168.2.3     : 3042 1/1 eESTABLISHED    3421  16763
    321.685.903 [5]: TCP    80 192.168.2.3     : 3043 1/1 eESTABLISHED    3501  16983
    321.685.938 [5]: UDP Port 30718
    321.685.969 [5]: UDP Port  2000
    321.686.005 [5]: UDP Port 30717
    321.686.026 [5]: UDP Port   123

Keep in mind that the resulting string of the ‘netstat’ command may become quite large.

Regards

andymcc0 wrote on Friday, March 06, 2015:

Glad to hear that defining ipconfigARP_STORES_REMOTE_ADDRESSES = 1 helps to solve your problem.

Me too :wink: though I’m still a little concerned that it fell over so badly without it.

Just curious: why isn’t your laptop on the same netmask as your embedded devices? Aren’t they both using the same DHCP server?

I’m not sure, they are plugged into the same network: the PC is on the 10.16.255.255 subnet and the dev board on 10.186.0.255

I have rewritten vTCPNetStat() to take a buffer pointer as a parameter

I’m sure Richard will like that too. It is much more in-line with the listings of tasks (uxTaskGetSystemState), that also works by providing a buffer and a buffer length.

I provide the size of the buffer (in the first sizeof(size_t) bytes of the buffer (I should perhaps create a struct with .length and .payload members)) and I check within vTCPNetStat() for potential overflow, returning if a newly snprintf()ed line will not fit in the remaining buffer. A refinement would be to be able to make multiple calls to get all of a large block of data, or deliberately restrict it to one line at a time. I’m not sure if that would be in danger of filling up the xNetworkEventQueue; probably not if subsequent calls for data wait for previous ones to finish, which is the likely case.

I’ll include the modified +TCP source when I ‘publish’ next week.

heinbali01 wrote on Friday, March 06, 2015:

This is my favorite way to respect the buffer size:

    int iLength = 0;

    pcBuffer[ 0 ] = '\0';
    for( ;; )
    {
        /* This method assumes that snprintf() will always
        leave the the buffer null-terminated. */
        iLength += snprintf( pcBuffer + iLength, iMaxLength - iLength, "xxx\n");
    }

the PC is on the 10.16.255.255 subnet and
the dev board on 10.186.0.255

Normally, with a 10.x.x.x address, the netmask should be set at 255.0.0.0.
Likewise a 192.168.x.x address normally has a netmask of 255.255.255.0
In your case, both devices should be on a 10.255.255.255 network.

But, as these IP-ranges are private, you’re entirely free to use whatever netmask you like.

In a meanwhile, I will start thinking about some simple routing rules. In a later stage, the possibility of multiple NIC’s should be added to +TCP and that will ask for routing.

regards,
Hein

andymcc0 wrote on Friday, March 13, 2015:

I wrote:

As an aside, I hope to make available an example project using FreeRTOS+TCP+CLI, built using LPCXpresso/LPCOpen and running on the Embedded Artists LPC4088 OEM + Base board.

DONE, it can now be found at:

http://interactive.freertos.org/entries/80118239-FreeRTOS-TCP-Labs-port-and-demo-for-Embedded-Artists-LPC4088-Dev-Kit

Andy McC