Simple TCP Echo server - does not respond to ping

andrei799 wrote on Wednesday, January 25, 2017:

Hello,

This is my first post on forum so first of all I want to say “Thank You” for the great job that you are doing with the FreeRTOS operating system. I started to use it due to the available features and excellent documentation provided.

I have a problem with server implementation from SimpleTCPEchoServer.c - in few words, does not respond to ping (and also arp) requests but even so at each 30 seconds it sends a “Gratuitos ARP” over the network.

Here are the details:
FreeRTOS v9.0
FreeRTOS Plus TCP version 160919
Custom hardware based on ARM Cortex M7 (Atmel ATSAME70Q21)
LogiLink USB to Ethernet adapter connected to PC - IP address 192.168.0.3
No DHCP (static IP - 192.168.0.2)
No DNS

The initial software application contained FreeRTOS (without TCP/ IP Stack) and Atmel’s Ethernet driver. This version responded to arp and ping requests thus I can exclude any hardware or network configuration issues.
Then I added +TCP and the SimpleTCPEchoServer.c but no answers from board.

What can be wrong?

Regards,
Andrei

rtel wrote on Wednesday, January 25, 2017:

The first thing to do will be to make sure the MAC is receiving
interrupts for incoming packets, then if it is, follow the packet’s path
into the the stack to see how far it gets.

First though, I’m curious about the following from your post:

The initial software application contained FreeRTOS (without TCP/ IP
Stack) and Atmel’s Ethernet driver. This version responded to arp and
ping requests thus I can exclude any hardware or network configuration
issues.

If it didn’t contain the TCP/IP stack, but did respond to ARP and Ping,
what was responding to ARP and Ping. Was there a different stack in use
that you removed? Or is there something in the hardware itself responding?

heinbali01 wrote on Wednesday, January 25, 2017:

And in addition to Richards questions:

Sometimes the simplest things are the most complex.
As far as I know we never provided a +TCP driver for ATSAME70Q21. Where did you get your driver?
There may be many causes. Like Richard asks, do you ever get a DMA reception (RX) interrupt?
Did you allow for broadcast messages in your EMAC?

andrei799 wrote on Wednesday, January 25, 2017:

Yes, MAC is receiving interrupts for incoming packets so I will have to check the path.

Atmel provided a mini TCP/ IP Stack capable to respond to ARP and Ping requests in order to test their MAC driver implementation.
This mini TCP/ IP Stack and Ethernet drivers were implemented by Atmel for ATSAM4E and KSZ8051.

I updated the code to properly function with custom hardware build around ATSAM7EQ21 uC and KSZ8041TL Ethernet driver -> board responded to ARP and Ping requests (continuously tested for few hours without failures).

Broadcast messages are allowed by EMAC.

FreeRTOS_IPInit() called before starting the scheduler; prvIP_Task priority = 3
IPHook function -> network up -> create server task with priority = 1

heinbali01 wrote on Thursday, January 26, 2017:

Hi Andrei,
I’m afraid I can’t help you much more on this.
Do you see that it attempts to send packets back? If not, you’ll really have to follow the entire path from reception to answering.
I’m not familiar with the mini IP-stack developed by Atmel. FreeRTOS has FreeRTOS+TCP, which has a driver and demo project for SAM4E.
Unfortunately I don’t have a ATSAM7EQ21 for testing.

andrei799 wrote on Thursday, January 26, 2017:

Hello Hein,
I think I was not so clear in explanations. Currently I am using the FreeRTOS+TCP with driver and demo project based on SAM4E but with some small updates necessary for ATSAME70Q21.

The mini TCP/ IP Stack provided by Atmel I initially use it just to test the EMAC driver, network configuration and possible hardware issues. After being confident that all things were well functioning I replaced the mini TCP/ IP Stack with FreeRTOS+TCP. Now comes my problem because the board does not respond to ARP and Ping requests.

It seems that TCP/ IP packets are not sent to IP Task due to pxNextNetworkBufferDescriptor which is NULL (prvEMACRxPoll function). Please have a look below.

	if( pxNextNetworkBufferDescriptor != NULL )
	{
		/* Point pucUseBuffer to the buffer pointed to by the descriptor. */
		pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
	}

** else
{
/* As long as pxNextNetworkBufferDescriptor is NULL, the incoming
messages will be flushed and ignored. /
pucUseBuffer = NULL;
}
*

I am trying to figure out why this is happening.

rtel wrote on Thursday, January 26, 2017:

Which buffer allocation file are you using? BufferAllocation_1.c or
BufferAllocation_2.c?

heinbali01 wrote on Thursday, January 26, 2017:

the board does not respond to ARP and Ping requests

Before being able to PING, an ARP request must be sent and answered.
So let’s focus at the ARP requests.

Do you see ARP requests arrive at your device? If not, did you allow for broadcast addresses?

If ARP requests do arrive, do you see that xNetworkInterfaceOutput() gets called?
Do you see an answer to the ARP request on the LAN, when looking with Wireshark?
If you do not see an answer, has the DMA been initialised well? Did you start the peripheral clock for DMA? Did you enable RX and TX? Were all descriptors well initialised?

If pxNextNetworkBufferDescriptor equals to NULL, that would mean that some Network Buffers do not get released. You’re running out of Network Buffers.

Would you mind showing the adapted NetworkInterface.c ?
You might also attach a PCAP if you want, when trying out an ARP / PING.

Regards.

andrei799 wrote on Thursday, January 26, 2017:

I am using BufferAllocation_2.c

For an ARP request I don’t see any network transfer with Wireshark but in debug mode if I store data received into a buffer (gs_uc_eth_buffer) I can see the received packet, please see .png image and Wireshark capture.

For Ping request please see Wireshark capture named “Ping request.pcapng”.

xNetworkInterfaceOutput () gets called
For all the other questions the answers are affirmative.

andrei799 wrote on Thursday, January 26, 2017:

… and in attachment it is the updated NetworkInterface.c source code

heinbali01 wrote on Saturday, January 28, 2017:

Hi Ion Andrei,

Your PCAP called “ARP request.pcapng” looks strange:

It shows 32 so-called gratuitous ARP requests, which are sent within less than a ms.
The IP-stack will send these ‘gratuitous ARP requests’ regularly but not that often. The requests help other devices to keep ARP tables up-to-date, and also to help the detection of double IP-addresses.

Within “PING request.pcapng”, I see three gratuitous ARP requests, sent at an acceptable frequency of two per minute.

The ping command (e.g. ping 192.168.0.2) will always start with an ARP command. In you PCAP, the ARP commando isn’t answered by the device.
As the device is sending gratuitous ARP requests, I would conclude that its RX path isn’t working properly.

andrei799 wrote on Sunday, January 29, 2017:

Hello Hein,

Related to ARP requests - after some time (dozens of seconds) the “gratuitos ARP requests” are sent at much lower frequency as you pointed out.

I’m fully agree that issue is on Rx path.
Please have a look at first image with an ethernet frame received stored in gs_uc_eth_buffer. All data bytes seems to be correctly received (e.g. ethernet header, …) but aren’t sent further to IP Task because all time pxNextNetworkBufferDescriptor == NULL and ```
As long as pxNextNetworkBufferDescriptor is NULL, the incoming
messages will be flushed and ignored.
pucUseBuffer = NULL;


It seems that TCP/ IP packets are not sent to IP Task due to pxNextNetworkBufferDescriptor which is NULL (prvEMACRxPoll function). Please have a look below.

if( pxNextNetworkBufferDescriptor != NULL )
{
    /* Point pucUseBuffer to the buffer pointed to by the descriptor. */
    pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE );
}

**> > else

{
/ As long as pxNextNetworkBufferDescriptor is NULL, the incoming
messages will be flushed and ignored. /
pucUseBuffer = NULL;
}

Please give me some hints about why pxNextNetworkBufferDescriptor equals NULL. What could be the reason for this? Thanks you.

Regards,
Andrei

andrei799 wrote on Friday, October 20, 2017:

Hello,

It’s been a while since I have worked at this project and now it’s comming back with high priority therefore I will have to fix somehow the ethernet communication bug.

I think I know the reason for board not responding to ARP request but I do not know how to fix it.
It seems that Ethernet packet is wrong interpreted due to pxEthernetHeader which is pointing to a wrong address - instead of 0x20406938 is pointing to 0x2040693A. Having this 2 bytes offset error leads to not correctly identify the ethernet type (instead of 0x0608 is seen 0x0100) so the switch will always execute the default case (release buffer) and not the ARP case. Please see the attachment.

Please let me know from where this offset is comming. What to check? Thank you.
(All TCP structures are packed in code so there is not any padded byte)

MAC destination address - 00:04:25:1C:A0:02
MAC source address - 00:60:6E:43:61:FB

Regards,
Andrei

static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
EthernetHeader_t *pxEthernetHeader;
volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */

	configASSERT( pxNetworkBuffer );

	/* Interpret the Ethernet frame. */
	eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
	pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );

	if( eReturned == eProcessBuffer )
	{
		/* Interpret the received Ethernet packet. */
		**switch( pxEthernetHeader->usFrameType )**
		{
			case ipARP_FRAME_TYPE :
				/* The Ethernet frame contains an ARP packet. */
				eReturned = eARPProcessPacket( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
				break;

			case ipIPv4_FRAME_TYPE :
				/* The Ethernet frame contains an IP packet. */
				eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );
				break;

			**default :
				/* No other packet types are handled.  Nothing to do. */
				eReturned = eReleaseBuffer;
				break;**
		}
	}

heinbali01 wrote on Saturday, October 21, 2017:

Hi Andrei, it looks like you have correctly defined ipconfigPACKET_FILLER_SIZE in your FreeRTOSIPConfig.h as follows:

#define ipconfigPACKET_FILLER_SIZE   2

See a discussion about this padding here:

FreeRTOS_TCP - zero copy - ipBUFFER_PADDING

This means that any Ethernet packet (pxDescriptor->pucEthernetBuffer) will start at a (32-bit) aligned offset plus 2. The reason for this is that almost all 32-bit values in the IP and TCP/UDP packets will become 32-bit aligned.

But your CPU peripheral must know that you want packets to be written at a +2 byte offset. This is done by setting:

    GMAC Network Configuration Register: GMAC_NCFGR

    ● RXBUFO: Receive Buffer Offset
    Indicates the number of bytes by which the received data is
    offset from the start of the receive buffer.

You could set the offset like this:

    gmac_set_config(p_gmac,
        ( gmac_get_config(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) |
          GMAC_NCFGR_RFCS |   /*  Remove FCS, frame check sequence (last 4 bytes) */
          GMAC_NCFGR_PEN |    /* Pause Enable */
          GMAC_NCFGR_RXBUFO( ipconfigPACKET_FILLER_SIZE ) | /* Set Ethernet Offset  */
          GMAC_RXD_RXCOEN );    /* RXCOEN related function */

For transmitting packets there should not be a problem: the contents of pucEthernetBuffer will be sent, which is already aligned with an offset of 2 bytes.

Please let me know if this helps. Hein

heinbali01 wrote on Saturday, October 21, 2017:

PS.
I just ordered an evaluation board ATSAME70-XPLD so I can help testing the driver.
Until now I could only test the SAM4E.
I am working on a “unified” driver that works both on SAM4E, as well as on SAME70.

andrei799 wrote on Saturday, October 21, 2017:

Hello Hein,

Thank you very much for the support.
UnfortunatelIy I can update the code and test it only Monday when for sure that I will post the test result.
I just wait to do it.

Best regards,
Andrei

andrei799 wrote on Monday, October 23, 2017:

Hello Hein,

I just tested and it seems the issue is now fixed so the ethernet frame is right processed.

Now I have another issue on transmit path in Atmel’s GMAC driver, gmac_dev_write() function, so the answer is not sent back (test using ARP command) because there are no free trasmit descriptors and function will always return GMAC_TX_BUSY.

	/* Pointers to the current transmit descriptor */
	p_tx_td = &p_gmac_queue->p_tx_dscr[p_gmac_queue->us_tx_head];

	/* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
	if (CIRC_SPACE(p_gmac_queue->us_tx_head, p_gmac_queue->us_tx_tail,
					p_gmac_queue->us_tx_list_size) == 0) {
		if (p_tx_td[p_gmac_queue->us_tx_head].status.val & GMAC_TXD_USED)
		**	return GMAC_TX_BUSY;**
	}

Please give me some hints about what I can do.

Best regards,
Andrei

andrei799 wrote on Monday, October 23, 2017:

I fixed the “no free tx descriptor” issue. The number of Tx buffers was defined in FreeRTOSIPConfig.h by constant GMAC_TX_BUFFERS with default value of 2. It seems that it was not enough so I increased it to 4 (empirical value and not computed) now having 4 Tx buffers each of 1518 bytes length.

/* Number of DMA buffer used by the driver for TX. */
#define GMAC_TX_BUFFERS  4  /* 4 * 1518 = 6072 bytes -> ~6kB */

I still do not understand why 2 buffers were not enough but for the moment it is a good thing that I have an ATSAME70Q21 custom board running FreeRTOS + TCPIP.

Best regards,
Andrei

heinbali01 wrote on Monday, October 23, 2017:

I still do not understand why 2 buffers were not enough but for the moment

I suppose that your driver uses zero-copy for sending?
If you need 4 TX buffers, it means that your CPU ( ATSAME70 ) is pretty fast.
What happens if xNetworkInterfaceOutput() finds that all DMA buffers are occupied? Doesn’t it wait a few uS? It would be worth blocking on a ( counting ) semaphore.
Like I mentioned here above, I am waiting for a ATSAME70 evaluation board.

andrei799 wrote on Tuesday, October 24, 2017:

Driver copies the buffer to one of the GMAC Tx buffers so it does not use zero-copy for sending. The function is that one provided by Atmel and I have not modified it. Below is the function prototype.

/**
 * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
 * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready.
 * If lEndOfFrame is true then the data being copied is the end of the frame
 * and the frame can be transmitted.
 *
 * \param p_gmac_dev Pointer to the GMAC device instance.
 * \param p_buffer   Pointer to the data buffer.
 * \param ul_size    Length of the frame.
 * \param func_tx_cb  Transmit callback function.
 *
 * \return Length sent.
 */
uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, gmac_quelist_t queue_idx, void *p_buffer, uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb)