cancel
Showing results forย 
Search instead forย 
Did you mean:ย 

How to receive a 4k UDP packet when my MTU is 1500, using fragmented IP packets?

Mz.1
Associate III

Hey,

I Have STM32H743Zi

I'm new at this, so please forgive me if I'm unclear.

I'm trying to receive 4k UDP packets but I'm getting only 1k each time.

I did a Google search and understand that if I want to receive a UDP packet of 4k I need to use fragmentation due to the MTU being 1500.

I tried to enable the below parameters:

IP_REASSEMBLY - enabled

MEMP_NUM_REASSDATA - 5

IP_REASS_MAX_PBUFS - 10

MEMP_NUM_FRAG_PBUF - 4

inside my callback function, I'm trying to read all the 4k data, I'm getting 1k in the first node but the next node in the pbuf is always NULL.

I also see on Wirshak messages with 1k

while I'm sending using Hrecules 4k for sure.

this is the callback function code:

void UDP_TX_RECEIVE_CALLBACK(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)

{

 char TxUdpPacket[SPI_PACKET_SIZE] = {0, };

 // Process each received fragment

 while (p != NULL)

 {

  // Copy fragment data to appropriate position in udpPacket array

  memcpy(&TxUdpPacket[p->tot_len - p->len], p->payload, p->len);

  // Move to the next fragment

  struct pbuf *next = p->next;

  pbuf_free(p);

  p = next;

 }

}

pls, help!!

thank you ๐Ÿ™‚

21 REPLIES 21

@Pavel A.โ€‹ - I'm not sending a fragmented frame, I'm sending from the PC an entire 4k message.

I tried 2 scenarios:

  1. when I'm sending a smaller message of 1472 bytes (~1500 bytes) I see the message in low_level_input() method
  2. when I'm sending a 4k I don't see the message in low_level_input() method

maybe I need to configure specific parameters?

below is my lwipopts.h file:

/**

 ******************************************************************************

 * File Name     : Target/lwipopts.h

 * Description    : This file overrides LwIP stack default configuration

 *           done in opt.h file.

 ******************************************************************************

 * @attention

 *

 * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.

 * All rights reserved.</center></h2>

 *

 * This software component is licensed by ST under Ultimate Liberty license

 * SLA0044, the "License"; You may not use this file except in compliance with

 * the License. You may obtain a copy of the License at:

 *               www.st.com/SLA0044

 *

 ******************************************************************************

 */

/* Define to prevent recursive inclusion --------------------------------------*/

#ifndef __LWIPOPTS__H__

#define __LWIPOPTS__H__

#include "main.h"

/*-----------------------------------------------------------------------------*/

/* Current version of LwIP supported by CubeMx: 2.1.2 -*/

/*-----------------------------------------------------------------------------*/

/* Within 'USER CODE' section, code will be kept by default at each generation */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

#ifdef __cplusplus

 extern "C" {

#endif

/* STM32CubeMX Specific Parameters (not defined in opt.h) ---------------------*/

/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/

/*----- WITH_RTOS disabled (Since FREERTOS is not set) -----*/

#define WITH_RTOS 0

/*----- CHECKSUM_BY_HARDWARE enabled -----*/

#define CHECKSUM_BY_HARDWARE 1

/*-----------------------------------------------------------------------------*/

/* LwIP Stack Parameters (modified compared to initialization value in opt.h) -*/

/* Parameters set in STM32CubeMX LwIP Configuration GUI -*/

/*----- Default value in ETH configuration GUI in CubeMx: 1524 -----*/

#define ETH_RX_BUFFER_SIZE 512

/*----- Value in opt.h for NO_SYS: 0 -----*/

#define NO_SYS 1

/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/

#define SYS_LIGHTWEIGHT_PROT 0

/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/

#define MEM_ALIGNMENT 4

/*----- Default Value for H7 devices: 0x30044000 -----*/

#define LWIP_RAM_HEAP_POINTER 0x30044000

/*----- Value supported for H7 devices: 1 -----*/

#define LWIP_SUPPORT_CUSTOM_PBUF 1

/*----- Default Value for PBUF_POOL_SIZE: 16 ---*/

#define PBUF_POOL_SIZE 32

/*----- Default Value for PBUF_LINK_HLEN: 14 ---*/

#define PBUF_LINK_HLEN 1024

/*----- Default Value for PBUF_POOL_BUFSIZE: 592 ---*/

#define PBUF_POOL_BUFSIZE 4096

/*----- Value in opt.h for LWIP_ETHERNET: LWIP_ARP || PPPOE_SUPPORT -*/

#define LWIP_ETHERNET 1

/*----- Default Value for IP_REASSEMBLY: 1 ---*/

#define IP_REASSEMBLY 0

/*----- Value in opt.h for LWIP_DNS_SECURE: (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) -*/

#define LWIP_DNS_SECURE 7

/*----- Value in opt.h for TCP_SND_QUEUELEN: (4*TCP_SND_BUF + (TCP_MSS - 1))/TCP_MSS -----*/

#define TCP_SND_QUEUELEN 9

/*----- Value in opt.h for TCP_SNDLOWAT: LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) -*/

#define TCP_SNDLOWAT 1071

/*----- Value in opt.h for TCP_SNDQUEUELOWAT: LWIP_MAX(TCP_SND_QUEUELEN)/2, 5) -*/

#define TCP_SNDQUEUELOWAT 5

/*----- Value in opt.h for TCP_WND_UPDATE_THRESHOLD: LWIP_MIN(TCP_WND/4, TCP_MSS*4) -----*/

#define TCP_WND_UPDATE_THRESHOLD 536

/*----- Value in opt.h for LWIP_NETIF_LINK_CALLBACK: 0 -----*/

#define LWIP_NETIF_LINK_CALLBACK 1

/*----- Value in opt.h for LWIP_NETCONN: 1 -----*/

#define LWIP_NETCONN 0

/*----- Value in opt.h for LWIP_SOCKET: 1 -----*/

#define LWIP_SOCKET 0

/*----- Value in opt.h for RECV_BUFSIZE_DEFAULT: INT_MAX -----*/

#define RECV_BUFSIZE_DEFAULT 2000000000

/*----- Value in opt.h for LWIP_STATS: 1 -----*/

#define LWIP_STATS 0

/*----- Value in opt.h for CHECKSUM_GEN_IP: 1 -----*/

#define CHECKSUM_GEN_IP 0

/*----- Value in opt.h for CHECKSUM_GEN_UDP: 1 -----*/

#define CHECKSUM_GEN_UDP 0

/*----- Value in opt.h for CHECKSUM_GEN_TCP: 1 -----*/

#define CHECKSUM_GEN_TCP 0

/*----- Value in opt.h for CHECKSUM_GEN_ICMP6: 1 -----*/

#define CHECKSUM_GEN_ICMP6 0

/*----- Value in opt.h for CHECKSUM_CHECK_IP: 1 -----*/

#define CHECKSUM_CHECK_IP 0

/*----- Value in opt.h for CHECKSUM_CHECK_UDP: 1 -----*/

#define CHECKSUM_CHECK_UDP 0

/*----- Value in opt.h for CHECKSUM_CHECK_TCP: 1 -----*/

#define CHECKSUM_CHECK_TCP 0

/*----- Value in opt.h for CHECKSUM_CHECK_ICMP6: 1 -----*/

#define CHECKSUM_CHECK_ICMP6 0

/*-----------------------------------------------------------------------------*/

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

#ifdef __cplusplus

}

#endif

#endif /*__LWIPOPTS__H__ */

/************************* (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

When you send a 4K UDP message from PC (Windows?) it likely will be fragmented.

These fragments are 1k packets that you see in Wireshark.

@Pavel A.โ€‹ - I said in the above comments that the 1k messages I see in Wireshark are a mistake I did - now I see 4k messages.

yes, I'm using Windows.

> it likely will be fragmented.

I didn't know that, then if the messages are already fragmented then why I don't see the data I'm sending in the low_level_input() method? maybe I need to configure specific parameters?

LCE
Principal

Have you checked the descriptors' FIRST & LAST segment bits?

You must make sure that you build a correct pbuf chain which starts with data from FIRST segment, and ends with data from LAST segment. Only then it must be handed over to lwIP.

I don't know how well HAL stuff is handling all of that.

It looks like you have to dig a little deeper to find out what's going on between hardware and lwIP.

Hmm maybe Wireshark displays already re-assembled UDP? I haven't used it for a while. Are you sure the 4K packets are displayed at the ethernet layer ? (the data length in the ethernet header is matching)

Mz.1
Associate III

@Community memberโ€‹ - I'm not building the pbuf myself because I'm not sending the UDP packet from within the STM. I'm receiving the UDP packet from the PC:

let me explain the setup:

Windows PC uses simple Python code (with socket library) to send 4k UDP packet, the PC and the STM device are plugged directly with Ethernet cable (RJ45), and in the STM firmware I have simple code for a callback function (I used Google) such as this for example:

void udp_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)

{

/* Copy the data from the pbuf */

strncpy (buffer, (char *)p->payload, p->len);

/* Free receive pbuf */

pbuf_free(p);

}

I didn't generate the pbuf (the low_level_input() method did).

this callback method works perfectly if the PC sends a packet with a size of 1472 bytes (~1500 bytes), if the PC sends more than that then the callback function is not called.

I need the callback function to work when I'm sending more than 1472 bytes (~1500 bytes).

@Pavel A.โ€‹ - suggested debugging the low_level_input() method, but it doesn't even enter the method if the packet is bigger.

therefore, I thought maybe I need to configure some parameters in the ioc LWIP section file to enable the packet to receive, so I saw online the fragmentation option and the jumbo frame option but I failed to do that.

that's why I need help :(

Pavel A.
Evangelist III

>  low_level_input() method, but it doesn't even enter the method if the packet is bigger.

โ€‹

Recall that the low_level_input and its friends in ethernetif.c can work only if the setup has been done correctly (all these buffer arrays, descriptors...)

Are the buffer sizes enough to receive jumbo packets? Have you tried to enable jumbo packets in the ETH driver? Are any error callbacks of the ETH driver called?

LwIP parameters don't even have any significance before you get the low_level_input see the packet.

โ€‹

Or, just split your 4K packets and re-assemble in your code. Don't fight those wind mills.

โ€‹

LCE
Principal

From RM0468 page 2922 for STM32H723..735:

To support Jumbo Transmit/Receive packets, follow these steps:

โ€ข In the Operating mode configuration register (ETH_MACCR)

a) Set JE bit to 1.

b) Set JD and WD bits to 0 to avoid giant packet error reporting.

c) Set GPSLCE bit to 1

d) Set GPSL bitfield of the Extended operating mode configuration register

(ETH_MACECR) to a value > 9026

To support Transmit/Receive packets, up to 16K, follow these steps:

โ€ข In the Operating mode configuration register (ETH_MACCR)

a) Set JD and WD bits to 1 to avoid giant packet error reporting.

b) Set GPSLCE bit to 1.

c) Set GPSL bitfield of the Extended operating mode configuration register

(ETH_MACECR) to 16383.

I never used that, but maybe the hardware discards any larger packets if these settings are not correct.

So check the registers and bits and change them if necessary.

BUT that does not mean that tha HAL driver supports that, so you also have to check the HAL stuff.

LCE
Principal

Conclusion:

No matter what, you have to dive into the STM's ETH hardware, and into the HAL functions.

BTW, what's a method? :D

Mz.1
Associate III

@Community memberโ€‹ - thank you !! I'll try what you suggested and update ๐Ÿ™‚

> BTW, what's a method? :D

sorry I meant "function", my English is not so fluent ๐Ÿ˜…