FreeRTOS+TCP:STM32 TCP Client can't connect to PC Server until PC ping successfully to STM32

I set up a TCP client on the STM32F407, and try to connect to the server on the PC. But the connection was unsuccessful every time. When I opened the cmd terminal on the PC and ping the STM32, found that the TCP client was connected immediately.
After pinging the client, the client was able to connect to the server immediately. Do you know what causes this?

I also found the eARPGetCacheEntry always return “eARPCacheMiss” in prvTCPPrepareConnect function when TCP client can’t connect to the server.
/* Determine the ARP cache status for the requested IP address. */
eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) );

Is there any way to solve this problem? Thanks!

//Here is my TCP client code

#include "tcp_client.h"


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory>


#include <cmsis_os.h>
#include "FreeRTOSIPConfig.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"

#include "data/data.h"
#include "generate_protocol/search_protocol/search_protocol.h"
#include "protocol/message.h"
#include "protocol/protocol.h"
#include "protocol/node_id.h"
#include "package.h"

#define MAX_HEART_COUNT                5        //unit xReceiveTimeOut


struct freertos_sockaddr TcpServerAddress;
static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 2000 );
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 1000 );
Socket_t xSocket;
Recivebuff recivebuffes;
TaskHandle_t TCPTest_TaskHandle;
int try_count = 0;
int heart_miss_count = 0;

// connect fun
int TcpClientConnect(void)
{
        int ret = 0;
       recivebuffes.length = 0;
       
       Data* data = Data::GetInstance();
        unsigned short port = data->GetPort();
        TcpServerAddress.sin_port = FreeRTOS_htons(port);
        TcpServerAddress.sin_addr = FreeRTOS_htonl(data->GetRemoteIP());
         
        xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
        configASSERT( xSocket != FREERTOS_INVALID_SOCKET );

        FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
        FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
       
        ret = FreeRTOS_connect( xSocket, &TcpServerAddress, sizeof( TcpServerAddress ) );
       
        return ret;
}

void TcpClientDisconnect(void)
{
        TickType_t xTimeOnEntering;
        BaseType_t xReturned;
       
        FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
       
        xTimeOnEntering = xTaskGetTickCount();
        do
        {
                xReturned = FreeRTOS_recv( xSocket, recivebuffes.cRxBuffers, sizeof(recivebuffes.cRxBuffers), 0 );
                if( xReturned < 0 )
                {
                        break;
                }
        }
        while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut );
       
       FreeRTOS_closesocket( xSocket );
       
}

int TcpClientSend(char *pSendBuff,uint32_t lBuffLen)
{       
        BaseType_t lTransmitted;
       
        lTransmitted = FreeRTOS_send(xSocket,pSendBuff,lBuffLen,0 );
        //vTaskDelay(150 / portTICK_PERIOD_MS);
       
        if(lTransmitted < 0)
        {
                return 0;
        }
        else
        {
                return 1;
        }
}

void TcpClientRecive(void)
{
        BaseType_t lrecive;
       
        memset(recivebuffes.cRxBuffers, 0, sizeof(recivebuffes.cRxBuffers));
        lrecive = FreeRTOS_recv(xSocket, recivebuffes.cRxBuffers, sizeof(recivebuffes.cRxBuffers), 0);
        if(lrecive <= 0 )
                recivebuffes.length = 0;
        else
        {
                recivebuffes.length = lrecive;
        }
}

void TcpClientThread(const void *parameter)
{

        auto send_to_pc = [](const std::string& data) ->void
        {
                TcpClientSend((char *)data.c_str(), data.size());
        };
       
        do{
                if(TcpClientConnect() == 0)
                {
                        try_count = 0;
                        while(1)
                        {
                       
                                vTaskDelay(2000 / portTICK_RATE_MS );

                        }
                }

                TcpClientDisconnect();
                vTaskDelay(3000 / portTICK_RATE_MS );
               
        }while(++try_count);
       

        vTaskDelete(xTaskGetCurrentTaskHandle());
}
BaseType_t xReturned;
void Heart_Handler(const void *parameter)
{


        while(1)
        {
                if(FreeRTOS_issocketconnected(xSocket))
                {
                        memset(recivebuffes.cRxBuffers, 0, sizeof(recivebuffes.cRxBuffers));
                        xReturned = FreeRTOS_recv(         xSocket,                                        /* The socket being received from. */
                                                                        recivebuffes.cRxBuffers,                /* The buffer into which the received data will be written. */
                                                                        sizeof(recivebuffes.cRxBuffers),                /* The size of the buffer provided to receive the data. */
                                                                        0 );

                                                }
                else
                {
                        vTaskDelay( 1000 / portTICK_PERIOD_MS );
                }

        }

        vTaskDelete(xTaskGetCurrentTaskHandle());
}

