---
title: "W5500 behind a Mobile data router, NAT and disconnect missing TCP flag process"
url: "https://maker.wiznet.io/forum/15709"
markdown_url: "https://maker.wiznet.io/forum/15709/md"
type: "Forum topic"
category: "Ethernet Chips"
author: "xdrone"
created: "2025-04-24T00:51:00+09:00"
last_activity: "2025-04-24T15:52:39+09:00"
language: "en"
tags: ["W5500"]
views: 5
replies: 1
source: "WIZnet Makers forum (https://maker.wiznet.io/forum/)"
---

# W5500 behind a Mobile data router, NAT and disconnect missing TCP flag process

## Question

Asked by xdrone on 2025-04-24 in Ethernet Chips.

Hello,

Facing an issue with *TCP on W5500 and the underlying TCP flags upon disconnection or closing socket connection*.

**Architecture:**

STM32F407 with SPI to W5500 custom made board. Ethernet is tethered to a mobile data router. NAT is symmetric, port handling is strict.

An ECHO listener on the cloud implemented using python for testing.
STM32/W5500 board implements the IOLibrary from Wiznet github.

The custom board is supposed to connect to the cloud, send a string message, receive back the echo message, then through uart print the received string in return to confirm the W5500 library is in working order.

**Problem:**

First iteration: Message is transmitted by the custom board, received by the echo listener, connection is supposedly closed.

Second iteration: connection fails while attempting to connect through the same outgoing port from the W5500's side.

**Some Workaround:**
Attempting a port changing scheme at the socket level works regarding a successful connection and transmission, followed by reception of the echo message. However, giving 30 seconds per port swap, after 12 days the whole port range is consumed and custom board fails to transmit again.

**Some analysis:**

Upon looking at the TCP dump on the cloud, the echo listener sends FIN folllowed by ACK, the W5500 replies back with ACK, but doesn't follow through with sending a matching FIN+ACK.
Attempting to check with the ISP that supported the mobile router, the ports seem to remain open, even when ports at the cloud close back after a while, but for the ISP, the Ports remain open indefinitely because the W5500 didn't negotiate the FIN+ACK correctly.

**Code structure at the STM32 level:**

```c
    // error codes:
    // 99    failed to create socket
    // 98    failed to connect to destination
    // 97    failed to send data
    // 96    failed to receive
```

```c
uint8_t CONNECT(uint8_t destIP[4], uint16_t destPORT) {
    uint8_t response = 0;
    SerialPrintfmt("PortFlipper = %d\r\n", PortFlipper);
    SerialPrintfmt("Creating socket...\r\n");
    uint8_t code = socket(HTTP_SOCKET, Sn_MR_TCP, PortFlipper, 0);
    if (code != HTTP_SOCKET) {
        SerialPrintfmt("socket() failed, code = %d\r\n", code);
        response = 99;
        return response;
    } else SerialPrintfmt("socket() created, code = %d\r\n", code);
    SerialPrintfmt("Connecting to: %d.%d.%d.%d\r\n", destIP[0], destIP[1], destIP[2], destIP[3]);
    code = connect(HTTP_SOCKET, destIP, destPORT);
    if (code != SOCK_OK) {
        SerialPrintfmt("connect() failed, code = %d\r\n", code);
        close(HTTP_SOCKET);
        response = 98;
        return response;
    } else SerialPrintfmt("connected to destination, code = %d\r\n", code);
    return response;
}
```

```c
uint8_t SENDDATA(char *req) {
        uint8_t response = 0;
        uint16_t len = strlen(req) - 1;
        while (len > 0) {
            SerialPrintfmt("Sending %d bytes...\r\n", len);
            int32_t nbytes = send(HTTP_SOCKET,(uint8_t *) req, len);
            if (nbytes <= 0) {
                SerialPrintfmt("send() failed, %d returned\r\n", nbytes);
                close(HTTP_SOCKET);
                response = 97;
                return response;
            }
            SerialPrintfmt("%d bytes sent!\r\n", nbytes);
            len -= nbytes;
        }
    return response;
}
```

```c
uint8_t RECEIVEDATA() {
    uint8_t response = 0;
    SerialPrintfmt("Request sent. Reading response...\r\n");
    char buff[128];
    for (;;) {
        int32_t nbytes = recv(HTTP_SOCKET, (uint8_t*) &buff, sizeof(buff) - 1);
        if (nbytes == SOCKERR_SOCKSTATUS) {
            SerialPrintfmt("\r\nConnection closed.\r\n");
            response = 0;
            break;
        }
        if (nbytes <= 0) {
            SerialPrintfmt("\r\nrecv() failed, %d returned\r\n", nbytes);
            response = 96;
            break;
        }
        buff[nbytes] = ''\0'';
        SerialPrintfmt("%s", buff);
    }
    return response;
}
```

```c
void CLOSECONNECTION() {
    SerialPrintfmt("Closing socket.\r\n");
    disconnect(HTTP_SOCKET);
}
```

**Inside the main loop:**

```c
if (isTimerElapsed((uint64_t*)&timer, period)) {
            timer = HAL_GetTick();
            CONNECT((uint8_t *)&addr, testPort);
            SENDDATA(stringfmt(assignedBuff, "test message %d\r\n", HAL_GetTick()));
            RECEIVEDATA();
            CLOSECONNECTION();
            memset(assignedBuff, 0, 4096);
        }
```

Kindly note, so much of the code is missing since it wouldn't be possible to state the defines and global variables. The customer board does work on regular fiber optic connections without any issues. The fiber optic router NAT isn't symmetric, the custom board did operate flawlessly for many months without any incidents. However once the custom board operates behind a mobile router implementing symmetric NAT, then operation only works for the first run.

Please advise.

## Replies

### Reply 1 by Lihan__, 2025-04-24

Hello,xdrone

Based on your description, the issue appears to stem from an incomplete socket closure on the W5500 side. Here’s a concise explanation and solution.

After the W5500 connects to the server and exchanges messages, the connection is not being properly closed,
which leads to a situation where the same source port cannot be reused for subsequent connections.

This happens because the socket remains open in the NAT table, as it was never fully closed from the W5500 side.

After calling `disconnect()`, you must call `close()` to fully terminate the socket.

If you do not call `close()`, the socket remains open,
→ which prevents the port from being released and causes failures in future connection attempts.

## Example Code

```plaintext
void SAFE_DISCONNECT(uint8_t socket_num) {
    disconnect(socket_num);  // W5500 sends FIN packet

    // Wait up to 3 seconds for the socket to fully close
    uint32_t start = HAL_GetTick();
    while (getSn_SR(socket_num) != SOCK_CLOSED) {
        if (HAL_GetTick() - start > 3000) {
            SerialPrintfmt("Timeout waiting for socket to close.\r\n");
            break;
        }
        HAL_Delay(10);
    }

    close(socket_num);  // Fully release the socket
}
```

---

Source: https://maker.wiznet.io/forum/15709
