Skip to content

pico_cyw43_arch FreeRTOS+lwIP: route errno through newlib (LWIP_ERRNO_STDINCLUDE)#2974

Open
skycmoon wants to merge 1 commit into
raspberrypi:developfrom
skycmoon:fix/freertos-lwip-errno
Open

pico_cyw43_arch FreeRTOS+lwIP: route errno through newlib (LWIP_ERRNO_STDINCLUDE)#2974
skycmoon wants to merge 1 commit into
raspberrypi:developfrom
skycmoon:fix/freertos-lwip-errno

Conversation

@skycmoon

Copy link
Copy Markdown

Fixes #2973.

What

Swap LWIP_PROVIDE_ERRNO=1 for LWIP_ERRNO_STDINCLUDE=1 on the pico_cyw43_arch_lwip_sys_freertos variant. Single hunk in src/rp2_common/pico_cyw43_arch/CMakeLists.txt.

Why

LWIP_PROVIDE_ERRNO=1 is correct for bare-metal builds (no libc owns errno), but the FreeRTOS+lwIP variant always ships with newlib, which already provides a thread-local errno via <errno.h>. The unconditional LWIP_PROVIDE_ERRNO=1 makes lwIP declare its own extern int errno global, diverging from newlib's storage. Any code reading errno via <errno.h> — including the standard mbedTLS library/net_sockets.c BIO — misses the EWOULDBLOCK lwIP wrote, treats every non-blocking recv() poll as fatal, and tears the TLS session down right after handshake.

LWIP_ERRNO_STDINCLUDE=1 keeps lwIP's E* constants available but routes them via <errno.h>, so lwIP and the rest of the program share newlib's thread-local storage. Issue #2973 has the full diagnosis and an observable symptom description (TLS handshake completes → application sends e.g. MQTT CONNECT → server queues CONNACK → client immediately FINs without reading the response → loop forever at the application's backoff cadence).

Scope

  • Only pico_cyw43_arch_lwip_sys_freertos_headers is touched.
  • pico_cyw43_arch_lwip_threadsafe_background (bare-metal) does not currently set LWIP_PROVIDE_ERRNO=1, so no change needed there.
  • Comment block added inline explaining the choice for future maintainers.

Compatibility

Behaviour-preserving for users who don't touch errno directly — lwIP's E* constants still resolve, just through <errno.h>. Correcting for users on the stock mbedTLS BIO pattern (or any equivalent POSIX-style errno shim).

Test

I verified the equivalent fix locally as a project-side override in lwipopts.h: cancelling the SDK's -D LWIP_PROVIDE_ERRNO=1 and setting LWIP_ERRNO_STDINCLUDE=1 resolved a persistent MQTT CONNECT/CONNACK/close storm on Pico 2W (FreeRTOS + lwIP + mbedTLS + coreMQTT). This PR moves that fix from a per-project workaround to the SDK default for the variant.

The freertos+lwIP variant unconditionally sets LWIP_PROVIDE_ERRNO=1,
which makes lwIP declare its own `extern int errno` global. Under
FreeRTOS+newlib (the only libc shipped with the SDK's FreeRTOS port)
newlib already provides a thread-local errno via <errno.h>, so any
POSIX-style code that reads errno via <errno.h> diverges from the
storage lwIP writes to. The standard mbedTLS BIO pattern (stock
net_sockets.c) is exactly this — `recv()` returns -1, the shim reads
errno and never sees the EWOULDBLOCK lwIP set, so it treats every
non-blocking poll as a fatal error and tears the session down.

LWIP_ERRNO_STDINCLUDE=1 keeps lwIP's errno-constants behaviour but
routes through <errno.h>, so lwIP and the rest of the program share
newlib's thread-local storage. Behaviour for users not exercising
the BIO-shim pattern is unchanged.
@peterharperuk peterharperuk added this to the 2.2.1 milestone Jun 11, 2026
target_compile_definitions(pico_cyw43_arch_lwip_sys_freertos_headers INTERFACE
CYW43_LWIP=1
LWIP_PROVIDE_ERRNO=1
# FreeRTOS+lwIP uses newlib, which provides a thread-local errno

@kilograham kilograham Jun 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

um, who says it uses newlib? surely it is dependent on the compiler/toolchain?

@kilograham kilograham self-requested a review June 19, 2026 21:55

@kilograham kilograham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not convinced by this yet - as i say, who says that newlib is used? and this is non-overridable now as implemented

@peterharperuk

Copy link
Copy Markdown
Contributor

Yes. I think it was a mistake to add this to the library. It should have been left to be defined in lwipopts.h

@kilograham kilograham modified the milestones: 2.2.1, 2.3.0 Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants