Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] loopback is not working #1179

Closed
rickou opened this issue Aug 19, 2024 · 21 comments
Closed

[BUG] loopback is not working #1179

rickou opened this issue Aug 19, 2024 · 21 comments
Assignees
Labels
bug Something isn't working

Comments

@rickou
Copy link

rickou commented Aug 19, 2024

Describe the bug
i can't get the loopback interface to work at all.
I'm starting implementing the FreeRTOS+TCP to my project. Because i need to write my own interface for ENC424J600, before i would like to do some tests using the provided loopback interface.
I setup the loopback interface with IP 127.0.0.1/255.255.255.255
and try to send ping to 127.0.0.1 (it seems, it is not possible to resolve "localhost")
packet is send to the interface and it is put directly on the RxQueue by the interface.
but at the RxEvent, the packet is dropped because pxNetworkBuffer->pxInterface == NULL (in prvProcessEthernetPacket)

i'm using the ip stack v4.2.2

i'm not sure it is a bug, maybe only a mis-use..

@rickou rickou added the bug Something isn't working label Aug 19, 2024
@htibosch
Copy link
Contributor

I setup the loopback interface with IP 127.0.0.1/255.255.255.255

One thing for sure, there are 2^24 loopback addresses, and so the network mask for loopback is 255.0.0.0, and not "all ones" (255.255.255.255).

it seems, it is not possible to resolve "localhost"

It should be possible to do that your self, using mDNS or LLMNR, and the xApplicationDNSQueryHook().

Could you show two pieces of your code:

  • The initialisation of the interfaces
  • the code that you use on the loopback interface, ICMP, TCP, or UDP?

@rickou
Copy link
Author

rickou commented Aug 19, 2024

Hi @htibosch,

thank to point the mistake on the mask for loopback.

i implemented xApplicationDNSQueryHook_Multi(), but if i try to do a
ulIPAddress = FreeRTOS_gethostbyname( "localhost");
i do not go to the hook function.. and i get

DNS_ReadReply returns -11 (FreeRTOS_DNS_Networking.c:157)
prvIncreaseDNS4Index: from 0 to 0 (FreeRTOS_DNS.c:798)
DNS_ReadReply returns -11 (FreeRTOS_DNS_Networking.c:157)
prvIncreaseDNS4Index: from 0 to 0 (FreeRTOS_DNS.c:798)

but ok, it is not my main pb here.

Here is my init code (a little bit cleaned)

static const uint8_t _pu8_IPAddress[4] = {127, 0, 0, 1};
static const uint8_t _pu8_NetMask[4] = {255,0,0,0};
static const uint8_t _pu8_GatewayAddress[4] = {0,0,0,0};
static const uint8_t _pu8_DNSServerAddress[4] = {0,0,0,0};
static const uint8_t _pu8_MACAddress[6] = {0x11,0x22,0x33,0x44,0x55,0x66};
void Init(void)
{
    pxLoopback_FillInterfaceDescriptor(0, &_t_Interfaces[0]);
    FreeRTOS_FillEndPoint(&_t_Interfaces[0], &_t_EndPoints[0], _pu8_IPAddress, _pu8_NetMask, _pu8_GatewayAddress, 
    _pu8_DNSServerAddress, _pu8_MACAddress);
    xResult = FreeRTOS_IPInit_Multi();
}

what do you mean for the 2nd point ?
i use the loopback network interface as is.

