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
  • Hi,

    You can use UDP and TCP via the BSD sockets if you use Zepyr's OpenThread integration and IP stack. To use Zephyr's stack and BSD sockets, make sure that these configs are enabled:

    CONFIG_NETWORKING=y
    CONFIG_NET_L2_OPENTHREAD=y
    CONFIG_NET_SOCKETS=y

    Please note that nRF Connect SDK 3.1.0 the OpenThread samples were changed: by default they now use the architecture where Zephyr networking is disabled and the OpenThread stack is used directly with the 802.15.4 driver, meaning Zephyr’s networking features (including BSD sockets) are not available unless you explicitly re‑enable them, see Migration guide 3.1.

    Best regards,
    Marte

Reply
  • Hi,

    You can use UDP and TCP via the BSD sockets if you use Zepyr's OpenThread integration and IP stack. To use Zephyr's stack and BSD sockets, make sure that these configs are enabled:

    CONFIG_NETWORKING=y
    CONFIG_NET_L2_OPENTHREAD=y
    CONFIG_NET_SOCKETS=y

    Please note that nRF Connect SDK 3.1.0 the OpenThread samples were changed: by default they now use the architecture where Zephyr networking is disabled and the OpenThread stack is used directly with the 802.15.4 driver, meaning Zephyr’s networking features (including BSD sockets) are not available unless you explicitly re‑enable them, see Migration guide 3.1.

    Best regards,
    Marte

Children
Related