int CreateTcpThread(void)
{

    osThreadDef(TcpTask, TcpClientThread, osPriorityNormal, 0, 1024);
    osThreadCreate(osThread(TcpTask), (void*)0);

        osThreadDef(HeartTask, Heart_Handler, osPriorityNormal, 0, 700);
    osThreadCreate(osThread(HeartTask), (void*)0);

        return 0;
}

Hi Kevin,

I suspect that your unit is connected to a supervised switch that has some kind of port based authentication. As long as your hardware does not initiate network traffic by itself, the switch will not link the target IP address to your hardware’s MAC address which it needs to route the packets to the port.

This is the blessing and curse of lightweight network based devices; every Windows or Linux machine will become active at some point and identify themselves to the network, which is sufficient for your switch.

The only way around this would be for your firmware to force some kind of network activity such as a periodic attempt to open a “ghost connection.” This would also be an easy test for you to determine if this is the cause.

EDIT: No, wait, sorry. Your unit IS a TCP client, so this scenario doesn’t apply. Can we see a wireshark log taken from the segemtn that your unit is in? Could it be a routing/subnet mask problem?

Thanks for your reply!
Wireshark shows nothing when TCP client connect failed to server. In other words, the TCP client can’t send out the first SYN package.
When I start to ping client, Wireshark shows many message and client connect server well.
STM32 is connected to the computer with a network cable directly, without going through a router.

Might be a network driver issue. Can you verify and trace that xNetworkInterfaceOutput is called appropriately and works as expected (sending 1st ARP etc) ?

Yes, xNetworkInterfaceOutput was called in FreeRTOS_OutputARPRequest after eARPGetCacheEntry return eARPCacheMiss.
xNetworkInterfaceOutput return pdPASS everytime.
But Wireshark can’t capture any message while I set “ip.dst==192.168.11.77 || ip.src==192.168.11.77”
(client IP:192.168.11.77)
(server IP:192.168.11.37)

Can you include the ARPs (request and response) in the wireshark filter and if they’re there try to track the reception of the ARP response ?
Is there any other network device / software (firewall ?) involved or is it a direct, wired connection ?
BTW. Which FreeRTOS+TCP version and network driver (the one @htibosch provides ?) do you use ?

1.Can you include the ARPs (request and response) in the wireshark filter and if they’re there try to track the reception of the ARP response ?
Only when I ping the client, wireshark can capture the arp packet sent by the client. At other times, the client’s arp package cannot be founded at all. Wireshark filter is “arp”. The part of result ↓

20 7.999750 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.254? Tell 192.168.11.37
21 8.111623 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.77? Tell 192.168.11.37
22 8.111633 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.77? Tell 192.168.11.37
23 8.111847 10:22:33:4d:00:34 Dell_7f:6a:7c ARP 60 192.168.11.77 is at 10:22:33:4d:00:34
30 9.386287 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.254? Tell 192.168.11.37
31 9.386297 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.254? Tell 192.168.11.37
32 9.999496 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.254? Tell 192.168.11.37

2.Is there any other network device / software (firewall ?) involved or is it a direct, wired connection ?
My PC’s firewall is always turned off. STM32 is connected to my PC with a network cable directly, without going through a router.

3.Which FreeRTOS+TCP version and network driver (the one htibosch provides ?) do you use ?
FreeRTOS+TCP version: V2.0.1
network driver:
My phy chip is dp83848 and phyHandling.c shows below↓

  • FreeRTOS+TCP Multi Interface Labs Build 180222
  • Copyright (C) 2018 Amazon. com, Inc. or its affiliates. All Rights Reserved.
  • Authors include Hein Tibosch and Richard Barry

Well, at least the STM32F4 is able to send and receive ARP messages, it replies to the ARP lookup:

22 8.111633 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.77? Tell 192.168.11.37
23 8.111847 10:22:33:4d:00:34 Dell_7f:6a:7c ARP 60 192.168.11.77 is at 10:22:33:4d:00:34

So xNetworkInterfaceOutput() works well.

You connected the STM32F4 directly to the PC, and that might cause a problem. Would it be possible to connect both to a switch or a router? I think it will ‘solve’ the problem.

Please always uses the official releases from github:

FreeRTOS-Kernel
FreeRTOS-Plus-TCP
FreeRTOS-Plus-TCP Multi/IPv6
FreeRTOS-FAT

And if you like, there are also LTS releases. ( Long Term Support )

The releases on github are all well checked on their quality and tested on real hardware.

I also have a github page, but I mostly use it to prepare my pull-requests.
Some developers use the FTP/HTTP servers.

The release that you are using now (Labs Build 180222) is indeed a bit outdated, although it should work as well.

Thanks for your reply!
Now, I connect both to a Cisco switch. But this connection problem still exists. xNetworkInterfaceOutput return pdPASS everytime when FreeRTOS_connect was called.But wireshark can’t capture any arp packet sent from STM32 if I do not ping it.


Next, I will use the newer release version and test it again.

Maybe @htibosch can explain why a direct connection to a PC might cause the ARP request being dropped. On the other hand the switch also didn’t help :thinking: If the device successfully put it on the wire i.e. xNetworkInterfaceOutput really works (did you verify that the driver successfully sent it to the MAC ?), then it should be received by the PC and shown in the Wireshark capture. Strange… except the ARP request is malformed. With a direct ethernet connection you could capture ALL ethernet packets on the link to see if an unknown ethernet frame (a malformed ARP request) is captured.
Updating the network stack and driver before is for sure a good idea, too.

Hello Hartmut, it looks like the STM32 really receives and sends packets:

This in reply to an ARP look-up:

23 8.111847 10:22:33:4d:00:34 Dell_7f:6a:7c ARP 60 192.168.11.77 is at 10:22:33:4d:00:34

And ping also works after the PC has send it a message. So somewhere the ( initial? ) ARP requests from the STM32 are blocked.

It is years ago that I worked with a direct cable between device and PC. The problem is that you have two network stacks starting up at the same time.
One problem that I remember was DHCP of course: the 0.0.0.0 IP address gave a conflict.
At that moment I decided to always use a switch or router.
( Ethernet hubs are also trouble makers, in my experience ).

Kevin : you wrote that you disabled the firewall of the PC.
Can you try pinging your PC from another OS, another laptop maybe?

And yes, upgrading the software is also good.

Hi Kevin,

do you run Wireshark on the same machine that runs the TCP server, or a different computer hooked up to the segment?

What is your configuration with regard to number of ARP cache entries and so forth?

And another thing: Can you trace the packet flow a little closer? For example, if the network driver uses DMA based ETH output (which it mostly probably does), can you check if the packet really made it down to the DMA buffer chain and set the TxBuf ready flag to the MAC? I remember extremly subtle issues with a few network drivers under lwip where transmission was sort of out of sync on fringe conditions, after which it took a “kick start” from some other task to physically initiate a transmit. Here’s something you can do to test this: Spawn a second task which attempts to establish a connection to some other IP address. If the ARP request that the second of the two tasks submits also “pulls along” the first one, it’s exactly this kind of race condition.

I don’t think there is a problem with sending or receiving, because there has been a two-way communication in these fragments:

22 8.111633 Dell_7f:6a:7c Broadcast ARP 42 Who has 192.168.11.77? Tell 192.168.11.37
23 8.111847 10:22:33:4d:00:34 Dell_7f:6a:7c ARP 60 192.168.11.77 is at 10:22:33:4d:00:34

Here the PC is requesting the address of the STM32, who is giving an answer.

To me it looks like the initial ARP requests from the STM32 are ignored untill the PC is asking for its MAC address.

true, but my point is that possibly the very first outbound packet in Kevin’s firmware (which happens to be the ARP request) gets dropped (only because I’ve seen something similar in the past). The test I suggested would be easy and straightforward enough to rule out that kind of effect…

but my point is that possibly the very first outbound packet in Kevin’s firmware (which happens to be the ARP request) gets dropped

Ah yes, possible.
It is known that the very first UDP packet may get dropped, because the stack turns the packet into an ARP message.

I got another computer(Win10) with wireshark for testing. I found that it can receive all arp packets from STM32 and also connect to the server setup on this PC successfully.

Moreover, I built a TCP server on the NXP IMX6 development board(Linux), and the STM32 client can also connect it normally.
In short, the problem blamed on the previous computer. What the strange is that the firewall of the previous computer was indeed turned off by me, but I never received the first arp packet from STM32.
At last, Thank you for your patience to reply. @hs2 @RAc @htibosch

Hi Kevin,

thanks for letting us know that it works now! Glad your problem got solved.

This proves once again that networking - due to its heterogenous nature - is impossible to understand in full. Although I’d love to know why it didn’t work (I suspect some kind of autonegotiation issue on the PHY side), it wouldn’t help a whole lot. Kind of frustrating, but that’s the way it is…

Thanks again!