cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F745ZG ethernet high payload transmission problem

amirshn
Associate II

Hi,
I have been trying to implement a TCP server on a STM32F745ZG MCU using lwip library and ST example codes, however while I am trying to send data packets with payload bigger than 1460 bytes, my server wont be able to replay the client packet and the connection stops.

I know the ethernet standard MTU is 1500 bytes and the corresponding MSS is 1460, so i tried to increase mtu in both "ethernetif.c" and "lwipopt.h" files and also check this MCU reference manual and it seems it support bigger data packet size:

Screenshot 2024-05-23 112650.png

However, i still have no success in sending TCP payload bigger than 1460 Bytes.

Any help or hint would be highly apprecited.

 

9 REPLIES 9

@amirshn wrote:

check this MCU reference manual and it seems it support bigger data packet size:


But does LwIP support larger packet sizes?

Remember that the "Lw" in "LwIP" stands for light-weight - so maybe it's just a limitation of the stack?

https://savannah.nongnu.org/projects/lwip/

 

Have you tried debugging to see where it's failing?

https://community.st.com/t5/stm32-mcus-embedded-software/stm32f753-lwip-stack-not-initializing-after-reboot/m-p/676657/highlight/true#M47912

 

Muhammed Güler
Senior III

In Ethernet communication, the maximum amount of data you can send in a single packet is limited by the MTU. When the MTU is exceeded, data must be split into multiple packets. You should divide your data into more than one package with a code like the one below. LWIP can manage big data in itself, but personally, I'm one of those who want to control everything.

 

void BulkWrite(int conn,char *Buffer,int size)
{
	if(size<1400)
	{
		write(conn, Buffer, size);
	}
	else
	{
		write(conn, Buffer, 1400);
		BulkWrite(conn,&Buffer[1400],size-1400);
	}
}

 

  

AScha.3
Chief III

Hi,

just - why ? The connection will not run at another speed, so all you can "improve", is to have some bytes less for the headers.

see

https://stackoverflow.com/questions/2613734/maximum-packet-size-for-a-tcp-connection

This is an excellent question and I run in to this a lot at work actually. There are a lot of "technically correct" answers such as 65k and 1500. I've done a lot of work writing network interfaces and using 65k is silly, and 1500 can also get you in to big trouble. My work goes on a lot of different hardware / platforms / routers, and to be honest the place I start is 1400 bytes. If you NEED more than 1400 you can start to inch your way up, you can probably go to 1450 and sometimes to 1480'ish? If you need more than that then of course you need to split in to 2 packets, of which there are several obvious ways of doing..

The problem is that you're talking about creating a data packet and writing it out via TCP, but of course there's header data tacked on and so forth, so you have "baggage" that puts you to 1500 or beyond.. and also a lot of hardware has lower limits.

If you "push it" you can get some really weird things going on. Truncated data, obviously, or dropped data I've seen rarely. Corrupted data also rarely but certainly does happen.

If you feel a post has answered your question, please click "Accept as Solution".

Ah, yes - Postel's Law, aka The Robustness Principle:

 "Be conservative in what you send, be liberal in what you accept".

https://en.wikipedia.org/wiki/Robustness_principle 

Thanks a lot for your message.

using this solution, will I be able to acknowledge a received packet with around 1700 bytes of payload with two smaller packets from my server?( i am using a python script by scapy library act as a TCP clients which send the data to sever, and it gonna continue sending the packets only if it receive the complete reply from server)

here is my client side code:

amirshn_0-1716483988937.png

and here is my server side code for handling the received packet:

static void tcp_server_handle (struct tcp_pcb *tpcb, struct tcp_server_struct *es)

{

struct tcp_server_struct *esTx;

 

/* get the Remote IP */

ip4_addr_t inIP = tpcb->remote_ip;

uint16_t inPort = tpcb->remote_port;

 

/* Extract the IP */

char *remIP = ipaddr_ntoa(&inIP);

 

esTx->state = es->state;

esTx->pcb = es->pcb;

esTx->p = es->p;

 

char buf[1600];

memset(buf, '\0', 1600);

// Define the destination buffer

char res1_buf[1500]; // 1600 - 1450 = 150 bytes

memset(res1_buf, '\0', 1500);

char res2_buf[150]; // 1600 - 1450 = 150 bytes

memset(res2_buf, '\0', 150);

 

memcpy(buf, es->p->payload, es->p->tot_len);

 

#ifdef DEBUG

printf("%d\n", es->p->tot_len);

// Print data in hexadecimal format

for (int i = 1124 ; i < 1128; i++) {

printf("%02X ", (unsigned char)buf[i]);

}

printf("\n");

#endif

 

 

esTx->p->payload = (void *)buf;

esTx->p->tot_len = es->p->tot_len;

esTx->p->len = es->p->len;

 

if (es->p->len <= 1450){

tcp_server_send(tpcb, esTx);

pbuf_free(es->p);

}

else

{

memcpy(res1_buf,buf,1450);

esTx->p->payload = (void *)res1_buf;

esTx->p->tot_len = 1450;

esTx->p->len = 1450;

tcp_server_send(tpcb, esTx);

pbuf_free(esTx->p);

 

// Copy the bytes after the 1450th byte from buf to new_buf

memcpy(res2_buf, buf + 1450, 10);

esTx->p->payload = (void *)res2_buf;

esTx->p->tot_len = 10;

esTx->p->len = 10;

tcp_server_send(tpcb, esTx);

pbuf_free(es->p);

}

I have also attached the whole TCP server code.

Thanks for the help.

Please use this button to properly post source code:

AndrewNeil_0-1716484844791.png

Pavel A.
Evangelist III

What you want is called "jumbo packets". Look up in the RM how to enable it.

 

Hi,
I have already searched for it, found it ST HAL library for ethernet, tried it, no change.( i could not find something related to it in RM)

Pavel A.
Evangelist III

Maybe you should write code that configures the descriptors and sends raw packets without LwIP - just like you use scapy on the host side. Just get the packet on the wire and ensure that the other side is able to receive it (or you have a sniffer system with wireshark that is able to see it).