static BaseType_t prvLoopback_Output( NetworkInterface_t * pxInterface,
                                      NetworkBufferDescriptor_t * const pxGivenDescriptor,
                                      BaseType_t bReleaseAfterSend )
{
    NetworkBufferDescriptor_t * pxDescriptor = pxGivenDescriptor;

    ( void ) pxInterface;

    IPPacket_t * a = ( IPPacket_t * ) ( pxDescriptor->pucEthernetBuffer );

    if( a->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
    {
        usGenerateProtocolChecksum( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, pdTRUE );
    }

    {
        MACAddress_t xMACAddress;

        if( pxDescriptor->pxEndPoint->bits.bIPv6 != 0 )
        {
            #if ( ipconfigUSE_IPv6 != 0 )
                if( xIsIPv6Loopback( &( pxDescriptor->xIPAddress ) ) != pdFALSE )
                {
                    vNDRefreshCacheEntry( &xMACAddress, &( pxDescriptor->xIPAddress.xIP_IPv6 ), pxDescriptor->pxEndPoint );
                }
            #endif
        }
        else
        {
            #if ( ipconfigUSE_IPv4 != 0 )
                if( xIsIPv4Loopback( pxDescriptor->xIPAddress.ulIP_IPv4 ) )
                {
                    vARPRefreshCacheEntry( &xMACAddress, pxDescriptor->xIPAddress.ulIP_IPv4, pxDescriptor->pxEndPoint );
                }
            #endif
        }
    }

    if( bReleaseAfterSend == pdFALSE )
    {
        NetworkBufferDescriptor_t * pxNewDescriptor =
            pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, pxDescriptor->xDataLength );
        pxDescriptor = pxNewDescriptor;
    }

    if( pxDescriptor != NULL )
    {
        IPStackEvent_t xRxEvent;

        xRxEvent.eEventType = eNetworkRxEvent;
        xRxEvent.pvData = ( void * ) pxDescriptor;

        if( xSendEventStructToIPTask( &xRxEvent, 0u ) != pdTRUE )
        {
            vReleaseNetworkBufferAndDescriptor( pxDescriptor );
            iptraceETHERNET_RX_EVENT_LOST();
            FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
        }
    }

    /* The return value is actually ignored by the IP-stack. */
    return pdTRUE;
}

here the code i use to send ping (from example) (again little bit cleaned)

	BaseType_t xReturn;
	uint32_t ulIPAddress, ulBytesToPing;
	const uint32_t ulDefaultBytesToPing = 8UL;

	ulBytesToPing = ulDefaultBytesToPing;
	ulIPAddress = FreeRTOS_inet_addr( "127.0.0.1" );

	xReturn = FreeRTOS_SendPingRequest( ulIPAddress, ( uint16_t ) ulBytesToPing, portMAX_DELAY );

i checked the events received,
1st rx events right after the SendPingRequest do not have the interface filled, and is skipped
some time after i get some rx events with the interface filled and interpreted as ARP frame type. (but i don't regnise anything in it..)
i'm pretty sure i missed something somewhere...

@rickou
Copy link
Author

rickou commented Aug 21, 2024

Hello @htibosch
I progressed in the interface driver for the ENC424J600 and make it almost working (Rx, Tx packets and at least DHCP client, ping replies works)
but...
The 1st call to FreeRTOS_SendPingRequest do not send anything on the interface, but subsequent calls works as exoected and i receive the reply.
(i will check again with the loopback interface)

I also see something strange in the TCP source..
we can see at the begining of the function FreeRTOS_SendPingRequest a piece of code that suggest it will send 4 echo request packets:
if( ( uxGetNumberOfFreeNetworkBuffers() >= 4U ) && ( uxNumberOfBytesToSend >= 1U ) && ( xEnoughSpace != pdFALSE ) )

but i see nowhere a loop or something similar to add the 4 frames...

i continue to investiguate why 1st ping request is not sent
The frame do not come at interface level...
The xSendEventStructToIPTask returns without error, but prvProcessIPEventsAndTimers never receive it..

@ActoryOu
Copy link
Member

Hi @rickou,
I think the first ping gets lost because it is turned into an ARP packet. In FreeRTOS_SendPingRequest(), it sends a eStackTxEvent event to the stack, then vARPGenerateRequestPacket() turns that network buffer into ARP request during vProcessGeneratedUDPPacket() when cache miss. That's expected behavior for the stack.

Thank you.

@rickou
Copy link
Author

rickou commented Aug 22, 2024

Hello @ActoryOu, @htibosch
thank for your answer.

i understand that my pb is not linked to the loopback interface, but linked to the stack itself..
The loopback returns the ARP packet following the 1st ping, to the stack input
But i suspect the stack do not understand this incoming packet. So the ARP table is not filled then the ping request is never sent.

I understand, but that's mean all 1st ping for a target were lost ? In this case, how the application could be notified of this ?
If the ARP table is full and older entries are flushed, then again, the 1st request is dropped..
It is a very strange behavior (even if it is by design)

Another issue, seems to be linked:
if i try to resolve an external hostname, again the 1st time i call FreeRTOS_gethostbyname, it doesn't work.. the 2 DNS loockup fail with error -11..
This is more a problem than pinging...

<INFO  >    12863 [CLI       ] Resolving an.external.domain (Console.c:167)
<DEBUG >    12863 [IP-Task   ] ARP 192.168.254.10 miss using 192.168.254.10 (FreeRTOS_ARP.c:1095)
<DEBUG >    12863 [IP-Task   ] eth0: Sending frame with 42 bytes (ENC424J600.c:1283)
<DEBUG >    12864 [IP-Task   ] eth0: Frame sent successfully (ENC424J600.c:1295)
<DEBUG >    12865 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.87 -> 192.168.254.10 (FreeRTOS_Routing.c:987)
<DEBUG >    12865 [IP-Task   ] ipARP_REPLY from 192.168.254.10 to 192.168.254.87 end-point 192.168.254.87 (FreeRTOS_ARP.c:266)
<DEBUG >    12865 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    13972 [Tmr Svc   ] pxEasyFit: ARP 192.168.253.5 -> 192.168.253.100 (FreeRTOS_Routing.c:987)
<DEBUG >    13973 [IP-Task   ] ipARP_REQUEST from 192.168.253.5 to 192.168.253.100 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    13973 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    16377 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<DEBUG >    16901 [Tmr Svc   ] pxEasyFit: ARP 192.168.253.5 -> 192.168.253.100 (FreeRTOS_Routing.c:987)
<DEBUG >    16901 [IP-Task   ] ipARP_REQUEST from 192.168.253.5 to 192.168.253.100 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    16901 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    17118 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<DEBUG >    17258 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.82 -> 192.168.254.84 (FreeRTOS_Routing.c:987)
<DEBUG >    17258 [IP-Task   ] ipARP_REQUEST from 192.168.254.82 to 192.168.254.84 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    17258 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    17860 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<INFO  >    17864 [CLI       ] DNS_ReadReply returns -11 (FreeRTOS_DNS_Networking.c:157)
<INFO  >    17864 [CLI       ] prvIncreaseDNS4Index: from 0 to 1 (FreeRTOS_DNS.c:798)
<DEBUG >    17864 [IP-Task   ] ARP 192.168.254.2 miss using 192.168.254.2 (FreeRTOS_ARP.c:1095)
<DEBUG >    17864 [IP-Task   ] eth0: Sending frame with 42 bytes (ENC424J600.c:1283)
<DEBUG >    17865 [IP-Task   ] eth0: Frame sent successfully (ENC424J600.c:1295)
<DEBUG >    17866 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.87 -> 192.168.254.2 (FreeRTOS_Routing.c:987)
<DEBUG >    17866 [IP-Task   ] ipARP_REPLY from 192.168.254.2 to 192.168.254.87 end-point 192.168.254.87 (FreeRTOS_ARP.c:266)
<DEBUG >    17866 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    18290 [Tmr Svc   ] eth0: Receiving frame with 257 bytes (ENC424J600.c:944)
<DEBUG >    19057 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<DEBUG >    19793 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<DEBUG >    19949 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.82 -> 192.168.254.84 (FreeRTOS_Routing.c:987)
<DEBUG >    19949 [IP-Task   ] ipARP_REQUEST from 192.168.254.82 to 192.168.254.84 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    19950 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    20016 [Tmr Svc   ] pxEasyFit: ARP 192.168.253.5 -> 192.168.253.100 (FreeRTOS_Routing.c:987)
<DEBUG >    20016 [IP-Task   ] ipARP_REQUEST from 192.168.253.5 to 192.168.253.100 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    20016 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    20526 [Tmr Svc   ] eth0: Receiving frame with 93 bytes (ENC424J600.c:944)
<DEBUG >    20660 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.82 -> 192.168.254.84 (FreeRTOS_Routing.c:987)
<DEBUG >    20660 [IP-Task   ] ipARP_REQUEST from 192.168.254.82 to 192.168.254.84 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    20660 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    21633 [Tmr Svc   ] pxEasyFit: ARP 192.168.254.82 -> 192.168.254.84 (FreeRTOS_Routing.c:987)
<DEBUG >    21633 [IP-Task   ] ipARP_REQUEST from 192.168.254.82 to 192.168.254.84 end-point 192.168.254.87 (FreeRTOS_ARP.c:278)
<DEBUG >    21633 [Tmr Svc   ] eth0: Receiving frame with 61 bytes (ENC424J600.c:944)
<DEBUG >    22292 [Tmr Svc   ] eth0: Receiving frame with 244 bytes (ENC424J600.c:944)
<DEBUG >    22494 [Tmr Svc   ] eth0: Receiving frame with 131 bytes (ENC424J600.c:944)
<INFO  >    22865 [CLI       ] DNS_ReadReply returns -11 (FreeRTOS_DNS_Networking.c:157)
<INFO  >    22865 [CLI       ] prvIncreaseDNS4Index: from 1 to 0 (FreeRTOS_DNS.c:798)
Could not send ping request

2nd time, the resolution works as expected
I understand that the 1st attempt fill the ARP table with the 2 DNS entries, and the application can handle this, but it take a while (10s !) just to fill the ARP !

so, to summarize, each time a frame is sent to whatever ipaddress, that is not in the ARP table, will be dropped ?!

I can't agree with this (bad) behavior, but do you know a way to handle this at application side ?
or a way to improve this ? (i didn't checked yet if there is an ARP public function to check/fill the table ..)
At this time my ARP table is 6 entries length, i will increase this, but i need the application to handle these kind of failures

@shubnil shubnil self-assigned this Aug 22, 2024
@rickou
Copy link
Author

rickou commented Aug 22, 2024

related to my original post (loopback interface pb)
I made a new try with the loopback interface.
I added to my app to print the ARP cache. and i see strange (at least for me)..

It start just after boot. (the loopback interface MAC is 11:22:33:44:55:66, IP is 127.0.0.1/255.0.0.0)

printarptable
<INFO  >     6720 [CLI       ] Arp has 0 entries (FreeRTOS_ARP.c:1560)
printarptable
<INFO  >    13928 [CLI       ] ARP  0: 150 - 127.0.0.1 : 10:19:00 : 20:00:00 (FreeRTOS_ARP.c:1546)
<INFO  >    13928 [CLI       ] Arp has 1 entries (FreeRTOS_ARP.c:1560)
ping 127.0.0.1
Ping sent to 127.0.0.1 with identifier 1
printarptable
<INFO  >    84430 [CLI       ] ARP  0: 149 - 127.0.0.1 : 62:4b:00 : 20:84:4b (FreeRTOS_ARP.c:1546)
<INFO  >    84430 [CLI       ] Arp has 1 entries (FreeRTOS_ARP.c:1560)
ping 127.0.0.1
Ping sent to 127.0.0.1 with identifier 2
printarptable
<INFO  >   101530 [CLI       ] ARP  0: 150 - 127.0.0.1 : 10:19:00 : 20:00:00 (FreeRTOS_ARP.c:1546)
<INFO  >   101530 [CLI       ] Arp has 1 entries (FreeRTOS_ARP.c:1560)

as you can see, the ARP table contains an entry, but with a strange MAC address.. (changing at each update)

@htibosch
Copy link
Contributor

Hi @rickou,

if( ( uxGetNumberOfFreeNetworkBuffers() >= 4U ) &&
    ( uxNumberOfBytesToSend >= 1U ) &&
    ( xEnoughSpace != pdFALSE ) )
{
    // send a ping request
}

The value 4U doesn't have a scientific reason. It's just that I saw TCP suffering from sending frequent ping requests.
So the number 4 available buffers was just a guess. We could replace this with ( yet another ) configuration macro. I propose that the macro will have a very long name like:

#define SEND_ICMP_ONLY_WHEN_MINIMAL_N_BUFFERS_AVAILABLE   4

@rickou
Copy link
Author

rickou commented Aug 23, 2024

Hi @htibosch ,
Thank you for explanation.
but... hum... it's like to say "it works like this, but we don't know why" or some kind of magical number that make it to works almost fine... no ? 🤪
i think the same "problem" should occurs everywhere the stack needs to send a frame...
If this was used to send the ARP request previously to the ping request, ok i could understand...

Regarding the UDP packet replaced by ARP request, could it be possible to store the original UDP request waiting the ARP reply ? and then automatically send it after the reply ?
I made other tests yesterday, and honestly i'm a little bit frustrated by this behavior...

ex: on the local network we want to ping a server by its name..
so we need 3 attempts and 10+ seconds before it will works !
1st name resolving fail after 10s (2 DNSs)
2nd name resolving now returns the IP, but ping fail (without notification to the app..)
3rd ping works as expected..

maybe i need to do ping in another way, but at this time i don't know how to do better. (i use an example)

@htibosch
Copy link
Contributor

it's like to say "it works like this, but we don't know why" or some kind of magical number that make it to works almost fine... no ? 🤪

Only the number is called magic, not the algorithm.

Regarding the UDP packet replaced by ARP request, could it be possible to store the original UDP request waiting the ARP reply ? and then automatically send it after the reply ?

Yes for sure! In fact we already have such a mechanism. Look at the identifier pxARPWaitingNetworkBuffer. Suppose the DUT receives a UDP or TCP packet from a host that is unknown. In that case, the received packet will be stored in pxARPWaitingNetworkBuffer. As soon as a matching ARP reply is received, the packet may be processed. I think it was introduced in PR 318.

I made other tests yesterday, and honestly i'm a little bit frustrated by this behavior...

I can imagine, it is. Sometimes it is handy to explicitly send an ARP request:

    /* Send an ARP request and wait 500 ms for an answer. */
    BaseType_t xARPWaitResolution( FreeRTOS_inet_addr_quick( 192, 168, 2, 1 ), pdMS_TO_TICKS( 500U ) )

@htibosch
Copy link
Contributor

I just tested sending PING messages just after start-up. I am attaching a source file that contains my testing code which I used on an STM32F4.

arp_ping_test.zip

I have used these endpoints:

IP-address   Net mask
192.168.2.107 255.255.255.0
127.0.0.1     255.0.0.0

It calls 'arp_ping_test()` two times, once to ping a loopback node, and once to ping my laptop. It does not find the correct MAC-address for the loopback interface. I will check that later.

I think we'll need two changes;

In source/portable/NetworkInterface/loopback/loopbackNetworkInterface.c around line 166:

    if( pxDescriptor != NULL )
    {
        IPStackEvent_t xRxEvent;

        xRxEvent.eEventType = eNetworkRxEvent;
        xRxEvent.pvData = ( void * ) pxDescriptor;
+
+       pxDescriptor->pxInterface = xLoopbackInterface;
+       pxDescriptor->pxEndPoint = FreeRTOS_MatchingEndpoint( xLoopbackInterface, pxDescriptor->pucEthernetBuffer );
 
-        if( xSendEventStructToIPTask( &xRxEvent, 0u ) != pdTRUE )
+        if( ( pxDescriptor->pxEndPoint == NULL ) || ( xSendEventStructToIPTask( &xRxEvent, 0u ) != pdTRUE ) )
        {
            vReleaseNetworkBufferAndDescriptor( pxDescriptor );
            iptraceETHERNET_RX_EVENT_LOST();
            FreeRTOS_printf( ( "prvLoopback_Output: Can not queue return packet!\n" ) );
        }
    }

In source/FreeRTOS_DNS_Callback.c near line 70 :

     vTaskSuspendAll();
     {
         for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
              pxIterator != ( const ListItem_t * ) xEnd;
              pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
         {
             BaseType_t xMatching;
             DNSCallback_t * pxCallback = ( ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
             #if ( ipconfigUSE_MDNS == 1 )
                 /* mDNS port 5353. */
-                if( pxSet->usPortNumber == FreeRTOS_htons( ipMDNS_PORT ) )
+                if( pxSet->usPortNumber == ipMDNS_PORT )
                 {
                     /* In mDNS, the query ID field is ignored and the
                      * hostname will be compared with outstanding requests. */

But as said, I will come back to this.

@rickou
Copy link
Author

rickou commented Aug 26, 2024

Thank you @htibosch for your testing !

Do I (or you?) need to change the post subject ? (not only related to loopback now..)

At my side, i added the coreSNTP lib to my project..
and as i suspected, i get also pb to make it to work fine.. i haven't yet check deeply, but i need 3 attempts to get the clock update.

  1. Resolving the hostname fail a 1st time (same topic already described here)
  2. Resolving ok, querying the SNTP server seems ok, but timeout receiving the answer..
  3. Querying and reply well received...

for the 2nd step, i suspect it is also linked to the UDP packet replacement.. but i need to check deeply what's happen.

@htibosch
Copy link
Contributor

Calling this:

/* Send an ARP request and wait 500 ms for an answer. */
    uint32_t uxGateWay = xxx;
    BaseType_t xARPWaitResolution( uxGateWay ), pdMS_TO_TICKS( 500U ) )

should make it a bit faster because the gateway has been resolved.

Do I (or you?) need to change the post subject ? (not only related to loopback now..)

No problem. Other people might google for the exact title: "loopback not working" and find answers here.

The last time I tested, UDP and TCP worked well with the loopback interface. But today I saw that ARP is not working in a transparent way.

This will stop it:

            else if( ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) ) &&
                     ( ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) < ipLAST_LOOPBACK_IPv4 ) )
            {
                /* The local loopback addresses must never appear outside a host. See RFC 1122
                 * section 3.2.1.3. */
                iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
            }

Beside that, when ARP receives a packet from 127.0.0.1 to 127.0.0.1, it will decide that this is an IP collision.
This happens in a complex function eARPProcessPacket(). We won't make the +TCP team happy if we change fundamental functions.

I rather think of resolve loopback addresses in the same way as we do multicast addresses.

See the call to vSetMultiCastIPv4MacAddress() in the function eARPGetCacheEntry(). We could add:

        pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( ulAddressToLookup, 0 );

        if( xIsIPv4Loopback( ulAddressToLookup ) != 0 )
        {
            if( pxEndPoint != NULL )
            {
                /* For multi-cast, use the first IPv4 end-point. */
                memcpy( pxMACAddress->ucBytes, pxEndPoint->xMACAddress.ucBytes, sizeof( pxMACAddress->ucBytes ) );
                *( ppxEndPoint ) = pxEndPoint;
                eReturn = eARPCacheHit;
                //FreeRTOS_printf( ( "eARPGetCacheEntry: loopback found\n" ) );
            }
        }

@htibosch
Copy link
Contributor

OK, all loopback problems seem to be solved. I will attach a ZIP file with these 2 files:

  • loopback_ht.patch: A patch that should be applied to the latest repository
  • loopback_test_ht.c: A testing program called

patch_and_testing_program.zip

You can apply the patch with:

    git apply /home/me/Download/loopback_ht.patch

If it works for you too, we can turn it into a pull request.

@rickou
Copy link
Author

rickou commented Aug 27, 2024

Hello @htibosch

Thank for the patch, but it fail applying to the LTS version

I checked manually, but the file FreeRTOS_ARP.c is very different as the one expected in your patch..
What source version do you expect ?
as said, i'm using the latest FreeRTOS LTS repo with Plus-TCP v4.2.2

@htibosch
Copy link
Contributor

Here are the adapted sources: source_v4.2.2_with_patch.zip

These sources files have changed:

  • source/FreeRTOS_ARP.c
  • source/FreeRTOS_DNS_Callback.c
  • portable/NetworkInterface/loopback/loopbackNetworkInterface.c

Will that work?

When I have a commercial project, I also use the latest LTS release. For my Open Source work, I must use today's main branch.

@rickou
Copy link
Author

rickou commented Aug 27, 2024

Yes it works !
(And the 1st ping is not lost for the loopback interface)

thank for this patch.

@rickou
Copy link
Author

rickou commented Aug 27, 2024

Just seen another strange behavior, if i ping my own IP (using a normal interface), i never get a reply.. even if i made multiple tries.
you write in a previous answer:

The last time I tested, UDP and TCP worked well with the loopback interface. But today I saw that ARP is not working in a transparent way.

This will stop it:

            else if( ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) ) &&
                     ( ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) < ipLAST_LOOPBACK_IPv4 ) )
            {
                /* The local loopback addresses must never appear outside a host. See RFC 1122
                 * section 3.2.1.3. */
                iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
            }

Beside that, when ARP receives a packet from 127.0.0.1 to 127.0.0.1, it will decide that this is an IP collision. This happens in a complex function eARPProcessPacket(). We won't make the +TCP team happy if we change fundamental functions.

for me the correct behavior should be to get an ping reply even for our own IP address

@htibosch
Copy link
Contributor

When you ping 127.0.0.1, the packet will be send to the IP-task, using an eNetworkRxEvent.

The IP-task will recognise the ICMP packet, and send an answer back to the IP task, also through an eNetworkRxEvent.

We just saw that it works, and fast!

Now if you send a ping message to your local-LAN IP address, say 192.168.1.22, it will look up the MAC address issuing an ARP broadcast. It will never be found and so the ICMP packet will never get transmitted.

Suppose we do know the MAC-address, which is stored in the endpoint, we still won't get a reply.

For the sake of simplicity, I would recommend to leave it this way.

@rickou
Copy link
Author

rickou commented Aug 27, 2024

Now if you send a ping message to your local-LAN IP address, say 192.168.1.22, it will look up the MAC address issuing an ARP broadcast. It will never be found and so the ICMP packet will never get transmitted.

Suppose we do know the MAC-address, which is stored in the endpoint, we still won't get a reply.

Hum, I do not understand why we can't get a ping reply..
The stack and/or ARP should found/hit for our own interface IP/MAC without doing any request ! (all informations are available internally)

but ok, it is not important, just for me it is not a correct behavior.

@htibosch
Copy link
Contributor

Hum, I do not understand why we can't get a ping reply..

In short: the costs will be higher than the profits.

We want to keep the +TCP library as clear and clean as possible. When you turn each end-point into a possible peer, every endpoint will become a sort of "loopback device".

You don't want to change the NetworkInterface for this, because that would imply that all interfaces much be adapted.

I do not see a simple way to do this. It would give a lot of work, and also we'd have to be aware of potential security risks. All protocol tests (compliance to RFC) and all unit-testing will need a new round of changes.

@tony-josi-aws
Copy link
Member

@rickou Thanks for reporting this issue.

Closing this ticket as the associated PR #1185 has been merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants