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

Open
skycmoon wants to merge 1 commit from skycmoon/fix/freertos-lwip-errno into develop
skycmoon commented 2026-05-27 21:03:05 -05:00 (Migrated from github.com)

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.

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.
peterharperuk (Migrated from github.com) approved these changes 2026-06-11 05:42:36 -05:00
kilograham (Migrated from github.com) reviewed 2026-06-15 19:41:53 -05:00
@ -69,2 +69,3 @@
CYW43_LWIP=1
LWIP_PROVIDE_ERRNO=1
# FreeRTOS+lwIP uses newlib, which provides a thread-local errno
# via <errno.h>. LWIP_PROVIDE_ERRNO=1 would declare lwIP's own
kilograham (Migrated from github.com) commented 2026-06-15 19:41:53 -05:00

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

um, who says it uses newlib? surely it is dependent on the compiler/toolchain?
kilograham (Migrated from github.com) requested changes 2026-06-19 16:55:40 -05:00
kilograham (Migrated from github.com) left a comment

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

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 commented 2026-06-20 04:16:21 -05:00 (Migrated from github.com)

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

Yes. I think it was a mistake to add this to the library. It should have been left to be defined in lwipopts.h
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'skycmoon/fix/freertos-lwip-errno:skycmoon/fix/freertos-lwip-errno'
git switch 'skycmoon/fix/freertos-lwip-errno'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'develop'
git merge --no-ff 'skycmoon/fix/freertos-lwip-errno'
git switch 'skycmoon/fix/freertos-lwip-errno'
git rebase 'develop'
git switch 'develop'
git merge --ff-only 'skycmoon/fix/freertos-lwip-errno'
git switch 'skycmoon/fix/freertos-lwip-errno'
git rebase 'develop'
git switch 'develop'
git merge --no-ff 'skycmoon/fix/freertos-lwip-errno'
git switch 'develop'
git merge --squash 'skycmoon/fix/freertos-lwip-errno'
git switch 'develop'
git merge --ff-only 'skycmoon/fix/freertos-lwip-errno'
git switch 'develop'
git merge 'skycmoon/fix/freertos-lwip-errno'
git push origin 'develop'
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk!2974
No description provided.