This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM2732: LwIP UDP data corruption

Part Number: AM2732

Hello experts!
We found a weird problem while developing a UDP client: packet corruption while sending lots of data in a row.
I have replicated this issue by slightly modifying the enet_cpsw_udpclient example from the mcuplus sdk.

The most important piece of code is inside app_udpclient.c and inside the function AppSocket_simpleClient.

            CacheP_wbInv(snd_buf, sizeof(snd_buf), CacheP_TYPE_ALLD);
            ret = lwip_sendto(sock, snd_buf, sizeof(snd_buf), 0,
                    pAddr, sizeof(*pAddr));

            // NOTE: THIS FIXES THE PROBLEM
            // ClockP_usleep(10 * 1000);

By uncommenting that sleep, the code produces the expected behaviour, which is sending UDP packets of 1024 bytes each with alternating patterns (once 0xAA and then 0xBB).
If I don't have a sleep, packets get corrupted such that the pattern is no longer alternating each packet, and there are instead chains of packets with the same pattern.

Attached you can find:
- project sources
- wireshark capture of code without sleep
- wireshark capture of code with sleep

Thanks in advance

enet_cpsw_udpclient_am273x-evm_r5fss0-0_freertos_ti-arm-clang.zip

wireshark_captures.zip

  • Hi ,
    LwIP socket APIs are not well supported by LwIP, instead LwIP netconn APIs are suggested. 
    Can you modify the application and use netconn APIs to send UDP packets.

    Ref: https://lwip.fandom.com/wiki/Application_API_layers

    With regards,
    Pradeep

  • Hi  
    While trying to modify the example to use netconn API I also noticed that the socket API is built on top of netconn + netbuf.
    As you can see from the implementation of lwip_sendto:

    ssize_t
    lwip_sendto(int s, const void *data, size_t size, int flags,
                const struct sockaddr *to, socklen_t tolen)
    {
      struct lwip_sock *sock;
      err_t err;
      u16_t short_size;
      u16_t remote_port;
      struct netbuf buf;
    
      sock = get_socket(s);
      if (!sock) {
        return -1;
      }
    
      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
    #if LWIP_TCP
        done_socket(sock);
        return lwip_send(s, data, size, flags);
    #else /* LWIP_TCP */
        LWIP_UNUSED_ARG(flags);
        set_errno(err_to_errno(ERR_ARG));
        done_socket(sock);
        return -1;
    #endif /* LWIP_TCP */
      }
    
      if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) {
        /* cannot fit into one datagram (at least for us) */
        set_errno(EMSGSIZE);
        done_socket(sock);
        return -1;
      }
      short_size = (u16_t)size;
      LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
                 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
                  ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))),
                 set_errno(err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
      LWIP_UNUSED_ARG(tolen);
    
      /* initialize a buffer */
      buf.p = buf.ptr = NULL;
    #if LWIP_CHECKSUM_ON_COPY
      buf.flags = 0;
    #endif /* LWIP_CHECKSUM_ON_COPY */
      if (to) {
        SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
      } else {
        remote_port = 0;
        ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
      }
      netbuf_fromport(&buf) = remote_port;
    
    
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
                                  s, data, short_size, flags));
      ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr);
      LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
    
      /* make the buffer point to the data that should be sent */
    #if LWIP_NETIF_TX_SINGLE_PBUF
      /* Allocate a new netbuf and copy the data into it. */
      if (netbuf_alloc(&buf, short_size) == NULL) {
        err = ERR_MEM;
      } else {
    #if LWIP_CHECKSUM_ON_COPY
        if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
          u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
          netbuf_set_chksum(&buf, chksum);
        } else
    #endif /* LWIP_CHECKSUM_ON_COPY */
        {
          MEMCPY(buf.p->payload, data, short_size);
        }
        err = ERR_OK;
      }
    #else /* LWIP_NETIF_TX_SINGLE_PBUF */
      err = netbuf_ref(&buf, data, short_size);
    #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
      if (err == ERR_OK) {
    #if LWIP_IPV4 && LWIP_IPV6
        /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
        if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
          unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
          IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
        }
    #endif /* LWIP_IPV4 && LWIP_IPV6 */
    
        /* send the data */
        err = netconn_send(sock->conn, &buf);
      }
    
      /* deallocated the buffer */
      netbuf_free(&buf);
    
      set_errno(err_to_errno(err));
      done_socket(sock);
      return (err == ERR_OK ? short_size : -1);
    }


    Could you add more details on why switching to netconn API would do anything to fix this problem? 
    Thanks