TCP IPv6 connection fails with Zephyr BSD sockets (errno 116) on nRF54L15 Thread CLI, while OpenThread TCP works

I am working with nRF54L15 running Thread CLI. The device is successfully commissioned to a Thread network and communicates through a Border Router (BR). SDK version V3.1.0

Network Setup

  • PC and Thread Border Router are connected to the same router

  • nRF54L15 is connected to the Thread BR

  • PC acts as an IPv6 TCP server

  • nRF54L15 acts as a TCP client


Observed Behavior

Using OpenThread TCP (CLI commands)

When using OpenThread TCP commands from the CLI:

  • tcp init

  • tcp connect

  • tcp send

 TCP connection succeeds
 Data transfer works as expected

This uses the OpenThread socket API internally.


Using Zephyr BSD Sockets

When implementing the same TCP client logic using Zephyr BSD sockets, the TCP connection fails.

  • Socket creation succeeds

  • IPv6 address parsing succeeds

  • connect() fails with errno = 116 (ETIMEDOUT)

UDP works correctly in both cases

  • OpenThread UDP → works

  • Zephyr BSD UDP → works

The issue occurs only for TCP over BSD sockets.


Error Details

  • connect() returns < 0

  • errno = 116 (ETIMEDOUT)

Questions

  1. Is TCP over Zephyr BSD sockets fully supported on nRF54L15 Thread?

  2. Is additional Kconfig or socket offloading configuration required?

  3. Is there a known limitation or missing configuration for TCP over IPv6 with Thread?

int tcp_connect_test(void)
{
    int sock;
    struct sockaddr_in6 server;
    int ret;
    const char *msg = "Hello from Nordic (IPv6 TCP)\n";
    char rx_buf[128];

    /* Create IPv6 TCP socket */
    sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
    if (sock < 0) {
        LOG_ERR("Socket creation failed (%d)", errno);
        return -errno;
    }

    /* Fill server address */
    memset(&server, 0, sizeof(server));
    server.sin6_family = AF_INET6;
    server.sin6_port = htons(SERVER_PORT);

    if (inet_pton(AF_INET6, SERVER_IP6, &server.sin6_addr) != 1) {
        LOG_ERR("Invalid IPv6 address");
        close(sock);
        return -EINVAL;
    }

    LOG_INF("Connecting to [%s]:%d", SERVER_IP6, SERVER_PORT);

    /* Connect */
    ret = connect(sock, (struct sockaddr *)&server, sizeof(server));
    if (ret < 0) {
        LOG_ERR("TCP connect failed (%d)", errno);
        close(sock);
        return -errno;
    }

    LOG_INF("TCP IPv6 connection SUCCESSFUL");

    /* Send data */
    send(sock, msg, strlen(msg), 0);

    /* Receive response */
    ret = recv(sock, rx_buf, sizeof(rx_buf) - 1, 0);
    if (ret > 0) {
        rx_buf[ret] = '\0';
        LOG_INF("Received: %s", rx_buf);
    }

    close(sock);
    return 0;
}

Parents Reply Children
  • Thank you for the suggestion.

    I have already verified that the OpenThread native TCP API (as seen in cli_tcp.cpp) works correctly. I am able to establish a connection and send data using the otTcp CLI commands.

    However, my project requirements specifically require the use of the Standard BSD Socket API (socket(), connect(), send()) rather than the native OpenThread calls. Currently, when I attempt to use BSD sockets over the Thread interface, I am encountering errors (specifically 116 ) that do not occur when using the CLI.

    Could you please help me identify if there are specific Kconfig requirements or buffer configurations needed in Zephyr to properly bridge the BSD socket layer to the OpenThread TCP stack?

  • Hi,

    Can you share what you have in your prj.conf?

    There are some socket samples in Zephyr that use BSD sockets, such as the Echo server and Echo client. These can be built with OpenThread overlays (overlay-ot.conf), so I recommend looking at them. Please note that TCP is disabled in the OpenThread overlays in these samples to avoid heavy traffic, but it should still be possible to use TCP by leaving it enabled.

    Best regards,
    Marte

Related