diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 1bb51488ff..b81ad63dc2 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -70,6 +70,7 @@ body: - thorvg - touch_element - unit-test-app + - usrsctp - zlib - libjpeg-turbo - Other diff --git a/.github/workflows/upload_component.yml b/.github/workflows/upload_component.yml index d3e2000882..fc46d6139d 100644 --- a/.github/workflows/upload_component.yml +++ b/.github/workflows/upload_component.yml @@ -72,6 +72,7 @@ jobs: thorvg touch_element unit-test-app + usrsctp zlib libpng libjpeg-turbo diff --git a/.gitmodules b/.gitmodules index 2f1721b12c..80bdeccfb6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -81,3 +81,6 @@ [submodule "lua/lua"] path = lua/lua url = https://github.com/lua/lua.git +[submodule "usrsctp/usrsctp"] + path = usrsctp/usrsctp + url = https://github.com/sctplab/usrsctp.git diff --git a/.idf_build_apps.toml b/.idf_build_apps.toml index 9d7e746f4f..2b1c2af193 100644 --- a/.idf_build_apps.toml +++ b/.idf_build_apps.toml @@ -36,6 +36,7 @@ manifest_file = [ "quirc/.build-test-rules.yml", "thorvg/.build-test-rules.yml", "touch_element/.build-test-rules.yml", + "usrsctp/.build-test-rules.yml", "zlib/.build-test-rules.yml", "libjpeg-turbo/.build-test-rules.yml", ".build-test-rules.yml", diff --git a/usrsctp/.build-test-rules.yml b/usrsctp/.build-test-rules.yml new file mode 100644 index 0000000000..796e74a1cc --- /dev/null +++ b/usrsctp/.build-test-rules.yml @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +# +# usrsctp requires ESP-IDF 5.4+ (idf_component.yml `idf: ">=5.4"`). The +# disable rules below skip the build on older IDF releases so the repo-wide +# CI matrix (v5.1 / v5.2 / v5.3 / v5.4 / v5.5 / latest) doesn't try them. +# +# Path keys MUST be component-name-prefixed (`usrsctp/...`) — idf-build-apps +# resolves these relative to the repo root, not the component root. + +usrsctp/examples/get_started: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3", "esp32s3", "esp32c5", "esp32c6", "esp32p4"] + reason: "Build sanity on representative Xtensa + RISC-V targets." + disable: + - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4 + reason: "usrsctp requires ESP-IDF 5.4+." + +usrsctp/test_apps: + enable: + - if: IDF_TARGET in ["esp32", "esp32c3"] + reason: "Sufficient to exercise one Xtensa and one RISC-V target." + disable: + - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4 + reason: "usrsctp requires ESP-IDF 5.4+." + +usrsctp/host_test: + enable: + - if: IDF_TARGET == "linux" + reason: "Linux host build runs the usrsctp socket-lifecycle smoke test." + disable: + - if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4 + reason: "usrsctp requires ESP-IDF 5.4+." diff --git a/usrsctp/.github/workflows/publish.yml b/usrsctp/.github/workflows/publish.yml new file mode 100644 index 0000000000..5efa51046d --- /dev/null +++ b/usrsctp/.github/workflows/publish.yml @@ -0,0 +1,24 @@ +name: Publish to ESP Component Registry + +on: + push: + branches: [main] + paths: + - 'idf_component.yml' + workflow_dispatch: + +jobs: + upload: + runs-on: ubuntu-latest + steps: + - name: Checkout (with submodules) + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Upload usrsctp + uses: espressif/upload-components-ci-action@v1 + with: + name: usrsctp + namespace: vikramdattu + api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }} diff --git a/usrsctp/.gitignore b/usrsctp/.gitignore new file mode 100644 index 0000000000..211b06be94 --- /dev/null +++ b/usrsctp/.gitignore @@ -0,0 +1,16 @@ +# build outputs +build/ +build_*/ +dist/ +managed_components/ +dependencies.lock +sdkconfig +sdkconfig.old + +# OS / editor +.DS_Store +.vscode/ +.idea/ +*.swp +*.swo +*~ diff --git a/usrsctp/CHANGELOG.md b/usrsctp/CHANGELOG.md new file mode 100644 index 0000000000..4132a9d330 --- /dev/null +++ b/usrsctp/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +## 1.0.0 + +- First release. +- usrsctp wrapped as an ESP-IDF component. Submodule pins canonical + [sctplab/usrsctp](https://github.com/sctplab/usrsctp) at commit + `2e1ab10`; five ESP-IDF-specific patches are applied at build configure + time (see [`patches/README.md`](patches/README.md)). +- Supports the full ESP32 family plus the IDF Linux target for + host-side testing. +- Bundled patches add lwIP routing for the userspace conn layer, + thread-safe netif APIs, SPIRAM-backed worker-thread stacks, and + buildability on the IDF Linux target. +- Embedded smoke test (`test_apps/`) and host-side socket-lifecycle + test (`host_test/`) included. diff --git a/usrsctp/CMakeLists.txt b/usrsctp/CMakeLists.txt new file mode 100644 index 0000000000..25164e3929 --- /dev/null +++ b/usrsctp/CMakeLists.txt @@ -0,0 +1,133 @@ +# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 + +set(usrsctp_root_dir ${CMAKE_CURRENT_SOURCE_DIR}/usrsctp) +set(usrsctp_lib_dir ${usrsctp_root_dir}/usrsctplib) + +# Apply all patches in patches/*.patch onto the usrsctp submodule at +# configure time. Idempotent: dry-run check skips already-applied patches. +file(GLOB USRSCTP_PATCHES "${CMAKE_CURRENT_SOURCE_DIR}/patches/*.patch") +list(SORT USRSCTP_PATCHES) +foreach(_patch ${USRSCTP_PATCHES}) + execute_process( + COMMAND git apply --check -p1 ${_patch} + WORKING_DIRECTORY ${usrsctp_root_dir} + RESULT_VARIABLE _check + ERROR_QUIET OUTPUT_QUIET + ) + if(_check EQUAL 0) + execute_process( + COMMAND git apply -p1 ${_patch} + WORKING_DIRECTORY ${usrsctp_root_dir} + RESULT_VARIABLE _apply + ) + if(NOT _apply EQUAL 0) + message(FATAL_ERROR "usrsctp: failed to apply ${_patch}") + endif() + message(STATUS "usrsctp: applied ${_patch}") + endif() +endforeach() + +# Register our component with just the ESP-specific file +idf_component_register( + SRCS + usrsctp_register.c # empty TU so idf_component_register has a source + INCLUDE_DIRS + ${usrsctp_lib_dir} + ${usrsctp_lib_dir}/netinet + ${usrsctp_lib_dir}/netinet6 + REQUIRES + lwip + mbedtls + esp_common + pthread + freertos +) + +# Set up environment for usrsctp. Use CACHE BOOL ... FORCE because the +# inner usrsctp/CMakeLists.txt declares these as option() — without +# CACHE our local set() gets overridden by option()'s default at +# add_subdirectory time, and SCTP_USE_LWIP ends up defined on Linux +# (which then drags in lwip-specific headers usrsctp's userspace path +# can't satisfy on a host build). +if(IDF_TARGET STREQUAL "linux") + set(sctp_use_lwip OFF CACHE BOOL "build with lwip" FORCE) + set(sctp_use_rtos OFF CACHE BOOL "build with rtos" FORCE) +else() + set(sctp_use_lwip ON CACHE BOOL "build with lwip" FORCE) + set(sctp_use_rtos ON CACHE BOOL "build with rtos" FORCE) +endif() + +# Add definitions needed by usrsctp +add_definitions(-D__Userspace__) +add_definitions(-DSCTP_PROCESS_LEVEL_LOCKS) +add_definitions(-DSCTP_SIMPLE_ALLOCATOR) +add_definitions(-DHAVE_SYS_QUEUE_H) +add_definitions(-DHAVE_STDATOMIC_H) +add_definitions(-DSCTP_DEBUG) +add_definitions(-DESP_PLATFORM) + +if(sctp_use_lwip) + add_definitions(-DSCTP_USE_LWIP) +endif() + +if(sctp_use_rtos) + add_definitions(-DSCTP_USE_RTOS) +endif() + +if(NOT CONFIG_IDF_TARGET STREQUAL "linux") + add_definitions(-DHAVE_SCONN_LEN) +endif() + +# Set up options for usrsctp +set(sctp_build_programs OFF CACHE BOOL "Build usrsctp example programs" FORCE) +set(sctp_build_shared_lib OFF CACHE BOOL "Build usrsctp as shared library" FORCE) +set(sctp_invariants OFF CACHE BOOL "Add runtime checks" FORCE) +set(sctp_inet ON CACHE BOOL "Support IPv4" FORCE) +set(sctp_inet6 OFF CACHE BOOL "Support IPv6" FORCE) +set(SCTP_USE_MBEDTLS_SHA1 ON CACHE BOOL "Build with mbedtls sha1 support" FORCE) +set(sctp_werror OFF CACHE BOOL "Treat warning as error" FORCE) + +# Create a custom FindMbedTLS.cmake in the CMAKE_MODULE_PATH +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/FindMbedTLS.cmake" " +# Custom FindMbedTLS.cmake for ESP-IDF +set(MBEDTLS_FOUND TRUE) +set(MBEDTLS_INCLUDE_DIRS \"${IDF_PATH}/components/mbedtls/mbedtls/include\" \"${IDF_PATH}/components/mbedtls/port/include\") +set(MBEDTLS_LIBRARIES mbedtls mbedcrypto mbedx509) +") + +# Add the directory with our custom FindMbedTLS.cmake to CMAKE_MODULE_PATH +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}") + +# Add compiler flags to suppress warnings. Apple Clang doesn't know +# about `maybe-uninitialized` (only GCC has that name; LLVM uses plain +# `uninitialized`), and treats unknown warning options as errors under +# -Werror. Probe the flag and only add it when supported. +include(CheckCCompilerFlag) +check_c_compiler_flag("-Wno-error=maybe-uninitialized" HAS_NO_ERROR_MAYBE_UNINIT) + +add_compile_options( + -Wno-address-of-packed-member + -Wno-unused-but-set-variable + -Wno-unused-variable + -Wno-unused-function + -Wno-pointer-sign + -Wno-implicit-function-declaration + -Wno-incompatible-pointer-types + -Wno-format + -Wno-pedantic + -Wno-error=pedantic +) +if(HAS_NO_ERROR_MAYBE_UNINIT) + add_compile_options(-Wno-error=maybe-uninitialized) +endif() + +# Add usrsctp as a subdirectory +add_subdirectory(${usrsctp_root_dir} ${CMAKE_CURRENT_BINARY_DIR}/usrsctp) + +# so that we can use pthread and heap functions in usrsctp +target_link_libraries(usrsctp PRIVATE idf::pthread idf::heap) + +# Link against usrsctp library +target_link_libraries(${COMPONENT_LIB} PUBLIC usrsctp) diff --git a/usrsctp/Kconfig b/usrsctp/Kconfig new file mode 100644 index 0000000000..d1aa0b26d8 --- /dev/null +++ b/usrsctp/Kconfig @@ -0,0 +1,27 @@ +menu "usrsctp" + + config USRSCTP_DEBUG + bool "Enable SCTP_DEBUG runtime tracing" + default n + help + Builds usrsctp with verbose runtime trace logging via SCTP_DEBUG. + Adds binary size; only useful during development. + + config USRSCTP_THREAD_STACK_IN_SPIRAM + bool "Allocate usrsctp's internal pthread stacks from SPIRAM" + depends on SPIRAM + default y + help + Routes usrsctp's userspace-mode worker threads to SPIRAM. + Strongly recommended on memory-constrained chips + (esp32c6, esp32p4-eye) where internal RAM is at a premium. + + config USRSCTP_USE_MBEDTLS_SHA1 + bool "Use mbedTLS for SHA1 instead of usrsctp's bundled implementation" + default y + help + Uses ESP-IDF's mbedTLS (typically backed by the on-chip SHA + peripheral) for SHA-1 hashing inside usrsctp. Smaller binary + and faster than usrsctp's bundled software SHA-1. + +endmenu diff --git a/usrsctp/LICENSE b/usrsctp/LICENSE new file mode 100644 index 0000000000..67db858821 --- /dev/null +++ b/usrsctp/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/usrsctp/NOTICE b/usrsctp/NOTICE new file mode 100644 index 0000000000..dfd6c1f7a7 --- /dev/null +++ b/usrsctp/NOTICE @@ -0,0 +1,23 @@ +esp_usrsctp +Copyright 2024-2026 Espressif Systems (Shanghai) CO LTD + +This product includes software developed by the following third parties: + +================================================================================ + +usrsctp +https://github.com/sctplab/usrsctp (forked at https://github.com/vikramdattu/usrsctp) +Copyright (c) 2015, Randall Stewart and Michael Tuexen +Licensed under the BSD 3-Clause License (see usrsctp/LICENSE.md). + +A portable userland implementation of the SCTP protocol. Bundled as a +submodule from a fork (vikramdattu/usrsctp) carrying ESP-specific patches: +- SPIRAM thread stack allocation +- ESP_PLATFORM thread-safe netif API support +- sin6 overflow fix +- LWIP support layer + +The fork's ESP-specific commits are also under the BSD 3-Clause License, +matching upstream. + +================================================================================ diff --git a/usrsctp/README.md b/usrsctp/README.md new file mode 100644 index 0000000000..7692ef2568 --- /dev/null +++ b/usrsctp/README.md @@ -0,0 +1,56 @@ +# usrsctp + +[![Component Registry](https://components.espressif.com/components/espressif/usrsctp/badge.svg)](https://components.espressif.com/components/espressif/usrsctp) + +Userspace [SCTP](https://datatracker.ietf.org/doc/html/rfc4960) stack ([usrsctp](https://github.com/sctplab/usrsctp)) port for ESP-IDF. + +Used for WebRTC data channels and other SCTP-based protocols on ESP32-series chips. + +## Features + +- Canonical [sctplab/usrsctp](https://github.com/sctplab/usrsctp) submodule pinned at `2e1ab10` +- ESP-IDF specific patches applied at configure time (see [`patches/README.md`](patches/README.md)): + - LWIP routing for the userspace conn layer + - Thread-safe netif API support + - sin6 overflow fix + - SPIRAM-backed worker-thread stacks (Kconfig-gated) + - IDF Linux-target buildability + +## Add to a project + +```bash +idf.py add-dependency "vikramdattu/usrsctp^1.0.0" +``` + +Or in your project's `main/idf_component.yml`: + +```yaml +dependencies: + vikramdattu/usrsctp: "^1.0.0" +``` + +## Supported targets + +| Target | Status | +|---------|--------| +| esp32, esp32s2, esp32s3 | ✅ | +| esp32c3, esp32c5, esp32c6 | ✅ | +| esp32p4 | ✅ | +| linux (IDF Linux target) | ✅ (host build + `host_test/`) | + +Requires ESP-IDF ≥ 5.4. + +## Tests + +- `test_apps/` — embedded Unity smoke (`usrsctp_init` / `usrsctp_finish`). + Run with `pytest_usrsctp.py` against `esp32` / `esp32c3`. +- `host_test/` — IDF Linux-target binary that exercises socket creation / + close lifecycle. Run with `pytest_usrsctp_linux.py`. + +## Source + +This wrapper bundles canonical [sctplab/usrsctp](https://github.com/sctplab/usrsctp) as a submodule, pinned at commit `2e1ab10`. ESP-specific patches live under [`patches/`](patches/) and are applied at configure time. + +## License + +BSD-3-Clause (see `LICENSE.md`), matching upstream usrsctp. diff --git a/usrsctp/examples/get_started/CMakeLists.txt b/usrsctp/examples/get_started/CMakeLists.txt new file mode 100644 index 0000000000..e8825b02c7 --- /dev/null +++ b/usrsctp/examples/get_started/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(usrsctp_get_started) diff --git a/usrsctp/examples/get_started/README.md b/usrsctp/examples/get_started/README.md new file mode 100644 index 0000000000..6cbd5441aa --- /dev/null +++ b/usrsctp/examples/get_started/README.md @@ -0,0 +1,18 @@ +# usrsctp — get_started + +Minimal sanity-check application for [`usrsctp`](https://github.com/vikramdattu/usrsctp). Calls `usrsctp_init()` / `usrsctp_finish()`. Used by the repo's CI to verify the component compiles and links across supported targets; also a copy-paste starting point. + +## Build + +```bash +idf.py set-target esp32p4 # or esp32, esp32s3, esp32c3, esp32c6 +idf.py build +idf.py -p flash monitor +``` + +The example consumes the parent component via `override_path: ../../..` in `main/idf_component.yml`, so it always tracks the in-tree source. Replace with a registry version to consume the published component instead: + +```yaml +dependencies: + vikramdattu/usrsctp: "^1.0.0" +``` diff --git a/usrsctp/examples/get_started/main/CMakeLists.txt b/usrsctp/examples/get_started/main/CMakeLists.txt new file mode 100644 index 0000000000..6693249c21 --- /dev/null +++ b/usrsctp/examples/get_started/main/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 + +idf_component_register( + SRCS "main.c" + INCLUDE_DIRS "." + REQUIRES usrsctp +) diff --git a/usrsctp/examples/get_started/main/idf_component.yml b/usrsctp/examples/get_started/main/idf_component.yml new file mode 100644 index 0000000000..5554df8892 --- /dev/null +++ b/usrsctp/examples/get_started/main/idf_component.yml @@ -0,0 +1,7 @@ +## Build-check app for usrsctp. +## During CI / local build, override_path points at the parent repo so we +## consume the in-tree component instead of the registry version. +dependencies: + vikramdattu/usrsctp: + version: "*" + override_path: ../../.. diff --git a/usrsctp/examples/get_started/main/main.c b/usrsctp/examples/get_started/main/main.c new file mode 100644 index 0000000000..de8317260f --- /dev/null +++ b/usrsctp/examples/get_started/main/main.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * Minimal sanity-check app for usrsctp: brings the userspace SCTP + * stack up and tears it down. Used by .github/workflows/build.yml to + * verify the component compiles and links across supported ESP-IDF + * targets. + */ + +#include +#include "esp_log.h" +#include "usrsctp.h" + +static const char *TAG = "usrsctp_check"; + +void app_main(void) +{ + usrsctp_init(0, NULL, NULL); + ESP_LOGI(TAG, "usrsctp_init() OK"); + + usrsctp_finish(); + ESP_LOGI(TAG, "usrsctp build check complete"); +} diff --git a/usrsctp/host_test/CMakeLists.txt b/usrsctp/host_test/CMakeLists.txt new file mode 100644 index 0000000000..02319af3be --- /dev/null +++ b/usrsctp/host_test/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.16) + +set(COMPONENTS main) +set(EXTRA_COMPONENT_DIRS "..") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(host_test_usrsctp) diff --git a/usrsctp/host_test/main/CMakeLists.txt b/usrsctp/host_test/main/CMakeLists.txt new file mode 100644 index 0000000000..8d96ea4094 --- /dev/null +++ b/usrsctp/host_test/main/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 +idf_component_register( + SRCS "host_test_main.c" + INCLUDE_DIRS "." + REQUIRES usrsctp +) diff --git a/usrsctp/host_test/main/host_test_main.c b/usrsctp/host_test/main/host_test_main.c new file mode 100644 index 0000000000..2010c8dec6 --- /dev/null +++ b/usrsctp/host_test/main/host_test_main.c @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * Host (IDF Linux target) smoke + socket-lifecycle test for usrsctp. + * + * - usrsctp_init() with a no-op conn_output callback. + * - usrsctp_socket() to allocate a userspace SCTP endpoint. + * - usrsctp_close() + usrsctp_finish() shut down cleanly. + * + * A deeper loopback association test (two endpoints, real 4-way handshake) + * is tracked separately — it needs the upstream usrsctp timer thread + * driving conninput, which isn't trivial to spin up inside an + * IDF-Linux-target single-threaded entry point without leaking + * threads at exit. Out of scope for the registry submission. + */ +#include +#include +#include "usrsctp.h" + +static int rc = 0; + +#define CHECK(_cond, _msg) \ + do { \ + if (!(_cond)) { \ + fprintf(stderr, "FAIL: %s\n", _msg); \ + rc = 1; \ + } \ + } while (0) + +static int dummy_conn_output(void *addr, void *buf, size_t length, + uint8_t tos, uint8_t set_df) +{ + (void)addr; (void)buf; (void)length; (void)tos; (void)set_df; + return 0; +} + +static int run_smoke(void) +{ + printf("usrsctp host_test: starting\n"); + + usrsctp_init(0, dummy_conn_output, NULL); + + struct socket *sock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, + NULL, NULL, 0, NULL); + CHECK(sock != NULL, "usrsctp_socket returned NULL"); + + if (sock != NULL) { + usrsctp_close(sock); + } + + /* finish() returns the number of remaining endpoints — 0 means clean. */ + int remaining = usrsctp_finish(); + CHECK(remaining == 0, "usrsctp_finish left endpoints behind"); + + if (rc == 0) { + printf("usrsctp host_test: PASS\n"); + } else { + printf("usrsctp host_test: FAIL\n"); + } + return rc; +} + +void app_main(void) +{ + exit(run_smoke()); +} diff --git a/usrsctp/host_test/main/idf_component.yml b/usrsctp/host_test/main/idf_component.yml new file mode 100644 index 0000000000..e3d9f0b968 --- /dev/null +++ b/usrsctp/host_test/main/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + usrsctp: + version: "*" + override_path: "../.." diff --git a/usrsctp/host_test/pytest_usrsctp_linux.py b/usrsctp/host_test/pytest_usrsctp_linux.py new file mode 100644 index 0000000000..7594604620 --- /dev/null +++ b/usrsctp/host_test/pytest_usrsctp_linux.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import pytest + + +@pytest.mark.linux +@pytest.mark.host_test +def test_usrsctp_linux_host(dut): + dut.expect("usrsctp host_test: PASS", timeout=30) diff --git a/usrsctp/host_test/sdkconfig.defaults b/usrsctp/host_test/sdkconfig.defaults new file mode 100644 index 0000000000..efe1c5f660 --- /dev/null +++ b/usrsctp/host_test/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_COMPILER_OPTIMIZATION_DEBUG=y diff --git a/usrsctp/idf_component.yml b/usrsctp/idf_component.yml new file mode 100644 index 0000000000..f16a717015 --- /dev/null +++ b/usrsctp/idf_component.yml @@ -0,0 +1,56 @@ +version: "1.0.0" +description: "Userspace SCTP stack — wraps sctplab/usrsctp 0.9.5 as an ESP-IDF component. Used for WebRTC data channels and other SCTP-over-DTLS-over-UDP transports." +url: "https://github.com/espressif/idf-extra-components/tree/master/usrsctp" +repository: "https://github.com/espressif/idf-extra-components.git" +issues: "https://github.com/espressif/idf-extra-components/issues" +documentation: "https://github.com/espressif/idf-extra-components/blob/master/usrsctp/README.md" +license: "Apache-2.0 AND BSD-3-Clause" +tags: + # Library + protocol synonyms so this surfaces under any reasonable + # registry search (usrsctp / sctp / esp_usrsctp / etc.). + - usrsctp + - sctp + - sctp-over-udp + - sctplab + - esp_usrsctp + - esp_sctp + - libusrsctp + - webrtc + - data-channel + - data-channels + - rfc4960 + - networking + - transport + - lwip +targets: + - esp32 + - esp32s2 + - esp32s3 + - esp32c3 + - esp32c5 + - esp32c6 + - esp32p4 + - linux +dependencies: + idf: ">=5.4" + +# Surface the in-repo example so the registry UI links to it. +examples: + - path: examples/get_started + +# SBOM manifest for the wrapped upstream usrsctp. +sbom: + manifests: + - path: sbom_usrsctp.yml + dest: usrsctp + +# Trim the registry tarball: upstream tests/programs are linked at host_test +# build time; we don't need to ship them inside the registry artifact. +files: + exclude: + - "usrsctp/fuzzer/**" + - "usrsctp/Manual.md" + - "usrsctp/**/.git*" + - "host_test/build*" + - "test_apps/build*" + - "examples/*/build*" diff --git a/usrsctp/patches/0001-Added-LWIP-support.patch b/usrsctp/patches/0001-Added-LWIP-support.patch new file mode 100644 index 0000000000..3a4c194e51 --- /dev/null +++ b/usrsctp/patches/0001-Added-LWIP-support.patch @@ -0,0 +1,2245 @@ +From 435f8e8c35f3f1ff384b3b82b0611ea5d3c7d17c Mon Sep 17 00:00:00 2001 +From: Vikram Dattu +Date: Tue, 4 Feb 2025 16:58:02 +0530 +Subject: [PATCH 1/5] Added LWIP support + + - These changes are taken mostly from [this commit](https://github.com/ycyang1229/usrsctp/commit/4a4ac8d9b43acc830361ebc928368bbfde201233) + - Allows us using this port for devices with LWIP support +--- + CMakeLists.txt | 12 +- + fuzzer/pcap2corpus.c | 10 +- + usrsctplib/CMakeLists.txt | 6 + + usrsctplib/netinet/sctp_bsd_addr.c | 79 ++++++++++ + usrsctplib/netinet/sctp_callout.c | 6 + + usrsctplib/netinet/sctp_cc_functions.h | 8 + + usrsctplib/netinet/sctp_constants.h | 2 + + usrsctplib/netinet/sctp_header.h | 10 +- + usrsctplib/netinet/sctp_in_port.h | 86 +++++++++++ + usrsctplib/netinet/sctp_input.c | 52 +++---- + usrsctplib/netinet/sctp_ip_port.h | 91 +++++++++++ + usrsctplib/netinet/sctp_os_userspace.h | 21 ++- + usrsctplib/netinet/sctp_output.c | 204 ++++++++++++------------- + usrsctplib/netinet/sctp_pcb.c | 29 ++-- + usrsctplib/netinet/sctp_timer.c | 8 +- + usrsctplib/netinet/sctp_udp_port.h | 74 +++++++++ + usrsctplib/netinet/sctp_userspace.c | 8 + + usrsctplib/netinet/sctp_usrreq.c | 38 ++--- + usrsctplib/netinet/sctputil.c | 74 ++++----- + usrsctplib/netinet6/sctp6_usrreq.c | 6 +- + usrsctplib/user_environment.c | 39 ++++- + usrsctplib/user_ip_icmp.h | 5 +- + usrsctplib/user_recv_thread.c | 30 ++-- + usrsctplib/user_socket.c | 43 +++--- + usrsctplib/usrsctp.h | 6 +- + 25 files changed, 683 insertions(+), 264 deletions(-) + create mode 100644 usrsctplib/netinet/sctp_cc_functions.h + create mode 100644 usrsctplib/netinet/sctp_in_port.h + create mode 100644 usrsctplib/netinet/sctp_ip_port.h + create mode 100644 usrsctplib/netinet/sctp_udp_port.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3fc4ec6..4a2e71d 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -81,6 +81,12 @@ option(sctp_sanitizer_memory "Compile with memory sanitizer" 0) + + option(sctp_build_fuzzer "Compile in clang fuzzing mode" 0) + ++option(sctp_use_lwip "build with lwip" ON) ++ ++if(sctp_use_lwip) ++ add_definitions(-DSCTP_USE_LWIP) ++endif() ++ + if (sctp_sanitizer_address AND sctp_sanitizer_memory) + message(FATAL_ERROR "Can not compile with both sanitizer options") + endif () +@@ -129,7 +135,9 @@ set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/usrsctplib") + + check_include_file(usrsctp.h have_usrsctp_h) + if (NOT have_usrsctp_h) +- message(FATAL_ERROR "usrsctp.h not found") ++ if(NOT sctp_use_lwip) ++ message(FATAL_ERROR "usrsctp.h not found") ++ endif() + endif () + + check_struct_has_member("struct sockaddr" "sa_len" "sys/types.h;sys/socket.h" have_sa_len) +@@ -151,7 +159,7 @@ if (have_sin6_len) + endif () + + check_struct_has_member("struct sockaddr_conn" "sconn_len" "usrsctp.h" have_sconn_len) +-if (have_sconn_len) ++if (have_sconn_len OR sctp_use_lwip) + message(STATUS "HAVE_SCONN_LEN") + add_definitions(-DHAVE_SCONN_LEN) + endif () +diff --git a/fuzzer/pcap2corpus.c b/fuzzer/pcap2corpus.c +index 7419c71..0daa40f 100644 +--- a/fuzzer/pcap2corpus.c ++++ b/fuzzer/pcap2corpus.c +@@ -35,7 +35,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -110,7 +110,7 @@ packet_handler(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *byt + const u_char *bytes_out; + FILE *file; + char *filename; +- const struct ip *ip4_hdr_in; ++ const STRUCT_IP_HDR *ip4_hdr_in; + const struct ip6_hdr *ip6_hdr_in; + size_t offset, length; + int null = 0; +@@ -124,15 +124,15 @@ packet_handler(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *byt + goto out; + } + if (args->is_ipv4(bytes_in)) { +- offset = args->offset + sizeof(struct ip) + sizeof(struct sctphdr); ++ offset = args->offset + sizeof(STRUCT_IP_HDR) + sizeof(struct sctphdr); + if (pkthdr->caplen < offset) { + goto out; + } +- ip4_hdr_in = (const struct ip *)(const void *)(bytes_in + args->offset); ++ ip4_hdr_in = (const STRUCT_IP_HDR *)(const void *)(bytes_in + args->offset); + if (ip4_hdr_in->ip_p == IPPROTO_SCTP) { + unsigned int ip4_hdr_len; + +- ip4_hdr_len = ip4_hdr_in->ip_hl << 2; ++ ip4_hdr_len = GET_IP_HDR_LEN_VAL(ip4_hdr_in) << 2; + offset = args->offset + ip4_hdr_len + sizeof(struct sctphdr); + if (pkthdr->caplen < offset) { + goto out; +diff --git a/usrsctplib/CMakeLists.txt b/usrsctplib/CMakeLists.txt +index 93f6f4d..2b82f49 100644 +--- a/usrsctplib/CMakeLists.txt ++++ b/usrsctplib/CMakeLists.txt +@@ -58,6 +58,9 @@ option(SCTP_USE_MBEDTLS_SHA1 "Build with mbedtls sha1 support." OFF) + add_definitions(-D__Userspace__) + add_definitions(-DSCTP_SIMPLE_ALLOCATOR) + add_definitions(-DSCTP_PROCESS_LEVEL_LOCKS) ++if(NOT sctp_use_lwip) ++ add_definitions(-D__native_client__) ++endif() + + if(SCTP_USE_MBEDTLS_SHA1) + add_definitions(-DSCTP_USE_MBEDTLS_SHA1) +@@ -129,6 +132,7 @@ list(APPEND usrsctp_netinet_headers + netinet/sctp_header.h + netinet/sctp_indata.h + netinet/sctp_input.h ++ netinet/sctp_ip_port.h + netinet/sctp_lock_userspace.h + netinet/sctp_os_userspace.h + netinet/sctp_os.h +@@ -140,6 +144,8 @@ list(APPEND usrsctp_netinet_headers + netinet/sctp_structs.h + netinet/sctp_sysctl.h + netinet/sctp_timer.h ++ netinet/sctp_udp_port.h ++ netinet/sctp_in_port.h + netinet/sctp_uio.h + netinet/sctp_var.h + netinet/sctputil.h +diff --git a/usrsctplib/netinet/sctp_bsd_addr.c b/usrsctplib/netinet/sctp_bsd_addr.c +index 3e0df08..9197dfd 100755 +--- a/usrsctplib/netinet/sctp_bsd_addr.c ++++ b/usrsctplib/netinet/sctp_bsd_addr.c +@@ -49,6 +49,10 @@ + #include + #endif + ++#if defined(SCTP_USE_LWIP) ++#include ++#endif ++ + /* Declare all of our malloc named types */ + MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor"); + MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array"); +@@ -410,6 +414,80 @@ sctp_init_ifns_for_vrf(int vrfid) + static void + sctp_init_ifns_for_vrf(int vrfid) + { ++#if defined(SCTP_USE_LWIP) ++ #define LWIP_IF_NUM_MAX 256 ++ ++ struct sctp_ifa *sctp_ifa; ++ uint32_t ifa_flags; ++ uint32_t if_num; ++ char if_name[NETIF_NAMESIZE]; ++ struct sockaddr* in_addr = malloc(sizeof(struct sockaddr)); ++ ++ for(if_num=1;if_numip_addr)){ ++ continue; ++ } ++ ++ if(tmp_if->ip_addr.type == IPADDR_TYPE_V4){ ++ in_addr->sa_family = AF_INET; ++ memcpy(&((struct sockaddr_in *)in_addr)->sin_addr, &tmp_if->ip_addr.u_addr, sizeof(uint32_t) ); ++ }else{ ++ in_addr->sa_family = AF_INET6; ++ memcpy(&((struct sockaddr_in6 *)in_addr)->sin6_addr, &tmp_if->ip_addr.u_addr, sizeof(uint32_t)*4); ++ } ++#if !defined(INET) ++ if (in_addr->sa_family != AF_INET6) { ++ /* non inet6 skip */ ++ continue; ++ } ++#elif !defined(INET6) ++ if (in_addr->sa_family != AF_INET) { ++ /* non inet skip */ ++ continue; ++ } ++#else ++ if ((in_addr->sa_family != AF_INET) && (in_addr->sa_family != AF_INET6)) { ++ /* non inet/inet6 skip */ ++ continue; ++ } ++#endif ++#if defined(INET6) ++ if ((in_addr->sa_family == AF_INET6) && ++ IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)in_addr)->sin6_addr)) { ++ /* skip unspecifed addresses */ ++ continue; ++ } ++#endif ++#if defined(INET) ++ if (in_addr->sa_family == AF_INET && ++ ((struct sockaddr_in *)in_addr)->sin_addr.s_addr == 0) { ++ continue; ++ } ++#endif ++ ifa_flags = 0; ++ sctp_ifa = sctp_add_addr_to_vrf(vrfid, ++ NULL, ++ if_num, ++ 0, ++ tmp_name, ++ NULL, ++ (struct sockaddr*)in_addr, ++ ifa_flags, ++ 0); ++ if (sctp_ifa) { ++ sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; ++ } ++ }else{ ++ break; ++ } ++ } ++ free(in_addr); ++#else + #if defined(INET) || defined(INET6) + int rc; + struct ifaddrs *ifa, *ifas; +@@ -469,6 +547,7 @@ sctp_init_ifns_for_vrf(int vrfid) + } + freeifaddrs(ifas); + #endif ++#endif + } + #endif + #if defined(__APPLE__) && !defined(__Userspace__) +diff --git a/usrsctplib/netinet/sctp_callout.c b/usrsctplib/netinet/sctp_callout.c +index ee6cd4c..d223b42 100755 +--- a/usrsctplib/netinet/sctp_callout.c ++++ b/usrsctplib/netinet/sctp_callout.c +@@ -45,7 +45,11 @@ + #include + #include + #include ++#if defined(SCTP_USE_LWIP) ++#include "lwip/errno.h" ++#else + #include ++#endif + #include + #include + #include +@@ -199,6 +203,8 @@ user_sctp_timer_iterate(void *arg) + for (;;) { + #if defined(_WIN32) + Sleep(TIMEOUT_INTERVAL); ++#elif defined(SCTP_USE_LWIP) ++ usleep(TIMEOUT_INTERVAL*1000); + #else + struct timespec amount, remaining; + +diff --git a/usrsctplib/netinet/sctp_cc_functions.h b/usrsctplib/netinet/sctp_cc_functions.h +new file mode 100644 +index 0000000..2ac5a7f +--- /dev/null ++++ b/usrsctplib/netinet/sctp_cc_functions.h +@@ -0,0 +1,8 @@ ++// Add these declarations ++void sctp_cwnd_update_exit_pf_common(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb, struct sctp_nets *net); ++void sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb, struct sctp_nets *net); +diff --git a/usrsctplib/netinet/sctp_constants.h b/usrsctplib/netinet/sctp_constants.h +index 69953e9..3ee3a90 100755 +--- a/usrsctplib/netinet/sctp_constants.h ++++ b/usrsctplib/netinet/sctp_constants.h +@@ -973,12 +973,14 @@ extern void getwintimeofday(struct timeval *tv); + ((((uint8_t *)&(a)->s_addr)[0] == 192) && \ + (((uint8_t *)&(a)->s_addr)[1] == 168))) + ++#if 1 + #define IN4_ISLOOPBACK_ADDRESS(a) \ + (((uint8_t *)&(a)->s_addr)[0] == 127) + + #define IN4_ISLINKLOCAL_ADDRESS(a) \ + ((((uint8_t *)&(a)->s_addr)[0] == 169) && \ + (((uint8_t *)&(a)->s_addr)[1] == 254)) ++#endif + + /* Maximum size of optval for IPPROTO_SCTP level socket options. */ + #define SCTP_SOCKET_OPTION_LIMIT (64 * 1024) +diff --git a/usrsctplib/netinet/sctp_header.h b/usrsctplib/netinet/sctp_header.h +index 7a5ab64..58f6234 100755 +--- a/usrsctplib/netinet/sctp_header.h ++++ b/usrsctplib/netinet/sctp_header.h +@@ -569,13 +569,13 @@ struct sctp_zero_checksum_acceptable { + sizeof(struct sctphdr) + \ + sizeof(struct sctp_ecne_chunk) + \ + sizeof(struct sctp_sack_chunk) + \ +- sizeof(struct ip)) ++ sizeof(STRUCT_IP_HDR)) + + #define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \ + sizeof(struct sctphdr) + \ +- sizeof(struct ip)) ++ sizeof(STRUCT_IP_HDR)) + +-#define SCTP_MIN_OVERHEAD (sizeof(struct ip) + \ ++#define SCTP_MIN_OVERHEAD (sizeof(STRUCT_IP_HDR) + \ + sizeof(struct sctphdr)) + + #endif /* INET6 */ +@@ -583,9 +583,9 @@ struct sctp_zero_checksum_acceptable { + + #define SCTP_MED_V4_OVERHEAD (sizeof(struct sctp_data_chunk) + \ + sizeof(struct sctphdr) + \ +- sizeof(struct ip)) ++ sizeof(STRUCT_IP_HDR)) + +-#define SCTP_MIN_V4_OVERHEAD (sizeof(struct ip) + \ ++#define SCTP_MIN_V4_OVERHEAD (sizeof(STRUCT_IP_HDR) + \ + sizeof(struct sctphdr)) + + #if defined(_WIN32) && !defined(__Userspace__) +diff --git a/usrsctplib/netinet/sctp_in_port.h b/usrsctplib/netinet/sctp_in_port.h +new file mode 100644 +index 0000000..58abff2 +--- /dev/null ++++ b/usrsctplib/netinet/sctp_in_port.h +@@ -0,0 +1,86 @@ ++/*- ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. ++ * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. ++ * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * a) Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * b) Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the distribution. ++ * ++ * c) Neither the name of Cisco Systems, Inc. nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(__FreeBSD__) && !defined(__Userspace__) ++#include ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 359195 2020-03-21 16:12:19Z tuexen $"); ++#endif ++ ++#ifndef _NETINET_SCTP_IN_PORT_H_ ++#define _NETINET_SCTP_IN_PORT_H_ ++ ++#if defined(SCTP_USE_LWIP) ++/* Standard well-known ports. */ ++enum ++ { ++ IPPORT_ECHO = 7, /* Echo service. */ ++ IPPORT_DISCARD = 9, /* Discard transmissions service. */ ++ IPPORT_SYSTAT = 11, /* System status service. */ ++ IPPORT_DAYTIME = 13, /* Time of day service. */ ++ IPPORT_NETSTAT = 15, /* Network status service. */ ++ IPPORT_FTP = 21, /* File Transfer Protocol. */ ++ IPPORT_TELNET = 23, /* Telnet protocol. */ ++ IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ ++ IPPORT_TIMESERVER = 37, /* Timeserver service. */ ++ IPPORT_NAMESERVER = 42, /* Domain Name Service. */ ++ IPPORT_WHOIS = 43, /* Internet Whois service. */ ++ IPPORT_MTP = 57, ++ ++ IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ ++ IPPORT_RJE = 77, ++ IPPORT_FINGER = 79, /* Finger service. */ ++ IPPORT_TTYLINK = 87, ++ IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ ++ ++ ++ IPPORT_EXECSERVER = 512, /* execd service. */ ++ IPPORT_LOGINSERVER = 513, /* rlogind service. */ ++ IPPORT_CMDSERVER = 514, ++ IPPORT_EFSSERVER = 520, ++ ++ /* UDP ports. */ ++ IPPORT_BIFFUDP = 512, ++ IPPORT_WHOSERVER = 513, ++ IPPORT_ROUTESERVER = 520, ++ ++ /* Ports less than this value are reserved for privileged processes. */ ++ IPPORT_RESERVED = 1024, ++ ++ /* Ports greater this value are reserved for (non-privileged) servers. */ ++ IPPORT_USERRESERVED = 5000 ++ }; ++ ++#define IP_HDRINCL 3 /* int; Header is included with data. */ ++#endif ++#endif//!< _NETINET_SCTP_IN_PORT_H_ +diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c +index a3c1476..61fb6cc 100755 +--- a/usrsctplib/netinet/sctp_input.c ++++ b/usrsctplib/netinet/sctp_input.c +@@ -49,11 +49,7 @@ + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include + #endif +-#if defined(INET) || defined(INET6) +-#if !defined(_WIN32) +-#include +-#endif +-#endif ++#include + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include + #endif +@@ -5773,13 +5769,13 @@ validate_cksum: + (net != NULL) && (net->port != port)) { + if (net->port == 0) { + /* UDP encapsulation turned on. */ +- net->mtu -= sizeof(struct udphdr); ++ net->mtu -= sizeof(STRUCT_UDP_HDR); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ +- net->mtu += sizeof(struct udphdr); ++ net->mtu += sizeof(STRUCT_UDP_HDR); + /* XXX Update smallest_mtu */ + } + net->port = port; +@@ -5842,13 +5838,13 @@ cksum_validated: + (net != NULL) && (net->port != port)) { + if (net->port == 0) { + /* UDP encapsulation turned on. */ +- net->mtu -= sizeof(struct udphdr); ++ net->mtu -= sizeof(STRUCT_UDP_HDR); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ +- net->mtu += sizeof(struct udphdr); ++ net->mtu += sizeof(STRUCT_UDP_HDR); + /* XXX Update smallest_mtu */ + } + net->port = port; +@@ -5966,13 +5962,13 @@ cksum_validated: + (net != NULL) && (net->port != port)) { + if (net->port == 0) { + /* UDP encapsulation turned on. */ +- net->mtu -= sizeof(struct udphdr); ++ net->mtu -= sizeof(STRUCT_UDP_HDR); + if (stcb->asoc.smallest_mtu > net->mtu) { + sctp_pathmtu_adjustment(stcb, net->mtu, true); + } + } else if (port == 0) { + /* UDP encapsulation turned off. */ +- net->mtu += sizeof(struct udphdr); ++ net->mtu += sizeof(STRUCT_UDP_HDR); + /* XXX Update smallest_mtu */ + } + net->port = port; +@@ -6221,7 +6217,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) + uint32_t vrf_id = 0; + uint8_t ecn_bits; + struct sockaddr_in src, dst; +- struct ip *ip; ++ STRUCT_IP_HDR *ip; + struct sctphdr *sh; + struct sctp_chunkhdr *ch; + int length, offset; +@@ -6289,7 +6285,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) + return; + } + } +- ip = mtod(m, struct ip *); ++ ip = mtod(m, STRUCT_IP_HDR *); + sh = (struct sctphdr *)((caddr_t)ip + iphlen); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); +@@ -6299,32 +6295,32 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) + src.sin_len = sizeof(struct sockaddr_in); + #endif + src.sin_port = sh->src_port; +- src.sin_addr = ip->ip_src; ++ src.sin_addr = GET_IP_SRC(ip); + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); + #endif + dst.sin_port = sh->dest_port; +- dst.sin_addr = ip->ip_dst; ++ dst.sin_addr.s_addr = GET_IP_DEST(ip); + #if defined(_WIN32) && !defined(__Userspace__) +- NTOHS(ip->ip_len); ++ NTOHS(GET_IP_LEN(ip)); + #endif + #if defined(__linux__) || (defined(_WIN32) && defined(__Userspace__)) +- ip->ip_len = ntohs(ip->ip_len); ++ GET_IP_LEN(ip) = NTOHS(GET_IP_LEN(ip)); + #endif + #if defined(__Userspace__) + #if defined(__linux__) || defined(_WIN32) +- length = ip->ip_len; ++ length = GET_IP_LEN(ip); + #else +- length = ip->ip_len + iphlen; ++ length = GET_IP_LEN(ip) + iphlen; + #endif + #elif defined(__FreeBSD__) +- length = ntohs(ip->ip_len); ++ length = NTOHS(GET_IP_LEN(ip)); + #elif defined(__APPLE__) +- length = ip->ip_len + iphlen; ++ length = GET_IP_LEN(ip) + iphlen; + #else +- length = ip->ip_len; ++ length = GET_IP_LEN(ip); + #endif + /* Validate mbuf chain length with IP payload length. */ + if (SCTP_HEADER_LEN(m) != length) { +@@ -6334,13 +6330,13 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) + goto out; + } + /* SCTP does not allow broadcasts or multicasts */ +- if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { ++ if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr.s_addr))) { + goto out; + } +- if (SCTP_IS_IT_BROADCAST(dst.sin_addr, m)) { ++ if (SCTP_IS_IT_BROADCAST(dst.sin_addr.s_addr, m)) { + goto out; + } +- ecn_bits = ip->ip_tos; ++ ecn_bits = GET_IP_TOS(ip); + #if defined(__FreeBSD__) && !defined(__Userspace__) + if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { + SCTP_STAT_INCR(sctps_recvhwcrc); +@@ -6348,7 +6344,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) + } else { + #else + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && +- ((src.sin_addr.s_addr == dst.sin_addr.s_addr) || ++ ((src.sin_addr.s_addr == dst.sin_addr.s_addr.s_addr) || + (SCTP_IS_IT_LOOPBACK(m)))) { + SCTP_STAT_INCR(sctps_recvhwcrc); + compute_crc = 0; +@@ -6397,7 +6393,7 @@ sctp_input(struct mbuf *m, int off) + #if defined(__FreeBSD__) && !defined(__Userspace__) + #if defined(SCTP_MCORE_INPUT) && defined(SMP) + if (mp_ncpus > 1) { +- struct ip *ip; ++ STRUCT_IP_HDR *ip; + struct sctphdr *sh; + int offset; + int cpu_to_use; +@@ -6416,7 +6412,7 @@ sctp_input(struct mbuf *m, int off) + return (IPPROTO_DONE); + } + } +- ip = mtod(m, struct ip *); ++ ip = mtod(m, STRUCT_IP_HDR *); + sh = (struct sctphdr *)((caddr_t)ip + off); + tag = htonl(sh->v_tag); + flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); +diff --git a/usrsctplib/netinet/sctp_ip_port.h b/usrsctplib/netinet/sctp_ip_port.h +new file mode 100644 +index 0000000..2e382eb +--- /dev/null ++++ b/usrsctplib/netinet/sctp_ip_port.h +@@ -0,0 +1,91 @@ ++/*- ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. ++ * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. ++ * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * a) Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * b) Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the distribution. ++ * ++ * c) Neither the name of Cisco Systems, Inc. nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(__FreeBSD__) && !defined(__Userspace__) ++#include ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 359195 2020-03-21 16:12:19Z tuexen $"); ++#endif ++ ++#ifndef _NETINET_SCTP_IP_PORT_H_ ++#define _NETINET_SCTP_IP_PORT_H_ ++ ++#if !defined(SCTP_USE_LWIP) ++#include ++#define STRUCT_IP_HDR struct ip ++//#define GET_IP_VERSION(ip) ((struct ip_hdr*)(ip))->ip_v ++//#define GET_IP_HDR_LEN(ip) ((struct ip_hdr*)(ip))->ip_hl ++#define GET_IP_TOS(ip) ((struct ip*)(ip))->ip_tos ++#define GET_IP_LEN(ip) ((struct ip*)ip)->ip_len ++#define GET_IP_ID(ip) ((struct ip*)ip)->ip_id ++#define GET_IP_OFFSET(ip) ((struct ip*)ip)->ip_off ++#define GET_IP_TTL(ip) ((struct ip*)ip)->ip_ttl ++#define GET_IP_PROTO(ip) ((struct ip*)ip)->ip_p ++#define GET_IP_CHKSUM(ip) ((struct ip*)ip)->ip_sum ++#define GET_IP_SRC(ip) ((struct ip*)ip)->ip_src ++#define GET_IP_DEST(ip) ((struct ip*)ip)->ip_dst ++#define GET_IP_SRC_ADDR(ip) ((struct ip*)ip)->ip_src.s_addr ++#define GET_IP_DEST_ADDR(ip) ((struct ip*)ip)->ip_dst.s_addr ++ ++#define GET_IP_VERSION_VAL(ip) ((struct ip_hdr*)(ip))->ip_v ++#define GET_IP_HDR_LEN_VAL(ip) ((struct ip_hdr*)(ip))->ip_hl ++ ++#define SET_IP_VHL(hdr, v, hl) do{\ ++ (hdr)->ip_v = v;\ ++ (hdr)->ip_hl = hl;\ ++ }while(0) ++#else ++#include "lwip/ip.h" ++#define STRUCT_IP_HDR struct ip_hdr ++//#define GET_IP_VERSION(ip) ((struct ip_hdr*)(ip))->_v_hl ++//#define GET_IP_HDR_LEN(ip) ((struct ip_hdr*)(ip))->_v_hl ++#define GET_IP_TOS(ip) IPH_TOS(ip)//((struct ip_hdr*)(ip))->_tos ++#define GET_IP_LEN(ip) IPH_LEN(ip)//((struct ip_hdr*)ip)->_len ++#define GET_IP_ID(ip) IPH_ID(ip)//((struct ip_hdr*)ip)->_id ++#define GET_IP_OFFSET(ip) IPH_OFFSET(ip)//((struct ip_hdr*)ip)->_offset ++#define GET_IP_TTL(ip) IPH_TTL(ip)//((struct ip_hdr*)ip)->_ttl ++#define GET_IP_PROTO(ip) IPH_PROTO(ip)//((struct ip_hdr*)ip)->_proto ++#define GET_IP_CHKSUM(ip) IPH_CHKSUM(ip)//((struct ip_hdr*)ip)->_chksum ++#define GET_IP_SRC(ip) ((struct ip_hdr*)ip)->src ++#define GET_IP_DEST(ip) ((struct ip_hdr*)ip)->dest ++#define GET_IP_SRC_ADDR(ip) ((struct ip_hdr*)ip)->src.addr ++#define GET_IP_DEST_ADDR(ip) ((struct ip_hdr*)ip)->dest.addr ++ ++ ++#define GET_IP_VERSION_VAL(ip) IPH_V(ip) ++#define GET_IP_HDR_LEN_VAL(ip) IPH_HL(ip) ++ ++#define SET_IP_VHL(hdr, v, hl) IPH_VHL_SET(hdr, v, hl) ++#endif ++ ++#endif//!< _NETINET_SCTP_UDP_PORT_H_ +diff --git a/usrsctplib/netinet/sctp_os_userspace.h b/usrsctplib/netinet/sctp_os_userspace.h +index 493ae02..53e8267 100755 +--- a/usrsctplib/netinet/sctp_os_userspace.h ++++ b/usrsctplib/netinet/sctp_os_userspace.h +@@ -40,8 +40,11 @@ + * All the opt_xxx.h files are placed in the kernel build directory. + * We will place them in userspace stack build directory. + */ +- ++#if defined(SCTP_USE_LWIP) ++#include "lwip/errno.h" ++#else + #include ++#endif + + #if defined(_WIN32) + #include +@@ -292,6 +295,12 @@ typedef char* caddr_t; + + #include + ++#if defined(SCTP_USE_LWIP) ++#define IPVERSION 4 ++#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \ ++ & (size_t) ~(sizeof (size_t) - 1)) ++#endif/* */ ++ + typedef pthread_mutex_t userland_mutex_t; + typedef pthread_rwlock_t userland_rwlock_t; + typedef pthread_cond_t userland_cond_t; +@@ -464,8 +473,10 @@ struct sx {int dummy;}; + #if !defined(_WIN32) && !defined(__native_client__) + #include + #include ++#if !defined(SCTP_USE_LWIP) + #include +-#include ++#endif ++#include + #endif + #if defined(HAVE_NETINET_IP_ICMP_H) + #include +@@ -479,9 +490,11 @@ struct sx {int dummy;}; + #include + #if !defined(_WIN32) + #if defined(INET) || defined(INET6) ++#if !defined(SCTP_USE_LWIP) + #include + #endif + ++#endif + /* for ioctl */ + #include + +@@ -514,13 +527,17 @@ struct sx {int dummy;}; + #include + #endif + #if !defined(_WIN32) ++#if !defined(SCTP_USE_LWIP) + #include + #endif ++#endif + #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(_WIN32) || defined(__EMSCRIPTEN__) + #include "user_ip6_var.h" + #else ++#if !defined(SCTP_USE_LWIP) + #include + #endif ++#endif + #if defined(__FreeBSD__) + #include + #include +diff --git a/usrsctplib/netinet/sctp_output.c b/usrsctplib/netinet/sctp_output.c +index 50c4bfd..5e2f5ae 100755 +--- a/usrsctplib/netinet/sctp_output.c ++++ b/usrsctplib/netinet/sctp_output.c +@@ -57,11 +57,8 @@ + #if defined(__linux__) + #define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */ + #endif +-#if defined(INET) || defined(INET6) +-#if !defined(_WIN32) +-#include +-#endif +-#endif ++#include ++ + #if !defined(__Userspace__) + #if defined(__APPLE__) + #include +@@ -4112,7 +4109,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + #if defined(INET) || defined(INET6) + struct mbuf *o_pak; + sctp_route_t *ro = NULL; +- struct udphdr *udp = NULL; ++ STRUCT_UDP_HDR *udp = NULL; + #endif + uint8_t tos_value; + #if defined(__APPLE__) && !defined(__Userspace__) +@@ -4156,13 +4153,13 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + #ifdef INET + case AF_INET: + { +- struct ip *ip = NULL; ++ STRUCT_IP_HDR *ip = NULL; + sctp_route_t iproute; + int len; + + len = SCTP_MIN_V4_OVERHEAD; + if (port) { +- len += sizeof(struct udphdr); ++ len += sizeof(STRUCT_UDP_HDR); + } + newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); + if (newm == NULL) { +@@ -4184,9 +4181,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + } + #endif + packet_length = sctp_calculate_len(m); +- ip = mtod(m, struct ip *); +- ip->ip_v = IPVERSION; +- ip->ip_hl = (sizeof(struct ip) >> 2); ++ ip = mtod(m, STRUCT_IP_HDR *); ++ SET_IP_VHL(ip, IPVERSION, (sizeof(STRUCT_IP_HDR) >> 2)); + if (tos_value == 0) { + /* + * This means especially, that it is not set at the +@@ -4200,47 +4196,47 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + } + if ((nofragment_flag) && (port == 0)) { + #if defined(__FreeBSD__) && !defined(__Userspace__) +- ip->ip_off = htons(IP_DF); ++ GET_IP_OFFSET(ip) = htons(IP_DF); + #elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) +- ip->ip_off = IP_DF; ++ GET_IP_OFFSET(ip) = IP_DF; + #else +- ip->ip_off = htons(IP_DF); ++ GET_IP_OFFSET(ip) = htons(IP_DF); + #endif + } else { + #if defined(__FreeBSD__) && !defined(__Userspace__) +- ip->ip_off = htons(0); ++ GET_IP_OFFSET(ip) = htons(0); + #else +- ip->ip_off = 0; ++ GET_IP_OFFSET(ip) = 0; + #endif + } + #if defined(__Userspace__) +- ip->ip_id = htons(SCTP_IP_ID(inp)++); ++ GET_IP_ID(ip) = htons(SCTP_IP_ID(inp)++); + #elif defined(__FreeBSD__) + /* FreeBSD has a function for ip_id's */ + ip_fillid(ip); + #elif defined(__APPLE__) + #if RANDOM_IP_ID +- ip->ip_id = ip_randomid(); ++ GET_IP_ID(ip) = ip_randomid(); + #else +- ip->ip_id = htons(ip_id++); ++ GET_IP_ID(ip) = htons(ip_id++); + #endif + #else +- ip->ip_id = SCTP_IP_ID(inp)++; ++ GET_IP_ID(ip) = SCTP_IP_ID(inp)++; + #endif + +- ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl; ++ GET_IP_TTL(ip) = inp->ip_inp.inp.inp_ip_ttl; + #if defined(__FreeBSD__) && !defined(__Userspace__) +- ip->ip_len = htons(packet_length); ++ GET_IP_LEN(ip) = htons(packet_length); + #else +- ip->ip_len = packet_length; ++ GET_IP_LEN(ip) = packet_length; + #endif +- ip->ip_tos = tos_value; ++ GET_IP_TOS(ip) = tos_value; + if (port) { +- ip->ip_p = IPPROTO_UDP; ++ GET_IP_PROTO(ip) = IPPROTO_UDP; + } else { +- ip->ip_p = IPPROTO_SCTP; ++ GET_IP_PROTO(ip) = IPPROTO_SCTP; + } +- ip->ip_sum = 0; ++ GET_IP_CHKSUM(ip) = 0; + if (net == NULL) { + ro = &iproute; + memset(&iproute, 0, sizeof(iproute)); +@@ -4253,7 +4249,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + ro = (sctp_route_t *)&net->ro; + } + /* Now the address selection part */ +- ip->ip_dst.s_addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; ++ GET_IP_DEST_ADDR(ip) = ((struct sockaddr_in *)to)->sin_addr.s_addr; + + /* call the routine to select the src address */ + if (net && out_of_asoc_ok == 0) { +@@ -4285,7 +4281,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + sctp_m_freem(m); + return (EHOSTUNREACH); + } +- ip->ip_src = net->ro._s_addr->address.sin.sin_addr; ++ GET_IP_SRC_ADDR(ip) = net->ro._s_addr->address.sin.sin_addr.s_addr; + } else { + if (over_addr == NULL) { + struct sctp_ifa *_lsrc; +@@ -4300,10 +4296,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + sctp_m_freem(m); + return (EHOSTUNREACH); + } +- ip->ip_src = _lsrc->address.sin.sin_addr; ++ GET_IP_SRC_ADDR(ip) = _lsrc->address.sin.sin_addr.s_addr; + sctp_free_ifa(_lsrc); + } else { +- ip->ip_src = over_addr->sin.sin_addr; ++ GET_IP_SRC_ADDR(ip) = over_addr->sin.sin_addr.s_addr; + SCTP_RTALLOC(ro, vrf_id, inp->fibnum); + } + } +@@ -4314,26 +4310,26 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + sctp_m_freem(m); + return (EHOSTUNREACH); + } +- udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); +- udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); +- udp->uh_dport = port; +- udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip))); ++ udp = (STRUCT_UDP_HDR *)((caddr_t)ip + sizeof(STRUCT_IP_HDR)); ++ GET_UDP_SRC(udp) = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); ++ GET_UDP_DEST(udp) = port; ++ GET_UDP_LEN(udp) = htons((uint16_t)(packet_length - sizeof(STRUCT_IP_HDR))); + #if !defined(__Userspace__) + #if defined(__FreeBSD__) + if (V_udp_cksum) { +- udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); ++ GET_UDP_CHKSUM(ip) = in_pseudo(GET_IP_SRC_ADDR(ip).s_addr, GET_IP_DEST_ADDR(ip), GET_UDP_LEN(udp) + htons(IPPROTO_UDP)); + } else { +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + } + #else +- udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); ++ GET_UDP_CHKSUM(ip) = in_pseudo(GET_IP_SRC_ADDR(ip).s_addr, GET_IP_DEST_ADDR(ip), GET_UDP_LEN(udp) + htons(IPPROTO_UDP)); + #endif + #else +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + #endif +- sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); ++ sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(STRUCT_UDP_HDR)); + } else { +- sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip)); ++ sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(STRUCT_IP_HDR)); + } + + sctphdr->src_port = src_port; +@@ -4367,9 +4363,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + memcpy(&iproute, ro, sizeof(*ro)); + } + SCTPDBG(SCTP_DEBUG_OUTPUT3, "Calling ipv4 output routine from low level src addr:%x\n", +- (uint32_t) (ntohl(ip->ip_src.s_addr))); ++ (uint32_t) (ntohl(GET_IP_SRC_ADDR(ip)))); + SCTPDBG(SCTP_DEBUG_OUTPUT3, "Destination is %x\n", +- (uint32_t)(ntohl(ip->ip_dst.s_addr))); ++ (uint32_t)(ntohl(GET_IP_DEST_ADDR(ip)))); + #if defined(__FreeBSD__) && !defined(__Userspace__) + SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n", + (void *)ro->ro_nh); +@@ -4389,7 +4385,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + if (use_zero_crc) { + SCTP_STAT_INCR(sctps_sendzerocrc); + } else { +- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); ++ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(STRUCT_IP_HDR) + sizeof(STRUCT_UDP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + } + #if !defined(__Userspace__) +@@ -4412,7 +4408,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + #else + if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && + (stcb) && (stcb->asoc.scope.loopback_scope))) { +- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip)); ++ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(STRUCT_IP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + } else { + SCTP_STAT_INCR(sctps_sendhwcrc); +@@ -4481,7 +4477,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + #endif + if (mtu > 0) { + if (net->port) { +- mtu -= sizeof(struct udphdr); ++ mtu -= sizeof(STRUCT_UDP_HDR); + } + if (mtu < net->mtu) { + net->mtu = mtu; +@@ -4546,7 +4542,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + flowlabel &= 0x000fffff; + len = SCTP_MIN_OVERHEAD; + if (port) { +- len += sizeof(struct udphdr); ++ len += sizeof(STRUCT_UDP_HDR); + } + newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); + if (newm == NULL) { +@@ -4811,12 +4807,12 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + sctp_m_freem(m); + return (EHOSTUNREACH); + } +- udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); +- udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); +- udp->uh_dport = port; +- udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); +- udp->uh_sum = 0; +- sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); ++ udp = (STRUCT_UDP_HDR *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); ++ GET_UDP_SRC(udp) = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); ++ GET_UDP_DEST(udp) = port; ++ GET_UDP_LEN(udp) = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); ++ GET_UDP_CHKSUM(ip) = 0; ++ sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(STRUCT_UDP_HDR)); + } else { + sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); + } +@@ -4861,14 +4857,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + } + SCTP_ATTACH_CHAIN(o_pak, m, packet_length); + if (port) { +- sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); ++ sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(STRUCT_UDP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + #if !defined(__Userspace__) + #if defined(_WIN32) +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + #else +- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { +- udp->uh_sum = 0xffff; ++ if ((GET_UDP_CHKSUM(ip) = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { ++ GET_UDP_CHKSUM(ip) = 0xffff; + } + #endif + #endif +@@ -4971,7 +4967,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, + #endif + if (mtu > 0) { + if (net->port) { +- mtu -= sizeof(struct udphdr); ++ mtu -= sizeof(STRUCT_UDP_HDR); + } + if (mtu < net->mtu) { + net->mtu = mtu; +@@ -5573,7 +5569,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, + #ifdef INET6 + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + #else +- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); ++ SCTP_BUF_RESV_UF(op_err, sizeof(STRUCT_IP_HDR)); + #endif + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); +@@ -5615,7 +5611,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, + #ifdef INET6 + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + #else +- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); ++ SCTP_BUF_RESV_UF(op_err, sizeof(STRUCT_IP_HDR)); + #endif + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); +@@ -5706,7 +5702,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, + #ifdef INET6 + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + #else +- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); ++ SCTP_BUF_RESV_UF(op_err, sizeof(STRUCT_IP_HDR)); + #endif + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); +@@ -11743,7 +11739,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + struct sctphdr *shout; + struct sctp_chunkhdr *ch; + #if defined(INET) || defined(INET6) +- struct udphdr *udp; ++ STRUCT_UDP_HDR *udp; + #endif + int ret, len, cause_len, padding_len; + #ifdef INET +@@ -11751,7 +11747,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + sctp_route_t ro; + #endif + struct sockaddr_in *src_sin, *dst_sin; +- struct ip *ip; ++ STRUCT_IP_HDR *ip; + #endif + #ifdef INET6 + struct sockaddr_in6 *src_sin6, *dst_sin6; +@@ -11786,7 +11782,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + switch (dst->sa_family) { + #ifdef INET + case AF_INET: +- len += sizeof(struct ip); ++ len += sizeof(STRUCT_IP_HDR); + break; + #endif + #ifdef INET6 +@@ -11799,7 +11795,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + } + #if defined(INET) || defined(INET6) + if (port) { +- len += sizeof(struct udphdr); ++ len += sizeof(STRUCT_UDP_HDR); + } + #endif + #if defined(__APPLE__) && !defined(__Userspace__) +@@ -11844,40 +11840,42 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + case AF_INET: + src_sin = (struct sockaddr_in *)src; + dst_sin = (struct sockaddr_in *)dst; +- ip = mtod(mout, struct ip *); +- ip->ip_v = IPVERSION; +- ip->ip_hl = (sizeof(struct ip) >> 2); +- ip->ip_tos = 0; ++ ip = mtod(mout, STRUCT_IP_HDR *); ++ // ip->ip_v = IPVERSION; ++ // ip->ip_hl = (sizeof(STRUCT_IP_HDR) >> 2); ++ SET_IP_VHL(ip, IPVERSION, (sizeof(STRUCT_IP_HDR) >> 2)); ++ ++ GET_IP_TOS(ip) = 0; + #if defined(__FreeBSD__) && !defined(__Userspace__) +- ip->ip_off = htons(IP_DF); ++ GET_IP_OFFSET(ip) = htons(IP_DF); + #elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) +- ip->ip_off = IP_DF; ++ GET_IP_OFFSET(ip) = IP_DF; + #else +- ip->ip_off = htons(IP_DF); ++ GET_IP_OFFSET(ip) = htons(IP_DF); + #endif + #if defined(__Userspace__) +- ip->ip_id = htons(ip_id++); ++ GET_IP_ID(ip) = htons(ip_id++); + #elif defined(__FreeBSD__) + ip_fillid(ip); + #elif defined(__APPLE__) + #if RANDOM_IP_ID +- ip->ip_id = ip_randomid(); ++ GET_IP_ID(ip) = ip_randomid(); + #else +- ip->ip_id = htons(ip_id++); ++ GET_IP_ID(ip) = htons(ip_id++); + #endif + #else +- ip->ip_id = ip_id++; ++ GET_IP_ID(ip) = ip_id++; + #endif +- ip->ip_ttl = MODULE_GLOBAL(ip_defttl); ++ GET_IP_TTL(ip) = MODULE_GLOBAL(ip_defttl); + if (port) { +- ip->ip_p = IPPROTO_UDP; ++ GET_IP_PROTO(ip) = IPPROTO_UDP; + } else { +- ip->ip_p = IPPROTO_SCTP; ++ GET_IP_PROTO(ip) = IPPROTO_SCTP; + } +- ip->ip_src.s_addr = dst_sin->sin_addr.s_addr; +- ip->ip_dst.s_addr = src_sin->sin_addr.s_addr; +- ip->ip_sum = 0; +- len = sizeof(struct ip); ++ GET_IP_SRC_ADDR(ip) = dst_sin->sin_addr.s_addr; ++ GET_IP_DEST_ADDR(ip) = src_sin->sin_addr.s_addr; ++ GET_IP_CHKSUM(ip) = 0; ++ len = sizeof(STRUCT_IP_HDR); + shout = (struct sctphdr *)((caddr_t)ip + len); + break; + #endif +@@ -11919,16 +11917,16 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + sctp_m_freem(mout); + return; + } +- udp = (struct udphdr *)shout; +- udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); +- udp->uh_dport = port; +- udp->uh_sum = 0; +- udp->uh_ulen = htons((uint16_t)(sizeof(struct udphdr) + ++ udp = (STRUCT_UDP_HDR *)shout; ++ GET_UDP_SRC(udp) = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); ++ GET_UDP_DEST(udp) = port; ++ GET_UDP_CHKSUM(ip) = 0; ++ GET_UDP_LEN(udp) = htons((uint16_t)(sizeof(STRUCT_UDP_HDR) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + cause_len + padding_len)); +- len += sizeof(struct udphdr); +- shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr)); ++ len += sizeof(STRUCT_UDP_HDR); ++ shout = (struct sctphdr *)((caddr_t)shout + sizeof(STRUCT_UDP_HDR)); + } else { + udp = NULL; + } +@@ -11969,26 +11967,26 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + #if !defined(_WIN32) && !defined(__Userspace__) + #if defined(__FreeBSD__) + if (V_udp_cksum) { +- udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); ++ GET_UDP_CHKSUM(ip) = in_pseudo(GET_IP_SRC_ADDR(ip).s_addr, GET_IP_DEST_ADDR(ip), GET_UDP_LEN(udp) + htons(IPPROTO_UDP)); + } else { +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + } + #else +- udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); ++ GET_UDP_CHKSUM(ip) = in_pseudo(GET_IP_SRC_ADDR(ip).s_addr, GET_IP_DEST_ADDR(ip), GET_UDP_LEN(udp) + htons(IPPROTO_UDP)); + #endif + #else +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + #endif + } + #if defined(__FreeBSD__) && !defined(__Userspace__) +- ip->ip_len = htons(len); ++ GET_IP_LEN(ip) = htons(len); + #elif defined(__APPLE__) || defined(__Userspace__) +- ip->ip_len = len; ++ GET_IP_LEN(ip) = len; + #else +- ip->ip_len = htons(len); ++ GET_IP_LEN(ip) = htons(len); + #endif + if (port) { +- shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip) + sizeof(struct udphdr)); ++ shout->checksum = sctp_calculate_cksum(mout, sizeof(STRUCT_IP_HDR) + sizeof(STRUCT_UDP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + #if !defined(_WIN32) && !defined(__Userspace__) + #if defined(__FreeBSD__) +@@ -12005,7 +12003,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); + SCTP_STAT_INCR(sctps_sendhwcrc); + #else +- shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip)); ++ shout->checksum = sctp_calculate_cksum(mout, sizeof(STRUCT_IP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + #endif + } +@@ -12033,14 +12031,14 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, + case AF_INET6: + ip6->ip6_plen = htons((uint16_t)(len - sizeof(struct ip6_hdr))); + if (port) { +- shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); ++ shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(STRUCT_UDP_HDR)); + SCTP_STAT_INCR(sctps_sendswcrc); + #if !defined(__Userspace__) + #if defined(_WIN32) +- udp->uh_sum = 0; ++ GET_UDP_CHKSUM(ip) = 0; + #else +- if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { +- udp->uh_sum = 0xffff; ++ if ((GET_UDP_CHKSUM(ip) = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { ++ GET_UDP_CHKSUM(ip) = 0xffff; + } + #endif + #endif +diff --git a/usrsctplib/netinet/sctp_pcb.c b/usrsctplib/netinet/sctp_pcb.c +index 83d2511..5738688 100755 +--- a/usrsctplib/netinet/sctp_pcb.c ++++ b/usrsctplib/netinet/sctp_pcb.c +@@ -46,18 +46,17 @@ + #include + #include + #include +-#if defined(INET) || defined(INET6) +-#if !defined(_WIN32) +-#include +-#endif +-#endif ++#include ++#include + #ifdef INET6 + #if defined(__Userspace__) + #include "user_ip6_var.h" + #else ++#if !defined(SCTP_USE_LWIP) + #include + #endif + #endif ++#endif + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include + #include +@@ -486,7 +485,11 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, + if (if_name != NULL) { + SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", if_name); + } else { ++#if defined(SCTP_USE_LWIP) ++ SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "na"); ++#else + SCTP_SNPRINTF(sctp_ifnp->ifn_name, SCTP_IFNAMSIZ, "%s", "unknown"); ++#endif + } + hash_ifn_head = &SCTP_BASE_INFO(vrf_ifn_hash)[(ifn_index & SCTP_BASE_INFO(vrf_ifn_hashmark))]; + LIST_INIT(&sctp_ifnp->ifalist); +@@ -4485,7 +4488,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, + } + #if defined(INET) || defined(INET6) + if (net->port) { +- net->mtu += (uint32_t)sizeof(struct udphdr); ++ net->mtu += (uint32_t)sizeof(STRUCT_UDP_HDR); + } + #endif + } else if (net->ro._s_addr != NULL) { +@@ -4546,7 +4549,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, + } + #if defined(INET) || defined(INET6) + if (net->port) { +- net->mtu += (uint32_t)sizeof(struct udphdr); ++ net->mtu += (uint32_t)sizeof(STRUCT_UDP_HDR); + } + #endif + } else { +@@ -4573,7 +4576,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, + } + #if defined(INET) || defined(INET6) + if (net->port) { +- net->mtu -= (uint32_t)sizeof(struct udphdr); ++ net->mtu -= (uint32_t)sizeof(STRUCT_UDP_HDR); + } + #endif + if (from == SCTP_ALLOC_ASOC) { +@@ -6364,7 +6367,7 @@ sctp_startup_mcore_threads(void) + static struct mbuf * + sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) + { +- struct ip *ip; ++ STRUCT_IP_HDR *ip; + struct sctphdr *sh; + int offset; + uint32_t flowid, tag; +@@ -6373,16 +6376,16 @@ sctp_netisr_hdlr(struct mbuf *m, uintptr_t source) + * No flow id built by lower layers fix it so we + * create one. + */ +- ip = mtod(m, struct ip *); +- offset = (ip->ip_hl << 2) + sizeof(struct sctphdr); ++ ip = mtod(m, STRUCT_IP_HDR *); ++ offset = GET_IP_HDR_LEN_VAL(ip) + sizeof(struct sctphdr); + if (SCTP_BUF_LEN(m) < offset) { + if ((m = m_pullup(m, offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + return (NULL); + } +- ip = mtod(m, struct ip *); ++ ip = mtod(m, STRUCT_IP_HDR *); + } +- sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); ++ sh = (struct sctphdr *)((caddr_t)ip + (GET_IP_HDR_LEN_VAL(ip) << 2)); + tag = htonl(sh->v_tag); + flowid = tag ^ ntohs(sh->dest_port) ^ ntohs(sh->src_port); + m->m_pkthdr.flowid = flowid; +diff --git a/usrsctplib/netinet/sctp_timer.c b/usrsctplib/netinet/sctp_timer.c +index 497f2f0..2f07c6e 100755 +--- a/usrsctplib/netinet/sctp_timer.c ++++ b/usrsctplib/netinet/sctp_timer.c +@@ -51,11 +51,7 @@ + #include + #include + #include +-#if defined(INET) || defined(INET6) +-#if !(defined(_WIN32) && defined(__Userspace__)) +-#include +-#endif +-#endif ++#include + + void + sctp_audit_retranmission_queue(struct sctp_association *asoc) +@@ -1542,7 +1538,7 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp, + #endif + #if defined(INET) || defined(INET6) + if (net->port) { +- mtu -= sizeof(struct udphdr); ++ mtu -= sizeof(STRUCT_UDP_HDR); + } + #endif + if (mtu > next_mtu) { +diff --git a/usrsctplib/netinet/sctp_udp_port.h b/usrsctplib/netinet/sctp_udp_port.h +new file mode 100644 +index 0000000..4f51a80 +--- /dev/null ++++ b/usrsctplib/netinet/sctp_udp_port.h +@@ -0,0 +1,74 @@ ++/*- ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. ++ * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. ++ * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * a) Redistributions of source code must retain the above copyright notice, ++ * this list of conditions and the following disclaimer. ++ * ++ * b) Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the distribution. ++ * ++ * c) Neither the name of Cisco Systems, Inc. nor the names of its ++ * contributors may be used to endorse or promote products derived ++ * from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#if defined(__FreeBSD__) && !defined(__Userspace__) ++#include ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 359195 2020-03-21 16:12:19Z tuexen $"); ++#endif ++ ++#ifndef _NETINET_SCTP_UDP_PORT_H_ ++#define _NETINET_SCTP_UDP_PORT_H_ ++ ++#if !defined(_WIN32) ++#if defined(INET) || defined(INET6) ++#if !defined(SCTP_USE_LWIP) ++#include ++ ++#define STRUCT_UDP_HDR struct udphdr ++#define GET_UDP_SRC(udp) ((struct udphdr*)udp)->source ++#define GET_UDP_DEST(udp) ((struct udphdr*)udp)->dest ++#define GET_UDP_LEN(udp) ((struct udphdr*)udp)->len ++#define GET_UDP_CHKSUM(udp) ((struct udphdr*)udp)->check ++ ++#else ++#include "lwip/udp.h" ++#define STRUCT_UDP_HDR struct udp_hdr ++#define GET_UDP_SRC(udp) ((struct udp_hdr*)udp)->src ++#define GET_UDP_DEST(udp) ((struct udp_hdr*)udp)->dest ++#define GET_UDP_LEN(udp) ((struct udp_hdr*)udp)->len ++#define GET_UDP_CHKSUM(udp) ((struct udp_hdr*)udp)->chksum ++ ++// #TBD ++#define UIO_MAXIOV 1024 ++#define ERESTART 85 /* Interrupted system call should be restarted */ ++ ++#endif ++#endif ++#include ++#else ++#include ++#endif ++ ++#endif//!< _NETINET_SCTP_UDP_PORT_H_ +diff --git a/usrsctplib/netinet/sctp_userspace.c b/usrsctplib/netinet/sctp_userspace.c +index 7188890..5a77f6d 100755 +--- a/usrsctplib/netinet/sctp_userspace.c ++++ b/usrsctplib/netinet/sctp_userspace.c +@@ -98,6 +98,13 @@ sctp_userspace_set_threadname(const char *name) + int + sctp_userspace_get_mtu_from_ifn(uint32_t if_index) + { ++#if defined(SCTP_USE_LWIP) ++ struct netif* net_if = netif_get_by_index(if_index); ++ if(net_if != NULL){ ++ return net_if->mtu; ++ } ++ return 0; ++#else + #if defined(INET) || defined(INET6) + struct ifreq ifr; + int fd; +@@ -126,6 +133,7 @@ sctp_userspace_get_mtu_from_ifn(uint32_t if_index) + #endif + } + return (mtu); ++#endif + } + #endif + +diff --git a/usrsctplib/netinet/sctp_usrreq.c b/usrsctplib/netinet/sctp_usrreq.c +index 53aeaa1..a07b7e8 100755 +--- a/usrsctplib/netinet/sctp_usrreq.c ++++ b/usrsctplib/netinet/sctp_usrreq.c +@@ -54,7 +54,7 @@ + #if defined(__Userspace__) + #include + #else +-#include ++#include + #endif + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include +@@ -356,13 +356,13 @@ sctp_notify(struct sctp_inpcb *inp, + } + /* Update the path MTU. */ + if (net->port) { +- next_mtu -= sizeof(struct udphdr); ++ next_mtu -= sizeof(STRUCT_UDP_HDR); + } + if (net->mtu > next_mtu) { + net->mtu = next_mtu; + #if defined(__FreeBSD__) && !defined(__Userspace__) + if (net->port) { +- sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr)); ++ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(STRUCT_UDP_HDR)); + } else { + sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu); + } +@@ -387,7 +387,7 @@ sctp_notify(struct sctp_inpcb *inp, + #if defined(__FreeBSD__) + void sctp_ctlinput(struct icmp *icmp) + { +- struct ip *inner_ip, *outer_ip; ++ STRUCT_IP_HDR *inner_ip, *outer_ip; + struct sctphdr *sh; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; +@@ -398,19 +398,19 @@ void sctp_ctlinput(struct icmp *icmp) + if (icmp_errmap(icmp) == 0) + return; + +- outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); ++ outer_ip = (STRUCT_IP_HDR *)((caddr_t)icmp - sizeof(STRUCT_IP_HDR)); + inner_ip = &icmp->icmp_ip; +- sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); ++ sh = (struct sctphdr *)((caddr_t)inner_ip + (GET_IP_HDR_LEN_VAL(inner_ip) << 2)); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + src.sin_port = sh->src_port; +- src.sin_addr = inner_ip->ip_src; ++ src.sin_addr = GET_IP_SRC(inner_ip); + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + dst.sin_port = sh->dest_port; +- dst.sin_addr = inner_ip->ip_dst; ++ dst.sin_addr.s_addr = GET_IP_DEST(inner_ip); + /* + * 'dst' holds the dest of the packet that failed to be sent. + * 'src' holds our local endpoint address. Thus we reverse +@@ -437,9 +437,9 @@ void sctp_ctlinput(struct icmp *icmp) + return; + } + } else { +- if (ntohs(outer_ip->ip_len) >= +- sizeof(struct ip) + +- 8 + (inner_ip->ip_hl << 2) + 20) { ++ if (ntohs(GET_IP_LEN(outer_ip)) >= ++ sizeof(STRUCT_IP_HDR) + ++ 8 + (GET_IP_HDR_LEN_VAL(inner_ip) << 2) + 20) { + /* + * In this case we can check if we + * got an INIT chunk and if the +@@ -459,7 +459,7 @@ void sctp_ctlinput(struct icmp *icmp) + sctp_notify(inp, stcb, net, + icmp->icmp_type, + icmp->icmp_code, +- ntohs(inner_ip->ip_len), ++ ntohs(GET_IP_LEN(inner_ip)), + (uint32_t)ntohs(icmp->icmp_nextmtu)); + } else { + if ((stcb == NULL) && (inp != NULL)) { +@@ -481,7 +481,7 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip, struct ifnet *ifp SCTP_UN + sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) + #endif + { +- struct ip *inner_ip; ++ STRUCT_IP_HDR *inner_ip; + struct sctphdr *sh; + struct icmp *icmp; + struct sctp_inpcb *inp; +@@ -501,24 +501,24 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) + return; + } + if (vip != NULL) { +- inner_ip = (struct ip *)vip; ++ inner_ip = (STRUCT_IP_HDR *)vip; + icmp = (struct icmp *)((caddr_t)inner_ip - +- (sizeof(struct icmp) - sizeof(struct ip))); +- sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); ++ (sizeof(struct icmp) - sizeof(STRUCT_IP_HDR))); ++ sh = (struct sctphdr *)((caddr_t)inner_ip + (GET_IP_HDR_LEN_VAL(inner_ip) << 2)); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + src.sin_len = sizeof(struct sockaddr_in); + #endif + src.sin_port = sh->src_port; +- src.sin_addr = inner_ip->ip_src; ++ src.sin_addr = GET_IP_SRC(inner_ip); + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); + #endif + dst.sin_port = sh->dest_port; +- dst.sin_addr = inner_ip->ip_dst; ++ dst.sin_addr.s_addr = GET_IP_DEST(inner_ip); + /* + * 'dst' holds the dest of the packet that failed to be sent. + * 'src' holds our local endpoint address. Thus we reverse +@@ -551,7 +551,7 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) + sctp_notify(inp, stcb, net, + icmp->icmp_type, + icmp->icmp_code, +- inner_ip->ip_len, ++ GET_IP_LEN(inner_ip), + (uint32_t)ntohs(icmp->icmp_nextmtu)); + #if defined(__Userspace__) + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && +diff --git a/usrsctplib/netinet/sctputil.c b/usrsctplib/netinet/sctputil.c +index bd41414..62e3cf6 100755 +--- a/usrsctplib/netinet/sctputil.c ++++ b/usrsctplib/netinet/sctputil.c +@@ -58,7 +58,7 @@ + #if defined(INET6) || defined(INET) + #include + #endif +-#include ++#include + #include + #include + #ifdef INET6 +@@ -8102,12 +8102,12 @@ static bool + sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, + const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) + { +- struct ip *iph; ++ STRUCT_IP_HDR *iph; + #ifdef INET6 + struct ip6_hdr *ip6; + #endif + struct mbuf *sp, *last; +- struct udphdr *uhdr; ++ STRUCT_UDP_HDR *uhdr; + uint16_t port; + + if ((m->m_flags & M_PKTHDR) == 0) { +@@ -8115,9 +8115,9 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, + goto out; + } + /* Pull the src port */ +- iph = mtod(m, struct ip *); +- uhdr = (struct udphdr *)((caddr_t)iph + off); +- port = uhdr->uh_sport; ++ iph = mtod(m, STRUCT_IP_HDR *); ++ uhdr = (STRUCT_UDP_HDR *)((caddr_t)iph + off); ++ port = GET_UDP_SRC(uhdr); + /* Split out the mbuf chain. Leave the + * IP header in m, place the + * rest in the sp. +@@ -8127,19 +8127,19 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, + /* Gak, drop packet, we can't do a split */ + goto out; + } +- if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { ++ if (sp->m_pkthdr.len < sizeof(STRUCT_UDP_HDR) + sizeof(struct sctphdr)) { + /* Gak, packet can't have an SCTP header in it - too small */ + m_freem(sp); + goto out; + } + /* Now pull up the UDP header and SCTP header together */ +- sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); ++ sp = m_pullup(sp, sizeof(STRUCT_UDP_HDR) + sizeof(struct sctphdr)); + if (sp == NULL) { + /* Gak pullup failed */ + goto out; + } + /* Trim out the UDP header */ +- m_adj(sp, sizeof(struct udphdr)); ++ m_adj(sp, sizeof(STRUCT_UDP_HDR)); + + /* Now reconstruct the mbuf chain */ + for (last = m; last->m_next; last = last->m_next); +@@ -8157,18 +8157,18 @@ sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, + if_name(m->m_pkthdr.rcvif), + (int)m->m_pkthdr.csum_flags, CSUM_BITS); + m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID; +- iph = mtod(m, struct ip *); +- switch (iph->ip_v) { ++ iph = mtod(m, STRUCT_IP_HDR *); ++ switch (GET_IP_VERSION_VAL(iph)) { + #ifdef INET + case IPVERSION: +- iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); ++ GET_IP_LEN(iph) = htons(ntohs(GET_IP_LEN(iph)) - sizeof(STRUCT_UDP_HDR)); + sctp_input_with_port(m, off, port); + break; + #endif + #ifdef INET6 + case IPV6_VERSION >> 4: + ip6 = mtod(m, struct ip6_hdr *); +- ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); ++ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(STRUCT_UDP_HDR)); + sctp6_input_with_port(&m, &off, port); + break; + #endif +@@ -8188,9 +8188,9 @@ static void + sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + { + struct icmp *icmp = param.icmp; +- struct ip *outer_ip, *inner_ip; ++ STRUCT_IP_HDR *outer_ip, *inner_ip; + struct sctphdr *sh; +- struct udphdr *udp; ++ STRUCT_UDP_HDR *udp; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; +@@ -8199,12 +8199,12 @@ sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + uint8_t type, code; + + inner_ip = &icmp->icmp_ip; +- outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); +- if (ntohs(outer_ip->ip_len) < +- sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { ++ outer_ip = (STRUCT_IP_HDR *)((caddr_t)icmp - sizeof(STRUCT_IP_HDR)); ++ if (ntohs(GET_UDP_LEN(outer_ip)) < ++ sizeof(STRUCT_IP_HDR) + 8 + (GET_IP_HDR_LEN_VAL(inner_ip) << 2) + sizeof(STRUCT_UDP_HDR) + 8) { + return; + } +- udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); ++ udp = (STRUCT_UDP_HDR *)((caddr_t)inner_ip + (GET_IP_HDR_LEN_VAL(inner_ip) << 2)); + sh = (struct sctphdr *)(udp + 1); + memset(&src, 0, sizeof(struct sockaddr_in)); + src.sin_family = AF_INET; +@@ -8212,14 +8212,14 @@ sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + src.sin_len = sizeof(struct sockaddr_in); + #endif + src.sin_port = sh->src_port; +- src.sin_addr = inner_ip->ip_src; ++ src.sin_addr = GET_IP_SRC(inner_ip); + memset(&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); + #endif + dst.sin_port = sh->dest_port; +- dst.sin_addr = inner_ip->ip_dst; ++ dst.sin_addr.s_addr = GET_IP_DEST(inner_ip); + /* + * 'dst' holds the dest of the packet that failed to be sent. + * 'src' holds our local endpoint address. Thus we reverse +@@ -8235,8 +8235,8 @@ sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + (net != NULL) && + (inp != NULL)) { + /* Check the UDP port numbers */ +- if ((udp->uh_dport != net->port) || +- (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { ++ if ((GET_UDP_DEST(udp) != net->port) || ++ (GET_UDP_SRC(udp) != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { + SCTP_TCB_UNLOCK(stcb); + return; + } +@@ -8253,9 +8253,9 @@ sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + return; + } + } else { +- if (ntohs(outer_ip->ip_len) >= +- sizeof(struct ip) + +- 8 + (inner_ip->ip_hl << 2) + 8 + 20) { ++ if (ntohs(GET_UDP_LEN(outer_ip)) >= ++ sizeof(STRUCT_IP_HDR) + ++ 8 + (GET_IP_HDR_LEN_VAL(inner_ip) << 2) + 8 + 20) { + /* + * In this case we can check if we + * got an INIT chunk and if the +@@ -8279,7 +8279,7 @@ sctp_recv_icmp_tunneled_packet(udp_tun_icmp_param_t param) + code = ICMP_UNREACH_PROTOCOL; + } + sctp_notify(inp, stcb, net, type, code, +- ntohs(inner_ip->ip_len), ++ ntohs(GET_UDP_LEN(inner_ip)), + (uint32_t)ntohs(icmp->icmp_nextmtu)); + #if defined(__Userspace__) + if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && +@@ -8323,7 +8323,7 @@ sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctphdr sh; +- struct udphdr udp; ++ STRUCT_UDP_HDR udp; + struct sockaddr_in6 src, dst; + uint8_t type, code; + +@@ -8338,19 +8338,19 @@ sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) + * verification tag of the SCTP common header. + */ + if (ip6cp->ip6c_m->m_pkthdr.len < +- ip6cp->ip6c_off + sizeof(struct udphdr)+ offsetof(struct sctphdr, checksum)) { ++ ip6cp->ip6c_off + sizeof(STRUCT_UDP_HDR)+ offsetof(struct sctphdr, checksum)) { + return; + } + /* Copy out the UDP header. */ +- memset(&udp, 0, sizeof(struct udphdr)); ++ memset(&udp, 0, sizeof(STRUCT_UDP_HDR)); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off, +- sizeof(struct udphdr), ++ sizeof(STRUCT_UDP_HDR), + (caddr_t)&udp); + /* Copy out the port numbers and the verification tag. */ + memset(&sh, 0, sizeof(struct sctphdr)); + m_copydata(ip6cp->ip6c_m, +- ip6cp->ip6c_off + sizeof(struct udphdr), ++ ip6cp->ip6c_off + sizeof(STRUCT_UDP_HDR), + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), + (caddr_t)&sh); + memset(&src, 0, sizeof(struct sockaddr_in6)); +@@ -8386,8 +8386,8 @@ sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) + (net != NULL) && + (inp != NULL)) { + /* Check the UDP port numbers */ +- if ((udp.uh_dport != net->port) || +- (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { ++ if ((GET_UDP_DEST(udp) != net->port) || ++ (GET_UDP_SRC(udp) != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { + SCTP_TCB_UNLOCK(stcb); + return; + } +@@ -8405,7 +8405,7 @@ sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) + } else { + #if defined(__FreeBSD__) && !defined(__Userspace__) + if (ip6cp->ip6c_m->m_pkthdr.len >= +- ip6cp->ip6c_off + sizeof(struct udphdr) + ++ ip6cp->ip6c_off + sizeof(STRUCT_UDP_HDR) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr) + + offsetof(struct sctp_init, a_rwnd)) { +@@ -8419,13 +8419,13 @@ sctp_recv_icmp6_tunneled_packet(udp_tun_icmp_param_t param) + + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + +- sizeof(struct udphdr) + ++ sizeof(STRUCT_UDP_HDR) + + sizeof(struct sctphdr), + sizeof(uint8_t), + (caddr_t)&chunk_type); + m_copydata(ip6cp->ip6c_m, + ip6cp->ip6c_off + +- sizeof(struct udphdr) + ++ sizeof(STRUCT_UDP_HDR) + + sizeof(struct sctphdr) + + sizeof(struct sctp_chunkhdr), + sizeof(uint32_t), +diff --git a/usrsctplib/netinet6/sctp6_usrreq.c b/usrsctplib/netinet6/sctp6_usrreq.c +index 39fddb6..28ebc92 100644 +--- a/usrsctplib/netinet6/sctp6_usrreq.c ++++ b/usrsctplib/netinet6/sctp6_usrreq.c +@@ -55,7 +55,7 @@ + #include + #if !defined(_WIN32) + #include +-#include ++#include + #endif + #if defined(__Userspace__) + int ip6_v6only=0; +@@ -368,13 +368,13 @@ sctp6_notify(struct sctp_inpcb *inp, + } + /* Update the path MTU. */ + if (net->port) { +- next_mtu -= sizeof(struct udphdr); ++ next_mtu -= sizeof(STRUCT_UDP_HDR); + } + if (net->mtu > next_mtu) { + net->mtu = next_mtu; + #if defined(__FreeBSD__) + if (net->port) { +- sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr)); ++ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(STRUCT_UDP_HDR)); + } else { + sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu); + } +diff --git a/usrsctplib/user_environment.c b/usrsctplib/user_environment.c +index ea52f0a..8a049a0 100755 +--- a/usrsctplib/user_environment.c ++++ b/usrsctplib/user_environment.c +@@ -380,5 +380,42 @@ finish_random(void) + return; + } + #else +-#error "Unknown platform. Please provide platform specific RNG." ++void ++init_random(void) ++{ ++ struct timeval now; ++ unsigned int seed; ++ ++ (void)SCTP_GETTIME_TIMEVAL(&now); ++ seed = 0; ++ seed |= (unsigned int)now.tv_sec; ++ seed |= (unsigned int)now.tv_usec; ++#if !defined(_WIN32) && !defined(__native_client__) ++ seed |= getpid(); ++#endif ++ srandom(seed); ++ return; ++} ++ ++void ++read_random(void *buf, size_t count) ++{ ++ uint32_t randval; ++ int size, i; ++ ++ /* Fill buf[] with random(9) output */ ++ for (i = 0; i < count; i+= (int)sizeof(uint32_t)) { ++ randval = random(); ++ size = MIN(count - i, (int)sizeof(uint32_t)); ++ memcpy(&((char *)buf)[i], &randval, (size_t)size); ++ } ++ ++ return; ++} ++ ++void ++finish_random(void) ++{ ++ return; ++} + #endif +diff --git a/usrsctplib/user_ip_icmp.h b/usrsctplib/user_ip_icmp.h +index a993411..dcfbdd6 100755 +--- a/usrsctplib/user_ip_icmp.h ++++ b/usrsctplib/user_ip_icmp.h +@@ -31,6 +31,8 @@ + #ifndef _USER_IP_ICMP_H_ + #define _USER_IP_ICMP_H_ + ++#include "netinet/sctp_ip_port.h" ++ + /* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. +@@ -122,7 +124,8 @@ struct icmp { + uint32_t its_ttime; /* Transmit */ + } id_ts; + struct id_ip { +- struct ip idi_ip; ++ // struct ip idi_ip; ++ STRUCT_IP_HDR idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; +diff --git a/usrsctplib/user_recv_thread.c b/usrsctplib/user_recv_thread.c +index 75c9076..d954422 100755 +--- a/usrsctplib/user_recv_thread.c ++++ b/usrsctplib/user_recv_thread.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #if 0 + #if defined(__linux__) + #include +@@ -271,7 +272,7 @@ static void * + recv_function_raw(void *arg) + { + struct mbuf **recvmbuf; +- struct ip *iphdr; ++ STRUCT_IP_HDR *iphdr; + struct sctphdr *sh; + uint16_t port; + int offset, ecn = 0; +@@ -379,34 +380,34 @@ recv_function_raw(void *arg) + } while (ncounter > 0); + } + +- offset = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); ++ offset = sizeof(STRUCT_IP_HDR) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + if (SCTP_BUF_LEN(recvmbuf[0]) < offset) { + if ((recvmbuf[0] = m_pullup(recvmbuf[0], offset)) == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + continue; + } + } +- iphdr = mtod(recvmbuf[0], struct ip *); +- sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(struct ip)); ++ iphdr = mtod(recvmbuf[0], STRUCT_IP_HDR *); ++ sh = (struct sctphdr *)((caddr_t)iphdr + sizeof(STRUCT_IP_HDR)); + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); + offset -= sizeof(struct sctp_chunkhdr); + +- if (iphdr->ip_tos != 0) { +- ecn = iphdr->ip_tos & 0x03; ++ if (GET_IP_TOS(iphdr) != 0) { ++ ecn = GET_IP_TOS(iphdr) & 0x03; + } + + dst.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); + #endif +- dst.sin_addr = iphdr->ip_dst; ++ dst.sin_addr.s_addr = GET_IP_DEST_ADDR(iphdr); + dst.sin_port = sh->dest_port; + + src.sin_family = AF_INET; + #ifdef HAVE_SIN_LEN + src.sin_len = sizeof(struct sockaddr_in); + #endif +- src.sin_addr = iphdr->ip_src; ++ src.sin_addr.s_addr = GET_IP_SRC_ADDR(iphdr); + src.sin_port = sh->src_port; + + /* SCTP does not allow broadcasts or multicasts */ +@@ -414,7 +415,7 @@ recv_function_raw(void *arg) + m_freem(recvmbuf[0]); + continue; + } +- if (SCTP_IS_IT_BROADCAST(dst.sin_addr, recvmbuf[0])) { ++ if (SCTP_IS_IT_BROADCAST(dst.sin_addr.s_addr, recvmbuf[0])) { + m_freem(recvmbuf[0]); + continue; + } +@@ -432,7 +433,7 @@ recv_function_raw(void *arg) + } + SCTPDBG(SCTP_DEBUG_USR, "%s: Received %d bytes.", __func__, n); + SCTPDBG(SCTP_DEBUG_USR, " - calling sctp_common_input_processing with off=%d\n", offset); +- sctp_common_input_processing(&recvmbuf[0], sizeof(struct ip), offset, n, ++ sctp_common_input_processing(&recvmbuf[0], sizeof(STRUCT_IP_HDR), offset, n, + (struct sockaddr *)&src, + (struct sockaddr *)&dst, + sh, ch, +@@ -792,7 +793,7 @@ recv_function_udp(void *arg) + dst.sin_len = sizeof(struct sockaddr_in); + #endif + info = (struct in_pktinfo *)CMSG_DATA(cmsgptr); +- memcpy((void *)&dst.sin_addr, (const void *)&(info->ipi_addr), sizeof(struct in_addr)); ++ memcpy((void *)&dst.sin_addr.s_addr, (const void *)&(info->ipi_addr), sizeof(struct in_addr)); + break; + } + #else +@@ -804,7 +805,7 @@ recv_function_udp(void *arg) + dst.sin_len = sizeof(struct sockaddr_in); + #endif + addr = (struct in_addr *)CMSG_DATA(cmsgptr); +- memcpy((void *)&dst.sin_addr, (const void *)addr, sizeof(struct in_addr)); ++ memcpy((void *)&dst.sin_addr.s_addr, (const void *)addr, sizeof(struct in_addr)); + break; + } + #endif +@@ -815,7 +816,7 @@ recv_function_udp(void *arg) + m_freem(udprecvmbuf[0]); + continue; + } +- if (SCTP_IS_IT_BROADCAST(dst.sin_addr, udprecvmbuf[0])) { ++ if (SCTP_IS_IT_BROADCAST(dst.sin_addr.s_addr, udprecvmbuf[0])) { + m_freem(udprecvmbuf[0]); + continue; + } +@@ -1077,6 +1078,9 @@ setReceiveBufferSize(int sfd, int new_size) + SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", WSAGetLastError()); + #else + SCTPDBG(SCTP_DEBUG_USR, "Can't set recv-buffers size (errno = %d).\n", errno); ++#endif ++#if defined(SCTP_USE_LWIP) ++ SCTP_PRINTF("lwIP does not support this socket option(SO_SNDBUF:%d), so you need to control this by yourself.", new_size); + #endif + } + return; +diff --git a/usrsctplib/user_socket.c b/usrsctplib/user_socket.c +index d1e091a..0471330 100755 +--- a/usrsctplib/user_socket.c ++++ b/usrsctplib/user_socket.c +@@ -50,14 +50,7 @@ + #if defined(__linux__) + #define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */ + #endif +-#if !defined(_WIN32) +-#if defined INET || defined INET6 +-#include +-#endif +-#include +-#else +-#include +-#endif ++#include + userland_mutex_t accept_mtx; + userland_cond_t accept_cond; + #ifdef _WIN32 +@@ -2844,8 +2837,8 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, + struct mbuf *m_orig; + int iovcnt; + int len; +- struct ip *ip; +- struct udphdr *udp; ++ STRUCT_IP_HDR *ip; ++ STRUCT_UDP_HDR *udp; + struct sockaddr_in dst; + #if defined(_WIN32) + WSAMSG win_msg_hdr; +@@ -2863,32 +2856,32 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, + m = SCTP_HEADER_TO_CHAIN(o_pak); + m_orig = m; + +- len = sizeof(struct ip); ++ len = sizeof(STRUCT_IP_HDR); + if (SCTP_BUF_LEN(m) < len) { + if ((m = m_pullup(m, len)) == 0) { + SCTP_PRINTF("Can not get the IP header in the first mbuf.\n"); + return; + } + } +- ip = mtod(m, struct ip *); +- use_udp_tunneling = (ip->ip_p == IPPROTO_UDP); ++ ip = mtod(m, STRUCT_IP_HDR *); ++ use_udp_tunneling = (GET_IP_PROTO(ip) == IPPROTO_UDP); + + if (use_udp_tunneling) { +- len = sizeof(struct ip) + sizeof(struct udphdr); ++ len = sizeof(STRUCT_IP_HDR) + sizeof(STRUCT_UDP_HDR); + if (SCTP_BUF_LEN(m) < len) { + if ((m = m_pullup(m, len)) == 0) { + SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n"); + return; + } +- ip = mtod(m, struct ip *); ++ ip = mtod(m, STRUCT_IP_HDR *); + } +- udp = (struct udphdr *)(ip + 1); ++ udp = (STRUCT_UDP_HDR *)(ip + 1); + } else { + udp = NULL; + } + + if (!use_udp_tunneling) { +- if (ip->ip_src.s_addr == INADDR_ANY) { ++ if (GET_IP_SRC_ADDR(ip) == INADDR_ANY) { + /* TODO get addr of outgoing interface */ + SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n"); + } +@@ -2901,19 +2894,19 @@ sctp_userspace_ip_output(int *result, struct mbuf *o_pak, + + memset((void *)&dst, 0, sizeof(struct sockaddr_in)); + dst.sin_family = AF_INET; +- dst.sin_addr.s_addr = ip->ip_dst.s_addr; ++ dst.sin_addr.s_addr = GET_IP_DEST_ADDR(ip); + #ifdef HAVE_SIN_LEN + dst.sin_len = sizeof(struct sockaddr_in); + #endif + if (use_udp_tunneling) { +- dst.sin_port = udp->uh_dport; ++ dst.sin_port = GET_UDP_DEST(udp); + } else { + dst.sin_port = 0; + } + + /* tweak the mbuf chain */ + if (use_udp_tunneling) { +- m_adj(m, sizeof(struct ip) + sizeof(struct udphdr)); ++ m_adj(m, sizeof(STRUCT_IP_HDR) + sizeof(STRUCT_UDP_HDR)); + } + + for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) { +@@ -2986,7 +2979,7 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, + int iovcnt; + int len; + struct ip6_hdr *ip6; +- struct udphdr *udp; ++ STRUCT_UDP_HDR *udp; + struct sockaddr_in6 dst; + #if defined(_WIN32) + WSAMSG win_msg_hdr; +@@ -3017,7 +3010,7 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, + use_udp_tunneling = (ip6->ip6_nxt == IPPROTO_UDP); + + if (use_udp_tunneling) { +- len = sizeof(struct ip6_hdr) + sizeof(struct udphdr); ++ len = sizeof(struct ip6_hdr) + sizeof(STRUCT_UDP_HDR); + if (SCTP_BUF_LEN(m) < len) { + if ((m = m_pullup(m, len)) == 0) { + SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n"); +@@ -3025,7 +3018,7 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, + } + ip6 = mtod(m, struct ip6_hdr *); + } +- udp = (struct udphdr *)(ip6 + 1); ++ udp = (STRUCT_UDP_HDR *)(ip6 + 1); + } else { + udp = NULL; + } +@@ -3046,14 +3039,14 @@ void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak, + #endif + + if (use_udp_tunneling) { +- dst.sin6_port = udp->uh_dport; ++ dst.sin6_port = GET_UDP_DEST(udp); + } else { + dst.sin6_port = 0; + } + + /* tweak the mbuf chain */ + if (use_udp_tunneling) { +- m_adj(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); ++ m_adj(m, sizeof(struct ip6_hdr) + sizeof(STRUCT_UDP_HDR)); + } else { + m_adj(m, sizeof(struct ip6_hdr)); + } +diff --git a/usrsctplib/usrsctp.h b/usrsctplib/usrsctp.h +index 93e89b3..940931c 100644 +--- a/usrsctplib/usrsctp.h ++++ b/usrsctplib/usrsctp.h +@@ -35,7 +35,11 @@ + extern "C" { + #endif + ++#if defined(SCTP_USE_LWIP) ++#include "lwip/errno.h" ++#else + #include ++#endif + #include + #ifdef _WIN32 + #ifdef _MSC_VER +@@ -120,7 +124,7 @@ struct sctp_common_header { + * tune with other sockaddr_* structures. + */ + #if defined(__APPLE__) || defined(__Bitrig__) || defined(__DragonFly__) || \ +- defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) ++ defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(SCTP_USE_LWIP) + struct sockaddr_conn { + uint8_t sconn_len; + uint8_t sconn_family; +-- +2.39.5 (Apple Git-154) + diff --git a/usrsctp/patches/0002-Fix-overflow-error-Allocate-for-larger-sin6-structur.patch b/usrsctp/patches/0002-Fix-overflow-error-Allocate-for-larger-sin6-structur.patch new file mode 100644 index 0000000000..1a3f006349 --- /dev/null +++ b/usrsctp/patches/0002-Fix-overflow-error-Allocate-for-larger-sin6-structur.patch @@ -0,0 +1,33 @@ +From 7233b98785769b8eeb9d15f39b0a9e888503bf6b Mon Sep 17 00:00:00 2001 +From: Vikram Dattu +Date: Tue, 3 Jun 2025 18:16:36 +0530 +Subject: [PATCH 2/5] Fix overflow error: Allocate for larger sin6 structure + +--- + usrsctplib/netinet/sctp_bsd_addr.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/usrsctplib/netinet/sctp_bsd_addr.c b/usrsctplib/netinet/sctp_bsd_addr.c +index 9197dfd..1d5277e 100755 +--- a/usrsctplib/netinet/sctp_bsd_addr.c ++++ b/usrsctplib/netinet/sctp_bsd_addr.c +@@ -421,12 +421,14 @@ sctp_init_ifns_for_vrf(int vrfid) + uint32_t ifa_flags; + uint32_t if_num; + char if_name[NETIF_NAMESIZE]; +- struct sockaddr* in_addr = malloc(sizeof(struct sockaddr)); ++ /* Allocate for sockaddr_in6 which is larger than sockaddr_in */ ++ struct sockaddr* in_addr = malloc(sizeof(struct sockaddr_in6)); + + for(if_num=1;if_numip_addr)){ +-- +2.39.5 (Apple Git-154) + diff --git a/usrsctp/patches/0003-ESP_PLATFORM-Added-support-for-thread_safe-netif-API.patch b/usrsctp/patches/0003-ESP_PLATFORM-Added-support-for-thread_safe-netif-API.patch new file mode 100644 index 0000000000..be9e656451 --- /dev/null +++ b/usrsctp/patches/0003-ESP_PLATFORM-Added-support-for-thread_safe-netif-API.patch @@ -0,0 +1,574 @@ +From 7f7dceb536dc74ed13033025786cd62681821005 Mon Sep 17 00:00:00 2001 +From: Vikram Dattu +Date: Thu, 10 Jul 2025 15:41:06 +0530 +Subject: [PATCH 3/5] ESP_PLATFORM: Added support for thread_safe netif API + implementations + + - The alternative path compiles only when ESP_PLATFORM and SCTP_USE_LWIP macros are set +--- + usrsctp.pc.in | 2 +- + usrsctplib/CMakeLists.txt | 1 + + usrsctplib/netinet/sctp_bsd_addr.c | 8 + + usrsctplib/netinet/sctp_lwip_thread_safe.c | 149 ++++++++++++++++++ + usrsctplib/netinet/sctp_lwip_thread_safe.h | 24 +++ + usrsctplib/netinet/sctp_userspace.c | 82 ++++++++++ + usrsctplib/user_socket.c | 174 +++++++++++++++++++++ + 7 files changed, 439 insertions(+), 1 deletion(-) + create mode 100644 usrsctplib/netinet/sctp_lwip_thread_safe.c + create mode 100644 usrsctplib/netinet/sctp_lwip_thread_safe.h + +diff --git a/usrsctp.pc.in b/usrsctp.pc.in +index 20c4631..1b675b8 100644 +--- a/usrsctp.pc.in ++++ b/usrsctp.pc.in +@@ -7,7 +7,7 @@ Name: usrsctp + Description: SCTP implementation + URL: https://github.com/sctplab/usrsctp + Version: @VERSION@ +-Requires: ++Requires: + Libs: -L${libdir} -lusrsctp + Libs.private: -lpthread + Cflags: -I${includedir} @APPCFLAGS@ +diff --git a/usrsctplib/CMakeLists.txt b/usrsctplib/CMakeLists.txt +index 2b82f49..49bd266 100644 +--- a/usrsctplib/CMakeLists.txt ++++ b/usrsctplib/CMakeLists.txt +@@ -126,6 +126,7 @@ list(APPEND usrsctp_netinet_headers + netinet/sctp_asconf.h + netinet/sctp_auth.h + netinet/sctp_bsd_addr.h ++ netinet/sctp_lwip_thread_safe.c + netinet/sctp_callout.h + netinet/sctp_constants.h + netinet/sctp_crc32.h +diff --git a/usrsctplib/netinet/sctp_bsd_addr.c b/usrsctplib/netinet/sctp_bsd_addr.c +index 1d5277e..816cd92 100755 +--- a/usrsctplib/netinet/sctp_bsd_addr.c ++++ b/usrsctplib/netinet/sctp_bsd_addr.c +@@ -51,6 +51,9 @@ + + #if defined(SCTP_USE_LWIP) + #include ++#if defined(ESP_PLATFORM) ++#include "sctp_lwip_thread_safe.h" ++#endif + #endif + + /* Declare all of our malloc named types */ +@@ -415,6 +418,10 @@ static void + sctp_init_ifns_for_vrf(int vrfid) + { + #if defined(SCTP_USE_LWIP) ++#if defined(ESP_PLATFORM) ++ // Use thread-safe wrapper for ESP platform ++ sctp_lwip_init_ifns_for_vrf_safe((uint32_t)vrfid); ++#else + #define LWIP_IF_NUM_MAX 256 + + struct sctp_ifa *sctp_ifa; +@@ -489,6 +496,7 @@ sctp_init_ifns_for_vrf(int vrfid) + } + } + free(in_addr); ++#endif + #else + #if defined(INET) || defined(INET6) + int rc; +diff --git a/usrsctplib/netinet/sctp_lwip_thread_safe.c b/usrsctplib/netinet/sctp_lwip_thread_safe.c +new file mode 100644 +index 0000000..5dc4758 +--- /dev/null ++++ b/usrsctplib/netinet/sctp_lwip_thread_safe.c +@@ -0,0 +1,149 @@ ++#if defined(ESP_PLATFORM) && defined(SCTP_USE_LWIP) ++#include ++#include ++ ++#include "lwip/tcpip.h" ++#include "lwip/err.h" ++#include "lwip/netif.h" ++#include "freertos/FreeRTOS.h" ++#include "freertos/task.h" ++#include "freertos/semphr.h" ++ ++#include "sctp_os_userspace.h" ++#include "sctp_pcb.h" ++#include "sctp_var.h" ++#include "sctp_constants.h" ++ ++#define LWIP_IF_NUM_MAX 256 ++ ++// Structure to pass data between threads for init_ifns ++typedef struct { ++ uint32_t vrfid; ++ SemaphoreHandle_t semaphore; ++} init_ifns_thread_data_t; ++ ++// Function to run in TCPIP thread for init_ifns ++static void init_ifns_tcpip_thread(void *arg) ++{ ++ init_ifns_thread_data_t *thread_data = (init_ifns_thread_data_t *)arg; ++ struct sctp_ifa *sctp_ifa; ++ uint32_t ifa_flags; ++ uint32_t if_num; ++ char if_name[NETIF_NAMESIZE]; ++ ++ /* Allocate for sockaddr_in6 which is larger than sockaddr_in */ ++ struct sockaddr* in_addr = malloc(sizeof(struct sockaddr_in6)); ++ if (in_addr == NULL) { ++ xSemaphoreGive(thread_data->semaphore); ++ return; ++ } ++ ++ for(if_num = 1; if_num < LWIP_IF_NUM_MAX; if_num++) { ++ struct netif* tmp_if = netif_get_by_index(if_num); ++ char * tmp_name = netif_index_to_name(if_num, if_name); ++ ++ /* Zero out the larger sockaddr_in6 structure */ ++ memset(in_addr, 0, sizeof(struct sockaddr_in6)); ++ ++ if(tmp_if != NULL) { ++ if(ip_addr_isloopback(&tmp_if->ip_addr)) { ++ continue; ++ } ++ ++ if(tmp_if->ip_addr.type == IPADDR_TYPE_V4) { ++ in_addr->sa_family = AF_INET; ++ memcpy(&((struct sockaddr_in *)in_addr)->sin_addr, &tmp_if->ip_addr.u_addr, sizeof(uint32_t)); ++ } else { ++ in_addr->sa_family = AF_INET6; ++ memcpy(&((struct sockaddr_in6 *)in_addr)->sin6_addr, &tmp_if->ip_addr.u_addr, sizeof(uint32_t) * 4); ++ } ++ ++#if !defined(INET) ++ if (in_addr->sa_family != AF_INET6) { ++ /* non inet6 skip */ ++ continue; ++ } ++#elif !defined(INET6) ++ if (in_addr->sa_family != AF_INET) { ++ /* non inet skip */ ++ continue; ++ } ++#else ++ if ((in_addr->sa_family != AF_INET) && (in_addr->sa_family != AF_INET6)) { ++ /* non inet/inet6 skip */ ++ continue; ++ } ++#endif ++#if defined(INET6) ++ if ((in_addr->sa_family == AF_INET6) && ++ IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)in_addr)->sin6_addr)) { ++ /* skip unspecifed addresses */ ++ continue; ++ } ++#endif ++#if defined(INET) ++ if (in_addr->sa_family == AF_INET && ++ ((struct sockaddr_in *)in_addr)->sin_addr.s_addr == 0) { ++ continue; ++ } ++#endif ++ ifa_flags = 0; ++ sctp_ifa = sctp_add_addr_to_vrf(thread_data->vrfid, ++ NULL, ++ if_num, ++ 0, ++ tmp_name, ++ NULL, ++ (struct sockaddr*)in_addr, ++ ifa_flags, ++ 0); ++ if (sctp_ifa) { ++ sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; ++ } ++ } else { ++ break; ++ } ++ } ++ ++ free(in_addr); ++ xSemaphoreGive(thread_data->semaphore); ++} ++ ++// Thread-safe wrapper for sctp_init_ifns_for_vrf ++void sctp_lwip_init_ifns_for_vrf_safe(uint32_t vrfid) ++{ ++ // Allocate the thread data on the heap to ensure it remains valid ++ // when the TCPIP thread processes it ++ init_ifns_thread_data_t *thread_data = malloc(sizeof(init_ifns_thread_data_t)); ++ if (thread_data == NULL) { ++ return; ++ } ++ ++ thread_data->vrfid = vrfid; ++ ++ // Create semaphore ++ thread_data->semaphore = xSemaphoreCreateBinary(); ++ if (thread_data->semaphore == NULL) { ++ free(thread_data); ++ return; ++ } ++ ++ // Execute in TCPIP thread ++ err_t err = tcpip_callback(init_ifns_tcpip_thread, thread_data); ++ if (err != ERR_OK) { ++ vSemaphoreDelete(thread_data->semaphore); ++ free(thread_data); ++ return; ++ } ++ ++ // Wait for completion (with timeout) ++ if (xSemaphoreTake(thread_data->semaphore, pdMS_TO_TICKS(5000)) != pdTRUE) { ++ // Even if timeout occurs, we can't free the data yet as the TCPIP thread might still be using it ++ // Just return and accept the memory leak in this rare timeout case ++ return; ++ } ++ ++ vSemaphoreDelete(thread_data->semaphore); ++ free(thread_data); ++} ++#endif +diff --git a/usrsctplib/netinet/sctp_lwip_thread_safe.h b/usrsctplib/netinet/sctp_lwip_thread_safe.h +new file mode 100644 +index 0000000..0777f6a +--- /dev/null ++++ b/usrsctplib/netinet/sctp_lwip_thread_safe.h +@@ -0,0 +1,24 @@ ++#ifndef SCTP_LWIP_THREAD_SAFE_H ++#define SCTP_LWIP_THREAD_SAFE_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * Thread-safe wrapper for sctp_init_ifns_for_vrf ++ * ++ * This function ensures that the network interface operations happen in the TCPIP thread ++ * to avoid thread safety issues with LWIP when CONFIG_LWIP_CHECK_THREAD_SAFETY is enabled. ++ * ++ * @param vrfid The VRF ID to initialize interfaces for ++ */ ++void sctp_lwip_init_ifns_for_vrf_safe(uint32_t vrfid); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* SCTP_LWIP_THREAD_SAFE_H */ +diff --git a/usrsctplib/netinet/sctp_userspace.c b/usrsctplib/netinet/sctp_userspace.c +index 5a77f6d..f0c9035 100755 +--- a/usrsctplib/netinet/sctp_userspace.c ++++ b/usrsctplib/netinet/sctp_userspace.c +@@ -95,15 +95,97 @@ sctp_userspace_set_threadname(const char *name) + } + + #if !defined(_WIN32) && !defined(__native_client__) ++#if defined(ESP_PLATFORM) && defined(SCTP_USE_LWIP) ++#include "lwip/tcpip.h" ++#include "lwip/err.h" ++#include "lwip/netif.h" ++#include "freertos/FreeRTOS.h" ++#include "freertos/task.h" ++#include "freertos/semphr.h" ++ ++// Structure to pass data between threads ++typedef struct { ++ uint32_t if_index; ++ SemaphoreHandle_t semaphore; ++ int mtu; ++} mtu_thread_data_t; ++ ++// Function to run in TCPIP thread ++void get_mtu_tcpip_thread(void *arg) ++{ ++ mtu_thread_data_t *thread_data = (mtu_thread_data_t *)arg; ++ struct netif* net_if = netif_get_by_index(thread_data->if_index); ++ ++ if(net_if != NULL) { ++ thread_data->mtu = net_if->mtu; ++ } else { ++ thread_data->mtu = 0; ++ } ++ ++ xSemaphoreGive(thread_data->semaphore); ++} ++ ++int sctp_userspace_get_mtu_from_ifn_safe(uint32_t if_index) ++{ ++ ++ // Special case for 0xffffffff (wildcard interface) ++ if (if_index == 0xffffffff) { ++ return 1280; ++ } ++ ++ // Allocate thread data on the heap to ensure it remains valid ++ mtu_thread_data_t *thread_data = malloc(sizeof(mtu_thread_data_t)); ++ if (thread_data == NULL) { ++ return 0; ++ } ++ ++ thread_data->if_index = if_index; ++ thread_data->mtu = 0; ++ ++ // Create semaphore ++ thread_data->semaphore = xSemaphoreCreateBinary(); ++ if (thread_data->semaphore == NULL) { ++ free(thread_data); ++ return 0; ++ } ++ ++ // Execute in TCPIP thread ++ err_t err = tcpip_callback(get_mtu_tcpip_thread, thread_data); ++ if (err != ERR_OK) { ++ vSemaphoreDelete(thread_data->semaphore); ++ free(thread_data); ++ return 0; ++ } ++ ++ // Wait for completion (with timeout) ++ if (xSemaphoreTake(thread_data->semaphore, pdMS_TO_TICKS(1000)) != pdTRUE) { ++ // Even if timeout occurs, we can't free the data yet as the TCPIP thread might still be using it ++ // Just return and accept the memory leak in this rare timeout case ++ return 0; ++ } ++ ++ int result = thread_data->mtu; ++ vSemaphoreDelete(thread_data->semaphore); ++ free(thread_data); ++ return result; ++} ++#endif ++ + int + sctp_userspace_get_mtu_from_ifn(uint32_t if_index) + { + #if defined(SCTP_USE_LWIP) ++#if defined(ESP_PLATFORM) ++ // When running on ESP platform, we need to ensure the network interface operations ++ // happen in the TCPIP thread to avoid thread safety issues with LWIP ++ return sctp_userspace_get_mtu_from_ifn_safe(if_index); ++#else + struct netif* net_if = netif_get_by_index(if_index); + if(net_if != NULL){ + return net_if->mtu; + } + return 0; ++#endif + #else + #if defined(INET) || defined(INET6) + struct ifreq ifr; +diff --git a/usrsctplib/user_socket.c b/usrsctplib/user_socket.c +index 0471330..95cb7b9 100755 +--- a/usrsctplib/user_socket.c ++++ b/usrsctplib/user_socket.c +@@ -3110,9 +3110,178 @@ free_mbuf: + } + #endif + ++#if defined(ESP_PLATFORM) && defined(SCTP_USE_LWIP) ++#include "lwip/tcpip.h" ++#include "lwip/err.h" ++#include "freertos/FreeRTOS.h" ++#include "freertos/task.h" ++#include "freertos/semphr.h" ++ ++// Structure to pass data between threads for register_address ++typedef struct { ++ struct sockaddr_conn *sconn; ++ SemaphoreHandle_t semaphore; ++} register_thread_data_t; ++ ++// Function to run in TCPIP thread for register_address ++void register_address_tcpip_thread(void *arg) ++{ ++ register_thread_data_t *thread_data = (register_thread_data_t *)arg; ++ ++ // This function is now running in the TCPIP thread context, so it's safe to call ++ sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, ++ NULL, ++ 0xffffffff, ++ 0, ++ "conn", ++ NULL, ++ (struct sockaddr *)thread_data->sconn, ++ 0, ++ 0); ++ ++ xSemaphoreGive(thread_data->semaphore); ++} ++ ++// Structure to pass data between threads for deregister_address ++typedef struct { ++ struct sockaddr_conn *sconn; ++ SemaphoreHandle_t semaphore; ++} deregister_thread_data_t; ++ ++// Function to run in TCPIP thread for deregister_address ++void deregister_address_tcpip_thread(void *arg) ++{ ++ deregister_thread_data_t *thread_data = (deregister_thread_data_t *)arg; ++ ++ // This function is now running in the TCPIP thread context, so it's safe to call ++ sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ++ (struct sockaddr *)thread_data->sconn, ++ NULL, 0xffffffff); ++ ++ xSemaphoreGive(thread_data->semaphore); ++} ++ ++static void usrsctp_deregister_address_safe(void *addr) ++{ ++ struct sockaddr_conn sconn; ++ ++ memset(&sconn, 0, sizeof(struct sockaddr_conn)); ++ sconn.sconn_family = AF_CONN; ++#ifdef HAVE_SCONN_LEN ++ sconn.sconn_len = sizeof(struct sockaddr_conn); ++#endif ++ sconn.sconn_port = 0; ++ sconn.sconn_addr = addr; ++ ++ // Allocate thread data on the heap to ensure it remains valid ++ deregister_thread_data_t *thread_data = malloc(sizeof(deregister_thread_data_t)); ++ if (thread_data == NULL) { ++ return; ++ } ++ ++ // Copy sockaddr to heap to ensure it remains valid ++ struct sockaddr_conn *heap_sconn = malloc(sizeof(struct sockaddr_conn)); ++ if (heap_sconn == NULL) { ++ free(thread_data); ++ return; ++ } ++ memcpy(heap_sconn, &sconn, sizeof(struct sockaddr_conn)); ++ ++ thread_data->sconn = heap_sconn; ++ ++ // Create semaphore ++ thread_data->semaphore = xSemaphoreCreateBinary(); ++ if (thread_data->semaphore == NULL) { ++ free(heap_sconn); ++ free(thread_data); ++ return; ++ } ++ ++ // Execute in TCPIP thread ++ err_t err = tcpip_callback(deregister_address_tcpip_thread, thread_data); ++ if (err != ERR_OK) { ++ vSemaphoreDelete(thread_data->semaphore); ++ free(heap_sconn); ++ free(thread_data); ++ return; ++ } ++ ++ // Wait for completion (with timeout) ++ if (xSemaphoreTake(thread_data->semaphore, pdMS_TO_TICKS(5000)) != pdTRUE) { ++ // Even if timeout occurs, we can't free the data yet as the TCPIP thread might still be using it ++ // Just return and accept the memory leak in this rare timeout case ++ return; ++ } ++ ++ vSemaphoreDelete(thread_data->semaphore); ++ free(heap_sconn); ++ free(thread_data); ++} ++ ++static void usrsctp_register_address_safe(void *addr) ++{ ++ struct sockaddr_conn sconn; ++ ++ memset(&sconn, 0, sizeof(struct sockaddr_conn)); ++ sconn.sconn_family = AF_CONN; ++#ifdef HAVE_SCONN_LEN ++ sconn.sconn_len = sizeof(struct sockaddr_conn); ++#endif ++ sconn.sconn_port = 0; ++ sconn.sconn_addr = addr; ++ ++ // Allocate thread data on the heap to ensure it remains valid ++ register_thread_data_t *thread_data = malloc(sizeof(register_thread_data_t)); ++ if (thread_data == NULL) { ++ return; ++ } ++ ++ // Copy sockaddr to heap to ensure it remains valid ++ struct sockaddr_conn *heap_sconn = malloc(sizeof(struct sockaddr_conn)); ++ if (heap_sconn == NULL) { ++ free(thread_data); ++ return; ++ } ++ memcpy(heap_sconn, &sconn, sizeof(struct sockaddr_conn)); ++ ++ thread_data->sconn = heap_sconn; ++ ++ // Create semaphore ++ thread_data->semaphore = xSemaphoreCreateBinary(); ++ if (thread_data->semaphore == NULL) { ++ free(heap_sconn); ++ free(thread_data); ++ return; ++ } ++ ++ // Execute in TCPIP thread ++ err_t err = tcpip_callback(register_address_tcpip_thread, thread_data); ++ if (err != ERR_OK) { ++ vSemaphoreDelete(thread_data->semaphore); ++ free(heap_sconn); ++ free(thread_data); ++ return; ++ } ++ ++ // Wait for completion (with timeout) ++ if (xSemaphoreTake(thread_data->semaphore, pdMS_TO_TICKS(5000)) != pdTRUE) { ++ // Even if timeout occurs, we can't free the data yet as the TCPIP thread might still be using it ++ // Just return and accept the memory leak in this rare timeout case ++ return; ++ } ++ ++ vSemaphoreDelete(thread_data->semaphore); ++ free(heap_sconn); ++ free(thread_data); ++} ++#endif ++ + void + usrsctp_register_address(void *addr) + { ++#if defined(ESP_PLATFORM) && defined(SCTP_USE_LWIP) ++ usrsctp_register_address_safe(addr); ++#else + struct sockaddr_conn sconn; + + memset(&sconn, 0, sizeof(struct sockaddr_conn)); +@@ -3131,11 +3300,15 @@ usrsctp_register_address(void *addr) + (struct sockaddr *)&sconn, + 0, + 0); ++#endif + } + + void + usrsctp_deregister_address(void *addr) + { ++#if defined(ESP_PLATFORM) && defined(SCTP_USE_LWIP) ++ usrsctp_deregister_address_safe(addr); ++#else + struct sockaddr_conn sconn; + + memset(&sconn, 0, sizeof(struct sockaddr_conn)); +@@ -3148,6 +3321,7 @@ usrsctp_deregister_address(void *addr) + sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, + (struct sockaddr *)&sconn, + NULL, 0xffffffff); ++#endif + } + + #define PREAMBLE_FORMAT "\n%c %02d:%02d:%02d.%06ld " +-- +2.39.5 (Apple Git-154) + diff --git a/usrsctp/patches/0004-feat-esp-allocate-usrsctp-thread-stacks-from-SPIRAM.patch b/usrsctp/patches/0004-feat-esp-allocate-usrsctp-thread-stacks-from-SPIRAM.patch new file mode 100644 index 0000000000..616b63bbfe --- /dev/null +++ b/usrsctp/patches/0004-feat-esp-allocate-usrsctp-thread-stacks-from-SPIRAM.patch @@ -0,0 +1,44 @@ +From 32bb935b2183a538287853b34cfd23994836acfe Mon Sep 17 00:00:00 2001 +From: Vikram Dattu +Date: Thu, 19 Feb 2026 19:29:58 +0530 +Subject: [PATCH 4/5] feat(esp): allocate usrsctp thread stacks from SPIRAM + +Use esp_pthread to configure SPIRAM allocation caps for threads +created by usrsctp on ESP32 platforms. This moves the thread stacks +out of internal SRAM, freeing it for DMA and other constrained uses. +--- + usrsctplib/netinet/sctp_userspace.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/usrsctplib/netinet/sctp_userspace.c b/usrsctplib/netinet/sctp_userspace.c +index f0c9035..0604365 100755 +--- a/usrsctplib/netinet/sctp_userspace.c ++++ b/usrsctplib/netinet/sctp_userspace.c +@@ -44,6 +44,11 @@ + #include + #endif + ++#if defined(ESP_PLATFORM) ++#include "esp_pthread.h" ++#include "esp_heap_caps.h" ++#endif ++ + #if defined(_WIN32) + /* Adapter to translate Unix thread start routines to Windows thread start + * routines. +@@ -76,6 +81,12 @@ sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_ro + int + sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine) + { ++#if defined(ESP_PLATFORM) ++ esp_pthread_cfg_t pthread_cfg = esp_pthread_get_default_config(); ++ pthread_cfg.stack_alloc_caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; ++ pthread_cfg.thread_name = "sctp_userspace"; ++ esp_pthread_set_cfg(&pthread_cfg); ++#endif + return pthread_create(thread, NULL, start_routine, NULL); + } + #endif +-- +2.39.5 (Apple Git-154) + diff --git a/usrsctp/patches/0005-Fix-non-LWIP-Linux-target-buildability-in-Added-LWIP.patch b/usrsctp/patches/0005-Fix-non-LWIP-Linux-target-buildability-in-Added-LWIP.patch new file mode 100644 index 0000000000..20018455cf --- /dev/null +++ b/usrsctp/patches/0005-Fix-non-LWIP-Linux-target-buildability-in-Added-LWIP.patch @@ -0,0 +1,164 @@ +From cfda51e0c654653ec9dee3487675c72d6422fa89 Mon Sep 17 00:00:00 2001 +From: Vikram Dattu +Date: Wed, 29 Apr 2026 16:27:08 +0530 +Subject: [PATCH 5/5] Fix non-LWIP / Linux-target buildability in 'Added LWIP + support' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Three regressions added by 435f8e8 ("Added LWIP support") that only +affected the SCTP_USE_LWIP=OFF path — and therefore went unnoticed +because every consumer of this fork had LWIP enabled until the +ESP-IDF Linux target tried it. + +1. usrsctplib/CMakeLists.txt: removed + `if(NOT sctp_use_lwip) add_definitions(-D__native_client__) endif()`. + __native_client__ is the Chrome Native Client toolchain marker; + defining it on a regular Linux/macOS host pushed sctp_os_userspace.h + into the Win32/NaCl block, which redefines `struct ip` / + `struct iovec` / `struct udphdr` and conflicts with system + / / . The right gate is + the existing `#if defined(SCTP_USE_LWIP)` blocks; no fake + `__native_client__` is needed. + +2. netinet/sctp_udp_port.h: GET_UDP_* macros were using glibc's + without-__FAVOR_BSD member names (`->source`/`->dest`/`->len`/ + `->check`). sctp_output.c defines __FAVOR_BSD on Linux, which + exposes the BSD-style `uh_*` names (and macOS only ever has the + `uh_*` form). Switched the macros to `uh_sport`/`uh_dport`/ + `uh_ulen`/`uh_sum` for portability across macOS, Linux+__FAVOR_BSD, + and BSD. + +3. netinet/sctp_ip_port.h + sctp_udp_port.h: macro-hygiene bug. Several + GET_IP_* and GET_UDP_* macros took a parameter named `ip` (or + `udp`) and the macro body contained the literal `struct ip` (or + `struct udphdr`). The C preprocessor doesn't know C syntax, so + when a caller passed a variable named `iphdr`, it rewrote + `struct ip` to `struct iphdr` — fabricating a non-existent type + and producing 'incomplete struct iphdr' errors. Renamed all such + parameters to `_h` so they don't collide with the type tokens. + +After these fixes the library compiles cleanly on the IDF Linux +target. The ESP target is unaffected — when SCTP_USE_LWIP is defined +(its default for real ESP builds), the `#else` branches with the +`struct ip_hdr` / `struct udp_hdr` LWIP types kick in unchanged. +--- + usrsctplib/CMakeLists.txt | 12 ++++++++--- + usrsctplib/netinet/sctp_ip_port.h | 34 +++++++++++++++++------------- + usrsctplib/netinet/sctp_udp_port.h | 25 +++++++++++++++------- + 3 files changed, 45 insertions(+), 26 deletions(-) + +diff --git a/usrsctplib/CMakeLists.txt b/usrsctplib/CMakeLists.txt +index 49bd266..7815911 100644 +--- a/usrsctplib/CMakeLists.txt ++++ b/usrsctplib/CMakeLists.txt +@@ -58,9 +58,15 @@ option(SCTP_USE_MBEDTLS_SHA1 "Build with mbedtls sha1 support." OFF) + add_definitions(-D__Userspace__) + add_definitions(-DSCTP_SIMPLE_ALLOCATOR) + add_definitions(-DSCTP_PROCESS_LEVEL_LOCKS) +-if(NOT sctp_use_lwip) +- add_definitions(-D__native_client__) +-endif() ++# NOTE: a previous "Added LWIP support" patch added an `add_definitions( ++# -D__native_client__)` here when SCTP_USE_LWIP was off. That was wrong ++# — `__native_client__` is the Chrome Native Client toolchain marker, ++# and defining it on a regular Linux/macOS host makes sctp_os_userspace.h ++# enter the Win32/NaCl block which defines its own `struct ip` / ++# `struct iovec` and conflicts with system / . ++# The fork only worked because every consumer set sctp_use_lwip=ON. ++# Removed so the upstream `__APPLE__` / `__linux__` paths can take ++# effect on real host builds; LWIP support stays opt-in via SCTP_USE_LWIP. + + if(SCTP_USE_MBEDTLS_SHA1) + add_definitions(-DSCTP_USE_MBEDTLS_SHA1) +diff --git a/usrsctplib/netinet/sctp_ip_port.h b/usrsctplib/netinet/sctp_ip_port.h +index 2e382eb..6bfcb8b 100644 +--- a/usrsctplib/netinet/sctp_ip_port.h ++++ b/usrsctplib/netinet/sctp_ip_port.h +@@ -43,22 +43,26 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 359195 2020-03-21 16:12:19Z tu + #if !defined(SCTP_USE_LWIP) + #include + #define STRUCT_IP_HDR struct ip +-//#define GET_IP_VERSION(ip) ((struct ip_hdr*)(ip))->ip_v +-//#define GET_IP_HDR_LEN(ip) ((struct ip_hdr*)(ip))->ip_hl +-#define GET_IP_TOS(ip) ((struct ip*)(ip))->ip_tos +-#define GET_IP_LEN(ip) ((struct ip*)ip)->ip_len +-#define GET_IP_ID(ip) ((struct ip*)ip)->ip_id +-#define GET_IP_OFFSET(ip) ((struct ip*)ip)->ip_off +-#define GET_IP_TTL(ip) ((struct ip*)ip)->ip_ttl +-#define GET_IP_PROTO(ip) ((struct ip*)ip)->ip_p +-#define GET_IP_CHKSUM(ip) ((struct ip*)ip)->ip_sum +-#define GET_IP_SRC(ip) ((struct ip*)ip)->ip_src +-#define GET_IP_DEST(ip) ((struct ip*)ip)->ip_dst +-#define GET_IP_SRC_ADDR(ip) ((struct ip*)ip)->ip_src.s_addr +-#define GET_IP_DEST_ADDR(ip) ((struct ip*)ip)->ip_dst.s_addr ++/* The parameter is named `_h` (not `ip`) on purpose: a parameter ++ * named `ip` would collide with the literal `ip` token inside ++ * `struct ip*`, and the preprocessor — which doesn't know C syntax — ++ * would substitute it, producing nonsense like `struct iphdr*` ++ * when the caller passes a variable named `iphdr`. That hygiene bug ++ * existed in the original "Added LWIP support" commit. */ ++#define GET_IP_TOS(_h) ((struct ip*)(_h))->ip_tos ++#define GET_IP_LEN(_h) ((struct ip*)(_h))->ip_len ++#define GET_IP_ID(_h) ((struct ip*)(_h))->ip_id ++#define GET_IP_OFFSET(_h) ((struct ip*)(_h))->ip_off ++#define GET_IP_TTL(_h) ((struct ip*)(_h))->ip_ttl ++#define GET_IP_PROTO(_h) ((struct ip*)(_h))->ip_p ++#define GET_IP_CHKSUM(_h) ((struct ip*)(_h))->ip_sum ++#define GET_IP_SRC(_h) ((struct ip*)(_h))->ip_src ++#define GET_IP_DEST(_h) ((struct ip*)(_h))->ip_dst ++#define GET_IP_SRC_ADDR(_h) ((struct ip*)(_h))->ip_src.s_addr ++#define GET_IP_DEST_ADDR(_h) ((struct ip*)(_h))->ip_dst.s_addr + +-#define GET_IP_VERSION_VAL(ip) ((struct ip_hdr*)(ip))->ip_v +-#define GET_IP_HDR_LEN_VAL(ip) ((struct ip_hdr*)(ip))->ip_hl ++#define GET_IP_VERSION_VAL(_h) ((struct ip*)(_h))->ip_v ++#define GET_IP_HDR_LEN_VAL(_h) ((struct ip*)(_h))->ip_hl + + #define SET_IP_VHL(hdr, v, hl) do{\ + (hdr)->ip_v = v;\ +diff --git a/usrsctplib/netinet/sctp_udp_port.h b/usrsctplib/netinet/sctp_udp_port.h +index 4f51a80..e96bf19 100644 +--- a/usrsctplib/netinet/sctp_udp_port.h ++++ b/usrsctplib/netinet/sctp_udp_port.h +@@ -46,19 +46,28 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.h 359195 2020-03-21 16:12:19Z tu + #if !defined(SCTP_USE_LWIP) + #include + ++/* Use BSD-style `uh_*` member names: present on macOS unconditionally, ++ * and present on Linux glibc when __FAVOR_BSD is defined (which ++ * sctp_output.c does, see its top of file). The previous form ++ * (`->source` / `->dest` / `->len` / `->check`) only worked on Linux ++ * glibc *without* __FAVOR_BSD — i.e. inconsistent with the rest of ++ * the file — and broke macOS host builds outright. */ ++/* Parameter name `_h` instead of `udp` — same preprocessor-hygiene ++ * concern as in sctp_ip_port.h: `udp` would collide with the ++ * `struct udphdr` token. */ + #define STRUCT_UDP_HDR struct udphdr +-#define GET_UDP_SRC(udp) ((struct udphdr*)udp)->source +-#define GET_UDP_DEST(udp) ((struct udphdr*)udp)->dest +-#define GET_UDP_LEN(udp) ((struct udphdr*)udp)->len +-#define GET_UDP_CHKSUM(udp) ((struct udphdr*)udp)->check ++#define GET_UDP_SRC(_h) ((struct udphdr*)(_h))->uh_sport ++#define GET_UDP_DEST(_h) ((struct udphdr*)(_h))->uh_dport ++#define GET_UDP_LEN(_h) ((struct udphdr*)(_h))->uh_ulen ++#define GET_UDP_CHKSUM(_h) ((struct udphdr*)(_h))->uh_sum + + #else + #include "lwip/udp.h" + #define STRUCT_UDP_HDR struct udp_hdr +-#define GET_UDP_SRC(udp) ((struct udp_hdr*)udp)->src +-#define GET_UDP_DEST(udp) ((struct udp_hdr*)udp)->dest +-#define GET_UDP_LEN(udp) ((struct udp_hdr*)udp)->len +-#define GET_UDP_CHKSUM(udp) ((struct udp_hdr*)udp)->chksum ++#define GET_UDP_SRC(_h) ((struct udp_hdr*)(_h))->src ++#define GET_UDP_DEST(_h) ((struct udp_hdr*)(_h))->dest ++#define GET_UDP_LEN(_h) ((struct udp_hdr*)(_h))->len ++#define GET_UDP_CHKSUM(_h) ((struct udp_hdr*)(_h))->chksum + + // #TBD + #define UIO_MAXIOV 1024 +-- +2.39.5 (Apple Git-154) + diff --git a/usrsctp/patches/README.md b/usrsctp/patches/README.md new file mode 100644 index 0000000000..025c40cbe9 --- /dev/null +++ b/usrsctp/patches/README.md @@ -0,0 +1,48 @@ +# Patches Applied to usrsctp + +Patches applied on top of the canonical +[sctplab/usrsctp](https://github.com/sctplab/usrsctp) submodule at build +configure time. The submodule pins commit `2e1ab10` (`Update cifuzz.yml`), +which is the immediate pre-patch base — patches apply cleanly without +adaptation. + +The component CMakeLists applies them automatically (idempotent: a +dry-run check skips already-applied patches). + +## Ledger + +| # | Patch | Category | Notes | +|---|-------|----------|-------| +| 0001 | Added LWIP support | aligned (candidate) | Routes usrsctp's userspace socket layer over lwIP instead of POSIX BSD sockets. Required for ESP-IDF / FreeRTOS targets. Upstream candidate: needs sctplab review. | +| 0002 | Fix overflow error: Allocate for larger sin6 structure | bug-fix | Stack-overflow guard around `sin6` allocations; small + safe; aligned-with-upstream. | +| 0003 | ESP_PLATFORM: Added support for thread_safe netif API implementations | ESP-IDF specific | Uses ESP-IDF's thread-safe lwIP netif APIs (`esp_netif_*` analogues) where canonical usrsctp would call `getifaddrs(3)`. Stays. | +| 0004 | feat(esp): allocate usrsctp thread stacks from SPIRAM | ESP-IDF specific | Targets memory-constrained chips (P4-EYE, C5/C6) by routing usrsctp's internal pthreads' stacks to SPIRAM. Stays. | +| 0005 | Fix non-LWIP / Linux-target buildability in 'Added LWIP support' | bug-fix | Compiles cleanly for IDF Linux target (CONFIG_IDF_TARGET_LINUX) where lwIP isn't pulled in. Should fold back into 0001 upstream. | + +## Future upstream sync + +The submodule pin (`2e1ab10`) is older than `sctplab/master`. To pull in +newer upstream fixes: + +1. `git fetch origin && git checkout origin/master` inside `usrsctp/`. +2. Try `git am --3way --keep-cr ../patches/*.patch` and resolve any + conflicts (most likely in 0001 since it touches a lot of files). +3. Re-generate patches via `git format-patch ..HEAD -o ../patches/`. +4. Bump the recorded submodule SHA in the parent and update this ledger. + +## Upstream submission plan + +- **LWIP support** (this directory's `0001` + `0005` squashed): + Will be submitted as a fresh PR on `sctplab/usrsctp`, superseding the + stale [#583](https://github.com/sctplab/usrsctp/pull/583) by + `@ycyang1229` (opened 2021-05-03, last activity from us in 2021). + Attribution: `Original-Author: ycyang1229` + `Co-authored-by: Vikram + Dattu `. The upstream version will be + strictly LWIP-only (no `ESP_PLATFORM` ifdef, no IDF-specific glue). +- **sin6 overflow fix** (this directory's `0002`): independent bug + fix, submit as a separate small PR on `sctplab/usrsctp`. +- **ESP-IDF-specific patches** (`0003` thread-safe netif, `0004` SPIRAM + stacks): stay downstream — not generic enough for upstream. + +When the upstream PRs land, drop the corresponding local patches and +bump the submodule SHA. diff --git a/usrsctp/sbom.yml b/usrsctp/sbom.yml new file mode 100644 index 0000000000..4c91e20720 --- /dev/null +++ b/usrsctp/sbom.yml @@ -0,0 +1,6 @@ +name: 'usrsctp' +supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' +originator: 'Organization: Espressif Systems (Shanghai) CO LTD' +description: ESP-IDF wrapper for userspace SCTP stack (usrsctp). Used for WebRTC data channels and other SCTP-based protocols on ESP32-series chips. +virtpackages: + - sbom_usrsctp.yml diff --git a/usrsctp/sbom_usrsctp.yml b/usrsctp/sbom_usrsctp.yml new file mode 100644 index 0000000000..3cb748a92e --- /dev/null +++ b/usrsctp/sbom_usrsctp.yml @@ -0,0 +1,11 @@ +name: usrsctp +version: 0.9.5 +cpe: cpe:2.3:a:sctplab:usrsctp:{}:*:*:*:*:*:*:* +supplier: 'Organization: sctplab ' +originator: 'Persons: Randall Stewart, Michael Tuexen' +description: A portable userland implementation of the SCTP protocol (RFC 4960). Submodule pinned at canonical sctplab/usrsctp commit 2e1ab10; ESP-IDF specific patches (LWIP integration, sin6 buffer overflow fix, thread-safe netif API, SPIRAM-backed worker-thread stacks, Linux-target buildability) live in the parent component's patches/ directory and are applied at configure time. +url: https://github.com/sctplab/usrsctp +hash: 2e1ab1050bbb6c710f6a475f1601acf1ae7ecb78 +cve-exclude-list: + - cve: CVE-2022-32230 + reason: Resolved in 0.9.5.0; current pin (2e1ab10) is post-0.9.5.0. diff --git a/usrsctp/test_apps/CMakeLists.txt b/usrsctp/test_apps/CMakeLists.txt new file mode 100644 index 0000000000..51450095a0 --- /dev/null +++ b/usrsctp/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS "..") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_app_usrsctp) diff --git a/usrsctp/test_apps/main/CMakeLists.txt b/usrsctp/test_apps/main/CMakeLists.txt new file mode 100644 index 0000000000..4f4707b75a --- /dev/null +++ b/usrsctp/test_apps/main/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 +idf_component_register( + SRCS "test_usrsctp_main.c" + INCLUDE_DIRS "." + REQUIRES unity usrsctp +) diff --git a/usrsctp/test_apps/main/idf_component.yml b/usrsctp/test_apps/main/idf_component.yml new file mode 100644 index 0000000000..e3d9f0b968 --- /dev/null +++ b/usrsctp/test_apps/main/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + usrsctp: + version: "*" + override_path: "../.." diff --git a/usrsctp/test_apps/main/test_usrsctp_main.c b/usrsctp/test_apps/main/test_usrsctp_main.c new file mode 100644 index 0000000000..28a010cfc4 --- /dev/null +++ b/usrsctp/test_apps/main/test_usrsctp_main.c @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + * + * Embedded smoke test for usrsctp. Validates that the component + * links cleanly on the chosen target and that usrsctp_init/finish work. + * + * Deeper coverage (real SCTP association over the userspace stack) + * lives in host_test/ under the IDF Linux target. + */ +#include +#include "unity.h" +#include "usrsctp.h" + +/* Empty stub used as the "outgoing packet" callback during the smoke + * init; we never actually send anything in this test. */ +static int dummy_conn_output(void *addr, void *buf, size_t length, + uint8_t tos, uint8_t set_df) +{ + (void)addr; (void)buf; (void)length; (void)tos; (void)set_df; + return 0; +} + +TEST_CASE("usrsctp_init then usrsctp_finish succeed", "[usrsctp]") +{ + usrsctp_init(0, dummy_conn_output, NULL); + /* usrsctp_finish() returns the number of remaining endpoints; 0 = clean. */ + TEST_ASSERT_EQUAL(0, usrsctp_finish()); +} + +void app_main(void) +{ + UNITY_BEGIN(); + unity_run_all_tests(); + UNITY_END(); +} diff --git a/usrsctp/test_apps/pytest_usrsctp.py b/usrsctp/test_apps/pytest_usrsctp.py new file mode 100644 index 0000000000..71086e05be --- /dev/null +++ b/usrsctp/test_apps/pytest_usrsctp.py @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import pytest + + +@pytest.mark.generic +@pytest.mark.parametrize("target", ["esp32", "esp32c3"], indirect=True) +def test_usrsctp_smoke(dut): + dut.expect_unity_test_output(timeout=30) diff --git a/usrsctp/test_apps/sdkconfig.defaults b/usrsctp/test_apps/sdkconfig.defaults new file mode 100644 index 0000000000..c3ec2cea7f --- /dev/null +++ b/usrsctp/test_apps/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_FREERTOS_UNICORE=y diff --git a/usrsctp/usrsctp b/usrsctp/usrsctp new file mode 160000 index 0000000000..2e1ab1050b --- /dev/null +++ b/usrsctp/usrsctp @@ -0,0 +1 @@ +Subproject commit 2e1ab1050bbb6c710f6a475f1601acf1ae7ecb78 diff --git a/usrsctp/usrsctp_register.c b/usrsctp/usrsctp_register.c new file mode 100644 index 0000000000..bbd7e43507 --- /dev/null +++ b/usrsctp/usrsctp_register.c @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Placeholder TU so idf_component_register has at least one source file. */