diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml deleted file mode 100644 index bd5513227..000000000 --- a/.github/workflows/cron.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Cron Deploy - -on: - schedule: -# ┌───────────── minute (0 - 59) -# │ ┌───────────── hour (0 - 23) -# │ │ ┌───────────── day of the month (1 - 31) -# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) -# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) -# │ │ │ │ │ -# │ │ │ │ │ -# │ │ │ │ │ -# * * * * * - - cron: '0 */6 * * *' - workflow_dispatch: # For testing - -defaults: - run: - shell: bash - -jobs: - build-libs: - name: Build with IDF ${{ matrix.idf_branch }} - uses: ./.github/workflows/cron_build.yml - with: - idf_branch: ${{ matrix.idf_branch }} - lib_builder_branch: ${{ matrix.lib_builder_branch }} - targets: ${{ matrix.targets }} - secrets: inherit - strategy: - fail-fast: false - matrix: - include: - - idf_branch: "release/v5.1" - lib_builder_branch: "release/v5.1" - targets: "esp32,esp32s2,esp32s3,esp32c3,esp32c6,esp32h2" - - idf_branch: "release/v5.3" - lib_builder_branch: "release/v5.3" - targets: "esp32,esp32s2,esp32s3,esp32c3,esp32c6,esp32h2,esp32p4" diff --git a/.github/workflows/cron_build.yml b/.github/workflows/cron_build.yml deleted file mode 100644 index f8767617c..000000000 --- a/.github/workflows/cron_build.yml +++ /dev/null @@ -1,161 +0,0 @@ -name: Cron Build Matrix - -on: - workflow_call: - inputs: - idf_branch: - type: string - required: true - description: 'IDF branch to build' - lib_builder_branch: - type: string - required: true - description: 'Branch of the lib-builder to use' - targets: - type: string - required: true - description: 'Targets to build' - -env: - IDF_BRANCH: ${{ inputs.idf_branch }} - -jobs: - check-if-needed: - name: Check if deploy is needed for ${{ inputs.idf_branch }} - runs-on: ubuntu-latest - outputs: - idf_commit: ${{ steps.check.outputs.idf_commit }} - ar_branch: ${{ steps.check.outputs.ar_branch }} - ar_new_commit_message: ${{ steps.check.outputs.ar_new_commit_message }} - ar_new_branch_name: ${{ steps.check.outputs.ar_new_branch_name }} - ar_new_pr_title: ${{ steps.check.outputs.ar_new_pr_title }} - ar_has_commit: ${{ steps.check.outputs.ar_has_commit }} - ar_has_branch: ${{ steps.check.outputs.ar_has_branch }} - ar_has_pr: ${{ steps.check.outputs.ar_has_pr }} - libs_release_tag: ${{ steps.check.outputs.libs_release_tag }} - libs_version: ${{ steps.check.outputs.libs_version }} - libs_release_id: ${{ steps.check.outputs.libs_release_id }} - libs_has_release: ${{ steps.check.outputs.libs_has_release }} - libs_asset_id: ${{ steps.check.outputs.libs_asset_id }} - libs_has_asset: ${{ steps.check.outputs.libs_has_asset }} - deploy_needed: ${{ steps.check.outputs.deploy_needed }} - targets_list: ${{ steps.check.outputs.targets_list }} - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.lib_builder_branch }} - - - name: Check deploy and generate variables - id: check - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - source ./tools/check-deploy-needed.sh - targets_list=$(echo "${{ inputs.targets }}" | sed 's/ *, */,/g' | sed 's/^/["/' | sed 's/$/"]/' | sed 's/,/","/g') - echo "Targets list: $targets_list" - echo "targets_list=$targets_list" >> $GITHUB_OUTPUT - - build-libs: - name: Build for ${{ matrix.target }} (${{ inputs.idf_branch }}) - runs-on: ubuntu-latest - if: needs.check-if-needed.outputs.deploy_needed == '1' - needs: check-if-needed - strategy: - fail-fast: false - matrix: - target: ${{ fromJson(needs.check-if-needed.outputs.targets_list) }} - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.lib_builder_branch }} - - - name: Install dependencies - run: bash ./tools/prepare-ci.sh - - - name: Build - env: - GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN || secrets.GITHUB_TOKEN }} - GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} - GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} - TARGET: ${{ matrix.target }} - run: | - bash ./tools/cron.sh - - - name: Replace invalid characters in the artifact name - run: | - branch=${{ inputs.idf_branch }} - echo "libs_branch=${branch//\//_}" >> $GITHUB_ENV - - - name: Upload build - if: failure() - uses: actions/upload-artifact@v4 - with: - name: build-${{ env.libs_branch }}-${{ matrix.target }} - path: build - - - name: Upload library files - uses: actions/upload-artifact@v4 - with: - name: libs-${{ env.libs_branch }}-${{ matrix.target }} - path: dist - - combine-artifacts: - name: Combine artifacts and push changes for IDF ${{ inputs.idf_branch }} - runs-on: ubuntu-latest - needs: [check-if-needed, build-libs] - if: needs.check-if-needed.outputs.deploy_needed == '1' - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.lib_builder_branch }} - - - name: Replace invalid characters in the artifact name - run: | - branch=${{ inputs.idf_branch }} - echo "libs_branch=${branch//\//_}" >> $GITHUB_ENV - - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - path: dist - pattern: libs-${{ env.libs_branch }}-* - merge-multiple: true - - - name: Combine artifacts - run: bash ./tools/combine-artifacts.sh - - - name: Upload full esp32-arduino-libs archive - uses: actions/upload-artifact@v4 - with: - name: esp32-arduino-libs-${{ env.libs_branch }} - path: dist/esp32-arduino-libs.zip - compression-level: 0 - - - name: Push changes - if: github.repository == 'espressif/esp32-arduino-lib-builder' - env: - GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN }} - GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} - GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} - IDF_COMMIT: ${{ needs.check-if-needed.outputs.idf_commit }} - AR_BRANCH: ${{ needs.check-if-needed.outputs.ar_branch }} - AR_NEW_COMMIT_MESSAGE: ${{ needs.check-if-needed.outputs.ar_new_commit_message }} - AR_NEW_BRANCH_NAME: ${{ needs.check-if-needed.outputs.ar_new_branch_name }} - AR_NEW_PR_TITLE: ${{ needs.check-if-needed.outputs.ar_new_pr_title }} - AR_HAS_COMMIT: ${{ needs.check-if-needed.outputs.ar_has_commit }} - AR_HAS_BRANCH: ${{ needs.check-if-needed.outputs.ar_has_branch }} - AR_HAS_PR: ${{ needs.check-if-needed.outputs.ar_has_pr }} - LIBS_RELEASE_TAG: ${{ needs.check-if-needed.outputs.libs_release_tag }} - LIBS_VERSION: ${{ needs.check-if-needed.outputs.libs_version }} - LIBS_RELEASE_ID: ${{ needs.check-if-needed.outputs.libs_release_id }} - LIBS_HAS_RELEASE: ${{ needs.check-if-needed.outputs.libs_has_release }} - LIBS_ASSET_ID: ${{ needs.check-if-needed.outputs.libs_asset_id }} - LIBS_HAS_ASSET: ${{ needs.check-if-needed.outputs.libs_has_asset }} - run: | - bash ./tools/push-to-arduino.sh - - - name: Upload package_esp32_index.template.json - uses: actions/upload-artifact@v4 - with: - name: package-esp32-index-json-${{ env.libs_branch }} - path: out/package_esp32_index.template.json diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index d6166a365..000000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Build and push Docker image - -on: - push: - branches: - - 'master' - - 'release/*' - tags: - - 'v*.*' - pull_request: - paths: - - ".github/workflows/docker.yml" - - "tools/config_editor/requirements.txt" - - "tools/docker/Dockerfile" - - "tools/docker/entrypoint.sh" - -env: - # Build the image for amd64 and arm64 - BUILD_PLATFORMS: linux/amd64,linux/arm64 - DOCKERHUB_REPO: ${{ github.repository_owner }}/esp32-arduino-lib-builder - -jobs: - docker: - # Disable the job in forks - if: ${{ github.event_name == 'pull_request' || github.repository_owner == 'espressif' }} - name: Build docker image and push if needed - runs-on: ubuntu-latest - steps: - # Depending on the branch/tag, set CLONE_BRANCH_OR_TAG variable (used in the Dockerfile - # as a build arg) and TAG_NAME (used when tagging the image). - # - # The following 3 steps cover the alternatives (tag, release branch, master branch): - - name: Set variables (tags) - if: ${{ github.ref_type == 'tag' }} - run: | - echo "CLONE_BRANCH_OR_TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV - echo "TAG_NAME=$GITHUB_REF_NAME" >> $GITHUB_ENV - echo "URL=${{ github.server_url }}/${{ github.repository }}.git" >> $GITHUB_ENV - - - name: Set variables (release branches) - if: ${{ github.ref_type == 'branch' && startsWith(github.ref_name, 'release/') }} - run: | - echo "CLONE_BRANCH_OR_TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV - echo "TAG_NAME=release-${GITHUB_REF_NAME##release/}" >> $GITHUB_ENV - echo "URL=${{ github.server_url }}/${{ github.repository }}.git" >> $GITHUB_ENV - - - name: Set variables (main branch) - if: ${{ github.ref_type == 'branch' && github.ref_name == 'master' }} - run: | - echo "CLONE_BRANCH_OR_TAG=master" >> $GITHUB_ENV - echo "TAG_NAME=latest" >> $GITHUB_ENV - echo "URL=${{ github.server_url }}/${{ github.repository }}.git" >> $GITHUB_ENV - - - name: Set variables (pull requests) - if: ${{ github.event_name == 'pull_request' }} - run: | - echo "CLONE_BRANCH_OR_TAG=${{ github.event.pull_request.head.ref }}" >> $GITHUB_ENV - echo "TAG_NAME=PR_${{ github.event.number }}" >> $GITHUB_ENV - echo "URL=${{ github.server_url }}/${{ github.event.pull_request.head.repo.full_name }}.git" >> $GITHUB_ENV - - # Display the variables set above, just in case. - - name: Check variables - run: | - echo "CLONE_BRANCH_OR_TAG: $CLONE_BRANCH_OR_TAG" - echo "TAG_NAME: $TAG_NAME" - echo "URL: $URL" - - - name: Checkout - uses: actions/checkout@v4 - - - name: Login to Docker Hub - if: ${{ github.event_name == 'push' }} - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Set up QEMU for multiarch builds - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: tools/docker - push: ${{ github.event_name == 'push' }} - tags: ${{ env.DOCKERHUB_REPO }}:${{ env.TAG_NAME }} - platforms: ${{ env.BUILD_PLATFORMS }} - build-args: | - LIBBUILDER_CLONE_URL=${{ env.URL }} - LIBBUILDER_CLONE_BRANCH_OR_TAG=${{ env.CLONE_BRANCH_OR_TAG }} - - - name: Update Docker Hub repository description (master branch) - if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && github.ref_name == 'master' }} - uses: peter-evans/dockerhub-description@v4 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - repository: ${{ env.DOCKERHUB_REPO }} - readme-filepath: ./tools/docker/README.md diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 649c84c81..babc7c1f5 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,82 +1,119 @@ -name: ESP32 Arduino Libs CI +# name: ESP32 Arduino Libs CI -on: - push: - branches: - - master - pull_request: - paths: - - "**" - - "!**.md" - - "!.github/workflows/cron_build.yml" - - "!.github/workflows/cron.yml" - - "!.github/workflows/docker.yml" - - "!.github/workflows/repository_dispatch.yml" - - "!tools/config_editor/**" - - "!tools/docker/**" +# on: +# push: +# branches: +# - master +# pull_request: +# paths: +# - "**" +# - "!**.md" +# - "!.github/workflows/cron_build.yml" +# - "!.github/workflows/cron.yml" +# - "!.github/workflows/docker.yml" +# - "!.github/workflows/repository_dispatch.yml" +# - "!tools/config_editor/**" +# - "!tools/docker/**" -concurrency: - group: esp-idf-libs-${{github.event.pull_request.number || github.ref}} - cancel-in-progress: true +# concurrency: +# group: esp-idf-libs-${{github.event.pull_request.number || github.ref}} +# cancel-in-progress: true -jobs: - build-libs: - name: Build Libs for ${{ matrix.target }} - runs-on: ubuntu-latest - strategy: - matrix: - target: [esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2] - fail-fast: false - steps: - - uses: actions/checkout@v4 +# jobs: +# build-libs: +# name: Build Libs for ${{ matrix.target }} +# runs-on: ubuntu-latest +# strategy: +# matrix: +# target: [esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c6, esp32h2] +# fail-fast: false +# steps: +# - uses: actions/checkout@v4 - - name: Install dependencies - run: bash ./tools/prepare-ci.sh +# - name: Install dependencies +# run: bash ./tools/prepare-ci.sh - - name: Build Libs for ${{ matrix.target }} - run: bash ./build.sh -e -t ${{ matrix.target }} +# - name: Build Libs for ${{ matrix.target }} +# run: bash ./build.sh -e -t ${{ matrix.target }} - - name: Upload build - if: failure() - uses: actions/upload-artifact@v4 - with: - name: build-${{ matrix.target }} - path: build +# - name: Upload build +# if: failure() +# uses: actions/upload-artifact@v4 +# with: +# name: build-${{ matrix.target }} +# path: build - - name: Upload archive - uses: actions/upload-artifact@v4 - with: - name: artifacts-${{ matrix.target }} - path: dist +# - name: Upload archive +# uses: actions/upload-artifact@v4 +# with: +# name: artifacts-${{ matrix.target }} +# path: dist - combine-artifacts: - name: Combine artifacts - needs: build-libs - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - path: dist - pattern: artifacts-* - merge-multiple: true +# combine-artifacts: +# name: Combine artifacts +# needs: build-libs +# runs-on: ubuntu-latest +# steps: +# - name: Download artifacts +# uses: actions/download-artifact@v4 +# with: +# path: dist +# pattern: artifacts-* +# merge-multiple: true - - shell: bash - run: | - mkdir -p out - find dist -name 'arduino-esp32-libs-esp*.tar.gz' -exec tar zxvf {} -C out \; - cd out/tools/esp32-arduino-libs && tar zcf ../../../dist/esp32-arduino-libs.tar.gz * && cd ../../.. - cp out/package_esp32_index.template.json dist/package_esp32_index.template.json +# - shell: bash +# run: | +# mkdir -p out +# find dist -name 'arduino-esp32-libs-esp*.tar.gz' -exec tar zxvf {} -C out \; +# cd out/tools/esp32-arduino-libs && tar zcf ../../../dist/esp32-arduino-libs.tar.gz * && cd ../../.. +# cp out/package_esp32_index.template.json dist/package_esp32_index.template.json - - name: Upload full esp32-arduino-libs archive - uses: actions/upload-artifact@v4 - with: - name: esp32-arduino-libs - path: dist/esp32-arduino-libs.tar.gz +# - name: Upload full esp32-arduino-libs archive +# uses: actions/upload-artifact@v4 +# with: +# name: esp32-arduino-libs +# path: dist/esp32-arduino-libs.tar.gz - - name: Upload package_esp32_index.template.json - uses: actions/upload-artifact@v4 - with: - name: package-esp32-index-json - path: dist/package_esp32_index.template.json +# - name: Upload package_esp32_index.template.json +# uses: actions/upload-artifact@v4 +# with: +# name: package-esp32-index-json +# path: dist/package_esp32_index.template.json +name: Build Arduino Libs +on: + workflow_dispatch: # Manually start a workflow + +jobs: + build-libs: + name: Build Arduino Libs + runs-on: macos-14 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install dependencies + run: bash ./tools/prepare-ci.sh + - name: Get current branch + run: | + echo "GIT_BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_ENV + - name: Build Arduino Libs + env: + GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN }} + GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} + run: bash ./build.sh -I release/v5.3 -A release/v3.1.x + - name: Release + uses: jason2866/action-gh-release@v1.3 + with: + tag_name: ${{ github.run_number }} + body_path: release-info.txt + prerelease: true + files: | + dist/framework* + release-info.txt + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/repository_dispatch.yml b/.github/workflows/repository_dispatch.yml deleted file mode 100644 index a18412a3d..000000000 --- a/.github/workflows/repository_dispatch.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Remote Trigger - -on: repository_dispatch - -jobs: - run: - name: Dispatch Event - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Install dependencies - run: bash ./tools/prepare-ci.sh - - name: Handle Event - env: - GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN }} - GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} - GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} - run: bash ./tools/repository_dispatch.sh - - name: Upload build - if: failure() - uses: actions/upload-artifact@v4 - with: - name: build - path: build - - name: Upload archive - uses: actions/upload-artifact@v4 - with: - name: artifacts - path: dist diff --git a/.gitignore b/.gitignore index b0749543f..9f1b252d4 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ version.txt dependencies.lock managed_components/ target/ +core_version.h +package.json +release-info.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..8e95acb8b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "components/lwip/lwip"] + path = components/lwip/lwip + url = https://github.com/hamzahajeir/esp-lwip diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b0fca085..1268b8e68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ add_custom_command( ) add_custom_target(mem-variant DEPENDS "mem_variant") +idf_build_set_property(COMPILE_DEFINITIONS "-DESP32_ARDUINO_LIB_BUILDER" APPEND) + ################## ### ESP Matter ### ################## diff --git a/build.sh b/build.sh index 9bceda087..7c149bec1 100755 --- a/build.sh +++ b/build.sh @@ -20,17 +20,18 @@ export IDF_COMPONENT_OVERWRITE_MANAGED_COMPONENTS=1 CCACHE_ENABLE=1 -TARGET="all" +export TARGET="all" BUILD_TYPE="all" BUILD_DEBUG="default" SKIP_ENV=0 COPY_OUT=0 -ARCHIVE_OUT=0 +ARCHIVE_OUT=1 if [ -z $DEPLOY_OUT ]; then DEPLOY_OUT=0 fi function print_help() { + echo "Usage: build.sh [-s] [-n] [-A ] [-I ] [-D ] [-i ] [-c ] [-t ] [-b ] [config ...]" echo " -s Skip installing/updating of ESP-IDF and all components" echo " -n Disable ccache" @@ -47,17 +48,17 @@ function print_help() { exit 1 } -while getopts ":A:I:i:c:t:b:D:sde" opt; do +while getopts ":A:I:i:c:t:b:D:sdne" opt; do case ${opt} in s ) SKIP_ENV=1 ;; - n ) - CCACHE_ENABLE=0 - ;; d ) DEPLOY_OUT=1 ;; + n ) + CCACHE_ENABLE=0 + ;; e ) ARCHIVE_OUT=1 ;; @@ -112,6 +113,8 @@ echo "TARGET(s): ${TARGET[@]}" mkdir -p dist +rm -rf dependencies.lock + if [ $SKIP_ENV -eq 0 ]; then echo "* Installing/Updating ESP-IDF and all components..." # update components from git @@ -131,6 +134,10 @@ else source ./tools/config.sh fi +if [ -f "$AR_MANAGED_COMPS/espressif__esp-sr/.component_hash" ]; then + rm -rf $AR_MANAGED_COMPS/espressif__esp-sr/.component_hash +fi + if [ "$BUILD_TYPE" != "all" ]; then if [ "$TARGET" = "all" ]; then echo "ERROR: You need to specify target for non-default builds" @@ -175,9 +182,20 @@ if [ "$BUILD_TYPE" != "all" ]; then exit 0 fi +git submodule update --init --recursive + rm -rf build sdkconfig out mkdir -p "$AR_TOOLS/esp32-arduino-libs" +# Add release-info +rm -rf release-info.txt +IDF_Commit_short=$(git -C "$IDF_PATH" rev-parse --short HEAD || echo "") +AR_Commit_short=$(git -C "$AR_COMPS/arduino" rev-parse --short HEAD || echo "") +echo "Framework built from +- $IDF_REPO branch [$IDF_BRANCH](https://github.com/$IDF_REPO/tree/$IDF_BRANCH) commit [$IDF_Commit_short](https://github.com/$IDF_REPO/commits/$IDF_BRANCH/#:~:text=$IDF_Commit_short) +- $AR_REPO branch [$AR_BRANCH](https://github.com/$AR_REPO/tree/$AR_BRANCH) commit [$AR_Commit_short](https://github.com/$AR_REPO/commits/$AR_BRANCH/#:~:text=$AR_Commit_short) +- Arduino lib builder branch: $GIT_BRANCH" >> release-info.txt + #targets_count=`jq -c '.targets[] | length' configs/builds.json` for target_json in `jq -c '.targets[]' configs/builds.json`; do target=$(echo "$target_json" | jq -c '.target' | tr -d '"') @@ -221,6 +239,9 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do idf_libs_configs="$idf_libs_configs;configs/defconfig.$defconf" done + if [ -f "$AR_MANAGED_COMPS/espressif__esp-sr/.component_hash" ]; then + rm -rf $AR_MANAGED_COMPS/espressif__esp-sr/.component_hash + fi echo "* Build IDF-Libs: $idf_libs_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$idf_libs_configs" idf-libs @@ -246,6 +267,10 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do bootloader_configs="$bootloader_configs;configs/defconfig.$defconf"; done + if [ -f "$AR_MANAGED_COMPS/espressif__esp-sr/.component_hash" ]; then + rm -rf $AR_MANAGED_COMPS/espressif__esp-sr/.component_hash + fi + echo "* Build BootLoader: $bootloader_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$bootloader_configs" copy-bootloader @@ -259,6 +284,10 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do mem_configs="$mem_configs;configs/defconfig.$defconf"; done + if [ -f "$AR_MANAGED_COMPS/espressif__esp-sr/.component_hash" ]; then + rm -rf $AR_MANAGED_COMPS/espressif__esp-sr/.component_hash + fi + echo "* Build Memory Variant: $mem_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$mem_configs" mem-variant @@ -304,15 +333,22 @@ if [ "$BUILD_TYPE" = "all" ]; then python3 ./tools/gen_tools_json.py -i "$IDF_PATH" -o "$TOOLS_JSON_OUT/" if [ $? -ne 0 ]; then exit 1; fi fi +export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) -# Generate PlatformIO manifest file +# Generate PlatformIO library manifest file if [ "$BUILD_TYPE" = "all" ]; then - echo "* Generating PlatformIO manifest file..." - pushd $IDF_PATH - ibr=$(git describe --all 2>/dev/null) - ic=$(git -C "$IDF_PATH" rev-parse --short HEAD) - popd - python3 ./tools/gen_platformio_manifest.py -o "$TOOLS_JSON_OUT/" -s "$ibr" -c "$ic" + python3 ./tools/gen_pio_lib_manifest.py -o "$TOOLS_JSON_OUT/" -s "v$IDF_VERSION" -c "$IDF_COMMIT" + if [ $? -ne 0 ]; then exit 1; fi +fi + +AR_VERSION=$(jq -c '.version' "$AR_COMPS/arduino/package.json" | tr -d '"') +AR_VERSION_UNDERSCORE=`echo "$AR_VERSION" | tr . _` + +# Generate PlatformIO framework manifest file +rm -rf "$AR_ROOT/package.json" + +if [ "$BUILD_TYPE" = "all" ]; then + python3 ./tools/gen_platformio_manifest.py -o "$AR_ROOT/" -s "v$AR_VERSION" -c "$IDF_COMMIT" if [ $? -ne 0 ]; then exit 1; fi fi @@ -322,6 +358,17 @@ if [ $COPY_OUT -eq 1 ] && [ -d "$ESP32_ARDUINO" ]; then ./tools/copy-to-arduino.sh if [ $? -ne 0 ]; then exit 1; fi fi +AR_VERSION=$(jq -c '.version' "$AR_COMPS/arduino/package.json" | tr -d '"') +AR_VERSION_UNDERSCORE=`echo "$AR_VERSION" | tr . _` + + + +# Generate core_version.h +rm -rf "$AR_ROOT/core_version.h" +echo "#define ARDUINO_ESP32_GIT_VER 0x$AR_Commit_short +#define ARDUINO_ESP32_GIT_DESC $AR_VERSION +#define ARDUINO_ESP32_RELEASE_$AR_VERSION_UNDERSCORE +#define ARDUINO_ESP32_RELEASE \"$AR_VERSION_UNDERSCORE\"" >> "$AR_ROOT/core_version.h" # push changes to esp32-arduino-libs and create pull request into arduino-esp32 if [ $DEPLOY_OUT -eq 1 ]; then diff --git a/components/arduino_tinyusb/Kconfig.projbuild b/components/arduino_tinyusb/Kconfig.projbuild index 1db30506f..65d9c37be 100755 --- a/components/arduino_tinyusb/Kconfig.projbuild +++ b/components/arduino_tinyusb/Kconfig.projbuild @@ -4,7 +4,7 @@ menu "Arduino TinyUSB" config TINYUSB_ENABLED bool "Enable TinyUSB driver" default y - depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4 select FREERTOS_SUPPORT_STATIC_ALLOCATION select FREERTOS_USE_AUTHENTIC_INCLUDE_PATHS help @@ -28,14 +28,16 @@ menu "Arduino TinyUSB" config TINYUSB_CDC_RX_BUFSIZE int "CDC FIFO size of RX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_CDC_ENABLED help CDC FIFO size of RX config TINYUSB_CDC_TX_BUFSIZE int "CDC FIFO size of TX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_CDC_ENABLED help CDC FIFO size of TX @@ -86,7 +88,8 @@ menu "Arduino TinyUSB" config TINYUSB_HID_BUFSIZE int "HID Buffer size" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_HID_ENABLED help HID Buffer size. Should be sufficient to hold ID (if any) + Data @@ -111,14 +114,16 @@ menu "Arduino TinyUSB" config TINYUSB_MIDI_RX_BUFSIZE int "MIDI FIFO size of RX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_MIDI_ENABLED help MIDI FIFO size of RX config TINYUSB_MIDI_TX_BUFSIZE int "MIDI FIFO size of TX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_MIDI_ENABLED help MIDI FIFO size of TX @@ -143,8 +148,9 @@ menu "Arduino TinyUSB" config TINYUSB_VIDEO_STREAMING_BUFSIZE int "VIDEO streaming endpoint size" - range 0 64 - default 64 + range 0 512 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_VIDEO_ENABLED help VIDEO streaming endpoint size @@ -219,14 +225,16 @@ menu "Arduino TinyUSB" config TINYUSB_VENDOR_RX_BUFSIZE int "VENDOR FIFO size of RX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_VENDOR_ENABLED help VENDOR FIFO size of RX config TINYUSB_VENDOR_TX_BUFSIZE int "VENDOR FIFO size of TX" - default 64 + default 64 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 512 if IDF_TARGET_ESP32P4 depends on TINYUSB_VENDOR_ENABLED help VENDOR FIFO size of TX diff --git a/components/arduino_tinyusb/include/tusb_config.h b/components/arduino_tinyusb/include/tusb_config.h index 90dd7f797..458c78cf1 100755 --- a/components/arduino_tinyusb/include/tusb_config.h +++ b/components/arduino_tinyusb/include/tusb_config.h @@ -100,11 +100,18 @@ extern "C" { # define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4) #endif +#if CONFIG_IDF_TARGET_ESP32P4 +#define CFG_TUD_MAX_SPEED OPT_MODE_HIGH_SPEED +#else +#define CFG_TUD_MAX_SPEED OPT_MODE_FULL_SPEED +#endif + /* */ /* DRIVER CONFIGURATION */ /* */ #define CFG_TUD_MAINTASK_SIZE 4096 +#define CFG_TUD_ENDOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_ENDOINT0_SIZE 64 // Enabled Drivers diff --git a/components/arduino_tinyusb/patches/dcd_dwc2.patch b/components/arduino_tinyusb/patches/dcd_dwc2.patch index a57df7ef6..e93f9629b 100644 --- a/components/arduino_tinyusb/patches/dcd_dwc2.patch +++ b/components/arduino_tinyusb/patches/dcd_dwc2.patch @@ -4,7 +4,7 @@ //-------------------------------------------------------------------- // Endpoint //-------------------------------------------------------------------- -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) +// Keep count of how many FIFOs are in use +static uint8_t _allocated_fifos = 1; //FIFO0 is always in use + @@ -17,13 +17,14 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); -@@ -336,7 +346,18 @@ - dwc2->epout[epnum].doepctl = dxepctl; - dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); - } else { -- dwc2->epin[epnum].diepctl = dxepctl | (epnum << DIEPCTL_TXFNUM_Pos); +@@ -332,7 +342,19 @@ + (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + if (dir == TUSB_DIR_IN) { +- epctl |= (epnum << DIEPCTL_TXFNUM_Pos); ++ //epctl |= (epnum << DIEPCTL_TXFNUM_Pos); + uint8_t fifo_num = epnum; -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + // Special Case for EP5, which is used by CDC but not actually called by the driver + // we can give it a fake FIFO + if (epnum == 5) { @@ -33,49 +34,49 @@ + } + //TU_ASSERT(fifo_num != 0); +#endif -+ dwc2->epin[epnum].diepctl = dxepctl | (fifo_num << DIEPCTL_TXFNUM_Pos); - dwc2->daintmsk |= TU_BIT(DAINTMSK_IEPM_Pos + epnum); ++ epctl |= (fifo_num << DIEPCTL_TXFNUM_Pos); } - } -@@ -850,6 +871,10 @@ - xfer_status[n][TUSB_DIR_IN].max_size = 0; + + dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; +@@ -840,6 +862,10 @@ + } } -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif + dfifo_flush_tx(dwc2, 0x10); // all tx fifo dfifo_flush_rx(dwc2); -@@ -1204,6 +1229,9 @@ +@@ -1186,6 +1212,9 @@ if (int_status & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif bus_reset(rhport); } -@@ -1235,7 +1263,11 @@ +@@ -1217,7 +1246,11 @@ if (int_status & GINTSTS_USBSUSP) { dwc2->gintsts = GINTSTS_USBSUSP; - dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); + //dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif } if (int_status & GINTSTS_WKUINT) { -@@ -1252,6 +1284,9 @@ +@@ -1234,6 +1267,9 @@ if (otg_int & GOTGINT_SEDET) { dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -+#if defined(TUP_USBIP_DWC2_ESP32) ++#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif } diff --git a/components/arduino_tinyusb/src/dcd_dwc2.c b/components/arduino_tinyusb/src/dcd_dwc2.c index 8bcc98166..e76bdf70e 100644 --- a/components/arduino_tinyusb/src/dcd_dwc2.c +++ b/components/arduino_tinyusb/src/dcd_dwc2.c @@ -316,7 +316,7 @@ static void dfifo_write_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const* //-------------------------------------------------------------------- // Endpoint //-------------------------------------------------------------------- -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) // Keep count of how many FIFOs are in use static uint8_t _allocated_fifos = 1; //FIFO0 is always in use @@ -337,17 +337,14 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoin xfer->interval = p_endpoint_desc->bInterval; // USBAEP, EPTYP, SD0PID_SEVNFRM, MPSIZ are the same for IN and OUT endpoints. - uint32_t const dxepctl = (1 << DOEPCTL_USBAEP_Pos) | - (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | - (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | - (xfer->max_size << DOEPCTL_MPSIZ_Pos); - - if (dir == TUSB_DIR_OUT) { - dwc2->epout[epnum].doepctl = dxepctl; - dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); - } else { + uint32_t epctl = (1 << DOEPCTL_USBAEP_Pos) | + (p_endpoint_desc->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + if (dir == TUSB_DIR_IN) { + //epctl |= (epnum << DIEPCTL_TXFNUM_Pos); uint8_t fifo_num = epnum; -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) // Special Case for EP5, which is used by CDC but not actually called by the driver // we can give it a fake FIFO if (epnum == 5) { @@ -357,44 +354,44 @@ static void edpt_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoin } //TU_ASSERT(fifo_num != 0); #endif - dwc2->epin[epnum].diepctl = dxepctl | (fifo_num << DIEPCTL_TXFNUM_Pos); - dwc2->daintmsk |= TU_BIT(DAINTMSK_IEPM_Pos + epnum); + epctl |= (fifo_num << DIEPCTL_TXFNUM_Pos); } + + dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; + dep->ctl = epctl; + dwc2->daintmsk |= TU_BIT(epnum + DAINT_SHIFT(dir)); } static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { (void) rhport; dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + const uint8_t epnum = tu_edpt_number(ep_addr); + const uint8_t dir = tu_edpt_dir(ep_addr); + dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; if (dir == TUSB_DIR_IN) { - dwc2_epin_t* epin = dwc2->epin; - // Only disable currently enabled non-control endpoint - if ((epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA)) { - epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + if ((epnum == 0) || !(dep->diepctl & DIEPCTL_EPENA)) { + dep->diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); } else { // Stop transmitting packets and NAK IN xfers. - epin[epnum].diepctl |= DIEPCTL_SNAK; - while ((epin[epnum].diepint & DIEPINT_INEPNE) == 0) {} + dep->diepctl |= DIEPCTL_SNAK; + while ((dep->diepint & DIEPINT_INEPNE) == 0) {} // Disable the endpoint. - epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); - while ((epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0) {} + dep->diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ((dep->diepint & DIEPINT_EPDISD_Msk) == 0) {} - epin[epnum].diepint = DIEPINT_EPDISD; + dep->diepint = DIEPINT_EPDISD; } // Flush the FIFO, and wait until we have confirmed it cleared. dfifo_flush_tx(dwc2, epnum); } else { - dwc2_epout_t* epout = dwc2->epout; - // Only disable currently enabled non-control endpoint - if ((epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA)) { - epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + if ((epnum == 0) || !(dep->doepctl & DOEPCTL_EPENA)) { + dep->doepctl |= stall ? DOEPCTL_STALL : 0; } else { // Asserting GONAK is required to STALL an OUT endpoint. // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt @@ -403,11 +400,11 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) { dwc2->dctl |= DCTL_SGONAK; while ((dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0) {} - // Ditto here- disable the endpoint. - epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); - while ((epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0) {} + // Ditto here disable the endpoint. + dep->doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ((dep->doepint & DOEPINT_EPDISD_Msk) == 0) {} - epout[epnum].doepint = DOEPINT_EPDISD; + dep->doepint = DOEPINT_EPDISD; // Allow other OUT endpoints to keep receiving. dwc2->dctl |= DCTL_CGONAK; @@ -423,12 +420,8 @@ static void bus_reset(uint8_t rhport) { tu_memclr(xfer_status, sizeof(xfer_status)); _sof_en = false; - _allocated_ep_in_count = 1; - // clear device address - dwc2->dcfg &= ~DCFG_DAD_Msk; - // 1. NAK for all OUT endpoints for (uint8_t n = 0; n < ep_count; n++) { dwc2->epout[n].doepctl |= DOEPCTL_SNAK; @@ -444,14 +437,18 @@ static void bus_reset(uint8_t rhport) { dfifo_flush_tx(dwc2, 0x10); // all tx fifo dfifo_flush_rx(dwc2); - // 3. Set up interrupt mask + // 3. Set up interrupt mask for EP0 dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + // 4. Set up DFIFO dfifo_init(rhport); - // Fixed control EP0 size to 64 bytes + // 5. Reset device address + dwc2->dcfg &= ~DCFG_DAD_Msk; + + // Fixed both control EP0 size to 64 bytes dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); dwc2->epout[0].doepctl &= ~(0x03 << DOEPCTL_MPSIZ_Pos); @@ -482,33 +479,33 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c } // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. - if (dir == TUSB_DIR_IN) { - dwc2_epin_t* epin = dwc2->epin; + const uint8_t is_epout = 1 - dir; + dwc2_dep_t* dep = &dwc2->ep[is_epout][epnum]; + if (dir == TUSB_DIR_IN) { // A full IN transfer (multiple packets, possibly) triggers XFRC. - epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | + dep->dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); if(dma_enabled(dwc2)) { - epin[epnum].diepdma = (uintptr_t)xfer->buffer; + dep->diepdma = (uintptr_t)xfer->buffer; // For ISO endpoint set correct odd/even bit for next frame. - if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { + if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); } - epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; } else { - - epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + dep->diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; // For ISO endpoint set correct odd/even bit for next frame. - if ((epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { + if ((dep->diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + dep->diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); } // Enable fifo empty interrupt only if there are something to put in the fifo. if (total_bytes != 0) { @@ -516,25 +513,23 @@ static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t c } } } else { - dwc2_epout_t* epout = dwc2->epout; - // A full OUT transfer (multiple packets, possibly) triggers XFRC. - epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); - epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | + dep->doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); + dep->doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); - if ((epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + if ((dep->doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && XFER_CTL_BASE(epnum, dir)->interval == 1) { // Take odd/even bit from frame counter. uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); - epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); + dep->doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); } if(dma_enabled(dwc2)) { - epout[epnum].doepdma = (uintptr_t)xfer->buffer; + dep->doepdma = (uintptr_t)xfer->buffer; } - epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; + dep->doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; } } @@ -658,7 +653,7 @@ static void phy_hs_init(dwc2_regs_t* dwc2) { static bool check_dwc2(dwc2_regs_t* dwc2) { #if CFG_TUSB_DEBUG >= DWC2_DEBUG // print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4 - // Run 'dwc2_info.py render-md' and check dwc2_info.md for bit-field value and comparison with other ports + // Run 'python dwc2_info.py' and check dwc2_info.md for bit-field value and comparison with other ports volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid; TU_LOG1("guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n"); for (size_t i = 0; i < 5; i++) { @@ -677,13 +672,15 @@ static bool check_dwc2(dwc2_regs_t* dwc2) { return true; } -void dcd_init(uint8_t rhport) { +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void) rhport; + (void) rh_init; // Programming model begins in the last section of the chapter on the USB // peripheral in each Reference Manual. dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Check Synopsys ID register, failed if controller clock/power is not enabled - TU_ASSERT(check_dwc2(dwc2), ); + TU_ASSERT(check_dwc2(dwc2)); dcd_disconnect(rhport); if (phy_hs_supported(dwc2)) { @@ -752,6 +749,8 @@ void dcd_init(uint8_t rhport) { // TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg); dcd_connect(rhport); + + return true; } void dcd_int_enable(uint8_t rhport) { @@ -858,20 +857,16 @@ void dcd_edpt_close_all(uint8_t rhport) { dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); for (uint8_t n = 1; n < ep_count; n++) { - // disable OUT endpoint - if (dwc2->epout[n].doepctl & DOEPCTL_EPENA) { - dwc2->epout[n].doepctl |= DOEPCTL_SNAK | DOEPCTL_EPDIS; - } - xfer_status[n][TUSB_DIR_OUT].max_size = 0; - - // disable IN endpoint - if (dwc2->epin[n].diepctl & DIEPCTL_EPENA) { - dwc2->epin[n].diepctl |= DIEPCTL_SNAK | DIEPCTL_EPDIS; + for (uint8_t d = 0; d < 2; d++) { + dwc2_dep_t* dep = &dwc2->ep[d][n]; + if (dep->ctl & EPCTL_EPENA) { + dep->ctl |= EPCTL_SNAK | EPCTL_EPDIS; + } + xfer_status[n][1-d].max_size = 0; } - xfer_status[n][TUSB_DIR_IN].max_size = 0; } -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) _allocated_fifos = 1; #endif @@ -942,7 +937,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t uint16_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. - if (short_packet_size > 0 || (total_bytes == 0)) num_packets++; + if (short_packet_size > 0 || (total_bytes == 0)) { + num_packets++; + } // Schedule packets to be sent within interrupt edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); @@ -962,50 +959,32 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - dwc2_regs_t* dwc2 = DWC2_REG(rhport); - uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); + dwc2_dep_t* dep = &dwc2->ep[1 - dir][epnum]; // Clear stall and reset data toggle - if (dir == TUSB_DIR_IN) { - dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; - dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; - } else { - dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; - dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; - } + dep->ctl &= ~EPCTL_STALL;; + dep->ctl |= EPCTL_SD0PID_SEVNFRM; } //-------------------------------------------------------------------- // Interrupt Handler //-------------------------------------------------------------------- +// Process shared receive FIFO, this interrupt is only used in Slave mode static void handle_rxflvl_irq(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); volatile uint32_t const* rx_fifo = dwc2->fifo[0]; // Pop control word off FIFO - uint32_t const ctl_word = dwc2->grxstsp; - uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos; - uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos; - uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos; - + uint32_t const grxstsp = dwc2->grxstsp; + uint8_t const pktsts = (grxstsp & GRXSTSP_PKTSTS_Msk) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (grxstsp & GRXSTSP_EPNUM_Msk) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (grxstsp & GRXSTSP_BCNT_Msk) >> GRXSTSP_BCNT_Pos; dwc2_epout_t* epout = &dwc2->epout[epnum]; -//#if CFG_TUSB_DEBUG >= DWC2_DEBUG -// const char * pktsts_str[] = -// { -// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)", -// "Setup Complete (ISR)", "ASSERT", "Setup Data Received" -// }; -// TU_LOG_LOCATION(); -// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]); -// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); -//#endif - switch (pktsts) { // Global OUT NAK: do nothing case GRXSTS_PKTSTS_GLOBALOUTNAK: @@ -1013,15 +992,14 @@ static void handle_rxflvl_irq(uint8_t rhport) { case GRXSTS_PKTSTS_SETUPRX: // Setup packet received - - // We can receive up to three setup packets in succession, but - // only the last one is valid. + // We can receive up to three setup packets in succession, but only the last one is valid. _setup_packet[0] = (*rx_fifo); _setup_packet[1] = (*rx_fifo); break; case GRXSTS_PKTSTS_SETUPDONE: - // Setup packet done (Interrupt) + // Setup packet done: + // After popping this out, dwc2 asserts a DOEPINT_SETUP interrupt which is handled by handle_epout_irq() epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); break; @@ -1049,20 +1027,16 @@ static void handle_rxflvl_irq(uint8_t rhport) { ep0_pending[TUSB_DIR_OUT] = 0; } } - } break; + } - // Out packet done (Interrupt) case GRXSTS_PKTSTS_OUTDONE: - // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a - // May (or not) be 3.10a specific feature/bug or depending on MCU configuration - // XFRC complete is additionally generated when - // - setup packet is received - // - complete the data stage of control write is complete - // It will be handled in handle_epout_irq() + /* Out packet done + After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed interrupt on + the specified OUT endpoint which will be handled by handle_epout_irq() */ break; - default: // Invalid + default: TU_BREAKPOINT(); break; } @@ -1074,80 +1048,70 @@ static void handle_epout_irq(uint8_t rhport) { // DAINT for a given EP clears when DOEPINTx is cleared. // OEPINT will be cleared when DAINT's out bits are cleared. - for (uint8_t n = 0; n < ep_count; n++) { - if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n)) { - dwc2_epout_t* epout = &dwc2->epout[n]; + for (uint8_t epnum = 0; epnum < ep_count; epnum++) { + if (dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + epnum)) { + dwc2_epout_t* epout = &dwc2->epout[epnum]; + const uint32_t doepint = epout->doepint; + TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, ); - uint32_t const doepint = epout->doepint; + // Setup and/or STPKTRX/STSPHSRX (from 3.00a) can be set along with XFRC, and also set independently. + if (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a) { + if (doepint & DOEPINT_STSPHSRX) { + // Status phase received for control write: In token received from Host + epout->doepint = DOEPINT_STSPHSRX; + } - TU_ASSERT((epout->doepint & DOEPINT_AHBERR) == 0, ); + if (doepint & DOEPINT_STPKTRX) { + // New setup packet received, but wait for Setup done, since we can receive up to 3 setup consecutively + epout->doepint = DOEPINT_STPKTRX; + } + } + + if (doepint & DOEPINT_SETUP) { + epout->doepint = DOEPINT_SETUP; + + if(dma_enabled(dwc2)) { + dma_setup_prepare(rhport); + } + + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + } // OUT XFER complete - if (epout->doepint & DOEPINT_XFRC) { + if (doepint & DOEPINT_XFRC) { epout->doepint = DOEPINT_XFRC; - xfer_ctl_t* xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + // only handle data skip if it is setup or status related + // Normal OUT transfer complete + if (!(doepint & (DOEPINT_SETUP | DOEPINT_STPKTRX | DOEPINT_STSPHSRX))) { + xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); - if(dma_enabled(dwc2)) { - if (doepint & DOEPINT_STUP) { - // STPKTRX is only available for version from 3_00a - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { - epout->doepint = DOEPINT_STPKTRX; - } - } else if (doepint & DOEPINT_OTEPSPR) { - epout->doepint = DOEPINT_OTEPSPR; - } else { - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { - epout->doepint = DOEPINT_STPKTRX; + if(dma_enabled(dwc2)) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { + // EP0 can only handle one packet Schedule another packet to be received. + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); } else { - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { - // Schedule another packet to be received. - edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); - } else { - // Fix packet length - uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; - xfer->total_len -= remain; - // this is ZLP, so prepare EP0 for next setup - if(n == 0 && xfer->total_len == 0) { - dma_setup_prepare(rhport); - } - - dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + // Fix packet length + uint16_t remain = (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + xfer->total_len -= remain; + // this is ZLP, so prepare EP0 for next setup + if(epnum == 0 && xfer->total_len == 0) { + dma_setup_prepare(rhport); } + + dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } - } - } else { - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) { - epout->doepint = DOEPINT_STPKTRX; } else { - if ((doepint & DOEPINT_OTEPSPR) && (dwc2->gsnpsid == DWC2_CORE_REV_3_10a)) { - epout->doepint = DOEPINT_OTEPSPR; - } - // EP0 can only handle one packet - if ((n == 0) && ep0_pending[TUSB_DIR_OUT]) { + if ((epnum == 0) && ep0_pending[TUSB_DIR_OUT]) { // Schedule another packet to be received. - edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + edpt_schedule_packets(rhport, epnum, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); } else { - dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(rhport, epnum, xfer->total_len, XFER_RESULT_SUCCESS, true); } } } } - - // SETUP packet Setup Phase done. - if (doepint & DOEPINT_STUP) { - epout->doepint = DOEPINT_STUP; - if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { - epout->doepint = DOEPINT_STPKTRX; - } - if(dma_enabled(dwc2) && (dwc2->gsnpsid > DWC2_CORE_REV_3_00a)) { - dma_setup_prepare(rhport); - } - - dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); - } } } } @@ -1220,6 +1184,29 @@ static void handle_epin_irq(uint8_t rhport) { } } +/* Interrupt Hierarchy + + DxEPMSK.XferComplMsk DxEPINTn.XferCompl + | | + +---------- AND --------+ + | + DAINT.xEPnInt DAINTMSK.xEPnMsk + | | + +---------- AND --------+ + | + GINTSTS.xEPInt GINTMSK.xEPIntMsk + | | + +---------- AND --------+ + | + GAHBCFG.GblIntrMsk + | + IRQn + + Note: when OTG_MULTI_PROC_INTRPT = 1, Device Each endpoint interrupt deachint/deachmsk/diepeachmsk/doepeachmsk + are combined to generate dedicated interrupt line for each endpoint. + */ + + void dcd_int_handler(uint8_t rhport) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); @@ -1229,7 +1216,7 @@ void dcd_int_handler(uint8_t rhport) { if (int_status & GINTSTS_USBRST) { // USBRST is start of reset. dwc2->gintsts = GINTSTS_USBRST; -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) _allocated_fifos = 1; #endif bus_reset(rhport); @@ -1265,7 +1252,7 @@ void dcd_int_handler(uint8_t rhport) { dwc2->gintsts = GINTSTS_USBSUSP; //dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) _allocated_fifos = 1; #endif } @@ -1284,7 +1271,7 @@ void dcd_int_handler(uint8_t rhport) { if (otg_int & GOTGINT_SEDET) { dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); -#if defined(TUP_USBIP_DWC2_ESP32) +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) _allocated_fifos = 1; #endif } @@ -1307,13 +1294,10 @@ void dcd_int_handler(uint8_t rhport) { // RxFIFO non-empty interrupt handling. if (int_status & GINTSTS_RXFLVL) { // RXFLVL bit is read-only + dwc2->gintmsk &= ~GINTMSK_RXFLVLM; // disable RXFLVL interrupt while reading - // Mask out RXFLVL while reading data from FIFO - dwc2->gintmsk &= ~GINTMSK_RXFLVLM; - - // Loop until all available packets were handled do { - handle_rxflvl_irq(rhport); + handle_rxflvl_irq(rhport); // read all packets } while(dwc2->gintsts & GINTSTS_RXFLVL); dwc2->gintmsk |= GINTMSK_RXFLVLM; diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt new file mode 100644 index 000000000..dbfd93f67 --- /dev/null +++ b/components/lwip/CMakeLists.txt @@ -0,0 +1,266 @@ +idf_build_get_property(target IDF_TARGET) +set(CONFIG_LWIP_ALTCP_TLS 1) + +if(CONFIG_LWIP_ENABLE) + if(NOT ${target} STREQUAL "linux") + # ESP platform targets share the same port folder + set(target esp32xx) + endif() + + set(include_dirs + include + include/apps + include/apps/sntp + lwip/src/include + port/include + port/freertos/include/ + port/${target}/include + port/${target}/include/arch + port/${target}/include/sys + ) + + set(srcs + "apps/sntp/sntp.c" + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/if_api.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/apps/netbiosns/netbiosns.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_napt.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/bridgeif.c" + "lwip/src/netif/bridgeif_fdb.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "port/hooks/tcp_isn_default.c" + "port/hooks/lwip_default_hooks.c" + "port/debug/lwip_debug.c" + "port/sockets_ext.c" + "port/freertos/sys_arch.c") + + if (${CONFIG_LWIP_ALTCP_TLS}) + + list(APPEND srcs + "lwip/src/core/altcp_alloc.c" + "lwip/src/core/altcp_tcp.c" + "lwip/src/core/altcp.c" + "lwip/src/apps/altcp_tls/altcp_tls_mbedtls_mem.c" + "lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c") + + list(APPEND include_dirs lwip/src/apps/altcp_tls) + # add_compile_definitions(LWIP_ALTCP=1) + # add_compile_definitions(LWIP_ALTCP_TLS=1) + endif() + + if(CONFIG_LWIP_NETIF_API) + list(APPEND srcs "port/if_index.c") + endif() + + if(CONFIG_LWIP_PPP_SUPPORT) + list(APPEND srcs + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c") + endif() + + if(NOT ${target} STREQUAL "linux") + # Support for vfs and linker fragments only for target builds + set(linker_fragments linker.lf) + if(CONFIG_VFS_SUPPORT_IO) + list(APPEND srcs "port/${target}/vfs_lwip.c") + else() + list(APPEND srcs "port/${target}/no_vfs_syscalls.c") + endif() + else() + # This wraps some posix IO functions to conditionally pass control to lwip + list(APPEND srcs "port/${target}/vfs_lwip.c") + endif() + + if(CONFIG_LWIP_ICMP) + list(APPEND srcs + "apps/ping/esp_ping.c" + "apps/ping/ping.c" + "apps/ping/ping_sock.c") + endif() + + if(NOT CONFIG_LWIP_USE_EXTERNAL_MBEDTLS) + list(APPEND srcs + "lwip/src/netif/ppp/polarssl/arc4.c" + "lwip/src/netif/ppp/polarssl/des.c" + "lwip/src/netif/ppp/polarssl/md4.c" + "lwip/src/netif/ppp/polarssl/md5.c" + "lwip/src/netif/ppp/polarssl/sha1.c") + endif() + + if(CONFIG_LWIP_DHCPS) + list(APPEND srcs "apps/dhcpserver/dhcpserver.c") + endif() + + if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) + list(APPEND srcs "port/esp32xx/netif/dhcp_state.c") + endif() +endif() # CONFIG_LWIP_ENABLE + +if(NOT ${target} STREQUAL "linux") + set(priv_requires vfs) +endif() + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ${include_dirs} + LDFRAGMENTS ${linker_fragments} + PRIV_REQUIRES ${priv_requires}) + +if(CONFIG_LWIP_ENABLE) + # lots of LWIP source files evaluate macros that check address of stack variables + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) + target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_LWIP_COMPONENT_BUILD) + + set_source_files_properties( + lwip/src/netif/ppp/pppos.c + PROPERTIES COMPILE_FLAGS + -Wno-type-limits + ) + # "comparison is always false due to limited range of data type" warning + # when setting CONFIG_LWIP_TCP_WND_DEFAULT to 65535 + set_source_files_properties( + lwip/src/core/tcp.c + PROPERTIES COMPILE_FLAGS + -Wno-type-limits + ) + + if (${CONFIG_LWIP_ALTCP_TLS}) + target_compile_definitions(${COMPONENT_LIB} PRIVATE -DLWIP_ALTCP=1 + -DLWIP_ALTCP_TLS=1 + -DLWIP_ALTCP_TLS_MBEDTLS=1 + -DALTCP_MBEDTLS_DEBUG=128U + -DALTCP_MBEDTLS_LIB_DEBUG=128U + -DALTCP_MBEDTLS_USE_SESSION_CACHE=1 + -DALTCP_MBEDTLS_USE_SESSION_TICKETS=1 + ) + idf_component_optional_requires(PRIVATE mbedtls) + endif() + # ignore some declaration mismatches + set_source_files_properties( + lwip/src/netif/ppp/chap_ms.c + PROPERTIES COMPILE_FLAGS + -Wno-array-parameter + ) + + if(CONFIG_OPENTHREAD_ENABLED) + idf_component_optional_requires(PRIVATE openthread) + endif() + + if(CONFIG_ETH_ENABLED) + idf_component_optional_requires(PRIVATE esp_eth) + endif() + + if(CONFIG_LWIP_DHCP_RESTORE_LAST_IP) + idf_component_optional_requires(PRIVATE nvs_flash) + endif() + + if(CONFIG_LWIP_USE_EXTERNAL_MBEDTLS) + idf_component_optional_requires(PRIVATE mbedtls) + endif() + + if(${target} STREQUAL "linux") + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) + set(WRAP_FUNCTIONS select + read + fcntl + write + close) + foreach(wrap ${WRAP_FUNCTIONS}) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __wrap_${wrap}") + endforeach() + endif() +endif() diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig new file mode 100644 index 000000000..6c54868de --- /dev/null +++ b/components/lwip/Kconfig @@ -0,0 +1,1436 @@ +menu "LWIP" + config LWIP_ENABLE + bool "Enable LwIP stack" + default y if !IDF_TARGET_LINUX + default n if IDF_TARGET_LINUX + help + Builds normally if selected. Excludes LwIP from build if unselected, even if it is a + dependency of a component or application. + Some applications can switch their IP stacks, e.g., when switching between chip + and Linux targets (LwIP stack vs. Linux IP stack). Since the LwIP dependency cannot + easily be excluded based on a Kconfig option, it has to be a dependency in all cases. + This switch allows the LwIP stack to be built selectively, even if it is a dependency. + + config LWIP_LOCAL_HOSTNAME + string "Local netif hostname" + default 'espressif' + help + The default name this device will report to other devices on the network. + Could be updated at runtime with esp_netif_set_hostname() + + config LWIP_NETIF_API + bool "Enable usage of standard POSIX APIs in LWIP" + default n + help + If this feature is enabled, standard POSIX APIs: if_indextoname(), if_nametoindex() + could be used to convert network interface index to name + instead of IDF specific esp-netif APIs (such as esp_netif_get_netif_impl_name()) + + config LWIP_TCPIP_TASK_PRIO + int "LWIP TCP/IP Task Priority" + default 18 + range 1 24 + help + LWIP tcpip task priority. In case of high throughput, this parameter + could be changed up to (configMAX_PRIORITIES-1). + + config LWIP_TCPIP_CORE_LOCKING + bool "Enable tcpip core locking" + default n + help + If Enable tcpip core locking,Creates a global mutex that is held + during TCPIP thread operations.Can be locked by client code to perform + lwIP operations without changing into TCPIP thread using callbacks. + See LOCK_TCPIP_CORE() and UNLOCK_TCPIP_CORE(). + + If disable tcpip core locking,TCP IP will perform tasks through context switching + + config LWIP_TCPIP_CORE_LOCKING_INPUT + bool "Enable tcpip core locking input" + depends on LWIP_TCPIP_CORE_LOCKING + default n + help + when LWIP_TCPIP_CORE_LOCKING is enabled, this lets tcpip_input() grab the + mutex for input packets as well, instead of allocating a message and passing + it to tcpip_thread. + + config LWIP_CHECK_THREAD_SAFETY + bool "Checks that lwip API runs in expected context" + default n + help + Enable to check that the project does not violate lwip thread safety. + If enabled, all lwip functions that require thread awareness run an assertion + to verify that the TCP/IP core functionality is either locked or accessed + from the correct thread. + + config LWIP_DNS_SUPPORT_MDNS_QUERIES + bool "Enable mDNS queries in resolving host name" + default y + help + If this feature is enabled, standard API such as gethostbyname + support .local addresses by sending one shot multicast mDNS + query + + config LWIP_L2_TO_L3_COPY + bool "Enable copy between Layer2 and Layer3 packets" + default n + help + If this feature is enabled, all traffic from layer2(WIFI Driver) will be + copied to a new buffer before sending it to layer3(LWIP stack), freeing + the layer2 buffer. + Please be notified that the total layer2 receiving buffer is fixed and + ESP32 currently supports 25 layer2 receiving buffer, when layer2 buffer + runs out of memory, then the incoming packets will be dropped in hardware. + The layer3 buffer is allocated from the heap, so the total layer3 receiving + buffer depends on the available heap size, when heap runs out of memory, + no copy will be sent to layer3 and packet will be dropped in layer2. + Please make sure you fully understand the impact of this feature before + enabling it. + + config LWIP_IRAM_OPTIMIZATION + bool "Enable LWIP IRAM optimization" + default n + help + If this feature is enabled, some functions relating to RX/TX in LWIP will be + put into IRAM, it can improve UDP/TCP throughput by >10% for single core mode, + it doesn't help too much for dual core mode. On the other hand, it needs about + 10KB IRAM for these optimizations. + + If this feature is disabled, all lwip functions will be put into FLASH. + + config LWIP_EXTRA_IRAM_OPTIMIZATION + bool "Enable LWIP IRAM optimization for TCP part" + default n + help + If this feature is enabled, some tcp part functions relating to RX/TX in LWIP will be + put into IRAM, it can improve TCP throughput. On the other hand, it needs about 17KB + IRAM for these optimizations. + + config LWIP_TIMERS_ONDEMAND + bool "Enable LWIP Timers on demand" + default y + help + If this feature is enabled, IGMP and MLD6 timers will be activated only + when joining groups or receiving QUERY packets. + + This feature will reduce the power consumption for applications which do not + use IGMP and MLD6. + + config LWIP_ND6 + bool "LWIP NDP6 Enable/Disable" + default y + depends on LWIP_IPV6 + help + This option is used to disable the Network Discovery Protocol (NDP) if it is not required. + Please use this option with caution, as the NDP is essential for IPv6 functionality within a local network. + + config LWIP_FORCE_ROUTER_FORWARDING + bool "LWIP Force Router Forwarding Enable/Disable" + default n + depends on LWIP_ND6 + help + This option is used to set the the router flag for the NA packets. + When enabled, the router flag in NA packet will always set to 1, + otherwise, never set router flag for NA packets. + + config LWIP_MAX_SOCKETS + int "Max number of open sockets" + range 1 16 + default 10 + help + Sockets take up a certain amount of memory, and allowing fewer + sockets to be open at the same time conserves memory. Specify + the maximum amount of sockets here. The valid value is from 1 + to 16. + + config LWIP_USE_ONLY_LWIP_SELECT + bool "Support LWIP socket select() only (DEPRECATED)" + default n + help + This option is deprecated. Do not use this option, use VFS_SUPPORT_SELECT instead. + + config LWIP_SO_LINGER + bool "Enable SO_LINGER processing" + default n + help + Enabling this option allows SO_LINGER processing. + l_onoff = 1,l_linger can set the timeout. + + If l_linger=0, When a connection is closed, TCP will terminate the connection. + This means that TCP will discard any data packets stored in the socket send buffer + and send an RST to the peer. + + If l_linger!=0,Then closesocket() calls to block the process until + the remaining data packets has been sent or timed out. + + config LWIP_SO_REUSE + bool "Enable SO_REUSEADDR option" + default y + help + Enabling this option allows binding to a port which remains in + TIME_WAIT. + + config LWIP_SO_REUSE_RXTOALL + bool "SO_REUSEADDR copies broadcast/multicast to all matches" + depends on LWIP_SO_REUSE + default y + help + Enabling this option means that any incoming broadcast or multicast + packet will be copied to all of the local sockets that it matches + (may be more than one if SO_REUSEADDR is set on the socket.) + + This increases memory overhead as the packets need to be copied, + however they are only copied per matching socket. You can safely + disable it if you don't plan to receive broadcast or multicast + traffic on more than one socket at a time. + + config LWIP_SO_RCVBUF + bool "Enable SO_RCVBUF option" + default n + help + Enabling this option allows checking for available data on a netconn. + + config LWIP_NETBUF_RECVINFO + bool "Enable IP_PKTINFO option" + default n + help + Enabling this option allows checking for the destination address + of a received IPv4 Packet. + + config LWIP_IP_DEFAULT_TTL + int "The value for Time-To-Live used by transport layers" + range 1 255 + default 64 + help + Set value for Time-To-Live used by transport layers. + + config LWIP_IP4_FRAG + bool "Enable fragment outgoing IP4 packets" + default y + depends on LWIP_IPV4 + help + Enabling this option allows fragmenting outgoing IP4 packets if their size + exceeds MTU. + + config LWIP_IP6_FRAG + bool "Enable fragment outgoing IP6 packets" + default y + depends on LWIP_IPV6 + help + Enabling this option allows fragmenting outgoing IP6 packets if their size + exceeds MTU. + + config LWIP_IP4_REASSEMBLY + bool "Enable reassembly incoming fragmented IP4 packets" + default n + depends on LWIP_IPV4 + help + Enabling this option allows reassemblying incoming fragmented IP4 packets. + + config LWIP_IP6_REASSEMBLY + bool "Enable reassembly incoming fragmented IP6 packets" + default n + depends on LWIP_IPV6 + help + Enabling this option allows reassemblying incoming fragmented IP6 packets. + + config LWIP_IP_REASS_MAX_PBUFS + int "The maximum amount of pbufs waiting to be reassembled" + range 10 100 + default 10 + help + Set the maximum amount of pbufs waiting to be reassembled. + + config LWIP_IP_FORWARD + bool "Enable IP forwarding" + default n + help + Enabling this option allows packets forwarding across multiple interfaces. + + config LWIP_IPV4_NAPT + bool "Enable NAT" + depends on LWIP_IP_FORWARD + default n + help + Enabling this option allows Network Address and Port Translation. + + config LWIP_IPV4_NAPT_PORTMAP + bool "Enable NAT Port Mapping" + depends on LWIP_IPV4_NAPT + default y + help + Enabling this option allows Port Forwarding or Port mapping. + + config LWIP_STATS + bool "Enable LWIP statistics" + default n + help + Enabling this option allows LWIP statistics + + config LWIP_ESP_GRATUITOUS_ARP + bool "Send gratuitous ARP periodically" + default y + depends on LWIP_IPV4 + help + Enable this option allows to send gratuitous ARP periodically. + + This option solve the compatibility issues.If the ARP table of the AP is old, and the AP + doesn't send ARP request to update it's ARP table, this will lead to the STA sending IP packet fail. + Thus we send gratuitous ARP periodically to let AP update it's ARP table. + + config LWIP_GARP_TMR_INTERVAL + int "GARP timer interval(seconds)" + default 60 + depends on LWIP_ESP_GRATUITOUS_ARP + help + Set the timer interval for gratuitous ARP. The default value is 60s + + config LWIP_ESP_MLDV6_REPORT + bool "Send mldv6 report periodically" + depends on LWIP_IPV6 + default y + help + Enable this option allows to send mldv6 report periodically. + + This option solve the issue that failed to receive multicast data. + Some routers fail to forward multicast packets. + To solve this problem, send multicast mdlv6 report to routers regularly. + + config LWIP_MLDV6_TMR_INTERVAL + int "mldv6 report timer interval(seconds)" + default 40 + depends on LWIP_ESP_MLDV6_REPORT + help + Set the timer interval for mldv6 report. The default value is 30s + + config LWIP_TCPIP_RECVMBOX_SIZE + int "TCPIP task receive mail box size" + default 32 + range 6 64 if !LWIP_WND_SCALE + range 6 1024 if LWIP_WND_SCALE + help + Set TCPIP task receive mail box size. Generally bigger value means higher throughput + but more memory. The value should be bigger than UDP/TCP mail box size. + + config LWIP_DHCP_DOES_ARP_CHECK + bool "DHCP: Perform ARP check on any offered address" + default y + depends on LWIP_IPV4 + help + Enabling this option performs a check (via ARP request) if the offered IP address + is not already in use by another host on the network. + + config LWIP_DHCP_DISABLE_CLIENT_ID + bool "DHCP: Disable Use of HW address as client identification" + default n + depends on LWIP_IPV4 + help + This option could be used to disable DHCP client identification with its MAC address. + (Client id is used by DHCP servers to uniquely identify clients and are included + in the DHCP packets as an option 61) + Set this option to "y" in order to exclude option 61 from DHCP packets. + + config LWIP_DHCP_DISABLE_VENDOR_CLASS_ID + bool "DHCP: Disable Use of vendor class identification" + default y + depends on LWIP_IPV4 + help + This option could be used to disable DHCP client vendor class identification. + Set this option to "y" in order to exclude option 60 from DHCP packets. + + config LWIP_DHCP_RESTORE_LAST_IP + bool "DHCP: Restore last IP obtained from DHCP server" + default n + depends on LWIP_IPV4 + help + When this option is enabled, DHCP client tries to re-obtain last valid IP address obtained from DHCP + server. Last valid DHCP configuration is stored in nvs and restored after reset/power-up. If IP is still + available, there is no need for sending discovery message to DHCP server and save some time. + + config LWIP_DHCP_OPTIONS_LEN + int "DHCP total option length" + default 68 if LWIP_DHCP_DISABLE_VENDOR_CLASS_ID + default 108 if !LWIP_DHCP_DISABLE_VENDOR_CLASS_ID + range 68 255 + depends on LWIP_IPV4 + help + Set total length of outgoing DHCP option msg. Generally bigger value means it can carry more + options and values. If your code meets LWIP_ASSERT due to option value is too long. + Please increase the LWIP_DHCP_OPTIONS_LEN value. + + config LWIP_NUM_NETIF_CLIENT_DATA + int "Number of clients store data in netif" + default 0 + range 0 256 + help + Number of clients that may store data in client_data member array of struct netif. + + config LWIP_DHCP_COARSE_TIMER_SECS + int "DHCP coarse timer interval(s)" + default 1 + range 1 10 + help + Set DHCP coarse interval in seconds. + A higher value will be less precise but cost less power consumption. + + menu "DHCP server" + + config LWIP_DHCPS + bool "DHCPS: Enable IPv4 Dynamic Host Configuration Protocol Server (DHCPS)" + default y + depends on LWIP_IPV4 + help + Enabling this option allows the device to run the DHCP server + (to dynamically assign IPv4 addresses to clients). + + config LWIP_DHCPS_LEASE_UNIT + int "Multiplier for lease time, in seconds" + range 1 3600 + default 60 + depends on LWIP_DHCPS + help + The DHCP server is calculating lease time multiplying the sent + and received times by this number of seconds per unit. + The default is 60, that equals one minute. + + config LWIP_DHCPS_MAX_STATION_NUM + int "Maximum number of stations" + range 1 64 + default 8 + depends on LWIP_DHCPS + help + The maximum number of DHCP clients that are connected to the server. + After this number is exceeded, DHCP server removes of the oldest device + from it's address pool, without notification. + + config LWIP_DHCPS_STATIC_ENTRIES + bool "Enable ARP static entries" + default y + depends on LWIP_DHCPS + help + Enabling this option allows DHCP server to support temporary static ARP entries + for DHCP Client. This will help the DHCP server to send the DHCP OFFER and DHCP ACK using IP unicast. + + endmenu # DHCPS + + menuconfig LWIP_AUTOIP + bool "Enable IPV4 Link-Local Addressing (AUTOIP)" + default n + depends on LWIP_IPV4 + help + Enabling this option allows the device to self-assign an address + in the 169.256/16 range if none is assigned statically or via DHCP. + + See RFC 3927. + + config LWIP_AUTOIP_TRIES + int "DHCP Probes before self-assigning IPv4 LL address" + range 1 100 + default 2 + depends on LWIP_AUTOIP + help + DHCP client will send this many probes before self-assigning a + link local address. + + From LWIP help: "This can be set as low as 1 to get an AutoIP + address very quickly, but you should be prepared to handle a + changing IP address when DHCP overrides AutoIP." (In the case of + ESP-IDF, this means multiple SYSTEM_EVENT_STA_GOT_IP events.) + + config LWIP_AUTOIP_MAX_CONFLICTS + int "Max IP conflicts before rate limiting" + range 1 100 + default 9 + depends on LWIP_AUTOIP + help + If the AUTOIP functionality detects this many IP conflicts while + self-assigning an address, it will go into a rate limited mode. + + config LWIP_AUTOIP_RATE_LIMIT_INTERVAL + int "Rate limited interval (seconds)" + range 5 120 + default 20 + depends on LWIP_AUTOIP + help + If rate limiting self-assignment requests, wait this long between + each request. + + config LWIP_IPV4 + bool "Enable IPv4" + default y + help + Enable IPv4 stack. If you want to use IPv6 only TCP/IP stack, disable this. + + config LWIP_IPV6 + bool "Enable IPv6" + default y + help + Enable IPv6 function. If not use IPv6 function, set this option to n. + If disabling LWIP_IPV6 then some other components (asio) will + no longer be available. + + config LWIP_IPV6_AUTOCONFIG + bool "Enable IPV6 stateless address autoconfiguration (SLAAC)" + depends on LWIP_IPV6 + default n + help + Enabling this option allows the devices to IPV6 stateless address autoconfiguration (SLAAC). + + See RFC 4862. + + config LWIP_IPV6_NUM_ADDRESSES + int "Number of IPv6 addresses on each network interface" + depends on LWIP_IPV6 + default 3 + help + The maximum number of IPv6 addresses on each interface. Any additional + addresses will be discarded. + + config LWIP_IPV6_FORWARD + bool "Enable IPv6 forwarding between interfaces" + depends on LWIP_IPV6 + default n + help + Forwarding IPv6 packets between interfaces is only required when acting as + a router. + + config LWIP_IPV6_RDNSS_MAX_DNS_SERVERS + int "Use IPv6 Router Advertisement Recursive DNS Server Option" + depends on LWIP_IPV6_AUTOCONFIG + default 0 + help + Use IPv6 Router Advertisement Recursive DNS Server Option (as per RFC 6106) to + copy a defined maximum number of DNS servers to the DNS module. + Set this option to a number of desired DNS servers advertised in the RA protocol. + This feature is disabled when set to 0. + + config LWIP_IPV6_DHCP6 + bool "Enable DHCPv6 stateless address autoconfiguration" + depends on LWIP_IPV6_AUTOCONFIG + default n + help + Enable DHCPv6 for IPv6 stateless address autoconfiguration. + Note that the dhcpv6 client has to be started using dhcp6_enable_stateless(netif); + Note that the stateful address autoconfiguration is not supported. + + config LWIP_NETIF_STATUS_CALLBACK + bool "Enable status callback for network interfaces" + default n + help + Enable callbacks when the network interface is up/down and addresses are changed. + + menuconfig LWIP_NETIF_LOOPBACK + bool "Support per-interface loopback" + default y + help + Enabling this option means that if a packet is sent with a destination + address equal to the interface's own IP address, it will "loop back" and + be received by this interface. + Disabling this option disables support of loopback interface in lwIP + + config LWIP_LOOPBACK_MAX_PBUFS + int "Max queued loopback packets per interface" + range 0 16 + default 8 + depends on LWIP_NETIF_LOOPBACK + help + Configure the maximum number of packets which can be queued for + loopback on a given interface. Reducing this number may cause packets + to be dropped, but will avoid filling memory with queued packet data. + + menu "TCP" + + config LWIP_MAX_ACTIVE_TCP + int "Maximum active TCP Connections" + range 1 1024 + default 16 + help + The maximum number of simultaneously active TCP + connections. The practical maximum limit is + determined by available heap memory at runtime. + + Changing this value by itself does not substantially + change the memory usage of LWIP, except for preventing + new TCP connections after the limit is reached. + + config LWIP_MAX_LISTENING_TCP + int "Maximum listening TCP Connections" + range 1 1024 + default 16 + help + The maximum number of simultaneously listening TCP + connections. The practical maximum limit is + determined by available heap memory at runtime. + + Changing this value by itself does not substantially + change the memory usage of LWIP, except for preventing + new listening TCP connections after the limit is reached. + + config LWIP_TCP_HIGH_SPEED_RETRANSMISSION + bool "TCP high speed retransmissions" + default y + help + Speed up the TCP retransmission interval. If disabled, + it is recommended to change the number of SYN retransmissions to 6, + and TCP initial rto time to 3000. + + config LWIP_TCP_MAXRTX + int "Maximum number of retransmissions of data segments" + default 12 + range 3 12 + help + Set maximum number of retransmissions of data segments. + + config LWIP_TCP_SYNMAXRTX + int "Maximum number of retransmissions of SYN segments" + default 6 if !LWIP_TCP_HIGH_SPEED_RETRANSMISSION + default 12 if LWIP_TCP_HIGH_SPEED_RETRANSMISSION + range 3 12 + help + Set maximum number of retransmissions of SYN segments. + + config LWIP_TCP_MSS + int "Maximum Segment Size (MSS)" + default 1440 + range 536 1460 + help + Set maximum segment size for TCP transmission. + + Can be set lower to save RAM, the default value 1460(ipv4)/1440(ipv6) will give best throughput. + IPv4 TCP_MSS Range: 576 <= TCP_MSS <= 1460 + IPv6 TCP_MSS Range: 1220<= TCP_MSS <= 1440 + + config LWIP_TCP_TMR_INTERVAL + int "TCP timer interval(ms)" + default 250 + help + Set TCP timer interval in milliseconds. + + Can be used to speed connections on bad networks. + A lower value will redeliver unacked packets faster. + + config LWIP_TCP_MSL + int "Maximum segment lifetime (MSL)" + default 60000 + help + Set maximum segment lifetime in milliseconds. + + config LWIP_TCP_FIN_WAIT_TIMEOUT + int "Maximum FIN segment lifetime" + default 20000 + help + Set maximum segment lifetime in milliseconds. + + config LWIP_TCP_SND_BUF_DEFAULT + int "Default send buffer size" + default 5760 # 4 * default MSS + range 2440 65535 if !LWIP_WND_SCALE + range 2440 1024000 if LWIP_WND_SCALE + help + Set default send buffer size for new TCP sockets. + + Per-socket send buffer size can be changed at runtime + with lwip_setsockopt(s, TCP_SNDBUF, ...). + + This value must be at least 2x the MSS size, and the default + is 4x the default MSS size. + + Setting a smaller default SNDBUF size can save some RAM, but + will decrease performance. + + config LWIP_TCP_WND_DEFAULT + int "Default receive window size" + default 5760 # 4 * default MSS + range 2440 65535 if !LWIP_WND_SCALE + range 2440 1024000 if LWIP_WND_SCALE + help + Set default TCP receive window size for new TCP sockets. + + Per-socket receive window size can be changed at runtime + with lwip_setsockopt(s, TCP_WINDOW, ...). + + Setting a smaller default receive window size can save some RAM, + but will significantly decrease performance. + + config LWIP_TCP_RECVMBOX_SIZE + int "Default TCP receive mail box size" + default 6 + range 6 64 if !LWIP_WND_SCALE + range 6 1024 if LWIP_WND_SCALE + help + Set TCP receive mail box size. Generally bigger value means higher throughput + but more memory. The recommended value is: LWIP_TCP_WND_DEFAULT/TCP_MSS + 2, e.g. if + LWIP_TCP_WND_DEFAULT=14360, TCP_MSS=1436, then the recommended receive mail box size is + (14360/1436 + 2) = 12. + + TCP receive mail box is a per socket mail box, when the application receives packets + from TCP socket, LWIP core firstly posts the packets to TCP receive mail box and the + application then fetches the packets from mail box. It means LWIP can caches maximum + LWIP_TCP_RECCVMBOX_SIZE packets for each TCP socket, so the maximum possible cached TCP packets + for all TCP sockets is LWIP_TCP_RECCVMBOX_SIZE multiples the maximum TCP socket number. In other + words, the bigger LWIP_TCP_RECVMBOX_SIZE means more memory. + On the other hand, if the receive mail box is too small, the mail box may be full. If the + mail box is full, the LWIP drops the packets. So generally we need to make sure the TCP + receive mail box is big enough to avoid packet drop between LWIP core and application. + + config LWIP_TCP_ACCEPTMBOX_SIZE + int "Default TCP accept mail box size" + default 6 + range 1 64 if !LWIP_WND_SCALE + range 1 255 if LWIP_WND_SCALE + help + Set TCP accept mail box size. Generally bigger value means supporting larger backlogs + but more memory. The recommended value is 6, but applications can set it to a lower value + if listening servers are meant to have a smaller backlog. + + TCP accept mail box is a per socket mail box, when the application listens for connections + with a given listening TCP socket. If the mailbox is full, LWIP will send a RST packet and + the client will fail to connect. + + config LWIP_TCP_QUEUE_OOSEQ + bool "Queue incoming out-of-order segments" + default y + help + Queue incoming out-of-order segments for later use. + + Disable this option to save some RAM during TCP sessions, at the expense + of increased retransmissions if segments arrive out of order. + + config LWIP_TCP_OOSEQ_TIMEOUT + int "Timeout for each pbuf queued in TCP OOSEQ, in RTOs." + depends on LWIP_TCP_QUEUE_OOSEQ + range 1 30 + default 6 + help + The timeout value is TCP_OOSEQ_TIMEOUT * RTO. + + config LWIP_TCP_OOSEQ_MAX_PBUFS + int "The maximum number of pbufs queued on OOSEQ per pcb" + depends on LWIP_TCP_QUEUE_OOSEQ + range 0 12 + default 4 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP + default 0 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP + help + If LWIP_TCP_OOSEQ_MAX_PBUFS = 0, TCP will not control the number of OOSEQ pbufs. + + In a poor network environment, many out-of-order tcp pbufs will be received. + These out-of-order pbufs will be cached in the TCP out-of-order queue which will + cause Wi-Fi/Ethernet fail to release RX buffer in time. + It is possible that all RX buffers for MAC layer are used by OOSEQ. + + Control the number of out-of-order pbufs to ensure + that the MAC layer has enough RX buffer to receive packets. + + In the Wi-Fi scenario, recommended OOSEQ PBUFS Range: + 0 <= TCP_OOSEQ_MAX_PBUFS <= CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM/(MAX_TCP_NUMBER + 1) + + In the Ethernet scenario,recommended Ethernet OOSEQ PBUFS Range: + 0 <= TCP_OOSEQ_MAX_PBUFS <= CONFIG_ETH_DMA_RX_BUFFER_NUM/(MAX_TCP_NUMBER + 1) + + Within the recommended value range, the larger the value, the better the performance. + + MAX_TCP_NUMBER represent Maximum number of TCP connections in Wi-Fi(STA+SoftAP) and Ethernet scenario. + + config LWIP_TCP_SACK_OUT + bool "Support sending selective acknowledgements" + default n + depends on LWIP_TCP_QUEUE_OOSEQ + help + TCP will support sending selective acknowledgements (SACKs). + + + choice LWIP_TCP_OVERSIZE + prompt "Pre-allocate transmit PBUF size" + default LWIP_TCP_OVERSIZE_MSS + help + Allows enabling "oversize" allocation of TCP transmission pbufs ahead of time, + which can reduce the length of pbuf chains used for transmission. + + This will not make a difference to sockets where Nagle's algorithm + is disabled. + + Default value of MSS is fine for most applications, 25% MSS may save + some RAM when only transmitting small amounts of data. Disabled will + have worst performance and fragmentation characteristics, but uses + least RAM overall. + + config LWIP_TCP_OVERSIZE_MSS + bool "MSS" + config LWIP_TCP_OVERSIZE_QUARTER_MSS + bool "25% MSS" + config LWIP_TCP_OVERSIZE_DISABLE + bool "Disabled" + + endchoice + + config LWIP_WND_SCALE + bool "Support TCP window scale" + depends on SPIRAM_TRY_ALLOCATE_WIFI_LWIP + default n + help + Enable this feature to support TCP window scaling. + + config LWIP_TCP_RCV_SCALE + int "Set TCP receiving window scaling factor" + depends on LWIP_WND_SCALE + range 0 14 + default 0 + help + Enable this feature to support TCP window scaling. + + config LWIP_TCP_RTO_TIME + int "Default TCP rto time" + default 3000 if !LWIP_TCP_HIGH_SPEED_RETRANSMISSION + default 1500 if LWIP_TCP_HIGH_SPEED_RETRANSMISSION + help + Set default TCP rto time for a reasonable initial rto. + In bad network environment, recommend set value of rto time to 1500. + + endmenu # TCP + + menu "UDP" + + config LWIP_MAX_UDP_PCBS + int "Maximum active UDP control blocks" + range 1 1024 + default 16 + help + The maximum number of active UDP "connections" (ie + UDP sockets sending/receiving data). + The practical maximum limit is determined by available + heap memory at runtime. + + config LWIP_UDP_RECVMBOX_SIZE + int "Default UDP receive mail box size" + default 6 + range 6 64 + help + Set UDP receive mail box size. The recommended value is 6. + + UDP receive mail box is a per socket mail box, when the application receives packets + from UDP socket, LWIP core firstly posts the packets to UDP receive mail box and the + application then fetches the packets from mail box. It means LWIP can caches maximum + UDP_RECCVMBOX_SIZE packets for each UDP socket, so the maximum possible cached UDP packets + for all UDP sockets is UDP_RECCVMBOX_SIZE multiples the maximum UDP socket number. In other + words, the bigger UDP_RECVMBOX_SIZE means more memory. + On the other hand, if the receive mail box is too small, the mail box may be full. If the + mail box is full, the LWIP drops the packets. So generally we need to make sure the UDP + receive mail box is big enough to avoid packet drop between LWIP core and application. + + endmenu # UDP + + menu "Checksums" + + config LWIP_CHECKSUM_CHECK_IP + bool "Enable LWIP IP checksums" + default n + help + Enable checksum checking for received IP messages + + config LWIP_CHECKSUM_CHECK_UDP + bool "Enable LWIP UDP checksums" + default n + help + Enable checksum checking for received UDP messages + + config LWIP_CHECKSUM_CHECK_ICMP + bool "Enable LWIP ICMP checksums" + default y + help + Enable checksum checking for received ICMP messages + + endmenu # Checksums + + config LWIP_TCPIP_TASK_STACK_SIZE + int "TCP/IP Task Stack Size" + default 3072 + # for high log levels, esp_netif API calls can end up + # a few calls deep and logging there can trigger a stack overflow + range 2048 65536 if LOG_DEFAULT_LEVEL < 4 + range 2560 65536 if LOG_DEFAULT_LEVEL >= 4 + help + Configure TCP/IP task stack size, used by LWIP to process multi-threaded TCP/IP operations. + Setting this stack too small will result in stack overflow crashes. + + choice LWIP_TCPIP_TASK_AFFINITY + prompt "TCP/IP task affinity" + default LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY + help + Allows setting LwIP tasks affinity, i.e. whether the task is pinned to + CPU0, pinned to CPU1, or allowed to run on any CPU. + Currently this applies to "TCP/IP" task and "Ping" task. + + config LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY + bool "No affinity" + config LWIP_TCPIP_TASK_AFFINITY_CPU0 + bool "CPU0" + config LWIP_TCPIP_TASK_AFFINITY_CPU1 + bool "CPU1" + depends on !FREERTOS_UNICORE + + endchoice + + config LWIP_TCPIP_TASK_AFFINITY + hex + default FREERTOS_NO_AFFINITY if LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY + default 0x0 if LWIP_TCPIP_TASK_AFFINITY_CPU0 + default 0x1 if LWIP_TCPIP_TASK_AFFINITY_CPU1 + + + menuconfig LWIP_PPP_SUPPORT + bool "Enable PPP support" + default n + help + Enable PPP stack. Now only PPP over serial is possible. + + config LWIP_PPP_ENABLE_IPV6 + bool "Enable IPV6 support for PPP connections (IPV6CP)" + depends on LWIP_PPP_SUPPORT && LWIP_IPV6 + default y + help + Enable IPV6 support in PPP for the local link between the DTE (processor) and DCE (modem). + There are some modems which do not support the IPV6 addressing in the local link. + If they are requested for IPV6CP negotiation, they may time out. + This would in turn fail the configuration for the whole link. + If your modem is not responding correctly to PPP Phase Network, try to disable IPV6 support. + + config LWIP_IPV6_MEMP_NUM_ND6_QUEUE + int "Max number of IPv6 packets to queue during MAC resolution" + depends on LWIP_IPV6 + range 3 20 + default 3 + help + Config max number of IPv6 packets to queue during MAC resolution. + + config LWIP_IPV6_ND6_NUM_NEIGHBORS + int "Max number of entries in IPv6 neighbor cache" + depends on LWIP_IPV6 + range 3 10 + default 5 + help + Config max number of entries in IPv6 neighbor cache + + config LWIP_PPP_NOTIFY_PHASE_SUPPORT + bool "Enable Notify Phase Callback" + depends on LWIP_PPP_SUPPORT + default n + help + Enable to set a callback which is called on change of the internal PPP state machine. + + config LWIP_PPP_PAP_SUPPORT + bool "Enable PAP support" + depends on LWIP_PPP_SUPPORT + default n + help + Enable Password Authentication Protocol (PAP) support + + config LWIP_PPP_CHAP_SUPPORT + bool "Enable CHAP support" + depends on LWIP_PPP_SUPPORT + default n + help + Enable Challenge Handshake Authentication Protocol (CHAP) support + + config LWIP_PPP_MSCHAP_SUPPORT + bool "Enable MSCHAP support" + depends on LWIP_PPP_SUPPORT + default n + help + Enable Microsoft version of the Challenge-Handshake Authentication Protocol (MSCHAP) support + + config LWIP_PPP_MPPE_SUPPORT + bool "Enable MPPE support" + depends on LWIP_PPP_SUPPORT + default n + help + Enable Microsoft Point-to-Point Encryption (MPPE) support + + config LWIP_PPP_SERVER_SUPPORT + bool "Enable PPP server support" + depends on LWIP_PPP_SUPPORT + default n + help + Enable to use PPP server + + config LWIP_PPP_VJ_HEADER_COMPRESSION + bool "Enable VJ IP Header compression" + depends on LWIP_PPP_SUPPORT + default y + help + Enable support for VJ header compression. + Please disable this if you're using NAPT on PPP interface, + since the compressed IP header might not be correctly interpreted + in NAT causing the compressed packet to be dropped. + + config LWIP_ENABLE_LCP_ECHO + bool "Enable LCP ECHO" + depends on LWIP_PPP_SUPPORT + default n + help + Enable LCP echo keepalive requests + + config LWIP_LCP_ECHOINTERVAL + int "Echo interval (s)" + range 0 1000000 + depends on LWIP_ENABLE_LCP_ECHO + default 3 + help + Interval in seconds between keepalive LCP echo requests, 0 to disable. + + config LWIP_LCP_MAXECHOFAILS + int "Maximum echo failures" + range 0 100000 + depends on LWIP_ENABLE_LCP_ECHO + default 3 + help + Number of consecutive unanswered echo requests before failure is indicated. + + config LWIP_PPP_DEBUG_ON + bool "Enable PPP debug log output" + depends on LWIP_PPP_SUPPORT + default n + help + Enable PPP debug log output + + config LWIP_USE_EXTERNAL_MBEDTLS + bool "Use mbedTLS instead of internal polarSSL" + depends on LWIP_PPP_SUPPORT + depends on !LWIP_PPP_MPPE_SUPPORT && !LWIP_PPP_MSCHAP_SUPPORT + default n + help + This option uses mbedTLS crypto functions (instead of internal PolarSSL + implementation) for PPP authentication modes (PAP, CHAP, etc.). + You can use this option to address symbol duplication issues, since + the internal functions are not namespaced (e.g. md5_init()). + + menuconfig LWIP_SLIP_SUPPORT + bool "Enable SLIP support (new/experimental)" + default n + help + Enable SLIP stack. Now only SLIP over serial is possible. + + SLIP over serial support is experimental and unsupported. + + config LWIP_SLIP_DEBUG_ON + bool "Enable SLIP debug log output" + depends on LWIP_SLIP_SUPPORT + default n + help + Enable SLIP debug log output + + menu "ICMP" + + config LWIP_ICMP + bool "ICMP: Enable ICMP" + default y + help + Enable ICMP module for check network stability + + config LWIP_MULTICAST_PING + bool "Respond to multicast pings" + default n + depends on LWIP_ICMP6 || LWIP_ICMP + + config LWIP_BROADCAST_PING + bool "Respond to broadcast pings" + default n + depends on LWIP_ICMP + + endmenu # ICMP + + menu "LWIP RAW API" + + config LWIP_MAX_RAW_PCBS + int "Maximum LWIP RAW PCBs" + range 1 1024 + default 16 + help + The maximum number of simultaneously active LWIP + RAW protocol control blocks. The practical maximum + limit is determined by available heap memory at runtime. + + endmenu # LWIP RAW API + + menu "SNTP" + + config LWIP_SNTP_MAX_SERVERS + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maximum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. + + config LWIP_DHCP_GET_NTP_SRV + bool "Request NTP servers from DHCP" + default n + help + If enabled, LWIP will add 'NTP' to Parameter-Request Option sent via DHCP-request. + DHCP server might reply with an NTP server address in option 42. + SNTP callback for such replies should be set accordingly (see sntp_servermode_dhcp() func.) + + config LWIP_DHCP_MAX_NTP_SERVERS + int "Maximum number of NTP servers acquired via DHCP" + default 1 + range 1 16 + depends on LWIP_DHCP_GET_NTP_SRV + help + Set maximum number of NTP servers acquired via DHCP-offer. + Should be less or equal to "Maximum number of NTP servers", any extra servers would be just ignored. + + config LWIP_SNTP_UPDATE_DELAY + int "Request interval to update time (ms)" + range 15000 4294967295 + default 3600000 + help + This option allows you to set the time update period via SNTP. + Default is 1 hour. Must not be below 15 seconds by specification. + (SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds). + + config LWIP_SNTP_STARTUP_DELAY + bool "Enable SNTP startup delay" + default y + help + It is recommended (RFC 4330) to delay the initial request after by a random timeout from 1 to 5 minutes + to reduce potential load of NTP servers after simultaneous power-up of many devices. + This option disables this initial delay. Please use this option with care, it could improve + a single device responsiveness but might cause peaks on the network after reset. + Another option to address responsiveness of devices while using the initial random delay + is to adjust LWIP_SNTP_MAXIMUM_STARTUP_DELAY. + + config LWIP_SNTP_MAXIMUM_STARTUP_DELAY + int "Maximum startup delay (ms)" + depends on LWIP_SNTP_STARTUP_DELAY + range 100 300000 + default 5000 + help + RFC 4330 recommends a startup delay before sending the initial request. + LWIP calculates this delay to a random number of milliseconds between 0 and this value. + + endmenu # SNTP + + menu "DNS" + + config LWIP_DNS_MAX_HOST_IP + int "Maximum number of IP addresses per host" + default 1 + help + Maximum number of IP addresses that can be returned by DNS queries for a single host. + + config LWIP_DNS_MAX_SERVERS + int "Maximum number of DNS servers" + default 3 + range 1 4 + help + Set maximum number of DNS servers. + If fallback DNS servers are supported, + the number of DNS servers needs to be greater than or equal to 3. + + config LWIP_FALLBACK_DNS_SERVER_SUPPORT + bool "Enable DNS fallback server support" + default n + depends on LWIP_DNS_MAX_SERVERS >= 3 + help + Enable this feature to support DNS fallback server. + + config LWIP_FALLBACK_DNS_SERVER_ADDRESS + string "DNS fallback server address" + default "114.114.114.114" + depends on LWIP_FALLBACK_DNS_SERVER_SUPPORT + help + This option allows you to config dns fallback server address. + + config LWIP_DNS_SETSERVER_WITH_NETIF + bool "Enable DNS server settings with netif" + default n + help + This option allows collecting DNS server settings per netif using + configurable callback function. + It's typically used with CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF + which configures a callback to collect the DNS info on esp_netif layer. + + endmenu # DNS + + config LWIP_BRIDGEIF_MAX_PORTS + int "Maximum number of bridge ports" + default 7 + range 1 63 + help + Set maximum number of ports a bridge can consists of. + + config LWIP_ESP_LWIP_ASSERT + bool "Enable LWIP ASSERT checks" + default y + depends on !COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE + help + Enable this option keeps LWIP assertion checks enabled. + It is recommended to keep this option enabled. + + If asserts are disabled for the entire project, they are also disabled + for LWIP and this option is ignored. + + menu "Hooks" + + choice LWIP_HOOK_TCP_ISN + prompt "TCP ISN Hook" + default LWIP_HOOK_TCP_ISN_DEFAULT + help + Enables to define a TCP ISN hook to randomize initial sequence + number in TCP connection. + The default TCP ISN algorithm used in IDF (standardized in RFC 6528) + produces ISN by combining an MD5 of the new TCP id and a stable + secret with the current time. + This is because the lwIP implementation (`tcp_next_iss`) is not + very strong, as it does not take into consideration any platform + specific entropy source. + + Set to LWIP_HOOK_TCP_ISN_CUSTOM to provide custom implementation. + Set to LWIP_HOOK_TCP_ISN_NONE to use lwIP implementation. + + + config LWIP_HOOK_TCP_ISN_NONE + bool "No hook declared" + config LWIP_HOOK_TCP_ISN_DEFAULT + bool "Default implementation" + config LWIP_HOOK_TCP_ISN_CUSTOM + bool "Custom implementation" + + endchoice + + choice LWIP_HOOK_IP6_ROUTE + prompt "IPv6 route Hook" + depends on LWIP_IPV6 + default LWIP_HOOK_IP6_ROUTE_NONE + help + Enables custom IPv6 route hook. + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_IP6_ROUTE_NONE + bool "No hook declared" + config LWIP_HOOK_IP6_ROUTE_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_IP6_ROUTE_CUSTOM + bool "Custom implementation" + + endchoice + + choice LWIP_HOOK_ND6_GET_GW + prompt "IPv6 get gateway Hook" + depends on LWIP_IPV6 + default LWIP_HOOK_ND6_GET_GW_NONE + help + Enables custom IPv6 route hook. + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_ND6_GET_GW_NONE + bool "No hook declared" + config LWIP_HOOK_ND6_GET_GW_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_ND6_GET_GW_CUSTOM + bool "Custom implementation" + + endchoice + + choice LWIP_HOOK_IP6_SELECT_SRC_ADDR + prompt "IPv6 source address selection Hook" + depends on LWIP_IPV6 + default LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE + help + Enables custom IPv6 source address selection. + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE + bool "No hook declared" + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM + bool "Custom implementation" + + endchoice + + choice LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE + prompt "Netconn external resolve Hook" + default LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE + help + Enables custom DNS resolve hook (without callback). + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE + bool "No hook declared" + config LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM + bool "Custom implementation" + + endchoice + + config LWIP_HOOK_DNS_EXTERNAL_RESOLVE_SELECT_CUSTOM + bool + default n + help + This hidden option helps configure the DNS external resolve + hook for external components like OpenThread. It ensures that + `LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM` is selected without directly + adding a dependency in the choice construct. + + choice LWIP_HOOK_DNS_EXTERNAL_RESOLVE + prompt "DNS external resolve Hook" + default LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM if LWIP_HOOK_DNS_EXTERNAL_RESOLVE_SELECT_CUSTOM + help + Enables custom DNS resolve hook (with callback). + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_DNS_EXT_RESOLVE_NONE + bool "No hook declared" + config LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM + bool "Custom implementation" + + endchoice + + choice LWIP_HOOK_IP6_INPUT + prompt "IPv6 packet input" + depends on LWIP_IPV6 + default LWIP_HOOK_IP6_INPUT_NONE + help + Enables custom IPv6 packet input. + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_IP6_INPUT_NONE + bool "No hook declared" + config LWIP_HOOK_IP6_INPUT_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_IP6_INPUT_CUSTOM + bool "Custom implementation" + + endchoice + + endmenu # Hooks + + menuconfig LWIP_DEBUG + bool "Enable LWIP Debug" + default n + help + Enabling this option allows different kinds of lwIP debug output. + + All lwIP debug features increase the size of the final binary. + + config LWIP_DEBUG_ESP_LOG + bool "Route LWIP debugs through ESP_LOG interface" + depends on LWIP_DEBUG + default n + help + Enabling this option routes all enabled LWIP debugs through ESP_LOGD. + + config LWIP_NETIF_DEBUG + bool "Enable netif debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_PBUF_DEBUG + bool "Enable pbuf debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_ETHARP_DEBUG + bool "Enable etharp debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_API_LIB_DEBUG + bool "Enable api lib debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_SOCKETS_DEBUG + bool "Enable socket debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_IP_DEBUG + bool "Enable IP debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_ICMP_DEBUG + bool "Enable ICMP debug messages" + depends on LWIP_DEBUG && LWIP_ICMP + default n + + config LWIP_DHCP_STATE_DEBUG + bool "Enable DHCP state tracking" + depends on LWIP_DEBUG + default n + + config LWIP_DHCP_DEBUG + bool "Enable DHCP debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_IP6_DEBUG + bool "Enable IP6 debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_ICMP6_DEBUG + bool "Enable ICMP6 debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_TCP_DEBUG + bool "Enable TCP debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_UDP_DEBUG + bool "Enable UDP debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_SNTP_DEBUG + bool "Enable SNTP debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_DNS_DEBUG + bool "Enable DNS debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_NAPT_DEBUG + bool "Enable NAPT debug messages" + depends on LWIP_DEBUG && LWIP_IPV4_NAPT + default n + + config LWIP_BRIDGEIF_DEBUG + bool "Enable bridge generic debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_BRIDGEIF_FDB_DEBUG + bool "Enable bridge FDB debug messages" + depends on LWIP_DEBUG + default n + + config LWIP_BRIDGEIF_FW_DEBUG + bool "Enable bridge forwarding debug messages" + depends on LWIP_DEBUG + default n + +endmenu diff --git a/components/lwip/apps/dhcpserver/dhcpserver.c b/components/lwip/apps/dhcpserver/dhcpserver.c new file mode 100644 index 000000000..2d961414f --- /dev/null +++ b/components/lwip/apps/dhcpserver/dhcpserver.c @@ -0,0 +1,1538 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "lwip/dhcp.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/udp.h" +#include "lwip/mem.h" +#include "lwip/ip_addr.h" +#include "lwip/timeouts.h" +#include "lwip/etharp.h" +#include "lwip/prot/ethernet.h" + +#include "dhcpserver/dhcpserver.h" +#include "dhcpserver/dhcpserver_options.h" + +#if ESP_DHCPS + +#ifdef LWIP_HOOK_FILENAME +#include LWIP_HOOK_FILENAME +#endif + +#ifndef LWIP_HOOK_DHCPS_POST_APPEND_OPTS +#define LWIP_HOOK_DHCPS_POST_APPEND_OPTS(netif, dhcps, state, pp_opts) +#endif + +#define BOOTP_BROADCAST 0x8000 +#define BROADCAST_BIT_IS_SET(flag) (flag & BOOTP_BROADCAST) + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPS_SERVER_PORT 67 +#define DHCPS_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_INTERFACE_MTU 26 +#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31 +#define DHCP_OPTION_BROADCAST_ADDRESS 28 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +//#define USE_CLASS_B_NET 1 +#define DHCPS_DEBUG 0 +#define DHCPS_LOG printf + +#define IS_INVALID_SUBNET_MASK(x) (((x-1) | x) != 0xFFFFFFFF) +/* Notes: +* CIDR eliminates the traditional Class A, Class B and Class C addresses. + */ +#define IP_CLASS_HOST_NUM(mask) (0xffffffff & ~mask) +#define DHCP_CHECK_SUBNET_MASK_IP(mask) \ + do { \ + if (IS_INVALID_SUBNET_MASK(mask)) { \ + DHCPS_LOG("dhcps: Illegal subnet mask.\n"); \ + return ERR_ARG; \ + } \ + } while (0) + +#define DHCP_CHECK_IP_MATCH_SUBNET_MASK(mask, ip) \ + u32_t start_ip = 0; \ + u32_t end_ip = 0; \ + do { \ + start_ip = ip & mask; \ + end_ip = start_ip | ~mask; \ + if (ip == end_ip || ip == start_ip) { \ + DHCPS_LOG("dhcps: ip address and subnet mask do not match.\n"); \ + return ERR_ARG; \ + } \ + } while (0) + +#define MAX_STATION_NUM CONFIG_LWIP_DHCPS_MAX_STATION_NUM + +#define DHCPS_STATE_OFFER 1 +#define DHCPS_STATE_DECLINE 2 +#define DHCPS_STATE_ACK 3 +#define DHCPS_STATE_NAK 4 +#define DHCPS_STATE_IDLE 5 +#define DHCPS_STATE_RELEASE 6 + +typedef enum { + DHCPS_HANDLE_CREATED = 0, + DHCPS_HANDLE_STARTED, + DHCPS_HANDLE_STOPPED, + DHCPS_HANDLE_DELETE_PENDING, +} dhcps_handle_state; + +typedef struct list_node { + void *pnode; + struct list_node *pnext; +} list_node; + +typedef struct { + ip4_addr_t ip; + ip4_addr_t netmask; + ip4_addr_t gw; +} ip_info_t; +//////////////////////////////////////////////////////////////////////////////////// + +static const u32_t magic_cookie = 0x63538263; + +struct dhcps_t { + struct netif *dhcps_netif; + ip4_addr_t broadcast_dhcps; + ip4_addr_t server_address; + ip4_addr_t dns_server; + ip4_addr_t client_address; + ip4_addr_t client_address_plus; + ip4_addr_t dhcps_mask; + list_node *plist; + bool renew; + dhcps_lease_t dhcps_poll; + dhcps_time_t dhcps_lease_time; + dhcps_offer_t dhcps_offer; + dhcps_offer_t dhcps_dns; + dhcps_cb_t dhcps_cb; + void* dhcps_cb_arg; + struct udp_pcb *dhcps_pcb; + dhcps_handle_state state; +}; + + +static void dhcps_tmr(void* arg); + + +dhcps_t *dhcps_new(void) +{ + dhcps_t *dhcps = mem_calloc(1, sizeof(dhcps_t)); + + if (dhcps == NULL) { + return NULL; + } + dhcps->dhcps_netif = NULL; + dhcps->dns_server.addr = 0; +#ifdef USE_CLASS_B_NET + dhcps->dhcps_mask.addr = PP_HTONL(LWIP_MAKEU32(255, 240, 0, 0)); +#else + dhcps->dhcps_mask.addr = PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0)); +#endif + dhcps->plist = NULL; + dhcps->renew = false; + dhcps->dhcps_lease_time = DHCPS_LEASE_TIME_DEF; + dhcps->dhcps_offer = 0xFF; + dhcps->dhcps_dns = 0x00; + dhcps->dhcps_pcb = NULL; + dhcps->state = DHCPS_HANDLE_CREATED; + return dhcps; +} + +void dhcps_delete(dhcps_t *dhcps) +{ + if (dhcps) { + if (dhcps->state == DHCPS_HANDLE_STARTED) { + // if the dhcp-server has started already, we have to postpone the deletion + dhcps->state = DHCPS_HANDLE_DELETE_PENDING; + } else { + // otherwise, we're free to delete the handle immediately + free(dhcps); + } + } +} + +static void get_ip_info(struct netif * netif, ip_info_t *ip_info) +{ + if (netif != NULL && netif_is_up(netif)) { + ip4_addr_set(&ip_info->ip, ip_2_ip4(&netif->ip_addr)); + ip4_addr_set(&ip_info->netmask, ip_2_ip4(&netif->netmask)); + ip4_addr_set(&ip_info->gw, ip_2_ip4(&netif->gw)); + } +} + +/****************************************************************************** + * FunctionName : dhcps_option_info + * Description : get the DHCP message option info + * Parameters : op_id -- DHCP message option id + * opt_len -- DHCP message option length + * Returns : DHCP message option addr +*******************************************************************************/ +void *dhcps_option_info(dhcps_t *dhcps, u8_t op_id, u32_t opt_len) +{ + void *option_arg = NULL; + if (dhcps == NULL) { + return NULL; + } + + switch (op_id) { + case IP_ADDRESS_LEASE_TIME: + if (opt_len == sizeof(dhcps_time_t)) { + option_arg = &dhcps->dhcps_lease_time; + } + + break; + + case REQUESTED_IP_ADDRESS: + if (opt_len == sizeof(dhcps_lease_t)) { + option_arg = &dhcps->dhcps_poll; + } + + break; + + case ROUTER_SOLICITATION_ADDRESS: + if (opt_len == sizeof(dhcps_offer_t)) { + option_arg = &dhcps->dhcps_offer; + } + + break; + + case DOMAIN_NAME_SERVER: + if (opt_len == sizeof(dhcps_offer_t)) { + option_arg = &dhcps->dhcps_dns; + } + + break; + case SUBNET_MASK: + if (opt_len == sizeof(dhcps->dhcps_mask)) { + option_arg = &dhcps->dhcps_mask; + } + + break; + default: + break; + } + + return option_arg; +} + +/****************************************************************************** + * FunctionName : dhcps_set_option_info + * Description : set the DHCP message option info + * Parameters : op_id -- DHCP message option id + * opt_info -- DHCP message option info + * opt_len -- DHCP message option length + * Returns : none +*******************************************************************************/ +err_t dhcps_set_option_info(dhcps_t *dhcps, u8_t op_id, void *opt_info, u32_t opt_len) +{ + if (dhcps == NULL || opt_info == NULL) { + return ERR_ARG; + } + switch (op_id) { + case IP_ADDRESS_LEASE_TIME: + if (opt_len == sizeof(dhcps_time_t)) { + dhcps->dhcps_lease_time = *(dhcps_time_t *)opt_info; + } + + break; + + case REQUESTED_IP_ADDRESS: + if (opt_len == sizeof(dhcps_lease_t)) { + dhcps->dhcps_poll = *(dhcps_lease_t *)opt_info; + } + + break; + + case ROUTER_SOLICITATION_ADDRESS: + if (opt_len == sizeof(dhcps_offer_t)) { + dhcps->dhcps_offer = *(dhcps_offer_t *)opt_info; + } + + break; + + case DOMAIN_NAME_SERVER: + if (opt_len == sizeof(dhcps_offer_t)) { + dhcps->dhcps_dns = *(dhcps_offer_t *)opt_info; + } + break; + + case SUBNET_MASK: + if (opt_len == sizeof(dhcps->dhcps_mask)) { + dhcps->dhcps_mask = *(ip4_addr_t *)opt_info; + } + + + default: + break; + } + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : node_insert_to_list + * Description : insert the node to the list + * Parameters : phead -- the head node of the list + * pinsert -- the insert node of the list + * Returns : none +*******************************************************************************/ +static void node_insert_to_list(list_node **phead, list_node *pinsert) +{ + list_node *plist = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + struct dhcps_pool *pdhcps_node = NULL; + + if (*phead == NULL) { + *phead = pinsert; + } else { + plist = *phead; + pdhcps_node = pinsert->pnode; + pdhcps_pool = plist->pnode; + + if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist; + *phead = pinsert; + } else { + while (plist->pnext != NULL) { + pdhcps_pool = plist->pnext->pnode; + + if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) { + pinsert->pnext = plist->pnext; + plist->pnext = pinsert; + break; + } + + plist = plist->pnext; + } + + if (plist->pnext == NULL) { + plist->pnext = pinsert; + } + } + } + +// pinsert->pnext = NULL; +} + +/****************************************************************************** + * FunctionName : node_delete_from_list + * Description : remove the node from list + * Parameters : phead -- the head node of the list + * pdelete -- the remove node of the list + * Returns : none +*******************************************************************************/ +void node_remove_from_list(list_node **phead, list_node *pdelete) +{ + list_node *plist = NULL; + + plist = *phead; + + if (plist == NULL) { + *phead = NULL; + } else { + if (plist == pdelete) { + // Note: Ignoring the "use after free" warnings, as it could only happen + // if the linked list contains loops + *phead = plist->pnext; // NOLINT(clang-analyzer-unix.Malloc) + pdelete->pnext = NULL; + } else { + while (plist != NULL) { + if (plist->pnext == pdelete) { // NOLINT(clang-analyzer-unix.Malloc) + plist->pnext = pdelete->pnext; + pdelete->pnext = NULL; + } + + plist = plist->pnext; + } + } + } +} + +/****************************************************************************** + * FunctionName : add_msg_type + * Description : add TYPE option of DHCP message + * Parameters : optptr -- the addr of DHCP message option + * Returns : the addr of DHCP message option +*******************************************************************************/ +static u8_t *add_msg_type(u8_t *optptr, u8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} + +/****************************************************************************** + * FunctionName : add_offer_options + * Description : add OFFER option of DHCP message + * Parameters : optptr -- the addr of DHCP message option + * Returns : the addr of DHCP message option +*******************************************************************************/ +static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr) +{ + ip4_addr_t ipadd; + + ipadd.addr = *((u32_t *) &dhcps->server_address); + + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = 4; + *optptr++ = ip4_addr1(&dhcps->dhcps_mask); + *optptr++ = ip4_addr2(&dhcps->dhcps_mask); + *optptr++ = ip4_addr3(&dhcps->dhcps_mask); + *optptr++ = ip4_addr4(&dhcps->dhcps_mask); + + *optptr++ = DHCP_OPTION_LEASE_TIME; + *optptr++ = 4; + *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 24) & 0xFF; + *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 16) & 0xFF; + *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 8) & 0xFF; + *optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 0) & 0xFF; + + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + *optptr++ = ip4_addr1(&ipadd); + *optptr++ = ip4_addr2(&ipadd); + *optptr++ = ip4_addr3(&ipadd); + *optptr++ = ip4_addr4(&ipadd); + + if (dhcps_router_enabled(dhcps->dhcps_offer)) { + ip_info_t if_ip = { 0 }; + get_ip_info(dhcps->dhcps_netif, &if_ip); + + ip4_addr_t* gw_ip = (ip4_addr_t*)&if_ip.gw; + + if (!ip4_addr_isany_val(*gw_ip)) { + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = 4; + *optptr++ = ip4_addr1(gw_ip); + *optptr++ = ip4_addr2(gw_ip); + *optptr++ = ip4_addr3(gw_ip); + *optptr++ = ip4_addr4(gw_ip); + } + } + + *optptr++ = DHCP_OPTION_DNS_SERVER; + *optptr++ = 4; + if (dhcps_dns_enabled(dhcps->dhcps_dns)) { + *optptr++ = ip4_addr1(&dhcps->dns_server); + *optptr++ = ip4_addr2(&dhcps->dns_server); + *optptr++ = ip4_addr3(&dhcps->dns_server); + *optptr++ = ip4_addr4(&dhcps->dns_server); + }else { + *optptr++ = ip4_addr1(&ipadd); + *optptr++ = ip4_addr2(&ipadd); + *optptr++ = ip4_addr3(&ipadd); + *optptr++ = ip4_addr4(&ipadd); + } + + ip4_addr_t broadcast_addr = { .addr = (ipadd.addr & dhcps->dhcps_mask.addr) | ~dhcps->dhcps_mask.addr }; + *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; + *optptr++ = 4; + *optptr++ = ip4_addr1(&broadcast_addr); + *optptr++ = ip4_addr2(&broadcast_addr); + *optptr++ = ip4_addr3(&broadcast_addr); + *optptr++ = ip4_addr4(&broadcast_addr); + + *optptr++ = DHCP_OPTION_INTERFACE_MTU; + *optptr++ = 2; + *optptr++ = 0x05; + *optptr++ = 0xdc; + + *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY; + *optptr++ = 1; + *optptr++ = 0x00; + + *optptr++ = 43; + *optptr++ = 6; + + *optptr++ = 0x01; + *optptr++ = 4; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x00; + *optptr++ = 0x02; + + return optptr; +} + +/****************************************************************************** + * FunctionName : add_end + * Description : add end option of DHCP message + * Parameters : optptr -- the addr of DHCP message option + * Returns : the addr of DHCP message option +*******************************************************************************/ +static u8_t *add_end(u8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} + +/****************************************************************************** + * FunctionName : create_msg + * Description : create response message + * Parameters : m -- DHCP message info + * Returns : none +*******************************************************************************/ +static void create_msg(dhcps_t *dhcps, struct dhcps_msg *m) +{ + ip4_addr_t client; + + + client.addr = *((uint32_t *) &dhcps->client_address); + + m->op = DHCP_REPLY; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = 6; + +#if !ETHARP_SUPPORT_STATIC_ENTRIES + /* If the DHCP server does not support sending unicast message to the client, + * need to set the 'flags' field to broadcast */ + m->flags = htons(BOOTP_BROADCAST); +#endif + + memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); + memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie)); +} + +/****************************************************************************** + * FunctionName : dhcps_response_ip_set + * Description : set the ip address for sending to the DHCP client + * Parameters : m -- DHCP message info + * ip4_out -- ip address for sending + * Returns : none +*******************************************************************************/ +static void dhcps_response_ip_set(dhcps_t *dhcps, struct dhcps_msg *m, ip4_addr_t *ip4_out) +{ +#if ETHARP_SUPPORT_STATIC_ENTRIES + ip4_addr_t ip4_giaddr; + ip4_addr_t ip4_ciaddr; + ip4_addr_t ip4_yiaddr; + + struct eth_addr chaddr; + memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr)); + memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr)); + memcpy((char *)&ip4_ciaddr.addr, (char *)m->ciaddr, sizeof(m->ciaddr)); + memcpy((char *)&ip4_yiaddr.addr, (char *)m->yiaddr, sizeof(m->yiaddr)); + + if (!ip4_addr_isany_val(ip4_giaddr)) { + /* If the 'giaddr' field is non-zero, send return message to the address in 'giaddr'. (RFC 2131)*/ + ip4_addr_set(ip4_out, &ip4_giaddr); + /* add the IP<->MAC as static entry into the arp table. */ + etharp_add_static_entry(&ip4_giaddr, &chaddr); + } else { + if (!ip4_addr_isany_val(ip4_ciaddr)) { + /* If the 'giaddr' field is zero and the 'ciaddr' is nonzero, + * the server unicasts DHCPOFFER and DHCPACK message to the address in 'ciaddr'*/ + ip4_addr_set(ip4_out, &ip4_ciaddr); + etharp_add_static_entry(&ip4_ciaddr, &chaddr); + } else if (!BROADCAST_BIT_IS_SET(htons(m->flags))) { + /* If the 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is not set, + * the server unicasts DHCPOFFER and DHCPACK message to the client's hardware address and + * 'yiaddr' address. */ + ip4_addr_set(ip4_out, &ip4_yiaddr); + etharp_add_static_entry(&ip4_yiaddr, &chaddr); + } else { + /* The server broadcast DHCPOFFER and DHCPACK message to 0xffffffff*/ + ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps); + } + } +#else + ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps); +#endif +} + + +struct pbuf * dhcps_pbuf_alloc(u16_t len) +{ + u16_t mlen = sizeof(struct dhcps_msg); + + if (len > mlen) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: len=%d mlen=%d", len, mlen); +#endif + mlen = len; + } + + return pbuf_alloc(PBUF_TRANSPORT, mlen, PBUF_RAM); +} + +/****************************************************************************** + * FunctionName : send_offer + * Description : DHCP message OFFER Response + * Parameters : m -- DHCP message info + * Returns : none +*******************************************************************************/ +static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) +{ + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt = 0; + u16_t i; +#if DHCPS_DEBUG + err_t SendOffer_err_t; +#endif + create_msg(dhcps, m); + + end = add_msg_type(&m->options[4], DHCPOFFER); + end = add_offer_options(dhcps, end); + LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPOFFER, &end) + end = add_end(end); + + p = dhcps_pbuf_alloc(len); +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_offer>>p->ref = %d\n", p->ref); +#endif + + if (p != NULL) { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_offer>>pbuf_alloc succeed\n"); + DHCPS_LOG("dhcps: send_offer>>p->tot_len = %d\n", p->tot_len); + DHCPS_LOG("dhcps: send_offer>>p->len = %d\n", p->len); +#endif + q = p; + + while (q != NULL) { + data = (u8_t *)q->payload; + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t *) m)[cnt++]; +#if DHCPS_DEBUG + DHCPS_LOG("%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + DHCPS_LOG("\n"); + } + +#endif + } + + q = q->next; + } + } else { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_offer>>pbuf_alloc failed\n"); +#endif + return; + } + + ip_addr_t ip_temp = IPADDR4_INIT(0x0); + dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp)); +#if DHCPS_DEBUG + SendOffer_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); + DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t); +#else + udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); +#endif + +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + + if (p->ref != 0) { +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_offer>>free pbuf\n"); +#endif + pbuf_free(p); + } +} + +/****************************************************************************** + * FunctionName : send_nak + * Description : DHCP message NACK Response + * Parameters : m -- DHCP message info + * Returns : none +*******************************************************************************/ +static void send_nak(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) +{ + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt = 0; + u16_t i; +#if DHCPS_DEBUG + err_t SendNak_err_t; +#endif + create_msg(dhcps, m); + + end = add_msg_type(&m->options[4], DHCPNAK); + LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPNAK, &end) + end = add_end(end); + + p = dhcps_pbuf_alloc(len); +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_nak>>p->ref = %d\n", p->ref); +#endif + + if (p != NULL) { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_nak>>pbuf_alloc succeed\n"); + DHCPS_LOG("dhcps: send_nak>>p->tot_len = %d\n", p->tot_len); + DHCPS_LOG("dhcps: send_nak>>p->len = %d\n", p->len); +#endif + q = p; + + while (q != NULL) { + data = (u8_t *)q->payload; + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t *) m)[cnt++]; +#if DHCPS_DEBUG + DHCPS_LOG("%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + DHCPS_LOG("\n"); + } + +#endif + } + + q = q->next; + } + } else { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_nak>>pbuf_alloc failed\n"); +#endif + return; + } + + ip_addr_t ip_temp = IPADDR4_INIT(0x0); + +#if ETHARP_SUPPORT_STATIC_ENTRIES + ip4_addr_t ip4_giaddr; + struct eth_addr chaddr; + memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr)); + memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr)); + + if (!ip4_addr_isany_val(ip4_giaddr)) { + ip4_addr_set(ip_2_ip4(&ip_temp), &ip4_giaddr); + /* add the IP<->MAC as static entry into the arp table. */ + etharp_add_static_entry(&ip4_giaddr, &chaddr); + } else { + /* when 'giaddr' is zero, the server broadcasts any DHCPNAK message to 0xffffffff. (RFC 2131)*/ + ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); + } +#else + ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); +#endif + +#if DHCPS_DEBUG + SendNak_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); + DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t); +#else + udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); +#endif + +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + + if (p->ref != 0) { +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_nak>>free pbuf\n"); +#endif + pbuf_free(p); + } +} + +/****************************************************************************** + * FunctionName : send_ack + * Description : DHCP message ACK Response + * Parameters : m -- DHCP message info + * Returns : none +*******************************************************************************/ +static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) +{ + u8_t *end; + struct pbuf *p, *q; + u8_t *data; + u16_t cnt = 0; + u16_t i; + err_t SendAck_err_t; + create_msg(dhcps, m); + + end = add_msg_type(&m->options[4], DHCPACK); + end = add_offer_options(dhcps, end); + LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPACK, &end) + end = add_end(end); + + p = dhcps_pbuf_alloc(len); +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_ack>>p->ref = %d\n", p->ref); +#endif + + if (p != NULL) { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_ack>>pbuf_alloc succeed\n"); + DHCPS_LOG("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len); + DHCPS_LOG("dhcps: send_ack>>p->len = %d\n", p->len); +#endif + q = p; + + while (q != NULL) { + data = (u8_t *)q->payload; + + for (i = 0; i < q->len; i++) { + data[i] = ((u8_t *) m)[cnt++]; +#if DHCPS_DEBUG + DHCPS_LOG("%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + DHCPS_LOG("\n"); + } + +#endif + } + + q = q->next; + } + } else { + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_ack>>pbuf_alloc failed\n"); +#endif + return; + } + + ip_addr_t ip_temp = IPADDR4_INIT(0x0); + dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp)); + SendAck_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n", SendAck_err_t); +#endif + +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + + if (SendAck_err_t == ERR_OK) { + dhcps->dhcps_cb(dhcps->dhcps_cb_arg, m->yiaddr, m->chaddr); + } + + if (p->ref != 0) { +#if DHCPS_DEBUG + DHCPS_LOG("udhcp: send_ack>>free pbuf\n"); +#endif + pbuf_free(p); + } +} + +/****************************************************************************** + * FunctionName : parse_options + * Description : parse DHCP message options + * Parameters : optptr -- DHCP message option info + * len -- DHCP message option length + * Returns : none +*******************************************************************************/ +static u8_t parse_options(dhcps_t *dhcps, u8_t *optptr, s16_t len) +{ + ip4_addr_t client; + bool is_dhcp_parse_end = false; + struct dhcps_state s; + + client.addr = *((uint32_t *) &dhcps->client_address); + + u8_t *end = optptr + len; + u16_t type = 0; + + s.state = DHCPS_STATE_IDLE; + + while (optptr < end) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: (s16_t)*optptr = %d\n", (s16_t)*optptr); +#endif + + switch ((s16_t) *optptr) { + + case DHCP_OPTION_MSG_TYPE: //53 + type = *(optptr + 2); + break; + + case DHCP_OPTION_REQ_IPADDR://50 + if (memcmp((char *) &client.addr, (char *) optptr + 2, 4) == 0) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\n"); +#endif + s.state = DHCPS_STATE_ACK; + } else { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\n"); +#endif + s.state = DHCPS_STATE_NAK; + } + + break; + + case DHCP_OPTION_END: { + is_dhcp_parse_end = true; + } + break; + } + + if (is_dhcp_parse_end) { + break; + } + + optptr += optptr[1] + 2; + } + + switch (type) { + + case DHCPDISCOVER://1 + s.state = DHCPS_STATE_OFFER; +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCPD_STATE_OFFER\n"); +#endif + break; + + case DHCPREQUEST://3 + if (!(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK)) { + if (dhcps->renew == true) { + s.state = DHCPS_STATE_ACK; + } else { + s.state = DHCPS_STATE_NAK; + } + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCPD_STATE_NAK\n"); +#endif + } + + break; + + case DHCPDECLINE://4 + s.state = DHCPS_STATE_IDLE; +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + + case DHCPRELEASE://7 + s.state = DHCPS_STATE_RELEASE; +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: DHCPD_STATE_IDLE\n"); +#endif + break; + } + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: return s.state = %d\n", s.state); +#endif + return s.state; +} + +/****************************************************************************** + * FunctionName : parse_msg + * Description : parse DHCP message from netif + * Parameters : m -- DHCP message info + * len -- DHCP message length + * Returns : DHCP message type +*******************************************************************************/ +static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) +{ + u32_t lease_timer = (dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT)/DHCPS_COARSE_TIMER_SECS; + + if (memcmp((char *)m->options, &magic_cookie, sizeof(magic_cookie)) == 0) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: len = %d\n", len); +#endif + ip4_addr_t addr_tmp; + + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pnode = NULL; + list_node *pback_node = NULL; + ip4_addr_t first_address; + bool flag = false; + + first_address.addr = dhcps->dhcps_poll.start_ip.addr; + dhcps->client_address.addr = dhcps->client_address_plus.addr; + dhcps->renew = false; + + if (dhcps->plist != NULL) { + for (pback_node = dhcps->plist; pback_node != NULL; pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + + if (memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0) { + if (memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) { + dhcps->renew = true; + } + + dhcps->client_address.addr = pdhcps_pool->ip.addr; + pdhcps_pool->lease_timer = lease_timer; + pnode = pback_node; + goto POOL_CHECK; + } else if (pdhcps_pool->ip.addr == dhcps->client_address_plus.addr) { + addr_tmp.addr = htonl(dhcps->client_address_plus.addr); + addr_tmp.addr++; + dhcps->client_address_plus.addr = htonl(addr_tmp.addr); + dhcps->client_address.addr = dhcps->client_address_plus.addr; + } + + if (flag == false) { // search the first unused ip + if (first_address.addr < pdhcps_pool->ip.addr) { + flag = true; + } else { + addr_tmp.addr = htonl(first_address.addr); + addr_tmp.addr++; + first_address.addr = htonl(addr_tmp.addr); + } + } + } + } else { + dhcps->client_address.addr = dhcps->dhcps_poll.start_ip.addr; + } + + if (dhcps->client_address_plus.addr > dhcps->dhcps_poll.end_ip.addr) { + dhcps->client_address.addr = first_address.addr; + } + + if (dhcps->client_address.addr > dhcps->dhcps_poll.end_ip.addr) { + dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr; + pdhcps_pool = NULL; + pnode = NULL; + } else { + pdhcps_pool = (struct dhcps_pool *)mem_calloc(1, sizeof(struct dhcps_pool)); + + pdhcps_pool->ip.addr = dhcps->client_address.addr; + memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)); + pdhcps_pool->lease_timer = lease_timer; + pnode = (list_node *)mem_calloc(1, sizeof(list_node)); + + pnode->pnode = pdhcps_pool; + pnode->pnext = NULL; + node_insert_to_list(&dhcps->plist, pnode); + + if (dhcps->client_address.addr == dhcps->dhcps_poll.end_ip.addr) { + dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr; + } else { + addr_tmp.addr = htonl(dhcps->client_address.addr); + addr_tmp.addr++; + dhcps->client_address_plus.addr = htonl(addr_tmp.addr); + } + } + +POOL_CHECK: + + if ((dhcps->client_address.addr > dhcps->dhcps_poll.end_ip.addr) || (ip4_addr_isany(&dhcps->client_address))) { + if (pnode != NULL) { + node_remove_from_list(&dhcps->plist, pnode); + free(pnode); + pnode = NULL; + } + + if (pdhcps_pool != NULL) { + free(pdhcps_pool); + pdhcps_pool = NULL; + } + + return 4; + } + + s16_t ret = parse_options(dhcps, &m->options[4], len);; + + if (ret == DHCPS_STATE_RELEASE || ret == DHCPS_STATE_NAK) { + if (pnode != NULL) { + node_remove_from_list(&dhcps->plist, pnode); + free(pnode); + pnode = NULL; + } + + if (pdhcps_pool != NULL) { + free(pdhcps_pool); + pdhcps_pool = NULL; + } + + memset(&dhcps->client_address, 0x0, sizeof(dhcps->client_address)); + } + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: xid changed\n"); + DHCPS_LOG("dhcps: client_address.addr = %x\n", dhcps->client_address.addr); +#endif + return ret; + } + + return 0; +} + +/****************************************************************************** + * FunctionName : handle_dhcp + * Description : If an incoming DHCP message is in response to us, then trigger the state machine + * Parameters : arg -- arg user supplied argument (udp_pcb.recv_arg) + * pcb -- the udp_pcb which received data + * p -- the packet buffer that was received + * addr -- the remote IP address from which the packet was received + * port -- the remote port from which the packet was received + * Returns : none +*******************************************************************************/ +static void handle_dhcp(void *arg, + struct udp_pcb *pcb, + struct pbuf *p, + const ip_addr_t *addr, + u16_t port) +{ + struct dhcps_t *dhcps = arg; + struct dhcps_msg *pmsg_dhcps = NULL; + s16_t tlen, malloc_len; + u16_t i; + u16_t dhcps_msg_cnt = 0; + u8_t *p_dhcps_msg = NULL; + u8_t *data; + s16_t state; + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> receive a packet\n"); +#endif + + if (p == NULL) { + return; + } + + malloc_len = sizeof(struct dhcps_msg); +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp malloc_len=%d rx_len=%d", malloc_len, p->tot_len); +#endif + if (malloc_len < p->tot_len) { + malloc_len = p->tot_len; + } + + pmsg_dhcps = (struct dhcps_msg *)mem_calloc(1, malloc_len); + if (NULL == pmsg_dhcps) { + pbuf_free(p); + return; + } + + p_dhcps_msg = (u8_t *)pmsg_dhcps; + tlen = p->tot_len; + data = p->payload; + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> p->tot_len = %d\n", tlen); + DHCPS_LOG("dhcps: handle_dhcp-> p->len = %d\n", p->len); +#endif + + for (i = 0; i < p->len; i++) { + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; +#if DHCPS_DEBUG + DHCPS_LOG("%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + DHCPS_LOG("\n"); + } + +#endif + } + + if (p->next != NULL) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> p->next != NULL\n"); + DHCPS_LOG("dhcps: handle_dhcp-> p->next->tot_len = %d\n", p->next->tot_len); + DHCPS_LOG("dhcps: handle_dhcp-> p->next->len = %d\n", p->next->len); +#endif + + data = p->next->payload; + + for (i = 0; i < p->next->len; i++) { + p_dhcps_msg[dhcps_msg_cnt++] = data[i]; +#if DHCPS_DEBUG + DHCPS_LOG("%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + DHCPS_LOG("\n"); + } + +#endif + } + } + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> parse_msg(p)\n"); +#endif + + state = parse_msg(dhcps, pmsg_dhcps, tlen - 240); +#ifdef LWIP_HOOK_DHCPS_POST_STATE + state = LWIP_HOOK_DHCPS_POST_STATE(pmsg_dhcps, malloc_len, state); +#endif /* LWIP_HOOK_DHCPS_POST_STATE */ + + switch (state) { + case DHCPS_STATE_OFFER://1 +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_OFFER\n"); +#endif + send_offer(dhcps, pmsg_dhcps, malloc_len); + break; + + case DHCPS_STATE_ACK://3 +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_ACK\n"); +#endif + send_ack(dhcps, pmsg_dhcps, malloc_len); + break; + + case DHCPS_STATE_NAK://4 +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_NAK\n"); +#endif + send_nak(dhcps, pmsg_dhcps, malloc_len); + break; + + default : + break; + } + +#if DHCPS_DEBUG + DHCPS_LOG("dhcps: handle_dhcp-> pbuf_free(p)\n"); +#endif + pbuf_free(p); + free(pmsg_dhcps); + pmsg_dhcps = NULL; +} + +/****************************************************************************** + * FunctionName : dhcps_poll_set + * Description : set ip poll from start to end for station + * Parameters : ip -- The current ip addr + * Returns : none +*******************************************************************************/ +static void dhcps_poll_set(dhcps_t *dhcps, u32_t ip) +{ + u32_t server_ip = 0; + u32_t start_ip = 0; + u32_t end_ip = 0; + u32_t range_start_ip = 0; + u32_t range_end_ip = 0; + dhcps_lease_t *dhcps_poll = &dhcps->dhcps_poll; + if (dhcps_poll->enable == true) { + server_ip = htonl(ip); + start_ip = htonl(dhcps_poll->start_ip.addr); + end_ip = htonl(dhcps_poll->end_ip.addr); + + /*config ip information can't contain local ip*/ + if ((server_ip >= start_ip) && (server_ip <= end_ip)) { + dhcps_poll->enable = false; + } else { + /*config ip information must be in the same segment as the local ip*/ + + if (!ip4_addr_netcmp(&dhcps_poll->start_ip, &dhcps->server_address, &dhcps->dhcps_mask) + || !ip4_addr_netcmp(&dhcps_poll->end_ip, &dhcps->server_address, &dhcps->dhcps_mask) + || (end_ip - start_ip + 1 > DHCPS_MAX_LEASE)) { + dhcps_poll->enable = false; + } + } + } + + if (dhcps_poll->enable == false) { + server_ip = htonl(ip); + range_start_ip = server_ip & htonl(dhcps->dhcps_mask.addr); + range_end_ip = range_start_ip | ~htonl(dhcps->dhcps_mask.addr); + + if (server_ip - range_start_ip > range_end_ip - server_ip) { + range_start_ip = range_start_ip + 1; + range_end_ip = server_ip - 1; + } else { + range_start_ip = server_ip + 1; + range_end_ip = range_end_ip - 1; + } + if (range_end_ip - range_start_ip + 1 > DHCPS_MAX_LEASE) { + range_end_ip = range_start_ip + DHCPS_MAX_LEASE - 1; + } + bzero(dhcps_poll, sizeof(*dhcps_poll)); + dhcps_poll->start_ip.addr = range_start_ip; + dhcps_poll->end_ip.addr = range_end_ip; + dhcps_poll->start_ip.addr = htonl(dhcps_poll->start_ip.addr); + dhcps_poll->end_ip.addr = htonl(dhcps_poll->end_ip.addr); + dhcps_poll->enable = true; + } + +} + + +/****************************************************************************** + * FunctionName : dhcps_set_new_lease_cb + * Description : set callback for dhcp server when it assign an IP + * to the connected dhcp client + * Parameters : cb -- callback for dhcp server + * Returns : ERR_OK on success +*******************************************************************************/ +err_t dhcps_set_new_lease_cb(dhcps_t *dhcps, dhcps_cb_t cb, void* cb_arg) +{ + if (dhcps == NULL) { + return ERR_ARG; + } + dhcps->dhcps_cb = cb; + dhcps->dhcps_cb_arg = cb_arg; + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : dhcps_start + * Description : start dhcp server function + * Parameters : netif -- The current netif addr + * : info -- The current ip info + * Returns : none +*******************************************************************************/ +err_t dhcps_start(dhcps_t *dhcps, struct netif *netif, ip4_addr_t ip) +{ + if (dhcps == NULL || netif == NULL) { + return ERR_ARG; + } + dhcps->dhcps_netif = netif; + if (dhcps->dhcps_pcb != NULL) { + udp_remove(dhcps->dhcps_pcb); + } + + dhcps->dhcps_pcb = udp_new(); + + if (dhcps->dhcps_pcb == NULL || ip4_addr_isany_val(ip)) { + DHCPS_LOG("dhcps_start(): could not obtain pcb\n"); + return ERR_ARG; + } + + IP4_ADDR(&dhcps->broadcast_dhcps, 255, 255, 255, 255); + + dhcps->server_address.addr = ip.addr; + DHCP_CHECK_SUBNET_MASK_IP(htonl(dhcps->dhcps_mask.addr)); + DHCP_CHECK_IP_MATCH_SUBNET_MASK(htonl(dhcps->dhcps_mask.addr), htonl(ip.addr)); + dhcps_poll_set(dhcps, dhcps->server_address.addr); + + dhcps->client_address_plus.addr = dhcps->dhcps_poll.start_ip.addr; + + udp_bind(dhcps->dhcps_pcb, &netif->ip_addr, DHCPS_SERVER_PORT); + udp_recv(dhcps->dhcps_pcb, handle_dhcp, dhcps); +#if DHCPS_DEBUG + DHCPS_LOG("dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\n"); +#endif + dhcps->state = DHCPS_HANDLE_STARTED; + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcps_tmr, dhcps); + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : dhcps_stop + * Description : stop dhcp server function + * Parameters : netif -- The current netif addr + * Returns : none +*******************************************************************************/ +err_t dhcps_stop(dhcps_t *dhcps, struct netif *netif) +{ + if (dhcps == NULL || netif == NULL || dhcps->dhcps_netif != netif) { +#if DHCPS_DEBUG + DHCPS_LOG("dhcps_stop: netif is NULL or invalid\n"); +#endif + return ERR_ARG; + } + + if (dhcps->dhcps_pcb != NULL) { + udp_disconnect(dhcps->dhcps_pcb); + udp_remove(dhcps->dhcps_pcb); + dhcps->dhcps_pcb = NULL; + } + + list_node *pnode = NULL; + list_node *pback_node = NULL; + pnode = dhcps->plist; + + while (pnode != NULL) { + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&dhcps->plist, pback_node); + free(pback_node->pnode); + pback_node->pnode = NULL; + free(pback_node); + pback_node = NULL; + } + sys_untimeout(dhcps_tmr, dhcps); + dhcps->state = DHCPS_HANDLE_STOPPED; + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : kill_oldest_dhcps_pool + * Description : remove the oldest node from list + * Parameters : none + * Returns : none +*******************************************************************************/ +static void kill_oldest_dhcps_pool(dhcps_t *dhcps) +{ + list_node *pre = NULL, *p = NULL; + list_node *minpre = NULL, *minp = NULL; + struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; + pre = dhcps->plist; + assert(pre != NULL && pre->pnext != NULL); // Expect the list to have at least 2 nodes + p = pre->pnext; + minpre = pre; + minp = pre; + + while (p != NULL) { + pdhcps_pool = p->pnode; + pmin_pool = minp->pnode; + + if (pdhcps_pool->lease_timer < pmin_pool->lease_timer) { + minp = p; + minpre = pre; + } + + pre = p; + p = p->pnext; + } + if (minp == dhcps->plist) { + dhcps->plist = minp->pnext; + } else { + minpre->pnext = minp->pnext; + } + free(minp->pnode); + minp->pnode = NULL; + free(minp); + minp = NULL; +} + +/****************************************************************************** + * FunctionName : dhcps_coarse_tmr + * Description : the lease time count + * Parameters : none + * Returns : none +*******************************************************************************/ +static void dhcps_tmr(void *arg) +{ + dhcps_t *dhcps = arg; + dhcps_handle_state state = dhcps->state; + if (state == DHCPS_HANDLE_DELETE_PENDING) { + free(dhcps); + return; + } + + if (state != DHCPS_HANDLE_STARTED) { + return; + } + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcps_tmr, dhcps); + u8_t num_dhcps_pool = 0; + list_node *pback_node = NULL; + list_node *pnode = NULL; + struct dhcps_pool *pdhcps_pool = NULL; + pnode = dhcps->plist; + + while (pnode != NULL) { + pdhcps_pool = pnode->pnode; + pdhcps_pool->lease_timer --; + + if (pdhcps_pool->lease_timer == 0) { + pback_node = pnode; + pnode = pback_node->pnext; + node_remove_from_list(&dhcps->plist, pback_node); + free(pback_node->pnode); + pback_node->pnode = NULL; + free(pback_node); + pback_node = NULL; + } else { + pnode = pnode ->pnext; + num_dhcps_pool ++; + } + } + + if (num_dhcps_pool > MAX_STATION_NUM) { + kill_oldest_dhcps_pool(dhcps); + } +} + +/****************************************************************************** + * FunctionName : dhcp_search_ip_on_mac + * Description : Search ip address based on mac address + * Parameters : mac -- The MAC addr + * ip -- The IP info + * Returns : true or false +*******************************************************************************/ +bool dhcp_search_ip_on_mac(dhcps_t *dhcps, u8_t *mac, ip4_addr_t *ip) +{ + struct dhcps_pool *pdhcps_pool = NULL; + list_node *pback_node = NULL; + bool ret = false; + + if (dhcps == NULL) { + return false; + } + + for (pback_node = dhcps->plist; pback_node != NULL; pback_node = pback_node->pnext) { + pdhcps_pool = pback_node->pnode; + + if (memcmp(pdhcps_pool->mac, mac, sizeof(pdhcps_pool->mac)) == 0) { + memcpy(&ip->addr, &pdhcps_pool->ip.addr, sizeof(pdhcps_pool->ip.addr)); + ret = true; + break; + } + } + + return ret; +} + +/****************************************************************************** + * FunctionName : dhcps_dns_setserver + * Description : set DNS server address for dhcpserver + * Parameters : dnsserver -- The DNS server address + * Returns : ERR_ARG if invalid handle, ERR_OK on success +*******************************************************************************/ +err_t dhcps_dns_setserver(dhcps_t *dhcps, const ip_addr_t *dnsserver) +{ + if (dhcps == NULL) { + return ERR_ARG; + } + if (dnsserver != NULL) { + dhcps->dns_server = *(ip_2_ip4(dnsserver)); + } else { + dhcps->dns_server = *(ip_2_ip4(IP_ADDR_ANY)); + } + return ERR_OK; +} + +/****************************************************************************** + * FunctionName : dhcps_dns_getserver + * Description : get DNS server address for dhcpserver + * Parameters : none + * Returns : ip4_addr_t +*******************************************************************************/ +err_t dhcps_dns_getserver(dhcps_t *dhcps, ip4_addr_t *dnsserver) +{ + if (dhcps) { + *dnsserver = dhcps->dns_server; + return ERR_OK; + } + return ERR_ARG; +} +#endif // ESP_DHCPS diff --git a/components/lwip/apps/ping/esp_ping.c b/components/lwip/apps/ping/esp_ping.c new file mode 100644 index 000000000..f440e80ae --- /dev/null +++ b/components/lwip/apps/ping/esp_ping.c @@ -0,0 +1,167 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_ping.h" + +#include "lwip/ip_addr.h" +typedef struct _ping_option { + ip_addr_t ping_target; + uint32_t ping_count; + uint32_t ping_rcv_timeout; + uint32_t ping_delay; + uint32_t interface; + size_t ping_data_len; + uint16_t ping_id; + u8_t ping_tos; + u8_t ping_ttl; + esp_ping_found_fn ping_res_fn; + esp_ping_found ping_res; + void *ping_reserve; +} ping_option; + +static ping_option ping_option_info[1]; + +esp_err_t esp_ping_set_target(ping_target_id_t opt_id, void *opt_val, uint32_t opt_len) +{ + esp_err_t ret = ESP_OK; + + if (opt_val == NULL) { + return ESP_ERR_PING_INVALID_PARAMS; + } + + switch (opt_id) { + case PING_TARGET_IP_ADDRESS: + ipaddr_aton(opt_val, &(ping_option_info->ping_target)); + break; + case PING_TARGET_IP_ADDRESS_COUNT: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + ping_option_info->ping_count = *(uint32_t *)opt_val; + break; + case PING_TARGET_IF_INDEX: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + ping_option_info->interface = *(uint32_t *)opt_val; + break; + case PING_TARGET_RCV_TIMEO: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + ping_option_info->ping_rcv_timeout = (*(uint32_t *)opt_val); + break; + case PING_TARGET_DELAY_TIME: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + ping_option_info->ping_delay = (*(uint32_t *)opt_val); + break; + case PING_TARGET_DATA_LEN: + ESP_PING_CHECK_OPTLEN(opt_len, size_t); + ping_option_info->ping_data_len = (*(size_t *)opt_val); + break; + case PING_TARGET_ID: + ESP_PING_CHECK_OPTLEN(opt_len, uint16_t); + ping_option_info->ping_id = *(uint16_t *)opt_val; + break; + case PING_TARGET_IP_TOS: + ESP_PING_CHECK_OPTLEN(opt_len, u8_t); + ping_option_info->ping_tos = *(u8_t *)opt_val; + break; + case PING_TARGET_RES_FN: + ping_option_info->ping_res_fn = opt_val; + break; + case PING_TARGET_RES_RESET: + memset(&ping_option_info->ping_res, 0, sizeof(ping_option_info->ping_res)); + break; + default: + ret = ESP_ERR_PING_INVALID_PARAMS; + break; + } + + return ret; +} + +esp_err_t esp_ping_get_target(ping_target_id_t opt_id, void *opt_val, uint32_t opt_len) +{ + esp_err_t ret = ESP_OK; + + if (opt_val == NULL) { + return ESP_ERR_PING_INVALID_PARAMS; + } + + switch (opt_id) { + case PING_TARGET_IP_ADDRESS: + ip_addr_copy(*(ip_addr_t*)opt_val, ping_option_info->ping_target); + break; + case PING_TARGET_IP_ADDRESS_COUNT: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + *(uint32_t *)opt_val = ping_option_info->ping_count; + break; + case PING_TARGET_IF_INDEX: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + *(uint32_t *)opt_val = ping_option_info->interface; + break; + case PING_TARGET_RCV_TIMEO: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + *(uint32_t *)opt_val = ping_option_info->ping_rcv_timeout; + break; + case PING_TARGET_DELAY_TIME: + ESP_PING_CHECK_OPTLEN(opt_len, uint32_t); + *(uint32_t *)opt_val = ping_option_info->ping_delay; + break; + case PING_TARGET_DATA_LEN: + ESP_PING_CHECK_OPTLEN(opt_len, size_t); + *(size_t *)opt_val = ping_option_info->ping_data_len; + break; + case PING_TARGET_ID: + ESP_PING_CHECK_OPTLEN(opt_len, uint16_t); + *(uint16_t *)opt_val = ping_option_info->ping_id; + break; + case PING_TARGET_IP_TOS: + ESP_PING_CHECK_OPTLEN(opt_len, uint16_t); + *(uint16_t *)opt_val = ping_option_info->ping_tos; + break; + default: + ret = ESP_ERR_PING_INVALID_PARAMS; + break; + } + + return ret; +} + +esp_err_t esp_ping_result(uint8_t res_val, uint16_t ping_len, uint32_t ping_time) +{ + esp_err_t ret = ESP_OK; + + ping_option_info->ping_res.ping_err = res_val; + + if (res_val != PING_RES_FINISH) { + ping_option_info->ping_res.bytes = ping_len; + ping_option_info->ping_res.resp_time = ping_time; + ping_option_info->ping_res.total_bytes += ping_len; + ping_option_info->ping_res.send_count ++; + + if (res_val == PING_RES_TIMEOUT) { + ping_option_info->ping_res.timeout_count ++; + } else { + if (!ping_option_info->ping_res.min_time || (ping_time < ping_option_info->ping_res.min_time)) { + ping_option_info->ping_res.min_time = ping_time; + } + + if (ping_time > ping_option_info->ping_res.max_time) { + ping_option_info->ping_res.max_time = ping_time; + } + + + ping_option_info->ping_res.total_time += ping_time; + ping_option_info->ping_res.recv_count ++; + } + } + + if (ping_option_info->ping_res_fn) { + ping_option_info->ping_res_fn(PING_TARGET_RES_FN, &ping_option_info->ping_res); + if (res_val == PING_RES_FINISH) { + memset(&ping_option_info->ping_res, 0, sizeof(esp_ping_found)); + } + } + + return ret; +} diff --git a/components/lwip/apps/ping/ping.c b/components/lwip/apps/ping/ping.c new file mode 100644 index 000000000..ea93432ea --- /dev/null +++ b/components/lwip/apps/ping/ping.c @@ -0,0 +1,311 @@ +/** + * @file + * Ping sender module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/** + * This is an example of a "ping" sender (with raw API and socket API). + * It can be used as a start point to maintain opened a network connection, or + * like a network "watchdog" for your device. + * + */ + +#include "lwip/opt.h" + +#if LWIP_IPV4 && LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "ping/ping.h" + +#include "lwip/mem.h" +#include "lwip/raw.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/inet_chksum.h" + +#if PING_USE_SOCKETS +#include "lwip/sockets.h" +#include "lwip/inet.h" +#include "esp_task.h" +#include "ping/ping_sock.h" +#endif /* PING_USE_SOCKETS */ + +#ifdef ESP_PING +#include "esp_ping.h" +#include "lwip/ip_addr.h" +#endif +/** + * PING_DEBUG: Enable debugging for PING. + */ +#ifndef PING_DEBUG +#define PING_DEBUG LWIP_DBG_OFF +#endif + +/** ping target - should be an "ip4_addr_t" */ +#ifndef PING_TARGET +#define PING_TARGET (netif_default ? *netif_ip4_gw(netif_default) : (*IP4_ADDR_ANY)) +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_DELAY +#define PING_DELAY 1000 +#endif + +/** ping identifier - must fit on a u16_t */ +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +/** ping additional data size to include in the packet */ +#ifndef PING_DATA_SIZE +#define PING_DATA_SIZE 32 +#endif + +/** ping result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#endif + +#define PING_TIME_DIFF_MS(_end, _start) ((uint32_t)(((_end).tv_sec - (_start).tv_sec) * 1000 + (_end.tv_usec - _start.tv_usec)/1000)) +#define PING_TIME_DIFF_SEC(_end, _start) ((uint32_t)((_end).tv_sec - (_start).tv_sec)) + +#if PING_USE_SOCKETS +/* ping handle */ +static esp_ping_handle_t ping = NULL; +#else +static struct raw_pcb *ping_pcb; +static u16_t ping_seq_num; +static struct timeval ping_time; + +/** Prepare a echo ICMP request */ +static void +ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) +{ + size_t i; + size_t data_len = len - sizeof(struct icmp_echo_hdr); + + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + iecho->seqno = htons(++ping_seq_num); + + /* fill the additional data buffer with some data */ + for(i = 0; i < data_len; i++) { + ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, len); +} + +/* Ping using the raw ip */ +static u8_t +ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) +{ + struct icmp_echo_hdr *iecho; + struct timeval now; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_ASSERT("p != NULL", p != NULL); + + if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && + pbuf_header(p, -PBUF_IP_HLEN) == 0) { + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) { + LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print(PING_DEBUG, addr); + gettimeofday(&now, NULL); + LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", PING_TIME_DIFF_MS(now, ping_time))); + + /* do some ping result processing */ + PING_RESULT(1); + pbuf_free(p); + return 1; /* eat the packet */ + } + /* not eaten, restore original packet */ + pbuf_header(p, PBUF_IP_HLEN); + } + + return 0; /* don't eat the packet */ +} + +static void +ping_send(struct raw_pcb *raw, ip_addr_t *addr) +{ + struct pbuf *p; + struct icmp_echo_hdr *iecho; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + + LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF( PING_DEBUG, ("\n")); + LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); + + p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); + if (!p) { + return; + } + if ((p->len == p->tot_len) && (p->next == NULL)) { + iecho = (struct icmp_echo_hdr *)p->payload; + + ping_prepare_echo(iecho, (u16_t)ping_size); + + raw_sendto(raw, p, addr); + ping_time = system_get_time(); + } + pbuf_free(p); +} + +static void +ping_timeout(void *arg) +{ + struct raw_pcb *pcb = (struct raw_pcb*)arg; + ip_addr_t ping_target; + + LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL); + + ip_addr_copy_from_ip4(ping_target, PING_TARGET); + ping_send(pcb, &ping_target); + sys_timeout(PING_DELAY, ping_timeout, pcb); +} + +static void +ping_raw_init(void) +{ + ping_pcb = raw_new(IP_PROTO_ICMP); + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + + raw_recv(ping_pcb, ping_recv, NULL); + raw_bind(ping_pcb, IP_ADDR_ANY); + sys_timeout(PING_DELAY, ping_timeout, ping_pcb); +} + +void +ping_send_now(void) +{ + ip_addr_t ping_target; + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + ip_addr_copy_from_ip4(ping_target, PING_TARGET); + ping_send(ping_pcb, &ping_target); +} + +#endif /* PING_USE_SOCKETS */ + +/** + * + * Re-implement ping_init and ping_deinit with the APIs from ping_sock.h for back-ward compatibility sake. + * It's highly recommended that users should use the new APIs from ping_sock.h. + * ToDo: ping.h and esp_ping.h are deprecated now and should be removed in idf v5.x. + * + */ + +static void +on_ping_success(esp_ping_handle_t hdl, void *args) +{ + uint32_t elapsed_time, recv_len; + esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time)); + esp_ping_result(PING_RES_OK, recv_len, elapsed_time); +} + +static void +on_ping_timeout(esp_ping_handle_t hdl, void *args) +{ + uint32_t elapsed_time, recv_len; + esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time)); + esp_ping_result(PING_RES_TIMEOUT, recv_len, elapsed_time); +} + +static void +on_ping_end(esp_ping_handle_t hdl, void *args) +{ + esp_ping_result(PING_RES_FINISH, 0, 0); + esp_ping_delete_session(hdl); +} + +int +ping_init(void) +{ +#if PING_USE_SOCKETS + uint32_t tos = 0; + uint32_t ping_timeout = PING_RCV_TIMEO; + uint32_t ping_delay = PING_DELAY; + uint32_t ping_count_max = 3; + uint32_t interface = 0; + ip_addr_t ipaddr; + + esp_ping_get_target(PING_TARGET_IP_ADDRESS_COUNT, &ping_count_max, sizeof(ping_count_max)); + esp_ping_get_target(PING_TARGET_RCV_TIMEO, &ping_timeout, sizeof(ping_timeout)); + esp_ping_get_target(PING_TARGET_DELAY_TIME, &ping_delay, sizeof(ping_delay)); + esp_ping_get_target(PING_TARGET_IP_ADDRESS, &ipaddr, sizeof(ip_addr_t)); + esp_ping_get_target(PING_TARGET_IP_TOS, &tos, sizeof(tos)); + esp_ping_get_target(PING_TARGET_IF_INDEX, &interface, sizeof(interface)); + + esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG(); + config.count = ping_count_max; + config.timeout_ms = ping_timeout; + config.interval_ms = ping_delay; + config.target_addr = ipaddr; + config.tos = tos; + config.interface = interface; + + esp_ping_callbacks_t cbs = { + .on_ping_end = on_ping_end, + .on_ping_success = on_ping_success, + .on_ping_timeout = on_ping_timeout, + }; + + esp_ping_new_session(&config, &cbs, &ping); + esp_ping_start(ping); +#else /* PING_USE_SOCKETS */ + ping_raw_init(); +#endif /* PING_USE_SOCKETS */ + return ERR_OK; +} + +void +ping_deinit(void) +{ + esp_ping_stop(ping); + esp_ping_delete_session(ping); +} + +#endif /* LWIP_IPV4 && LWIP_RAW */ diff --git a/components/lwip/apps/ping/ping_sock.c b/components/lwip/apps/ping/ping_sock.c new file mode 100644 index 000000000..b3326c9ed --- /dev/null +++ b/components/lwip/apps/ping/ping_sock.c @@ -0,0 +1,409 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "lwip/opt.h" +#include "lwip/init.h" +#include "lwip/mem.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/ip.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "esp_log.h" +#include "ping/ping_sock.h" +#include "esp_check.h" + +const static char *TAG = "ping_sock"; + +#define PING_TIME_DIFF_MS(_end, _start) ((uint32_t)(((_end).tv_sec - (_start).tv_sec) * 1000 + \ + ((_end).tv_usec - (_start).tv_usec) / 1000)) + +#define PING_CHECK_START_TIMEOUT_MS (1000) + +#define PING_FLAGS_INIT (1 << 0) +#define PING_FLAGS_START (1 << 1) + +typedef struct { + int sock; + struct sockaddr_storage target_addr; + TaskHandle_t ping_task_hdl; + struct icmp_echo_hdr *packet_hdr; + ip_addr_t recv_addr; + uint32_t recv_len; + uint32_t icmp_pkt_size; + uint32_t count; + uint32_t transmitted; + uint32_t received; + uint32_t interval_ms; + uint32_t elapsed_time_ms; + uint32_t total_time_ms; + uint8_t ttl; + uint8_t tos; + uint32_t flags; + void (*on_ping_success)(esp_ping_handle_t hdl, void *args); + void (*on_ping_timeout)(esp_ping_handle_t hdl, void *args); + void (*on_ping_end)(esp_ping_handle_t hdl, void *args); + void *cb_args; +} esp_ping_t; + +static esp_err_t esp_ping_send(esp_ping_t *ep) +{ + esp_err_t ret = ESP_OK; + ep->packet_hdr->seqno++; + /* generate checksum since "seqno" has changed */ + ep->packet_hdr->chksum = 0; + if (ep->packet_hdr->type == ICMP_ECHO) { + ep->packet_hdr->chksum = inet_chksum(ep->packet_hdr, ep->icmp_pkt_size); + } + + ssize_t sent = sendto(ep->sock, ep->packet_hdr, ep->icmp_pkt_size, 0, + (struct sockaddr *)&ep->target_addr, sizeof(ep->target_addr)); + + if (sent != (ssize_t)ep->icmp_pkt_size) { + int opt_val; + socklen_t opt_len = sizeof(opt_val); + getsockopt(ep->sock, SOL_SOCKET, SO_ERROR, &opt_val, &opt_len); + ESP_LOGE(TAG, "send error=%d", opt_val); + ret = ESP_FAIL; + } else { + ep->transmitted++; + } + return ret; +} + +static int esp_ping_receive(esp_ping_t *ep) +{ + char buf[64]; // 64 bytes are enough to cover IP header and ICMP header + int len = 0; + struct sockaddr_storage from; + int fromlen = sizeof(from); + uint16_t data_head = 0; + + while ((len = recvfrom(ep->sock, buf, sizeof(buf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) { +#if CONFIG_LWIP_IPV4 + if (from.ss_family == AF_INET) { + // IPv4 + struct sockaddr_in *from4 = (struct sockaddr_in *)&from; + inet_addr_to_ip4addr(ip_2_ip4(&ep->recv_addr), &from4->sin_addr); + IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V4); + data_head = (uint16_t)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr)); + } +#endif +#if CONFIG_LWIP_IPV6 + if (from.ss_family == AF_INET6) { + // IPv6 + struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from; + inet6_addr_to_ip6addr(ip_2_ip6(&ep->recv_addr), &from6->sin6_addr); + IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V6); + data_head = (uint16_t)(sizeof(struct ip6_hdr) + sizeof(struct icmp6_echo_hdr)); + } +#endif + if (len >= data_head) { +#if CONFIG_LWIP_IPV4 + if (IP_IS_V4_VAL(ep->recv_addr)) { // Currently we process IPv4 + struct ip_hdr *iphdr = (struct ip_hdr *)buf; + struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); + if ((iecho->id == ep->packet_hdr->id) && (iecho->seqno == ep->packet_hdr->seqno)) { + ep->received++; + ep->ttl = iphdr->_ttl; + ep->tos = iphdr->_tos; + ep->recv_len = lwip_ntohs(IPH_LEN(iphdr)) - data_head; // The data portion of ICMP + return len; + } + } +#endif // CONFIG_LWIP_IPV4 +#if CONFIG_LWIP_IPV6 + if (IP_IS_V6_VAL(ep->recv_addr)) { // Currently we process IPv6 + struct ip6_hdr *iphdr = (struct ip6_hdr *)buf; + struct icmp6_echo_hdr *iecho6 = (struct icmp6_echo_hdr *)(buf + sizeof(struct ip6_hdr)); // IPv6 head length is 40 + if ((iecho6->id == ep->packet_hdr->id) && (iecho6->seqno == ep->packet_hdr->seqno)) { + ep->received++; + ep->recv_len = IP6H_PLEN(iphdr) - sizeof(struct icmp6_echo_hdr); //The data portion of ICMPv6 + return len; + } + } +#endif // CONFIG_LWIP_IPV6 + } + fromlen = sizeof(from); + } + // if timeout, len will be -1 + return len; +} + +static void esp_ping_thread(void *args) +{ + esp_ping_t *ep = (esp_ping_t *)(args); + TickType_t last_wake; + struct timeval start_time, end_time; + int recv_ret; + + while (1) { + /* wait for ping start signal */ + if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(PING_CHECK_START_TIMEOUT_MS))) { + /* initialize runtime statistics */ + ep->packet_hdr->seqno = 0; + ep->transmitted = 0; + ep->received = 0; + ep->total_time_ms = 0; + + last_wake = xTaskGetTickCount(); + while ((ep->flags & PING_FLAGS_START) && ((ep->count == 0) || (ep->packet_hdr->seqno < ep->count))) { + esp_ping_send(ep); + gettimeofday(&start_time, NULL); + recv_ret = esp_ping_receive(ep); + gettimeofday(&end_time, NULL); + ep->elapsed_time_ms = PING_TIME_DIFF_MS(end_time, start_time); + ep->total_time_ms += ep->elapsed_time_ms; + if (recv_ret >= 0) { + if (ep->on_ping_success) { + ep->on_ping_success((esp_ping_handle_t)ep, ep->cb_args); + } + } else { + if (ep->on_ping_timeout) { + ep->on_ping_timeout((esp_ping_handle_t)ep, ep->cb_args); + } + } + if (pdMS_TO_TICKS(ep->interval_ms)) { + vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(ep->interval_ms)); // to get a more accurate delay + } + } + /* batch of ping operations finished */ + if (ep->on_ping_end) { + ep->on_ping_end((esp_ping_handle_t)ep, ep->cb_args); + } + } else { + // check if ping has been de-initialized + if (!(ep->flags & PING_FLAGS_INIT)) { + break; + } + } + } + /* before exit task, free all resources */ + if (ep->packet_hdr) { + free(ep->packet_hdr); + } + if (ep->sock > 0) { + close(ep->sock); + } + free(ep); + vTaskDelete(NULL); +} + +esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_callbacks_t *cbs, esp_ping_handle_t *hdl_out) +{ + esp_err_t ret = ESP_FAIL; + esp_ping_t *ep = NULL; + ESP_GOTO_ON_FALSE(config, ESP_ERR_INVALID_ARG, err, TAG, "ping config can't be null"); + ESP_GOTO_ON_FALSE(hdl_out, ESP_ERR_INVALID_ARG, err, TAG, "ping handle can't be null"); + + ep = mem_calloc(1, sizeof(esp_ping_t)); + ESP_GOTO_ON_FALSE(ep, ESP_ERR_NO_MEM, err, TAG, "no memory for esp_ping object"); + + /* set INIT flag, so that ping task won't exit (must set before create ping task) */ + ep->flags |= PING_FLAGS_INIT; + + /* create ping thread */ + BaseType_t xReturned = xTaskCreate(esp_ping_thread, "ping", config->task_stack_size, ep, + config->task_prio, &ep->ping_task_hdl); + ESP_GOTO_ON_FALSE(xReturned == pdTRUE, ESP_ERR_NO_MEM, err, TAG, "create ping task failed"); + + /* callback functions */ + if (cbs) { + ep->cb_args = cbs->cb_args; + ep->on_ping_end = cbs->on_ping_end; + ep->on_ping_timeout = cbs->on_ping_timeout; + ep->on_ping_success = cbs->on_ping_success; + } + /* set parameters for ping */ + ep->recv_addr = config->target_addr; + ep->count = config->count; + ep->interval_ms = config->interval_ms; + ep->icmp_pkt_size = sizeof(struct icmp_echo_hdr) + config->data_size; + ep->packet_hdr = mem_calloc(1, ep->icmp_pkt_size); + ESP_GOTO_ON_FALSE(ep->packet_hdr,ESP_ERR_NO_MEM, err, TAG, "no memory for echo packet"); + /* set ICMP type and code field */ + ep->packet_hdr->code = 0; + /* ping id should be unique, treat task handle as ping ID */ + ep->packet_hdr->id = ((intptr_t)ep->ping_task_hdl) & 0xFFFF; + /* fill the additional data buffer with some data */ + char *d = (char *)(ep->packet_hdr) + sizeof(struct icmp_echo_hdr); + for (uint32_t i = 0; i < config->data_size; i++) { + d[i] = 'A' + i; + } + + /* create socket */ + if (IP_IS_V4(&config->target_addr) +#if CONFIG_LWIP_IPV6 + || ip6_addr_isipv4mappedipv6(ip_2_ip6(&config->target_addr)) +#endif + ) { + ep->sock = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP); + } +#if CONFIG_LWIP_IPV6 + else { + ep->sock = socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6); + } +#endif + ESP_GOTO_ON_FALSE(ep->sock >= 0, ESP_FAIL, err, TAG, "create socket failed: %d", ep->sock); + /* set if index */ + if(config->interface) { + struct ifreq iface; + if(netif_index_to_name(config->interface, iface.ifr_name) == NULL) { + ESP_LOGE(TAG, "fail to find interface name with netif index %" PRIu32, config->interface); + goto err; + } + if(setsockopt(ep->sock, SOL_SOCKET, SO_BINDTODEVICE, &iface, sizeof(iface)) != 0) { + ESP_LOGE(TAG, "fail to setsockopt SO_BINDTODEVICE"); + goto err; + } + } + struct timeval timeout; + timeout.tv_sec = config->timeout_ms / 1000; + timeout.tv_usec = (config->timeout_ms % 1000) * 1000; + /* set receive timeout */ + setsockopt(ep->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + + /* set tos */ + setsockopt(ep->sock, IPPROTO_IP, IP_TOS, &config->tos, sizeof(config->tos)); + + /* set ttl */ + setsockopt(ep->sock, IPPROTO_IP, IP_TTL, &config->ttl, sizeof(config->ttl)); + + /* set socket address */ +#if CONFIG_LWIP_IPV4 + if (IP_IS_V4(&config->target_addr)) { + struct sockaddr_in *to4 = (struct sockaddr_in *)&ep->target_addr; + to4->sin_family = AF_INET; + inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(&config->target_addr)); + ep->packet_hdr->type = ICMP_ECHO; + } +#endif +#if CONFIG_LWIP_IPV6 + if (IP_IS_V6(&config->target_addr)) { + struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ep->target_addr; + to6->sin6_family = AF_INET6; + inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(&config->target_addr)); + ep->packet_hdr->type = ICMP6_TYPE_EREQ; + } +#endif + /* return ping handle to user */ + *hdl_out = (esp_ping_handle_t)ep; + return ESP_OK; +err: + if (ep) { + if (ep->sock > 0) { + close(ep->sock); + } + if (ep->packet_hdr) { + free(ep->packet_hdr); + } + if (ep->ping_task_hdl) { + vTaskDelete(ep->ping_task_hdl); + } + free(ep); + } + return ret; +} + +esp_err_t esp_ping_delete_session(esp_ping_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_ping_t *ep = (esp_ping_t *)hdl; + ESP_GOTO_ON_FALSE(ep, ESP_ERR_INVALID_ARG, err, TAG, "ping handle can't be null"); + /* reset init flags, then ping task will exit */ + ep->flags &= ~PING_FLAGS_INIT; + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_ping_start(esp_ping_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_ping_t *ep = (esp_ping_t *)hdl; + ESP_GOTO_ON_FALSE(ep, ESP_ERR_INVALID_ARG, err, TAG, "ping handle can't be null"); + ep->flags |= PING_FLAGS_START; + xTaskNotifyGive(ep->ping_task_hdl); + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_ping_stop(esp_ping_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_ping_t *ep = (esp_ping_t *)hdl; + ESP_GOTO_ON_FALSE(ep, ESP_ERR_INVALID_ARG, err, TAG, "ping handle can't be null"); + ep->flags &= ~PING_FLAGS_START; + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_ping_get_profile(esp_ping_handle_t hdl, esp_ping_profile_t profile, void *data, uint32_t size) +{ + esp_err_t ret = ESP_OK; + esp_ping_t *ep = (esp_ping_t *)hdl; + const void *from = NULL; + uint32_t copy_size = 0; + ESP_GOTO_ON_FALSE(ep, ESP_ERR_INVALID_ARG, err, TAG, "ping handle can't be null"); + ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "profile data can't be null"); + switch (profile) { + case ESP_PING_PROF_SEQNO: + from = &ep->packet_hdr->seqno; + copy_size = sizeof(ep->packet_hdr->seqno); + break; + case ESP_PING_PROF_TOS: + from = &ep->tos; + copy_size = sizeof(ep->tos); + break; + case ESP_PING_PROF_TTL: + from = &ep->ttl; + copy_size = sizeof(ep->ttl); + break; + case ESP_PING_PROF_REQUEST: + from = &ep->transmitted; + copy_size = sizeof(ep->transmitted); + break; + case ESP_PING_PROF_REPLY: + from = &ep->received; + copy_size = sizeof(ep->received); + break; + case ESP_PING_PROF_IPADDR: + from = &ep->recv_addr; + copy_size = sizeof(ep->recv_addr); + break; + case ESP_PING_PROF_SIZE: + from = &ep->recv_len; + copy_size = sizeof(ep->recv_len); + break; + case ESP_PING_PROF_TIMEGAP: + from = &ep->elapsed_time_ms; + copy_size = sizeof(ep->elapsed_time_ms); + break; + case ESP_PING_PROF_DURATION: + from = &ep->total_time_ms; + copy_size = sizeof(ep->total_time_ms); + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown profile: %d", profile); + break; + } + ESP_GOTO_ON_FALSE(size >= copy_size, ESP_ERR_INVALID_SIZE, err, TAG, "unmatched data size for profile %d", profile); + memcpy(data, from, copy_size); + return ESP_OK; +err: + return ret; +} diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c new file mode 100644 index 000000000..6c85b472c --- /dev/null +++ b/components/lwip/apps/sntp/sntp.c @@ -0,0 +1,276 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_sntp.h" + +// Remove compat macro and include lwip API +#undef SNTP_OPMODE_POLL +#include "lwip/apps/sntp.h" +#include "lwip/priv/tcpip_priv.h" +#include "esp_macros.h" + +static const char *TAG = "sntp"; + +ESP_STATIC_ASSERT(SNTP_OPMODE_POLL == ESP_SNTP_OPMODE_POLL, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct"); +ESP_STATIC_ASSERT(SNTP_OPMODE_LISTENONLY == ESP_SNTP_OPMODE_LISTENONLY, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct"); + +#define SNTP_ERROR(func, message) do { \ + err_t err = func; \ + LWIP_ERROR(message, err == ERR_OK, ); \ + } while (0) + +static volatile sntp_sync_mode_t sntp_sync_mode = SNTP_SYNC_MODE_IMMED; +static volatile sntp_sync_status_t sntp_sync_status = SNTP_SYNC_STATUS_RESET; +static sntp_sync_time_cb_t time_sync_notification_cb = NULL; +static uint32_t s_sync_interval = CONFIG_LWIP_SNTP_UPDATE_DELAY; + +inline void sntp_set_sync_status(sntp_sync_status_t sync_status) +{ + sntp_sync_status = sync_status; +} + +void __attribute__((weak)) sntp_sync_time(struct timeval *tv) +{ + if (sntp_sync_mode == SNTP_SYNC_MODE_IMMED) { + settimeofday(tv, NULL); + sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED); + } else if (sntp_sync_mode == SNTP_SYNC_MODE_SMOOTH) { + struct timeval tv_now; + gettimeofday(&tv_now, NULL); + int64_t cpu_time = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec; + int64_t sntp_time = (int64_t)tv->tv_sec * 1000000L + (int64_t)tv->tv_usec; + int64_t delta = sntp_time - cpu_time; + struct timeval tv_delta = { .tv_sec = delta / 1000000L, .tv_usec = delta % 1000000L }; + if (adjtime(&tv_delta, NULL) == -1) { + ESP_LOGD(TAG, "Function adjtime don't update time because the error is very big"); + settimeofday(tv, NULL); + ESP_LOGD(TAG, "Time was synchronized through settimeofday"); + sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED); + } else { + sntp_set_sync_status(SNTP_SYNC_STATUS_IN_PROGRESS); + } + } + if (time_sync_notification_cb) { + time_sync_notification_cb(tv); + } +} + +void sntp_set_sync_mode(sntp_sync_mode_t sync_mode) +{ + sntp_sync_mode = sync_mode; +} + +sntp_sync_mode_t sntp_get_sync_mode(void) +{ + return sntp_sync_mode; +} + +// set a callback function for time synchronization notification +void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback) +{ + time_sync_notification_cb = callback; +} + +sntp_sync_status_t sntp_get_sync_status(void) +{ + sntp_sync_status_t ret_sync_status = SNTP_SYNC_STATUS_RESET; + sntp_sync_status_t sync_status = sntp_sync_status; + if (sync_status == SNTP_SYNC_STATUS_COMPLETED) { + sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); + ret_sync_status = SNTP_SYNC_STATUS_COMPLETED; + } else if (sync_status == SNTP_SYNC_STATUS_IN_PROGRESS) { + struct timeval outdelta; + adjtime(NULL, &outdelta); + if (outdelta.tv_sec == 0 && outdelta.tv_usec == 0) { + sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); + ret_sync_status = SNTP_SYNC_STATUS_COMPLETED; + } else { + ret_sync_status = SNTP_SYNC_STATUS_IN_PROGRESS; + } + } + return ret_sync_status; +} + +void sntp_set_sync_interval(uint32_t interval_ms) +{ + if (interval_ms < 15000) { + // SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds + interval_ms = 15000; + } + s_sync_interval = interval_ms; +} + +uint32_t sntp_get_sync_interval(void) +{ + return s_sync_interval; +} + +static void sntp_do_restart(void *ctx) +{ + (void)ctx; + sntp_stop(); + sntp_init(); +} + +bool sntp_restart(void) +{ + if (sntp_enabled()) { + SNTP_ERROR(tcpip_callback(sntp_do_restart, NULL), "sntp_restart: tcpip_callback() failed"); + return true; + } + return false; +} + +void sntp_set_system_time(uint32_t sec, uint32_t us) +{ + // Note: SNTP/NTP timestamp is defined as 64-bit fixed point int + // in seconds from 1900 (integer part is the first 32 bits) + // which overflows in 2036. + // The lifetime of the NTP timestamps has been extended by convention + // of the MSB bit 0 to span between 1968 and 2104. This is implemented + // in lwip sntp module, so this API returns number of seconds/milliseconds + // representing dates range from 1968 to 2104. + // (see: RFC-4330#section-3 and https://github.com/lwip-tcpip/lwip/blob/239918cc/src/apps/sntp/sntp.c#L129-L134) + // Warning: Here, we convert the 32 bit NTP timestamp to 64 bit representation + // of system time (time_t). This won't work for timestamps in future + // after some time in 2104 + struct timeval tv = { .tv_sec = sec, .tv_usec = us }; + sntp_sync_time(&tv); +} + +void sntp_get_system_time(uint32_t *sec, uint32_t *us) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + gettimeofday(&tv, NULL); + // Warning: Here, we convert 64 bit representation of system time (time_t) to + // 32 bit NTP timestamp. This won't work for future timestamps after some time in 2104 + // (see: RFC-4330#section-3) + *(sec) = tv.tv_sec; + *(us) = tv.tv_usec; + sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); +} + +static void do_setoperatingmode(void *ctx) +{ + sntp_setoperatingmode((intptr_t)ctx); +} + +void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode) +{ + SNTP_ERROR(tcpip_callback(do_setoperatingmode, (void*)operating_mode), + "esp_sntp_setoperatingmode: tcpip_callback() failed"); +} + +static void do_init(void *ctx) +{ + sntp_init(); +} + +void esp_sntp_init(void) +{ + SNTP_ERROR(tcpip_callback(do_init, NULL), "esp_sntp_init: tcpip_callback() failed"); +} + +static void do_stop(void *ctx) +{ + sntp_stop(); +} + +void esp_sntp_stop(void) +{ + SNTP_ERROR(tcpip_callback(do_stop, NULL), "esp_sntp_stop: tcpip_callback() failed"); +} + +struct tcpip_setserver { + struct tcpip_api_call_data call; + u8_t idx; + const ip_addr_t *addr; +}; + +static err_t do_setserver(struct tcpip_api_call_data *msg) +{ + struct tcpip_setserver *params = __containerof(msg, struct tcpip_setserver, call); + sntp_setserver(params->idx, params->addr); + return ERR_OK; +} + +void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr) +{ + struct tcpip_setserver params = { + .idx = idx, + .addr = addr + }; + SNTP_ERROR(tcpip_api_call(do_setserver, ¶ms.call), "esp_sntp_setserver :tcpip_api_call() failed"); +} + +struct tcpip_setservername { + struct tcpip_api_call_data call; + u8_t idx; + const char *server; +}; + +static err_t do_setservername(struct tcpip_api_call_data *msg) +{ + struct tcpip_setservername *params = __containerof(msg, struct tcpip_setservername, call); + sntp_setservername(params->idx, params->server); + return ERR_OK; +} + +void esp_sntp_setservername(u8_t idx, const char *server) +{ + struct tcpip_setservername params = { + .idx = idx, + .server = server + }; + SNTP_ERROR(tcpip_api_call(do_setservername, ¶ms.call), "esp_sntp_setservername :tcpip_api_call() failed"); +} + +const char *esp_sntp_getservername(u8_t idx) +{ + return sntp_getservername(idx); +} + +const ip_addr_t* esp_sntp_getserver(u8_t idx) +{ + return sntp_getserver(idx); +} + +uint8_t esp_sntp_getreachability(uint8_t idx) +{ +#if SNTP_MONITOR_SERVER_REACHABILITY + return sntp_getreachability(idx); +#endif + LWIP_ERROR("sntp_getreachability() in not enabled in lwipopts", false, ); + return 0; +} + +esp_sntp_operatingmode_t esp_sntp_getoperatingmode(void) +{ + return (esp_sntp_operatingmode_t)sntp_getoperatingmode(); +} + +#if LWIP_DHCP_GET_NTP_SRV +static void do_servermode_dhcp(void* ctx) +{ + sntp_servermode_dhcp((intptr_t)ctx); +} + +void esp_sntp_servermode_dhcp(bool enable) +{ + SNTP_ERROR(tcpip_callback(do_servermode_dhcp, (void*)enable), "esp_sntp_servermode_dhcp: tcpip_callback() failed"); +} + +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +bool esp_sntp_enabled(void) +{ + return sntp_enabled(); +} diff --git a/components/lwip/include/apps/dhcpserver/dhcpserver.h b/components/lwip/include/apps/dhcpserver/dhcpserver.h new file mode 100644 index 000000000..aa83c4057 --- /dev/null +++ b/components/lwip/include/apps/dhcpserver/dhcpserver.h @@ -0,0 +1,192 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __DHCPS_H__ +#define __DHCPS_H__ + +#include "sdkconfig.h" +#include +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dhcps_state{ + s16_t state; +} dhcps_state; + +typedef struct dhcps_msg { + u8_t op, htype, hlen, hops; + u8_t xid[4]; + u16_t secs, flags; + u8_t ciaddr[4]; + u8_t yiaddr[4]; + u8_t siaddr[4]; + u8_t giaddr[4]; + u8_t chaddr[16]; + u8_t sname[64]; + u8_t file[128]; + u8_t options[312]; +}dhcps_msg; + +/* Defined in esp_misc.h */ +typedef struct { + bool enable; + ip4_addr_t start_ip; + ip4_addr_t end_ip; +} dhcps_lease_t; + +enum dhcps_offer_option{ + OFFER_START = 0x00, + OFFER_ROUTER = 0x01, + OFFER_DNS = 0x02, + OFFER_END +}; + +/** @brief DHCP server's description of compile time configuration values in dhcpserver.c + * + * - DHCPS_DEBUG: Prints very detailed debug messages if set to 1, hardcoded to 0 + * - USE_CLASS_B_NET: Use class B network mask if enabled, not-defined (could be enabled as CC_FLAGS) + * - MAX_STATION_NUM: Maximum number of clients, set to Kconfig value CONFIG_LWIP_DHCPS_MAX_STATION_NUM + * - LWIP_HOOK_DHCPS_POST_STATE: Used to inject user code after parsing DHCP message, not defined + * - could be enabled in lwipopts.h or via CC_FLAGS + * - basic usage of the hook to print hex representation of the entire option field is below: + * #define LWIP_HOOK_DHCPS_POST_STATE(msg, len, state) \ + * ({ s16_t ret = state; if (state == DHCPS_STATE_ACK) { ESP_LOG_BUFFER_HEXDUMP("DHCPS",msg->options, 312, ESP_LOG_INFO);} ret; }) + */ + +/** + * @brief Definitions related to lease time, units and limits + */ +#define DHCPS_COARSE_TIMER_SECS 1 +#define DHCPS_MAX_LEASE 0x64 +#define DHCPS_LEASE_TIME_DEF (120) +#define DHCPS_LEASE_UNIT CONFIG_LWIP_DHCPS_LEASE_UNIT + +struct dhcps_pool{ + ip4_addr_t ip; + u8_t mac[6]; + u32_t lease_timer; +}; + +typedef u32_t dhcps_time_t; +typedef u8_t dhcps_offer_t; + +typedef struct { + dhcps_offer_t dhcps_offer; + dhcps_offer_t dhcps_dns; + dhcps_time_t dhcps_time; + dhcps_lease_t dhcps_poll; +} dhcps_options_t; + +typedef void (*dhcps_cb_t)(void* cb_arg, u8_t client_ip[4], u8_t client_mac[6]); + +static inline bool dhcps_router_enabled (dhcps_offer_t offer) +{ + return (offer & OFFER_ROUTER) != 0; +} + +static inline bool dhcps_dns_enabled (dhcps_offer_t offer) +{ + return (offer & OFFER_DNS) != 0; +} + +typedef struct dhcps_t dhcps_t; + +/** + * @brief Creates new DHCP server object + * + * @return Pointer to the DHCP server handle on success, NULL on error + */ +dhcps_t *dhcps_new(void); + +/** + * @brief Deletes supplied DHPC server object + * + * @warning This may not delete the handle immediately if the server wasn't + * stopped properly, but mark for deleting once the timer callback occurs + * + * @param dhcps Pointer to the DHCP handle + */ +void dhcps_delete(dhcps_t *dhcps); + +/** + * @brief Starts the DHCP server on the specified network interface + * + * @param dhcps Pointer to the DHCP handle + * @param netif Pointer to the lwIP's network interface struct + * @param ip DHCP server's address + * @return ERR_ARG if invalid args, ERR_OK on success + */ +err_t dhcps_start(dhcps_t *dhcps, struct netif *netif, ip4_addr_t ip); + +/** + * @brief Stops the DHCP server on the specified netif + * @param dhcps Pointer to the DHCP handle + * @param netif Pointer to the lwIP's network interface struct + * @return ERR_ARG if invalid args, ERR_OK on success + */ +err_t dhcps_stop(dhcps_t *dhcps, struct netif *netif); + +/** + * @brief Gets the DHCP server option info + * @param dhcps Pointer to the DHCP handle + * @param op_id DHCP message option id + * @param opt_len DHCP message option length + * @return DHCP message option addr + */ +void *dhcps_option_info(dhcps_t *dhcps, u8_t op_id, u32_t opt_len); + +/** + * @brief Sets the DHCP server option info + * @param dhcps Pointer to the DHCP handle + * @param op_id DHCP message option id + * @param opt_info DHCP message option info + * @param opt_len DHCP message option length + * @return ERR_ARG if invalid args, ERR_OK on success + */ +err_t dhcps_set_option_info(dhcps_t *dhcps, u8_t op_id, void *opt_info, u32_t opt_len); + +/** + * @brief Tries to find IP address corresponding to the supplied MAC + * @param dhcps Pointer to the DHCP handle + * @param mac Supplied MAC address + * @param ip Pointer to the resultant IP address + * @return True if the IP address has been found + */ +bool dhcp_search_ip_on_mac(dhcps_t *dhcps, u8_t *mac, ip4_addr_t *ip); + +/** + * @brief Sets DNS server address for the DHCP server + * @param dhcps Pointer to the DHCP handle + * @param dnsserver Address of the DNS server + * @return ERR_ARG if invalid handle, ERR_OK on success + */ +err_t dhcps_dns_setserver(dhcps_t *dhcps, const ip_addr_t *dnsserver); + +/** + * @brief Gets DNS server associated with this DHCP server + * @param dhcps Pointer to the DHCP handle + * @param dnsserver Address of the DNS server + * @return ERR_ARG if invalid handle, ERR_OK on success + */ +err_t dhcps_dns_getserver(dhcps_t *dhcps, ip4_addr_t *dnsserver); + +/** + * @brief Sets callback on assigning an IP to the connected client + * @param dhcps Pointer to the DHCP handle + * @param cb Callback for dhcp server + * @param cb_arg Context pointer to be added to the callback + * @return ERR_ARG if invalid handle, ERR_OK on success + */ +err_t dhcps_set_new_lease_cb(dhcps_t *dhcps, dhcps_cb_t cb, void* cb_arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __DHCPS_H__ */ diff --git a/components/lwip/include/apps/dhcpserver/dhcpserver_options.h b/components/lwip/include/apps/dhcpserver/dhcpserver_options.h new file mode 100644 index 000000000..9959600ee --- /dev/null +++ b/components/lwip/include/apps/dhcpserver/dhcpserver_options.h @@ -0,0 +1,141 @@ +// Copyright 2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif +/** DHCP Options + + This macros are not part of the public dhcpserver.h interface. + **/ +typedef enum +{ + /* RFC 1497 Vendor Extensions */ + + PAD = 0, + END = 255, + + SUBNET_MASK = 1, + TIME_OFFSET = 2, + ROUTER = 3, + TIME_SERVER = 4, + NAME_SERVER = 5, + DOMAIN_NAME_SERVER = 6, + LOG_SERVER = 7, + COOKIE_SERVER = 8, + LPR_SERVER = 9, + IMPRESS_SERVER = 10, + RESOURCE_LOCATION_SERVER = 11, + HOST_NAME = 12, + BOOT_FILE_SIZE = 13, + MERIT_DUMP_FILE = 14, + DOMAIN_NAME = 15, + SWAP_SERVER = 16, + ROOT_PATH = 17, + EXTENSIONS_PATH = 18, + + /* IP Layer Parameters per Host */ + + IP_FORWARDING = 19, + NON_LOCAL_SOURCE_ROUTING = 20, + POLICY_FILTER = 21, + MAXIMUM_DATAGRAM_REASSEMBLY_SIZE = 22, + DEFAULT_IP_TIME_TO_LIVE = 23, + PATH_MTU_AGING_TIMEOUT = 24, + PATH_MTU_PLATEAU_TABLE = 25, + + /* IP Layer Parameters per Interface */ + + INTERFACE_MTU = 26, + ALL_SUBNETS_ARE_LOCAL = 27, + BROADCAST_ADDRESS = 28, + PERFORM_MASK_DISCOVERY = 29, + MASK_SUPPLIER = 30, + PERFORM_ROUTER_DISCOVERY = 31, + ROUTER_SOLICITATION_ADDRESS = 32, + STATIC_ROUTE = 33, + + /* Link Layer Parameters per Interface */ + + TRAILER_ENCAPSULATION = 34, + ARP_CACHE_TIMEOUT = 35, + ETHERNET_ENCAPSULATION = 36, + + /* TCP Parameters */ + + TCP_DEFAULT_TTL = 37, + TCP_KEEPALIVE_INTERVAL = 38, + TCP_KEEPALIVE_GARBAGE = 39, + + /* Application and Service Parameters */ + + NETWORK_INFORMATION_SERVICE_DOMAIN = 40, + NETWORK_INFORMATION_SERVERS = 41, + NETWORK_TIME_PROTOCOL_SERVERS = 42, + VENDOR_SPECIFIC_INFORMATION = 43, + NETBIOS_OVER_TCP_IP_NAME_SERVER = 44, + NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER = 45, + NETBIOS_OVER_TCP_IP_NODE_TYPE = 46, + NETBIOS_OVER_TCP_IP_SCOPE = 47, + X_WINDOW_SYSTEM_FONT_SERVER = 48, + X_WINDOW_SYSTEM_DISPLAY_MANAGER = 49, + NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN = 64, + NETWORK_INFORMATION_SERVICE_PLUS_SERVERS = 65, + MOBILE_IP_HOME_AGENT = 68, + SMTP_SERVER = 69, + POP3_SERVER = 70, + NNTP_SERVER = 71, + DEFAULT_WWW_SERVER = 72, + DEFAULT_FINGER_SERVER = 73, + DEFAULT_IRC_SERVER = 74, + STREETTALK_SERVER = 75, + STREETTALK_DIRECTORY_ASSISTANCE_SERVER = 76, + + /* DHCP Extensions */ + + REQUESTED_IP_ADDRESS = 50, + IP_ADDRESS_LEASE_TIME = 51, + OPTION_OVERLOAD = 52, + TFTP_SERVER_NAME = 66, + BOOTFILE_NAME = 67, + DHCP_MESSAGE_TYPE = 53, + SERVER_IDENTIFIER = 54, + PARAMETER_REQUEST_LIST = 55, + MESSAGE = 56, + MAXIMUM_DHCP_MESSAGE_SIZE = 57, + RENEWAL_T1_TIME_VALUE = 58, + REBINDING_T2_TIME_VALUE = 59, + VENDOR_CLASS_IDENTIFIER = 60, + CLIENT_IDENTIFIER = 61, + + USER_CLASS = 77, + FQDN = 81, + DHCP_AGENT_OPTIONS = 82, + NDS_SERVERS = 85, + NDS_TREE_NAME = 86, + NDS_CONTEXT = 87, + CLIENT_LAST_TRANSACTION_TIME = 91, + ASSOCIATED_IP = 92, + USER_AUTHENTICATION_PROTOCOL = 98, + AUTO_CONFIGURE = 116, + NAME_SERVICE_SEARCH = 117, + SUBNET_SELECTION = 118, + DOMAIN_SEARCH = 119, + CLASSLESS_ROUTE = 121, +} dhcp_msg_option; + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/include/apps/esp_ping.h b/components/lwip/include/apps/esp_ping.h new file mode 100644 index 000000000..2cf940a8d --- /dev/null +++ b/components/lwip/include/apps/esp_ping.h @@ -0,0 +1,112 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ESP_PING_H_ +#define ESP_PING_H_ + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// gen_esp_err_to_name.py: include this as "esp_ping.h" because "components/lwip/include/apps/" is in the compiler path +// and not "components/lwip/include" + +#define ESP_ERR_PING_BASE 0xa000 + +#define ESP_ERR_PING_INVALID_PARAMS ESP_ERR_PING_BASE + 0x01 +#define ESP_ERR_PING_NO_MEM ESP_ERR_PING_BASE + 0x02 + +#define ESP_PING_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return ESP_ERR_PING_INVALID_PARAMS; }}while(0) + +typedef struct _ping_found { + uint32_t resp_time; + uint32_t timeout_count; + uint32_t send_count; + uint32_t recv_count; + uint32_t err_count; + uint32_t bytes; + uint32_t total_bytes; + uint32_t total_time; + uint32_t min_time; + uint32_t max_time; + int8_t ping_err; +} esp_ping_found; + +typedef enum { + PING_TARGET_IP_ADDRESS = 50, /**< target IP address */ + PING_TARGET_IP_ADDRESS_COUNT = 51, /**< target IP address total counter */ + PING_TARGET_RCV_TIMEO = 52, /**< receive timeout in milliseconds */ + PING_TARGET_DELAY_TIME = 53, /**< delay time in milliseconds */ + PING_TARGET_ID = 54, /**< identifier */ + PING_TARGET_RES_FN = 55, /**< ping result callback function */ + PING_TARGET_RES_RESET = 56, /**< ping result statistic reset */ + PING_TARGET_DATA_LEN = 57, /**< ping data length*/ + PING_TARGET_IP_TOS = 58, /**< ping QOS*/ + PING_TARGET_IF_INDEX = 59 /**< ping if index*/ +} ping_target_id_t; + +typedef enum { + PING_RES_TIMEOUT = 0, + PING_RES_OK = 1, + PING_RES_FINISH = 2, +} ping_res_t; + +typedef void (* esp_ping_found_fn)(ping_target_id_t found_id, esp_ping_found *found_val); + +/** + * @brief Set PING function option + * + * @param[in] opt_id: option index, 50 for IP, 51 for COUNT, 52 for RCV TIMEOUT, 53 for DELAY TIME, 54 for ID + * @param[in] opt_val: option parameter + * @param[in] opt_len: option length + * + * @return + * - ESP_OK + * - ESP_ERR_PING_INVALID_PARAMS + */ +esp_err_t esp_ping_set_target(ping_target_id_t opt_id, void *opt_val, uint32_t opt_len); + +/** + * @brief Get PING function option + * + * @param[in] opt_id: option index, 50 for IP, 51 for COUNT, 52 for RCV TIMEOUT, 53 for DELAY TIME, 54 for ID + * @param[in] opt_val: option parameter + * @param[in] opt_len: option length + * + * @return + * - ESP_OK + * - ESP_ERR_PING_INVALID_PARAMS + */ +esp_err_t esp_ping_get_target(ping_target_id_t opt_id, void *opt_val, uint32_t opt_len); + +/** + * @brief Get PING function result action + * + * @param[in] res_val: ping function action, 1 for successful, 0 for fail. + * res_len: response bytes + * res_time: response time + * + * @return + * - ESP_OK + * - ESP_ERR_PING_INVALID_PARAMS + */ +esp_err_t esp_ping_result(uint8_t res_val, uint16_t res_len, uint32_t res_time); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_PING_H_ */ diff --git a/components/lwip/include/apps/esp_sntp.h b/components/lwip/include/apps/esp_sntp.h new file mode 100644 index 000000000..39aee2494 --- /dev/null +++ b/components/lwip/include/apps/esp_sntp.h @@ -0,0 +1,305 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ESP_SNTP_H__ +#define __ESP_SNTP_H__ + +#include "lwip/err.h" +#include "lwip/ip.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The time update takes place in the sntp_sync_time() function. + * The user has the ability to redefine this function in order + * to re-define its functionality. This function has two time update modes, + * which can be set via the sntp_set_sync_mode() function. + * Two available modes are as follows: + * - the first is an immediate update when receiving time from the sntp server, + * - the second is a smooth time update (if the time error is no more than 35 minutes, + * and an immediate update if the error is more than 35 minutes). + * + * To receive notification of time synchronization, + * you can use the callback function or get the synchronization status + * via the sntp_get_sync_status() function. + * + * To determine the time synchronization time on the device, you can use: + * 1) sntp_set_time_sync_notification_cb() function to set the callback function, + * which is convenient to use to receive notification of the update time. + * 2) sntp_get_sync_status() function for getting time synchronization status. + * After the time synchronization is completed, the status will be + * SNTP_SYNC_STATUS_COMPLETED, after, it will be reseted to SNTP_SYNC_STATUS_RESET + * to wait for the next sync cycle. + */ + +/// Aliases for esp_sntp prefixed API (inherently thread safe) +#define esp_sntp_sync_time sntp_sync_time +#define esp_sntp_set_sync_mode sntp_set_sync_mode +#define esp_sntp_get_sync_mode sntp_get_sync_mode +#define esp_sntp_get_sync_status sntp_get_sync_status +#define esp_sntp_set_sync_status sntp_set_sync_status +#define esp_sntp_set_time_sync_notification_cb sntp_set_time_sync_notification_cb +#define esp_sntp_set_sync_interval sntp_set_sync_interval +#define esp_sntp_get_sync_interval sntp_get_sync_interval +#define esp_sntp_restart sntp_restart + +#ifndef SNTP_OPMODE_POLL +#define SNTP_OPMODE_POLL ESP_SNTP_OPMODE_POLL +#else +#warning "Defined!" +#endif /* SNTP_OPMODE_POLL */ + +/// SNTP time update mode +typedef enum { + SNTP_SYNC_MODE_IMMED, /*!< Update system time immediately when receiving a response from the SNTP server. */ + SNTP_SYNC_MODE_SMOOTH, /*!< Smooth time updating. Time error is gradually reduced using adjtime function. If the difference between SNTP response time and system time is large (more than 35 minutes) then update immediately. */ +} sntp_sync_mode_t; + +/// SNTP sync status +typedef enum { + SNTP_SYNC_STATUS_RESET, // Reset status. + SNTP_SYNC_STATUS_COMPLETED, // Time is synchronized. + SNTP_SYNC_STATUS_IN_PROGRESS, // Smooth time sync in progress. +} sntp_sync_status_t; + +/// SNTP operating modes per lwip SNTP module +typedef enum { + ESP_SNTP_OPMODE_POLL, + ESP_SNTP_OPMODE_LISTENONLY, +} esp_sntp_operatingmode_t; + +/** + * @brief SNTP callback function for notifying about time sync event + * + * @param tv Time received from SNTP server. + */ +typedef void (*sntp_sync_time_cb_t) (struct timeval *tv); + +/** + * @brief This function updates the system time. + * + * This is a weak-linked function. It is possible to replace all SNTP update functionality + * by placing a sntp_sync_time() function in the app firmware source. + * If the default implementation is used, calling sntp_set_sync_mode() allows + * the time synchronization mode to be changed to instant or smooth. + * If a callback function is registered via sntp_set_time_sync_notification_cb(), + * it will be called following time synchronization. + * + * @param tv Time received from SNTP server. + */ +void sntp_sync_time(struct timeval *tv); + +/** + * @brief Set the sync mode + * + * Modes allowed: SNTP_SYNC_MODE_IMMED and SNTP_SYNC_MODE_SMOOTH. + * @param sync_mode Sync mode. + */ +void sntp_set_sync_mode(sntp_sync_mode_t sync_mode); + +/** + * @brief Get set sync mode + * + * @return SNTP_SYNC_MODE_IMMED: Update time immediately. + * SNTP_SYNC_MODE_SMOOTH: Smooth time updating. + */ +sntp_sync_mode_t sntp_get_sync_mode(void); + +/** + * @brief Get status of time sync + * + * After the update is completed, the status will be returned as SNTP_SYNC_STATUS_COMPLETED. + * After that, the status will be reset to SNTP_SYNC_STATUS_RESET. + * If the update operation is not completed yet, the status will be SNTP_SYNC_STATUS_RESET. + * If a smooth mode was chosen and the synchronization is still continuing (adjtime works), then it will be SNTP_SYNC_STATUS_IN_PROGRESS. + * + * @return SNTP_SYNC_STATUS_RESET: Reset status. + * SNTP_SYNC_STATUS_COMPLETED: Time is synchronized. + * SNTP_SYNC_STATUS_IN_PROGRESS: Smooth time sync in progress. + */ +sntp_sync_status_t sntp_get_sync_status(void); + +/** + * @brief Set status of time sync + * + * @param sync_status status of time sync (see sntp_sync_status_t) + */ +void sntp_set_sync_status(sntp_sync_status_t sync_status); + +/** + * @brief Set a callback function for time synchronization notification + * + * @param callback a callback function + */ +void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback); + +/** + * @brief Set the sync interval of SNTP operation + * + * Note: SNTPv4 RFC 4330 enforces a minimum sync interval of 15 seconds. + * This sync interval will be used in the next attempt update time throught SNTP. + * To apply the new sync interval call the sntp_restart() function, + * otherwise, it will be applied after the last interval expired. + * + * @param interval_ms The sync interval in ms. It cannot be lower than 15 seconds, otherwise 15 seconds will be set. + */ +void sntp_set_sync_interval(uint32_t interval_ms); + +/** + * @brief Get the sync interval of SNTP operation + * + * @return the sync interval + */ +uint32_t sntp_get_sync_interval(void); + +/** + * @brief Restart SNTP + * + * @return True - Restart + * False - SNTP was not initialized yet + */ +bool sntp_restart(void); + +/** + * @brief Sets SNTP operating mode. The mode has to be set before init. + * + * @param operating_mode Desired operating mode + */ +void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode); + +/** + * @brief Init and start SNTP service + */ +void esp_sntp_init(void); + +/** + * @brief Stops SNTP service + */ +void esp_sntp_stop(void); + +/** + * @brief Sets SNTP server address + * + * @param idx Index of the server + * @param addr IP address of the server + */ +void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr); + +/** + * @brief Sets SNTP hostname + * @param idx Index of the server + * @param server Name of the server + */ +void esp_sntp_setservername(u8_t idx, const char *server); + +/** + * @brief Gets SNTP server name + * @param idx Index of the server + * @return Name of the server + */ +const char *esp_sntp_getservername(u8_t idx); + +/** + * @brief Get SNTP server IP + * @param idx Index of the server + * @return IP address of the server + */ +const ip_addr_t* esp_sntp_getserver(u8_t idx); + +/** + * @brief Checks if sntp is enabled + * @return true if sntp module is enabled + */ +bool esp_sntp_enabled(void); + +/** + * @brief Gets the server reachability shift register as described in RFC 5905. + * @param idx Index of the SNTP server + * @return reachability shift register + */ +uint8_t esp_sntp_getreachability(uint8_t idx); + +/** + * @brief Get the configured operating mode + * + * @return operating mode enum + */ +esp_sntp_operatingmode_t esp_sntp_getoperatingmode(void); + +#if LWIP_DHCP_GET_NTP_SRV +/** + * @brief Enable acquiring SNTP server from DHCP + * @param enable True for enabling SNTP from DHCP + */ +void esp_sntp_servermode_dhcp(bool enable); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#if !defined(ESP_LWIP_COMPONENT_BUILD) && !defined(ESP_NETIF_COMPONENT_BUILD) +/** + * @brief if not build within lwip, provide translating inlines, + * that will warn about thread safety + */ +static inline __attribute__((deprecated("use esp_sntp_setoperatingmode() instead"))) +void sntp_setoperatingmode(u8_t operating_mode) +{ + esp_sntp_setoperatingmode((esp_sntp_operatingmode_t)operating_mode); +} + +static inline __attribute__((deprecated("use esp_sntp_servermode_dhcp() instead"))) +void sntp_servermode_dhcp(int set_servers_from_dhcp) +{ +#if LWIP_DHCP_GET_NTP_SRV + esp_sntp_servermode_dhcp(set_servers_from_dhcp); +#endif +} + +static inline __attribute__((deprecated("use esp_sntp_setservername() instead"))) +void sntp_setservername(u8_t idx, const char *server) +{ + esp_sntp_setservername(idx, server); +} + +static inline __attribute__((deprecated("use esp_sntp_init() instead"))) +void sntp_init(void) +{ + esp_sntp_init(); +} + +static inline __attribute__((deprecated("use esp_sntp_getservername() instead"))) +const char *sntp_getservername(u8_t idx) +{ + return esp_sntp_getservername(idx); +} + +static inline __attribute__((deprecated("use esp_sntp_getserver() instead"))) +const ip_addr_t* sntp_getserver(u8_t idx) +{ + return esp_sntp_getserver(idx); +} + +static inline __attribute__((deprecated("use esp_sntp_getreachability() instead"))) +uint8_t sntp_getreachability(uint8_t idx) +{ + return esp_sntp_getreachability(idx); +} + +static inline __attribute__((deprecated("use esp_sntp_getoperatingmode() instead"))) +esp_sntp_operatingmode_t sntp_getoperatingmode(void) +{ + return esp_sntp_getoperatingmode(); +} + +#endif /* ESP_LWIP_COMPONENT_BUILD */ + + +#ifdef __cplusplus +} +#endif + +#endif // __ESP_SNTP_H__ diff --git a/components/lwip/include/apps/ping/ping.h b/components/lwip/include/apps/ping/ping.h new file mode 100644 index 000000000..dd9ef342f --- /dev/null +++ b/components/lwip/include/apps/ping/ping.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +#ifndef LWIP_PING_H +#define LWIP_PING_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used + */ +#ifndef PING_USE_SOCKETS +#define PING_USE_SOCKETS LWIP_SOCKET +#endif + + +int ping_init(void) __attribute__ ((deprecated)); + +#ifdef ESP_PING +void ping_deinit(void) __attribute__ ((deprecated)); +#endif + +#if !PING_USE_SOCKETS +void ping_send_now(void); +#endif /* !PING_USE_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_PING_H */ diff --git a/components/lwip/include/apps/ping/ping_sock.h b/components/lwip/include/apps/ping/ping_sock.h new file mode 100644 index 000000000..c8e0a21ad --- /dev/null +++ b/components/lwip/include/apps/ping/ping_sock.h @@ -0,0 +1,166 @@ +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_err.h" +#include "lwip/ip_addr.h" + +/** +* @brief Type of "ping" session handle +* +*/ +typedef void *esp_ping_handle_t; + +/** +* @brief Type of "ping" callback functions +* +*/ +typedef struct { + /** + * @brief arguments for callback functions + * + */ + void *cb_args; + + /** + * @brief Invoked by internal ping thread when received ICMP echo reply packet + * + */ + void (*on_ping_success)(esp_ping_handle_t hdl, void *args); + + /** + * @brief Invoked by internal ping thread when receive ICMP echo reply packet timeout + * + */ + void (*on_ping_timeout)(esp_ping_handle_t hdl, void *args); + + /** + * @brief Invoked by internal ping thread when a ping session is finished + * + */ + void (*on_ping_end)(esp_ping_handle_t hdl, void *args); +} esp_ping_callbacks_t; + +/** +* @brief Type of "ping" configuration +* +*/ +typedef struct { + uint32_t count; /*!< A "ping" session contains count procedures */ + uint32_t interval_ms; /*!< Milliseconds between each ping procedure */ + uint32_t timeout_ms; /*!< Timeout value (in milliseconds) of each ping procedure */ + uint32_t data_size; /*!< Size of the data next to ICMP packet header */ + int tos; /*!< Type of Service, a field specified in the IP header */ + int ttl; /*!< Time to Live,a field specified in the IP header */ + ip_addr_t target_addr; /*!< Target IP address, either IPv4 or IPv6 */ + uint32_t task_stack_size; /*!< Stack size of internal ping task */ + uint32_t task_prio; /*!< Priority of internal ping task */ + uint32_t interface; /*!< Netif index, interface=0 means NETIF_NO_INDEX*/ +} esp_ping_config_t; + +/** + * @brief Default ping configuration + * + */ +#define ESP_PING_DEFAULT_CONFIG() \ + { \ + .count = 5, \ + .interval_ms = 1000, \ + .timeout_ms = 1000, \ + .data_size = 64, \ + .tos = 0, \ + .ttl = IP_DEFAULT_TTL, \ + .target_addr = *(IP_ANY_TYPE), \ + .task_stack_size = ESP_TASK_PING_STACK, \ + .task_prio = 2, \ + .interface = 0,\ + } + +#define ESP_PING_COUNT_INFINITE (0) /*!< Set ping count to zero will ping target infinitely */ + +/** +* @brief Profile of ping session +* +*/ +typedef enum { + ESP_PING_PROF_SEQNO, /*!< Sequence number of a ping procedure */ + ESP_PING_PROF_TOS, /*!< Type of service of a ping procedure */ + ESP_PING_PROF_TTL, /*!< Time to live of a ping procedure */ + ESP_PING_PROF_REQUEST, /*!< Number of request packets sent out */ + ESP_PING_PROF_REPLY, /*!< Number of reply packets received */ + ESP_PING_PROF_IPADDR, /*!< IP address of replied target */ + ESP_PING_PROF_SIZE, /*!< Size of received packet */ + ESP_PING_PROF_TIMEGAP, /*!< Elapsed time between request and reply packet */ + ESP_PING_PROF_DURATION /*!< Elapsed time of the whole ping session */ +} esp_ping_profile_t; + +/** + * @brief Create a ping session + * + * @param config ping configuration + * @param cbs a bunch of callback functions invoked by internal ping task + * @param hdl_out handle of ping session + * @return + * - ESP_ERR_INVALID_ARG: invalid parameters (e.g. configuration is null, etc) + * - ESP_ERR_NO_MEM: out of memory + * - ESP_FAIL: other internal error (e.g. socket error) + * - ESP_OK: create ping session successfully, user can take the ping handle to do follow-on jobs + */ +esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_callbacks_t *cbs, esp_ping_handle_t *hdl_out); + +/** + * @brief Delete a ping session + * + * @param hdl handle of ping session + * @return + * - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc) + * - ESP_OK: delete ping session successfully + */ +esp_err_t esp_ping_delete_session(esp_ping_handle_t hdl); + +/** + * @brief Start the ping session + * + * @param hdl handle of ping session + * @return + * - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc) + * - ESP_OK: start ping session successfully + */ +esp_err_t esp_ping_start(esp_ping_handle_t hdl); + +/** + * @brief Stop the ping session + * + * @param hdl handle of ping session + * @return + * - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc) + * - ESP_OK: stop ping session successfully + */ +esp_err_t esp_ping_stop(esp_ping_handle_t hdl); + +/** + * @brief Get runtime profile of ping session + * + * @param hdl handle of ping session + * @param profile type of profile + * @param data profile data + * @param size profile data size + * @return + * - ESP_ERR_INVALID_ARG: invalid parameters (e.g. ping handle is null, etc) + * - ESP_ERR_INVALID_SIZE: the actual profile data size doesn't match the "size" parameter + * - ESP_OK: get profile successfully + */ +esp_err_t esp_ping_get_profile(esp_ping_handle_t hdl, esp_ping_profile_t profile, void *data, uint32_t size); + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/include/apps/sntp/sntp.h b/components/lwip/include/apps/sntp/sntp.h new file mode 100644 index 000000000..f766078c5 --- /dev/null +++ b/components/lwip/include/apps/sntp/sntp.h @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#warning "sntp.h in IDF's lwip port folder is deprecated. Please include esp_sntp.h" +/* + * This header is provided only for compatibility reasons for existing + * applications which directly include "sntp.h" from the IDF default paths. + * and will be removed in IDF v6.0. + * It is recommended to use "esp_sntp.h" from IDF's lwip port folder + */ +#include "esp_sntp.h" diff --git a/components/lwip/include/lwip/netdb.h b/components/lwip/include/lwip/netdb.h new file mode 100644 index 000000000..b7e3dcf15 --- /dev/null +++ b/components/lwip/include/lwip/netdb.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include_next "lwip/netdb.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) +{ return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); } +static inline struct hostent *gethostbyname(const char *name) +{ return lwip_gethostbyname(name); } +static inline void freeaddrinfo(struct addrinfo *ai) +{ lwip_freeaddrinfo(ai); } +static inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) +{ return lwip_getaddrinfo(nodename, servname, hints, res); } + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/include/lwip/sockets.h b/components/lwip/include/lwip/sockets.h new file mode 100644 index 000000000..94bb6e35b --- /dev/null +++ b/components/lwip/include/lwip/sockets.h @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include_next "lwip/sockets.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int accept(int s,struct sockaddr *addr,socklen_t *addrlen) +{ return lwip_accept(s,addr,addrlen); } +static inline int bind(int s,const struct sockaddr *name, socklen_t namelen) +{ return lwip_bind(s,name,namelen); } +static inline int shutdown(int s,int how) +{ return lwip_shutdown(s,how); } +static inline int getpeername(int s,struct sockaddr *name,socklen_t *namelen) +{ return lwip_getpeername(s,name,namelen); } +static inline int getsockname(int s,struct sockaddr *name,socklen_t *namelen) +{ return lwip_getsockname(s,name,namelen); } +static inline int setsockopt(int s,int level,int optname,const void *opval,socklen_t optlen) +{ return lwip_setsockopt(s,level,optname,opval,optlen); } +static inline int getsockopt(int s,int level,int optname,void *opval,socklen_t *optlen) +{ return lwip_getsockopt(s,level,optname,opval,optlen); } +static inline int closesocket(int s) +{ return lwip_close(s); } +static inline int connect(int s,const struct sockaddr *name,socklen_t namelen) +{ return lwip_connect(s,name,namelen); } +static inline int listen(int s,int backlog) +{ return lwip_listen(s,backlog); } +static inline ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) +{ return lwip_recvmsg(sockfd, msg, flags); } +static inline ssize_t recv(int s,void *mem,size_t len,int flags) +{ return lwip_recv(s,mem,len,flags); } +static inline ssize_t recvfrom(int s,void *mem,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen) +{ return lwip_recvfrom(s,mem,len,flags,from,fromlen); } +static inline ssize_t send(int s,const void *dataptr,size_t size,int flags) +{ return lwip_send(s,dataptr,size,flags); } +static inline ssize_t sendmsg(int s,const struct msghdr *message,int flags) +{ return lwip_sendmsg(s,message,flags); } +static inline ssize_t sendto(int s,const void *dataptr,size_t size,int flags,const struct sockaddr *to,socklen_t tolen) +{ return lwip_sendto(s,dataptr,size,flags,to,tolen); } +static inline int socket(int domain,int type,int protocol) +{ return lwip_socket(domain,type,protocol); } +static inline const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ return lwip_inet_ntop(af, src, dst, size); } +static inline int inet_pton(int af, const char *src, void *dst) +{ return lwip_inet_pton(af, src, dst); } + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/linker.lf b/components/lwip/linker.lf new file mode 100644 index 000000000..b87c98bc4 --- /dev/null +++ b/components/lwip/linker.lf @@ -0,0 +1,138 @@ +[mapping:lwip] +archive: liblwip.a +entries: + if LWIP_IRAM_OPTIMIZATION = y: + sockets:get_socket (noflash_text) + sockets:tryget_socket_unconn_locked (noflash_text) + sockets:done_socket (noflash_text) + sockets:lwip_recvfrom (noflash_text) + sockets:lwip_recv_tcp (noflash_text) + sockets:lwip_send (noflash_text) + sockets:lwip_sendto (noflash_text) + sockets:event_callback (noflash_text) + sockets:lwip_select (noflash_text) + api_lib:netconn_recv_data (noflash_text) + api_lib:netconn_tcp_recvd (noflash_text) + api_lib:netconn_recv_data_tcp (noflash_text) + api_lib:netconn_recv_tcp_pbuf_flags (noflash_text) + api_lib:netconn_recv_udp_raw_netbuf_flags (noflash_text) + api_lib:netconn_recv (noflash_text) + api_lib:netconn_sendto (noflash_text) + api_lib:netconn_send (noflash_text) + api_lib:netconn_write_partly (noflash_text) + api_lib:netconn_write_vectors_partly (noflash_text) + api_msg:lwip_netconn_do_send (noflash_text) + api_msg:lwip_netconn_do_write (noflash_text) + netbuf:netbuf_alloc (noflash_text) + netbuf:netbuf_free (noflash_text) + tcpip:tcpip_thread (noflash_text) + tcpip:tcpip_inpkt (noflash_text) + tcpip:tcpip_input (noflash_text) + tcpip:tcpip_callback (noflash_text) + tcpip:tcpip_try_callback (noflash_text) + tcpip:tcpip_send_msg_wait_sem (noflash_text) + inet_chksum:inet_cksum_pseudo_base (noflash_text) + inet_chksum:inet_chksum_pseudo (noflash_text) + etharp:etharp_output_to_arp_index (noflash_text) + etharp:etharp_output (noflash_text) + ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text) + ip4:ip4_route_src (noflash_text) + ip4:ip4_route (noflash_text) + ip4:ip4_input (noflash_text) + ip4:ip4_output_if (noflash_text) + ip4:ip4_output_if_opt (noflash_text) + ip4:ip4_output_if_src (noflash_text) + ip4:ip4_output_if_opt_src (noflash_text) + ip4:ip4_output (noflash_text) + pbuf:pbuf_alloc (noflash_text) + pbuf:pbuf_add_header (noflash_text) + pbuf:pbuf_remove_header (noflash_text) + pbuf:pbuf_header (noflash_text) + pbuf:pbuf_free (noflash_text) + pbuf:pbuf_alloced_custom (noflash_text) + udp:udp_input_local_match (noflash_text) + udp:udp_input (noflash_text) + udp:udp_send (noflash_text) + udp:udp_sendto (noflash_text) + udp:udp_sendto_if (noflash_text) + udp:udp_sendto_if_src (noflash_text) + ethernet:ethernet_input (noflash_text) + ethernet:ethernet_output (noflash_text) + sys_arch:sys_mutex_lock (noflash_text) + sys_arch:sys_mutex_unlock (noflash_text) + sys_arch:sys_sem_signal (noflash_text) + sys_arch:sys_arch_sem_wait (noflash_text) + sys_arch:sys_mbox_post (noflash_text) + sys_arch:sys_mbox_trypost (noflash_text) + sys_arch:sys_arch_mbox_fetch (noflash_text) + lwip_default_hooks:ip4_route_src_hook (noflash_text) + if COMPILER_OPTIMIZATION_DEBUG = y: + sockets:tryget_socket_unconn (noflash_text) + sockets:tryget_socket (noflash_text) + sockets:lwip_recvfrom_udp_raw (noflash_text) + sockets:tryget_socket_unconn_nouse (noflash_text) + sockets:sock_inc_used (noflash_text) + tcpip:tcpip_thread_handle_msg (noflash_text) + api_lib:netconn_apimsg (noflash_text) + sockets:lwip_recv_tcp_from (noflash_text) + sockets:select_check_waiters (noflash_text) + api_lib:netconn_tcp_recvd_msg (noflash_text) + pbuf:pbuf_header_impl (noflash_text) + pbuf:pbuf_add_header_impl (noflash_text) + pbuf:pbuf_init_alloced_pbuf (noflash_text) + + if LWIP_EXTRA_IRAM_OPTIMIZATION = y: + api_msg:recv_udp (noflash_text) + inet_chksum:inet_chksum_pbuf (noflash_text) + inet_chksum:ip_chksum_pseudo (noflash_text) + inet_chksum:inet_chksum (noflash_text) + inet_chksum:lwip_standard_chksum (noflash_text) + pbuf:pbuf_copy (noflash_text) + pbuf:pbuf_copy_partial_pbuf (noflash_text) + pbuf:pbuf_clone (noflash_text) + tcp:tcp_fasttmr (noflash_text) + tcp:tcp_tmr (noflash_text) + tcp:tcp_update_rcv_ann_wnd (noflash_text) + tcp:tcp_recved (noflash_text) + tcp:tcp_slowtmr (noflash_text) + tcp:tcp_process_refused_data (noflash_text) + tcp:tcp_segs_free (noflash_text) + tcp:tcp_seg_free (noflash_text) + tcp:tcp_seg_copy (noflash_text) + tcp:tcp_recv_null (noflash_text) + tcp_in:tcp_input (noflash_text) + tcp_in:tcp_input_delayed_close (noflash_text) + tcp_in:tcp_oos_insert_segment (noflash_text) + tcp_in:tcp_receive (noflash_text) + tcp_in:tcp_parseopt (noflash_text) + tcp_out:tcp_route (noflash_text) + tcp_out:tcp_create_segment (noflash_text) + tcp_out:tcp_write (noflash_text) + tcp_out:tcp_split_unsent_seg (noflash_text) + tcp_out:tcp_rexmit_rto_prepare (noflash_text) + tcp_out:tcp_rexmit (noflash_text) + tcp_out:tcp_rexmit_fast (noflash_text) + tcp_out:tcp_output_control_segment (noflash_text) + tcp_out:tcp_rst (noflash_text) + tcp_out:tcp_send_empty_ack (noflash_text) + sys_arch:sys_arch_protect (noflash_text) + sys_arch:sys_arch_unprotect (noflash_text) + sys_arch:sys_thread_tcpip (noflash_text) + memp:memp_malloc (noflash_text) + mem:mem_malloc (noflash_text) + raw:raw_input (noflash_text) + if COMPILER_OPTIMIZATION_DEBUG = y: + tcp_in:tcp_free_acked_segments (noflash_text) + tcp_in:tcp_process (noflash_text) + tcp_out:tcp_output_segment (noflash_text) + tcp_out:tcp_output_fill_options (noflash_text) + tcp_out:tcp_output_alloc_header (noflash_text) + tcp_out:tcp_pbuf_prealloc (noflash_text) + tcp_out:tcp_write_checks (noflash_text) + raw:raw_input_local_match (noflash_text) + tcp_out:tcp_output_alloc_header_common (noflash_text) + memp:do_memp_malloc_pool (noflash_text) + if ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY = y: + * (extram_bss) + if VFS_SELECT_IN_RAM = y: + vfs_lwip:lwip_stop_socket_select_isr (noflash) diff --git a/components/lwip/lwip b/components/lwip/lwip new file mode 160000 index 000000000..836c99c09 --- /dev/null +++ b/components/lwip/lwip @@ -0,0 +1 @@ +Subproject commit 836c99c09f78525bc119091c68551d4000294539 diff --git a/components/lwip/port/debug/lwip_debug.c b/components/lwip/port/debug/lwip_debug.c new file mode 100644 index 000000000..f3e08801b --- /dev/null +++ b/components/lwip/port/debug/lwip_debug.c @@ -0,0 +1,211 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "debug/lwip_debug.h" +#include "lwip/api.h" +#include "lwip/netbuf.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "lwip/priv/tcp_priv.h" +#include "lwip/stats.h" +#include "lwip/priv/memp_priv.h" +#include "lwip/memp.h" +#include "esp_log.h" + +#if CONFIG_LWIP_IPV6 && CONFIG_LWIP_IPV4 +#define DBG_LWIP_IP_SHOW(info, ip) ESP_LWIP_LOGI("%s type=%" PRIu8 " ip=%" PRIX32, (info), (ip).type, (ip).u_addr.ip4.addr) +#elif CONFIG_LWIP_IPV4 +#define DBG_LWIP_IP_SHOW(info, ip) ESP_LWIP_LOGI("%s type=%" PRIu8 " ip=%" PRIX32, (info), IPADDR_TYPE_V4, (ip).addr) +#elif CONFIG_LWIP_IPV6 +#define DBG_LWIP_IP_SHOW(info, ip) ESP_LWIP_LOGI("%s type=%" PRIu8 " ip=%" PRIX32 ", %" PRIX32 ", %" PRIX32 ", %" PRIX32 , (info), IPADDR_TYPE_V6, (ip).addr[0], (ip).addr[1], (ip).addr[2], (ip).addr[3]) +#endif +#define DBG_LWIP_IP_PCB_SHOW(pcb) \ + DBG_LWIP_IP_SHOW("local ip", (pcb)->local_ip);\ + DBG_LWIP_IP_SHOW("remote ip", (pcb)->remote_ip);\ + ESP_LWIP_LOGI("so_options=%x, tos=%" PRIu8 " ttl=%" PRIu8, (pcb)->so_options, (pcb)->tos, (pcb)->ttl) + +#define DBG_LWIP_SEG_SHOW(seg) while(seg) { ESP_LWIP_LOGI("\tseg=%p next=%p pbuf=%p flags=%x", (seg), (seg)->next, (seg)->p, (seg)->flags); (seg)=(seg)->next;} +#define DBG_LWIP_ITEM_NUMBER_PER_LINE 9 + +#if ESP_STATS_TCP +static void dbg_lwip_tcp_pcb_cnt_show(struct tcp_pcb *pcb) +{ + int len = 0; + char *buf; + char *p; + int i; + + buf = mem_malloc(512); + if (!buf) { + return; + } + + p = buf; + len += sprintf(p + len, "%11s", "tcp_retry: "); + for (i=0; iretry_cnt[i]); + } + ESP_LWIP_LOGI("%s", buf); + p = buf; + len = 0; + len += sprintf(p + len, "%11s", "tcp_rto#0:"); + for (i=0; irto_cnt[i]); + } + ESP_LWIP_LOGI("%s", buf); + + free(buf); +} +#endif + +static void dbg_lwip_tcp_pcb_one_show(struct tcp_pcb* pcb) +{ + struct tcp_seg *seg = NULL; + + if (!pcb) { + return; + } + + ESP_LWIP_LOGI("pcb=%p next=%p cb_arg=%p", pcb, pcb->next, pcb->callback_arg); + DBG_LWIP_IP_PCB_SHOW(pcb); + ESP_LWIP_LOGI("state=%x", pcb->state); + ESP_LWIP_LOGI("prio=%d", pcb->prio); + ESP_LWIP_LOGI("local_port=%d, remote_port=%d", pcb->local_port, pcb->remote_port); + ESP_LWIP_LOGI("flags=%x", pcb->flags); + ESP_LWIP_LOGI("pooltmr=%d pollinterval=%d, last_tmr=%d tmr=%" PRIu32 " rtmer=%d", pcb->polltmr, pcb->pollinterval, pcb->last_timer, pcb->tmr, pcb->rtime); + ESP_LWIP_LOGI("recv_nxt=%" PRIu32 " recv_wnd=%"TCPWNDSIZE_F" recv_ann_wnd=%"TCPWNDSIZE_F" recv_ann_right_edge=%" PRIu32, pcb->rcv_nxt, pcb->rcv_wnd, pcb->rcv_ann_wnd, pcb->rcv_ann_right_edge); + ESP_LWIP_LOGI("mss=%d", pcb->mss); + ESP_LWIP_LOGI("rttest=%" PRIu32 " rtseq=%" PRIu32 " sa=%d sv=%d", pcb->rttest, pcb->rtseq, pcb->sa, pcb->sv); + ESP_LWIP_LOGI("rto=%d nrtx=%d", pcb->rto, pcb->nrtx); + ESP_LWIP_LOGI("dupacks=%d lastack=%" PRIu32, pcb->dupacks, pcb->lastack); +#if ESP_PER_SOC_TCP_WND + ESP_LWIP_LOGI("per_soc_window=%d per_soc_snd_buf=%d", pcb->per_soc_tcp_wnd, pcb->per_soc_tcp_snd_buf); +#endif + ESP_LWIP_LOGI("cwnd=%"TCPWNDSIZE_F" ssthreash=%"TCPWNDSIZE_F, pcb->cwnd, pcb->ssthresh); + ESP_LWIP_LOGI("snd_next=%" PRIu32 " snd_wl1=%" PRIu32 " snd_wl2=%" PRIu32, pcb->snd_nxt, pcb->snd_wl1, pcb->snd_wl2); + ESP_LWIP_LOGI("snd_lbb=%" PRIu32 " snd_wnd=%"TCPWNDSIZE_F" snd_wnd_max=%"TCPWNDSIZE_F, pcb->snd_lbb, pcb->snd_wnd, pcb->snd_wnd_max); + //ESP_LWIP_LOGI("acked=%d", pcb->acked); + ESP_LWIP_LOGI("snd_buf=%"TCPWNDSIZE_F" snd_queuelen=%d", pcb->snd_buf, pcb->snd_queuelen); + ESP_LWIP_LOGI("unsent_oversize=%d", pcb->unsent_oversize); + ESP_LWIP_LOGI("keep_idle=%" PRIu32 " keep_intvl=%" PRIu32 " keep_cnt=%" PRIu32, pcb->keep_idle, pcb->keep_intvl, pcb->keep_cnt); + ESP_LWIP_LOGI("persist_cnt=%d persist_backoff=%d", pcb->persist_cnt, pcb->persist_backoff); + ESP_LWIP_LOGI("keep_cnt_sent=%d", pcb->keep_cnt_sent); + + ESP_LWIP_LOGI("unsent segments:"); + seg = pcb->unsent; + DBG_LWIP_SEG_SHOW(seg) + + ESP_LWIP_LOGI("unacked segments:"); + seg = pcb->unacked; + DBG_LWIP_SEG_SHOW(seg); + +#if TCP_QUEUE_OOSEQ + ESP_LWIP_LOGI("ooseq segments:"); + seg = pcb->ooseq; + DBG_LWIP_SEG_SHOW(seg); +#endif + + ESP_LWIP_LOGI("refused data=%p", pcb->refused_data); + +#if ESP_STATS_TCP + dbg_lwip_tcp_pcb_cnt_show(pcb); +#endif +} + +static void dbg_lwip_tcp_pcb_list_show(struct tcp_pcb* pcb) +{ + while(pcb){ + dbg_lwip_tcp_pcb_one_show(pcb); + pcb = pcb->next; + } +} + +extern struct tcp_pcb *tcp_bound_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; +extern struct tcp_pcb *tcp_tw_pcbs; +void dbg_lwip_tcp_pcb_show(void) +{ + ESP_LWIP_LOGI("-------------active pcbs------------"); + dbg_lwip_tcp_pcb_list_show(tcp_active_pcbs); + ESP_LWIP_LOGI("-------------bound pcbs-------------"); + dbg_lwip_tcp_pcb_list_show(tcp_bound_pcbs); + ESP_LWIP_LOGI("-------------tw pcbs------------"); + dbg_lwip_tcp_pcb_list_show(tcp_tw_pcbs); +} + +void dbg_lwip_udp_pcb_one_show(struct udp_pcb *pcb) +{ + ESP_LWIP_LOGI("pcb=%p next=%p", pcb, (void*)pcb->next); + DBG_LWIP_IP_PCB_SHOW(pcb); + ESP_LWIP_LOGI("flags=%x", pcb->flags); + ESP_LWIP_LOGI("local_port=%d remote_port=%d", pcb->local_port, pcb->remote_port); + ESP_LWIP_LOGI("recv cb=%p recv_arg=%p", pcb->recv, pcb->recv_arg); +} + +extern struct udp_pcb *udp_pcbs; +void dbg_lwip_udp_pcb_show(void) +{ + struct udp_pcb *pcb = udp_pcbs; + + while (pcb){ + dbg_lwip_udp_pcb_one_show(pcb); + pcb = pcb->next; + } +} + +void dbg_lwip_tcp_rxtx_show(void) +{ + ESP_LWIP_LOGI("TBC"); +} + +void dbg_lwip_udp_rxtx_show(void) +{ + ESP_LWIP_LOGI("TBC"); +} + +void dbg_lwip_stats_show(void) +{ + TCP_STATS_DISPLAY(); + UDP_STATS_DISPLAY(); + ICMP_STATS_DISPLAY(); + IGMP_STATS_DISPLAY(); + IP_STATS_DISPLAY(); + IPFRAG_STATS_DISPLAY(); + ETHARP_STATS_DISPLAY(); + LINK_STATS_DISPLAY(); + MEM_STATS_DISPLAY(); + SYS_STATS_DISPLAY(); + IP6_STATS_DISPLAY(); + ICMP6_STATS_DISPLAY(); + IP6_FRAG_STATS_DISPLAY(); + MLD6_STATS_DISPLAY(); + ND6_STATS_DISPLAY(); +} + +#if (ESP_STATS_MEM == 1) + +uint32_t g_lwip_mem_cnt[MEMP_MAX][2]; +extern const struct memp_desc * const memp_pools[MEMP_MAX]; + +void dbg_lwip_cnt_show(void) +{ + int i=0; + + ESP_LWIP_LOGI("-----lwip memory counter-----"); + ESP_LWIP_LOGI("%6s %8s %8s", "index", "alloc", "free"); + for (i=0; i +#include +#include +#include + +#include "sdkconfig.h" +#include "arch/sys_arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif // BYTE_ORDER + +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#define htons(x) __builtin_bswap16(x) +#define ntohs(x) __builtin_bswap16(x) +#define htonl(x) __builtin_bswap32(x) +#define ntohl(x) __builtin_bswap32(x) + +#ifndef CONFIG_LWIP_ESP_LWIP_ASSERT +#define LWIP_NOASSERT 1 +#endif + +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; + + +typedef int sys_prot_t; + +#define S16_F "d" +#define U16_F "d" +#define X16_F "x" + +#define S32_F PRId32 +#define U32_F PRIu32 +#define X32_F PRIx32 + +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END + +#include + +#ifdef CONFIG_LWIP_DEBUG_ESP_LOG +// lwip debugs routed to ESP_LOGD +#include "esp_log.h" +#define LWIP_ESP_LOG_FUNC(format, ...) ESP_LOG_LEVEL(ESP_LOG_DEBUG, "lwip", format, ##__VA_ARGS__) +#define LWIP_PLATFORM_DIAG(x) LWIP_ESP_LOG_FUNC x +#else +// lwip debugs routed to printf +#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) +#endif + +#ifdef NDEBUG + +#define LWIP_NOASSERT 1 + +#else // Assertions enabled + +#if CONFIG_OPTIMIZATION_ASSERTIONS_SILENT +#define LWIP_PLATFORM_ASSERT(message) abort() +#else +// __assert_func is the assertion failure handler from newlib, defined in assert.h +#define LWIP_PLATFORM_ASSERT(message) __assert_func(__FILE__, __LINE__, __ASSERT_FUNC, message) +#endif + +// If assertions are on, the default LWIP_ERROR handler behaviour is to +// abort w/ an assertion failure. Don't do this, instead just print the error (if LWIP_DEBUG is set) +// and run the handler (same as the LWIP_ERROR behaviour if LWIP_NOASSERT is set). +#ifdef LWIP_DEBUG +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + puts(message); handler;}} while(0) +#else +// If LWIP_DEBUG is not set, return the error silently (default LWIP behaviour, also.) +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;}} while(0) +#endif // LWIP_DEBUG + +#endif /* NDEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_CC_H__ */ diff --git a/components/lwip/port/esp32xx/include/arch/perf.h b/components/lwip/port/esp32xx/include/arch/perf.h new file mode 100644 index 000000000..033d8fac1 --- /dev/null +++ b/components/lwip/port/esp32xx/include/arch/perf.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2001 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __PERF_H__ +#define __PERF_H__ + +#define PERF_START /* null definition */ +#define PERF_STOP(x) /* null definition */ + +#endif /* __PERF_H__ */ diff --git a/components/lwip/port/esp32xx/include/arch/vfs_lwip.h b/components/lwip/port/esp32xx/include/arch/vfs_lwip.h new file mode 100644 index 000000000..17cd0daf5 --- /dev/null +++ b/components/lwip/port/esp32xx/include/arch/vfs_lwip.h @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +void esp_vfs_lwip_sockets_register(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/port/esp32xx/include/sys/socket.h b/components/lwip/port/esp32xx/include/sys/socket.h new file mode 100644 index 000000000..3ece4a90f --- /dev/null +++ b/components/lwip/port/esp32xx/include/sys/socket.h @@ -0,0 +1,22 @@ +/** + * @file + * This file is a posix wrapper for lwip/sockets.h. + */ +/* + * SPDX-FileCopyrightText: 2001-2004 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + */ +#ifndef LWIP_HDR_SYS_SOCKETS_H +#define LWIP_HDR_SYS_SOCKETS_H + +#include "lwip/sockets.h" +/* + SOMAXCONN is expected to be found in this header too, + while for ESP32 port is defined in net/if.h +*/ +#include + +#endif /* LWIP_HDR_SYS_SOCKETS_H */ diff --git a/components/lwip/port/esp32xx/netif/dhcp_state.c b/components/lwip/port/esp32xx/netif/dhcp_state.c new file mode 100644 index 000000000..cadee81ee --- /dev/null +++ b/components/lwip/port/esp32xx/netif/dhcp_state.c @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nvs.h" +#include "lwip/dhcp.h" +#include "lwip/netif.h" +#include "netif/dhcp_state.h" + +#define DHCP_NAMESPACE "dhcp_state" +#define IF_KEY_SIZE 3 + +/* + * As a NVS key, use string representation of the interface index number + */ +static inline char *gen_if_key(struct netif *netif, char *name) +{ + lwip_itoa(name, IF_KEY_SIZE, netif->num); + return name; +} + +bool dhcp_ip_addr_restore(struct netif *netif) +{ + nvs_handle_t nvs; + char if_key[IF_KEY_SIZE]; + bool err = false; + if (netif == NULL) { + return false; + } + struct dhcp *dhcp = netif_dhcp_data(netif); + + uint32_t *ip_addr = &dhcp->offered_ip_addr.addr; + if (nvs_open(DHCP_NAMESPACE, NVS_READONLY, &nvs) == ESP_OK) { + if (nvs_get_u32(nvs, gen_if_key(netif, if_key), ip_addr) == ESP_OK) { + err = true; + } + nvs_close(nvs); + } + return err; +} + +void dhcp_ip_addr_store(struct netif *netif) +{ + nvs_handle_t nvs; + char if_key[IF_KEY_SIZE]; + if (netif == NULL) { + return; + } + struct dhcp *dhcp = netif_dhcp_data(netif); + uint32_t ip_addr = dhcp->offered_ip_addr.addr; + + if (nvs_open(DHCP_NAMESPACE, NVS_READWRITE, &nvs) == ESP_OK) { + nvs_set_u32(nvs, gen_if_key(netif, if_key), ip_addr); + nvs_commit(nvs); + nvs_close(nvs); + } +} + +void dhcp_ip_addr_erase(struct netif *netif) +{ + nvs_handle_t nvs; + char if_key[IF_KEY_SIZE]; + if (netif == NULL) { + return; + } + if (nvs_open(DHCP_NAMESPACE, NVS_READWRITE, &nvs) == ESP_OK) { + nvs_erase_key(nvs, gen_if_key(netif, if_key)); + nvs_commit(nvs); + nvs_close(nvs); + } +} diff --git a/components/lwip/port/esp32xx/no_vfs_syscalls.c b/components/lwip/port/esp32xx/no_vfs_syscalls.c new file mode 100644 index 000000000..4c99a35c7 --- /dev/null +++ b/components/lwip/port/esp32xx/no_vfs_syscalls.c @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#ifdef CONFIG_VFS_SUPPORT_IO +#error This file should only be built when CONFIG_VFS_SUPPORT_IO=n +#endif + +/* Default implementations of read/write provided in newlib component, + * used as a fallback for console I/O. + */ +extern ssize_t _write_r_console(struct _reent *r, int fd, const void * data, size_t size); +extern ssize_t _read_r_console(struct _reent *r, int fd, const void * data, size_t size); + +ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) +{ + if (fd < LWIP_SOCKET_OFFSET) { + return _write_r_console(r, fd, data, size); + } + return lwip_write(fd, data, size); +} + +ssize_t _read_r(struct _reent *r, int fd, void * dst, size_t size) +{ + if (fd < LWIP_SOCKET_OFFSET) { + return _read_r_console(r, fd, dst, size); + } + return lwip_read(fd, dst, size); +} + +int _close_r(struct _reent *r, int fd) +{ + if (fd < LWIP_SOCKET_OFFSET) { + errno = ENOSYS; + return -1; + } + return lwip_close(fd); +} + +int _fcntl_r(struct _reent *r, int fd, int cmd, int arg) +{ + return lwip_fcntl(fd, cmd, arg); +} + +int ioctl(int fd, int cmd, ...) +{ + va_list args; + va_start(args, cmd); + int res = lwip_ioctl(fd, cmd, va_arg(args, void*)); + va_end(args); + return res; +} + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) +{ + return lwip_select(nfds, readfds, writefds, errorfds, timeout); +} + +void esp_vfs_lwip_sockets_register(void) +{ + /* Doesn't register anything, just a hook to force linking this file */ +} diff --git a/components/lwip/port/esp32xx/vfs_lwip.c b/components/lwip/port/esp32xx/vfs_lwip.c new file mode 100644 index 000000000..0190325e8 --- /dev/null +++ b/components/lwip/port/esp32xx/vfs_lwip.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include "esp_attr.h" +#include "esp_vfs.h" +#include "sdkconfig.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#ifndef CONFIG_VFS_SUPPORT_IO +#error This file should only be built when CONFIG_VFS_SUPPORT_IO=y +#endif + +_Static_assert(MAX_FDS >= CONFIG_LWIP_MAX_SOCKETS, "MAX_FDS < CONFIG_LWIP_MAX_SOCKETS"); + +#ifdef CONFIG_VFS_SUPPORT_SELECT + +/** + * @brief This function is implemented only in FreeRTOS port (ingroup sys_sem) + * and has no official API counterpart in lwip's sys.h declarations + * Signals a semaphore from ISR + * @param sem the semaphore to signal + * @return 1 if the signal has caused a high-prio task to unblock (pxHigherPriorityTaskWoken) + */ +int sys_sem_signal_isr(sys_sem_t *sem); + +static void lwip_stop_socket_select(void *sem) +{ + sys_sem_signal(sem); //socket_select will return +} + +static void lwip_stop_socket_select_isr(void *sem, BaseType_t *woken) +{ + if (sys_sem_signal_isr(sem) && woken) { + *woken = pdTRUE; + } +} + +static void *lwip_get_socket_select_semaphore(void) +{ + /* Calling this from the same process as select() will ensure that the semaphore won't be allocated from + * ISR (lwip_stop_socket_select_isr). + */ + return (void *) sys_thread_sem_get(); +} +#else // CONFIG_VFS_SUPPORT_SELECT + +int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) +{ + return lwip_select(nfds, readfds, writefds, errorfds, timeout); +} + +#endif // CONFIG_VFS_SUPPORT_SELECT + +static int lwip_fcntl_r_wrapper(int fd, int cmd, int arg) +{ + return lwip_fcntl(fd, cmd, arg); +} + +static int lwip_ioctl_r_wrapper(int fd, int cmd, va_list args) +{ + return lwip_ioctl(fd, cmd, va_arg(args, void *)); +} + +static int lwip_fstat(int fd, struct stat * st) +{ + if (st == NULL || fd < LWIP_SOCKET_OFFSET || fd > (MAX_FDS - 1)) { + errno = EBADF; + return -1; + } + memset(st, 0, sizeof(*st)); + /* set the stat mode to socket type */ + st->st_mode = S_IFSOCK; + return 0; +} + +void esp_vfs_lwip_sockets_register(void) +{ + esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &lwip_write, + .open = NULL, + .fstat = &lwip_fstat, + .close = &lwip_close, + .read = &lwip_read, + .fcntl = &lwip_fcntl_r_wrapper, + .ioctl = &lwip_ioctl_r_wrapper, +#ifdef CONFIG_VFS_SUPPORT_SELECT + .socket_select = &lwip_select, + .get_socket_select_semaphore = &lwip_get_socket_select_semaphore, + .stop_socket_select = &lwip_stop_socket_select, + .stop_socket_select_isr = &lwip_stop_socket_select_isr, +#endif // CONFIG_VFS_SUPPORT_SELECT + }; + /* Non-LWIP file descriptors are from 0 to (LWIP_SOCKET_OFFSET-1). LWIP + * file descriptors are registered from LWIP_SOCKET_OFFSET to + * MAX_FDS-1. + */ + + ESP_ERROR_CHECK(esp_vfs_register_fd_range(&vfs, NULL, LWIP_SOCKET_OFFSET, MAX_FDS)); +} diff --git a/components/lwip/port/freertos/include/arch/sys_arch.h b/components/lwip/port/freertos/include/arch/sys_arch.h new file mode 100644 index 000000000..529871246 --- /dev/null +++ b/components/lwip/port/freertos/include/arch/sys_arch.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + */ +#ifndef __SYS_ARCH_H__ +#define __SYS_ARCH_H__ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef SemaphoreHandle_t sys_sem_t; +typedef SemaphoreHandle_t sys_mutex_t; +typedef TaskHandle_t sys_thread_t; + +typedef struct sys_mbox_s { + QueueHandle_t os_mbox; + void *owner; +}* sys_mbox_t; + +/** This is returned by _fromisr() sys functions to tell the outermost function + * that a higher priority task was woken and the scheduler needs to be invoked. + */ +#define ERR_NEED_SCHED 123 + +void sys_delay_ms(uint32_t ms); +#define sys_msleep(ms) sys_delay_ms(ms) + +#define LWIP_COMPAT_MUTEX 0 + +#if !LWIP_COMPAT_MUTEX +#define sys_mutex_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define sys_mutex_set_invalid( x ) ( ( *x ) = NULL ) +#endif + +#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) + +/* Define the sys_mbox_set_invalid() to empty to support lock-free mbox in ESP LWIP. + * + * The basic idea about the lock-free mbox is that the mbox should always be valid unless + * no socket APIs are using the socket and the socket is closed. ESP LWIP achieves this by + * following two changes to official LWIP: + * 1. Postpone the deallocation of mbox to netconn_free(), in other words, free the mbox when + * no one is using the socket. + * 2. Define the sys_mbox_set_invalid() to empty if the mbox is not actually freed. + + * The second change is necessary. Consider a common scenario: the application task calls + * recv() to receive packets from the socket, the sys_mbox_valid() returns true. Because there + * is no lock for the mbox, the LWIP CORE can call sys_mbox_set_invalid() to set the mbox at + * anytime and the thread-safe issue may happen. + * + * However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(), + * we need to initialize the mbox to invalid explicitly since sys_mbox_set_invalid() now is empty. + */ +#define sys_mbox_set_invalid( x ) *x = NULL + +#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) +#define sys_sem_set_invalid( x ) ( ( *x ) = NULL ) + +void sys_delay_ms(uint32_t ms); +sys_sem_t* sys_thread_sem_init(void); +void sys_thread_sem_deinit(void); +sys_sem_t* sys_thread_sem_get(void); + +typedef enum { + LWIP_CORE_LOCK_QUERY_HOLDER, + LWIP_CORE_LOCK_MARK_HOLDER, + LWIP_CORE_LOCK_UNMARK_HOLDER, + LWIP_CORE_MARK_TCPIP_TASK, + LWIP_CORE_IS_TCPIP_INITIALIZED, +} sys_thread_core_lock_t; + +bool +sys_thread_tcpip(sys_thread_core_lock_t type); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYS_ARCH_H__ */ diff --git a/components/lwip/port/freertos/sys_arch.c b/components/lwip/port/freertos/sys_arch.c new file mode 100644 index 000000000..04ab919ec --- /dev/null +++ b/components/lwip/port/freertos/sys_arch.c @@ -0,0 +1,585 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + */ + +/* lwIP includes. */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "lwip/debug.h" +#include "lwip/def.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/stats.h" +#include "arch/sys_arch.h" +#include "arch/vfs_lwip.h" +#include "esp_log.h" +#include "esp_compiler.h" + +static const char* TAG = "lwip_arch"; + +static sys_mutex_t g_lwip_protect_mutex = NULL; + +static pthread_key_t sys_thread_sem_key; +static void sys_thread_sem_free(void* data); + +#if !LWIP_COMPAT_MUTEX + +/** + * @brief Create a new mutex + * + * @param pxMutex pointer of the mutex to create + * @return ERR_OK on success, ERR_MEM when out of memory + */ +err_t +sys_mutex_new(sys_mutex_t *pxMutex) +{ + *pxMutex = xSemaphoreCreateMutex(); + if (*pxMutex == NULL) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: out of mem\r\n")); + return ERR_MEM; + } + + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex)); + + return ERR_OK; +} + +/** + * @brief Lock a mutex + * + * @param pxMutex pointer of mutex to lock + */ +void +sys_mutex_lock(sys_mutex_t *pxMutex) +{ + BaseType_t ret = xSemaphoreTake(*pxMutex, portMAX_DELAY); + + LWIP_ASSERT("failed to take the mutex", ret == pdTRUE); + (void)ret; +} + +/** + * @brief Unlock a mutex + * + * @param pxMutex pointer of mutex to unlock + */ +void +sys_mutex_unlock(sys_mutex_t *pxMutex) +{ + BaseType_t ret = xSemaphoreGive(*pxMutex); + + LWIP_ASSERT("failed to give the mutex", ret == pdTRUE); + (void)ret; +} + +/** + * @brief Delete a mutex + * + * @param pxMutex pointer of mutex to delete + */ +void +sys_mutex_free(sys_mutex_t *pxMutex) +{ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex)); + vSemaphoreDelete(*pxMutex); + *pxMutex = NULL; +} + +#endif /* !LWIP_COMPAT_MUTEX */ + +/** + * @brief Creates a new semaphore + * + * @param sem pointer of the semaphore + * @param count initial state of the semaphore + * @return err_t + */ +err_t +sys_sem_new(sys_sem_t *sem, u8_t count) +{ + LWIP_ASSERT("initial_count invalid (neither 0 nor 1)", + (count == 0) || (count == 1)); + + *sem = xSemaphoreCreateBinary(); + if (*sem == NULL) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_sem_new: out of mem\r\n")); + return ERR_MEM; + } + + if (count == 1) { + BaseType_t ret = xSemaphoreGive(*sem); + LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); + (void)ret; + } + + return ERR_OK; +} + +/** + * @brief Signals a semaphore + * + * @param sem pointer of the semaphore + */ +void +sys_sem_signal(sys_sem_t *sem) +{ + BaseType_t ret = xSemaphoreGive(*sem); + /* queue full is OK, this is a signal only... */ + LWIP_ASSERT("sys_sem_signal: sane return value", + (ret == pdTRUE) || (ret == errQUEUE_FULL)); + (void)ret; +} + +/*-----------------------------------------------------------------------------------*/ +// Signals a semaphore (from ISR) +int +sys_sem_signal_isr(sys_sem_t *sem) +{ + BaseType_t woken = pdFALSE; + xSemaphoreGiveFromISR(*sem, &woken); + return woken == pdTRUE; +} + +/** + * @brief Wait for a semaphore to be signaled + * + * @param sem pointer of the semaphore + * @param timeout if zero, will wait infinitely, or will wait at least for milliseconds specified by this argument + * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise + */ +u32_t +sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + BaseType_t ret; + + if (!timeout) { + /* wait infinite */ + ret = xSemaphoreTake(*sem, portMAX_DELAY); + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); + } else { + /* Round up the number of ticks. + * Not only we need to round up the number of ticks, but we also need to add 1. + * Indeed, this function shall wait for AT LEAST timeout, but on FreeRTOS, + * if we specify a timeout of 1 tick to `xSemaphoreTake`, it will take AT MOST + * 1 tick before triggering a timeout. Thus, we need to pass 2 ticks as a timeout + * to `xSemaphoreTake`. */ + TickType_t timeout_ticks = ((timeout + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS) + 1; + ret = xSemaphoreTake(*sem, timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + return SYS_ARCH_TIMEOUT; + } + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); + } + + return 0; +} + +/** + * @brief Delete a semaphore + * + * @param sem pointer of the semaphore to delete + */ +void +sys_sem_free(sys_sem_t *sem) +{ + vSemaphoreDelete(*sem); + *sem = NULL; +} + +/** + * @brief Create an empty mailbox. + * + * @param mbox pointer of the mailbox + * @param size size of the mailbox + * @return ERR_OK on success, ERR_MEM when out of memory + */ +err_t +sys_mbox_new(sys_mbox_t *mbox, int size) +{ + *mbox = mem_malloc(sizeof(struct sys_mbox_s)); + if (*mbox == NULL){ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox\n")); + return ERR_MEM; + } + + (*mbox)->os_mbox = xQueueCreate(size, sizeof(void *)); + + if ((*mbox)->os_mbox == NULL) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new (*mbox)->os_mbox\n")); + free(*mbox); + return ERR_MEM; + } + +#if ESP_THREAD_SAFE + (*mbox)->owner = NULL; +#endif + + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("new *mbox ok mbox=%p os_mbox=%p\n", *mbox, (*mbox)->os_mbox)); + return ERR_OK; +} + +/** + * @brief Send message to mailbox + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + */ +void +sys_mbox_post(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret = xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY); + LWIP_ASSERT("mbox post failed", ret == pdTRUE); + (void)ret; +} + +/** + * @brief Try to post a message to mailbox + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + * @return ERR_OK on success, ERR_MEM when mailbox is full + */ +err_t +sys_mbox_trypost(sys_mbox_t *mbox, void *msg) +{ + err_t xReturn; + + if (xQueueSend((*mbox)->os_mbox, &msg, 0) == pdTRUE) { + xReturn = ERR_OK; + } else { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox)); + xReturn = ERR_MEM; + } + + return xReturn; +} + +/** + * @brief Try to post a message to mailbox from ISR + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + * @return ERR_OK on success + * ERR_MEM when mailbox is full + * ERR_NEED_SCHED when high priority task wakes up + */ +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + ret = xQueueSendFromISR((*mbox)->os_mbox, &msg, &xHigherPriorityTaskWoken); + if (ret == pdTRUE) { + if (xHigherPriorityTaskWoken == pdTRUE) { + return ERR_NEED_SCHED; + } + return ERR_OK; + } else { + LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); + return ERR_MEM; + } +} + +/** + * @brief Fetch message from mailbox + * + * @param mbox pointer of mailbox + * @param msg pointer of the received message, could be NULL to indicate the message should be dropped + * @param timeout if zero, will wait infinitely; or will wait milliseconds specify by this argument + * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise + */ +u32_t +sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) +{ + BaseType_t ret; + void *msg_dummy; + + if (msg == NULL) { + msg = &msg_dummy; + } + + if (timeout == 0) { + /* wait infinite */ + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY); + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + } else { + TickType_t timeout_ticks = timeout / portTICK_PERIOD_MS; + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + *msg = NULL; + return SYS_ARCH_TIMEOUT; + } + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + } + + return 0; +} + +/** + * @brief try to fetch message from mailbox + * + * @param mbox pointer of mailbox + * @param msg pointer of the received message + * @return SYS_MBOX_EMPTY if mailbox is empty, 1 otherwise + */ +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) +{ + BaseType_t ret; + void *msg_dummy; + + if (msg == NULL) { + msg = &msg_dummy; + } + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), 0); + if (ret == errQUEUE_EMPTY) { + *msg = NULL; + return SYS_MBOX_EMPTY; + } + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); + + return 0; +} + +void +sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) +{ + if (mbox && *mbox) { + (*mbox)->owner = owner; + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("set mbox=%p owner=%p", *mbox, owner)); + } +} + +/** + * @brief Delete a mailbox + * + * @param mbox pointer of the mailbox to delete + */ +void +sys_mbox_free(sys_mbox_t *mbox) +{ + if ((NULL == mbox) || (NULL == *mbox)) { + return; + } + UBaseType_t msgs_waiting = uxQueueMessagesWaiting((*mbox)->os_mbox); + LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0); + + vQueueDelete((*mbox)->os_mbox); + free(*mbox); + *mbox = NULL; + + (void)msgs_waiting; +} + +/** + * @brief Create a new thread + * + * @param name thread name + * @param thread thread function + * @param arg thread arguments + * @param stacksize stacksize of the thread + * @param prio priority of the thread + * @return thread ID + */ +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) +{ + TaskHandle_t rtos_task; + BaseType_t ret; + + /* LwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the + thread function without adaption here. */ + ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task, + CONFIG_LWIP_TCPIP_TASK_AFFINITY); + + LWIP_DEBUGF(TCPIP_DEBUG, ("new lwip task : %" U32_F ", prio:%d,stack:%d\n", + (u32_t)rtos_task, prio, stacksize)); + + if (ret != pdTRUE) { + return NULL; + } + + return (sys_thread_t)rtos_task; +} + +/** + * @brief Initialize the sys_arch layer + * + */ +void +sys_init(void) +{ + if (!g_lwip_protect_mutex) { + if (ERR_OK != sys_mutex_new(&g_lwip_protect_mutex)) { + ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex"); + } + } + + // Create the pthreads key for the per-thread semaphore storage + pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free); + + esp_vfs_lwip_sockets_register(); +} + +/** + * @brief Get system ticks + * + * @return system tick counts + */ +u32_t +sys_jiffies(void) +{ + return xTaskGetTickCount(); +} + +/** + * @brief Get current time, in miliseconds + * + * @return current time + */ +u32_t +sys_now(void) +{ + return xTaskGetTickCount() * portTICK_PERIOD_MS; +} + +/** + * @brief Protect critical region + * + * @note This function is only called during very short critical regions. + * + * @return previous protection level + */ +sys_prot_t +sys_arch_protect(void) +{ + if (unlikely(!g_lwip_protect_mutex)) { + sys_mutex_new(&g_lwip_protect_mutex); + } + sys_mutex_lock(&g_lwip_protect_mutex); + return (sys_prot_t) 1; +} + +/** + * @brief Unprotect critical region + * + * @param pval protection level + */ +void +sys_arch_unprotect(sys_prot_t pval) +{ + LWIP_UNUSED_ARG(pval); + sys_mutex_unlock(&g_lwip_protect_mutex); +} + +/* + * get per thread semaphore + */ +sys_sem_t* +sys_thread_sem_get(void) +{ + sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); + + if (!sem) { + sem = sys_thread_sem_init(); + } + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem)); + return sem; +} + +static void +sys_thread_sem_free(void* data) // destructor for TLS semaphore +{ + sys_sem_t *sem = (sys_sem_t*)(data); + + if (sem && *sem){ + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem del, sem=%p\n", *sem)); + vSemaphoreDelete(*sem); + } + + if (sem) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem pointer del, sem_p=%p\n", sem)); + free(sem); + } +} + +sys_sem_t* +sys_thread_sem_init(void) +{ + sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*)); + + if (!sem){ + ESP_LOGE(TAG, "thread_sem_init: out of memory"); + return 0; + } + + *sem = xSemaphoreCreateBinary(); + if (!(*sem)){ + free(sem); + ESP_LOGE(TAG, "thread_sem_init: out of memory"); + return 0; + } + + pthread_setspecific(sys_thread_sem_key, sem); + return sem; +} + +void +sys_thread_sem_deinit(void) +{ + sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); + if (sem != NULL) { + sys_thread_sem_free(sem); + pthread_setspecific(sys_thread_sem_key, NULL); + } +} + +void +sys_delay_ms(uint32_t ms) +{ + vTaskDelay(ms / portTICK_PERIOD_MS); +} + +bool +sys_thread_tcpip(sys_thread_core_lock_t type) +{ + static sys_thread_t lwip_task = NULL; +#if LWIP_TCPIP_CORE_LOCKING + static sys_thread_t core_lock_holder = NULL; +#endif + switch (type) { + default: + return false; + case LWIP_CORE_IS_TCPIP_INITIALIZED: + return lwip_task != NULL; + case LWIP_CORE_MARK_TCPIP_TASK: + LWIP_ASSERT("LWIP_CORE_MARK_TCPIP_TASK: lwip_task == NULL", (lwip_task == NULL)); + lwip_task = (sys_thread_t) xTaskGetCurrentTaskHandle(); + return true; +#if LWIP_TCPIP_CORE_LOCKING + case LWIP_CORE_LOCK_QUERY_HOLDER: + return lwip_task ? core_lock_holder == (sys_thread_t) xTaskGetCurrentTaskHandle() : true; + case LWIP_CORE_LOCK_MARK_HOLDER: + core_lock_holder = (sys_thread_t) xTaskGetCurrentTaskHandle(); + return true; + case LWIP_CORE_LOCK_UNMARK_HOLDER: + core_lock_holder = NULL; + return true; +#else + case LWIP_CORE_LOCK_QUERY_HOLDER: + return lwip_task == NULL || lwip_task == (sys_thread_t) xTaskGetCurrentTaskHandle(); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + } + return true; +} diff --git a/components/lwip/port/hooks/lwip_default_hooks.c b/components/lwip/port/hooks/lwip_default_hooks.c new file mode 100644 index 000000000..38b1661b8 --- /dev/null +++ b/components/lwip/port/hooks/lwip_default_hooks.c @@ -0,0 +1,280 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lwip_default_hooks.h" +#include "lwip/prot/dhcp.h" +#include "lwip/dhcp.h" +#include "lwip/prot/iana.h" +#include + +#define __weak __attribute__((weak)) + +#ifdef CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT +struct netif *__weak +lwip_hook_ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest) +{ + LWIP_UNUSED_ARG(src); + LWIP_UNUSED_ARG(dest); + + return NULL; +} +#endif + +#ifdef CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT +int __weak lwip_hook_netconn_external_resolve(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err) +{ + LWIP_UNUSED_ARG(name); + LWIP_UNUSED_ARG(addr); + LWIP_UNUSED_ARG(addrtype); + LWIP_UNUSED_ARG(err); + + return 0; +} +#endif + +#ifdef CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT +const ip6_addr_t *__weak lwip_hook_nd6_get_gw(struct netif *netif, const ip6_addr_t *dest) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(dest); + + return NULL; +} +#endif + +#ifdef CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT +const ip_addr_t *__weak lwip_hook_ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(dest); + + return NULL; +} +#endif + +#ifdef CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT +int __weak lwip_hook_ip6_input(struct pbuf *p, struct netif *inp) +{ + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(inp); + + return 0; +} +#endif + +#ifdef CONFIG_LWIP_IPV4 + +#ifdef LWIP_HOOK_IP4_ROUTE_SRC +#if ESP_IP4_ROUTE +#include "lwip/netif.h" + +bool ip4_netif_exist(const ip4_addr_t *src, const ip4_addr_t *dest) +{ + struct netif *netif = NULL; + + for (netif = netif_list; netif != NULL; netif = netif->next) { + /* is the netif up, does it have a link and a valid address? */ + if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* source netif and dest netif match? */ + if (ip4_addr_netcmp(src, netif_ip4_addr(netif), netif_ip4_netmask(netif)) || ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) { + /* return false when both netif don't match */ + return true; + } + } + } + + return false; +} + +/** + * Source based IPv4 routing hook function. + */ +struct netif * +ip4_route_src_hook(const ip4_addr_t *src,const ip4_addr_t *dest) +{ + struct netif *netif = NULL; + + /* destination IP is broadcast IP? */ + if ((src != NULL) && !ip4_addr_isany(src)) { + /* iterate through netifs */ + for (netif = netif_list; netif != NULL; netif = netif->next) { + /* is the netif up, does it have a link and a valid address? */ + if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) { + /* source IP matches? */ + if (ip4_addr_cmp(src, netif_ip4_addr(netif))) { + /* return netif on which to forward IP packet */ + + return netif; + } + } + } + } + return netif; +} +#endif +#endif /* LWIP_HOOK_IP4_ROUTE_SRC */ + +#define LWIP_DHCP_ENABLE_MTU_UPDATE 1 +#define LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER +#define LWIP_DHCP_ENABLE_CLIENT_ID !ESP_DHCP_DISABLE_CLIENT_ID + +#if LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS +#define DHCP_OPTION_VSI 43 +#define DHCP_OPTION_VCI 60 +#define DHCP_OPTION_VSI_MAX 64 + +static u8_t vendor_class_len = 0; +static char *vendor_class_buf = NULL; +static u8_t dhcp_option_vsi[DHCP_OPTION_VSI_MAX]; + +void dhcp_free_vendor_class_identifier(void) +{ + mem_free(vendor_class_buf); +} + +int dhcp_get_vendor_specific_information(uint8_t len, char * str) +{ + u8_t copy_len = 0; + + if (len == 0 || str == NULL) { + return ERR_ARG; + } + + copy_len = LWIP_MIN(len, sizeof(dhcp_option_vsi)); + + memcpy(str, dhcp_option_vsi, copy_len); + + return ERR_OK; +} + +int dhcp_set_vendor_class_identifier(uint8_t len, const char * str) +{ + if (len == 0 || str == NULL) { + return ERR_ARG; + } + + if (vendor_class_buf && vendor_class_len != len) { + mem_free(vendor_class_buf); + vendor_class_buf = NULL; + } + + if (!vendor_class_buf) { + vendor_class_buf = (char *)mem_malloc(len + 1); + if (vendor_class_buf == NULL) { + return ERR_MEM; + } + + vendor_class_len = len; + } + + memcpy(vendor_class_buf, str, len); + return ERR_OK; +} +#endif /* LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS */ + +void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset) +{ + LWIP_UNUSED_ARG(dhcp); + LWIP_UNUSED_ARG(state); + LWIP_UNUSED_ARG(option); + LWIP_UNUSED_ARG(len); + LWIP_UNUSED_ARG(p); + LWIP_UNUSED_ARG(offset); +#if LWIP_DHCP_ENABLE_MTU_UPDATE + if ((option == DHCP_OPTION_MTU) && + (state == DHCP_STATE_REBOOTING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_RENEWING || state == DHCP_STATE_REQUESTING)) { + u32_t mtu = 0; + struct netif *netif; + LWIP_ERROR("dhcp_parse_extra_opts(): MTU option's len != 2", len == 2, return;); + LWIP_ERROR("dhcp_parse_extra_opts(): extracting MTU option failed", + pbuf_copy_partial(p, &mtu, 2, offset) == 2, return;); + mtu = lwip_htons((u16_t)mtu); + NETIF_FOREACH(netif) { + /* find the netif related to this dhcp */ + if (dhcp == netif_dhcp_data(netif)) { + if (mtu < netif->mtu) { + netif->mtu = mtu; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_parse_extra_opts(): Negotiated netif MTU is %d\n", netif->mtu)); + } + return; + } + } + } /* DHCP_OPTION_MTU */ +#endif /* LWIP_DHCP_ENABLE_MTU_UPDATE */ +#if LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS + if ((option == DHCP_OPTION_VSI) && + (state == DHCP_STATE_REBOOTING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_RENEWING || state == DHCP_STATE_REQUESTING || state == DHCP_STATE_SELECTING)) { + u16_t copy_len; + copy_len = LWIP_MIN(len, sizeof(dhcp_option_vsi)); + LWIP_ERROR("dhcp_parse_extra_opts(): extracting VSI option failed", + pbuf_copy_partial(p, &dhcp_option_vsi, copy_len, offset) == copy_len, return;); + } /* DHCP_OPTION_VSI */ +#endif /* LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS */ +} + +void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(state); + LWIP_UNUSED_ARG(msg_out); + LWIP_UNUSED_ARG(options_out_len); +#if LWIP_DHCP_ENABLE_CLIENT_ID + if (state == DHCP_STATE_RENEWING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_REBOOTING || state == DHCP_STATE_OFF || + state == DHCP_STATE_REQUESTING || state == DHCP_STATE_BACKING_OFF || state == DHCP_STATE_SELECTING) { + size_t i; + u8_t *options = msg_out->options + *options_out_len; + LWIP_ERROR("dhcp_append(client_id): options_out_len + 3 + netif->hwaddr_len <= DHCP_OPTIONS_LEN", + *options_out_len + 3U + netif->hwaddr_len <= DHCP_OPTIONS_LEN, return;); + *options_out_len = *options_out_len + netif->hwaddr_len + 3; + *options++ = DHCP_OPTION_CLIENT_ID; + *options++ = netif->hwaddr_len + 1; /* option size */ + *options++ = LWIP_IANA_HWTYPE_ETHERNET; + for (i = 0; i < netif->hwaddr_len; i++) { + *options++ = netif->hwaddr[i]; + } + } +#endif /* LWIP_DHCP_ENABLE_CLIENT_ID */ +#if LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS + if (state == DHCP_STATE_RENEWING || state == DHCP_STATE_REBINDING || + state == DHCP_STATE_REBOOTING || state == DHCP_STATE_OFF || + state == DHCP_STATE_REQUESTING || state == DHCP_STATE_BACKING_OFF || state == DHCP_STATE_SELECTING) { + size_t i; + const char *p = NULL; + u8_t len = 0; + + if (vendor_class_buf && vendor_class_len) { + p = vendor_class_buf; + len = vendor_class_len; + } else { +#if LWIP_NETIF_HOSTNAME + size_t namelen; + if (netif->hostname != NULL && (namelen = strlen(netif->hostname)) < 0xff) { + p = netif->hostname; + len = (u8_t)namelen; + } +#endif /* LWIP_NETIF_HOSTNAME */ + } + LWIP_ERROR("dhcp_append(vci): options_out_len + 3 + vci_size <= DHCP_OPTIONS_LEN", + *options_out_len + 3U + len <= DHCP_OPTIONS_LEN, return;); + if (p) { + u8_t *options = msg_out->options + *options_out_len; + *options_out_len = *options_out_len + len + 3; + *options++ = DHCP_OPTION_VCI; + *options++ = len; + for (i = 0; i < len; i ++) { + *options++ = p[i]; + } + } + return; + } +#endif /* LWIP_DHCP_ENABLE_VENDOR_SPEC_IDS */ + +} + +#endif /* CONFIG_LWIP_IPV4 */ diff --git a/components/lwip/port/hooks/tcp_isn_default.c b/components/lwip/port/hooks/tcp_isn_default.c new file mode 100644 index 000000000..7567b4d13 --- /dev/null +++ b/components/lwip/port/hooks/tcp_isn_default.c @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * @file + * + * Reference implementation of the TCP ISN algorithm standardized in RFC 6528. + * Produce TCP Initial Sequence Numbers by combining an MD5-generated hash + * based on the new TCP connection's identity and a stable secret, with the + * current time at 4-microsecond granularity. + * + * Specifically, the implementation uses MD5 to compute a hash of the input + * buffer, which contains both the four-tuple of the new TCP connection (local + * and remote IP address and port), as well as a 16-byte secret to make the + * results unpredictable to external parties. The secret must be given at + * initialization time and should ideally remain the same across system + * reboots. To be sure: the spoofing-resistance of the resulting ISN depends + * mainly on the strength of the supplied secret! + * + * The implementation takes 32 bits from the computed hash, and adds to it the + * current time, in 4-microsecond units. The current time is computed from a + * boot time given at initialization, and the current uptime as provided by + * sys_now(). Thus, it assumes that sys_now() returns a time value that is + * relative to the boot time, i.e., that it starts at 0 at system boot, and + * only ever increases monotonically. + * + * For efficiency reasons, a single MD5 input buffer is used, and partially + * filled in at initialization time. Specifically, of this 64-byte buffer, the + * first 36 bytes are used for the four-way TCP tuple data, followed by the + * 16-byte secret, followed by 12-byte zero padding. The 64-byte size of the + * buffer should achieve the best performance for the actual MD5 computation. + * + * Basic usage: + * + * 1. in your lwipopts.h, add the following lines: + * + * #include + * struct ip_addr; + * u32_t lwip_hook_tcp_isn(const struct ip_addr *local_ip, u16_t local_port, + * const struct ip_addr *remote_ip, u16_t remote_port); + * "#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn"; + * + * 2. from your own code, call lwip_init_tcp_isn() at initialization time, with + * appropriate parameters. + */ + +/* + * Copyright (c) 2016 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * Author: David van Moolenbroek + */ + +#include "lwip_default_hooks.h" +#include "lwip/ip_addr.h" +#include "lwip/sys.h" +#include +#include "esp_rom_md5.h" +#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY +#include "esp_memory_utils.h" +#endif + +#ifdef CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT + +static u8_t input[64]; +static u32_t base_time; + +/** + * Initialize the TCP ISN module, with the boot time and a secret. + * + * @param boot_time Wall clock boot time of the system, in seconds. + * @param secret_16_bytes A 16-byte secret used to randomize the TCP ISNs. + */ +void +lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes) +{ + /* Initialize the input buffer with the secret and trailing zeroes. */ + memset(input, 0, sizeof(input)); + + MEMCPY(&input[36], secret_16_bytes, 16); + + /* Save the boot time in 4-us units. Overflow is no problem here. */ + base_time = boot_time * 250000; +} + +/** + * Hook to generate an Initial Sequence Number (ISN) for a new TCP connection. + * + * @param local_ip The local IP address. + * @param local_port The local port number, in host-byte order. + * @param remote_ip The remote IP address. + * @param remote_port The remote port number, in host-byte order. + * @return The ISN to use for the new TCP connection. + */ +u32_t +lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port) +{ + u8_t output[16]; + u32_t isn; + +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_V6(local_ip)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV6 + { + const ip6_addr_t *local_ip6, *remote_ip6; + + local_ip6 = ip_2_ip6(local_ip); + remote_ip6 = ip_2_ip6(remote_ip); + + SMEMCPY(&input[0], &local_ip6->addr, 16); + SMEMCPY(&input[16], &remote_ip6->addr, 16); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + const ip4_addr_t *local_ip4, *remote_ip4; + + local_ip4 = ip_2_ip4(local_ip); + remote_ip4 = ip_2_ip4(remote_ip); + + /* Represent IPv4 addresses as IPv4-mapped IPv6 addresses, to ensure that + * the IPv4 and IPv6 address spaces are completely disjoint. */ + memset(&input[0], 0, 10); + input[10] = 0xff; + input[11] = 0xff; + SMEMCPY(&input[12], &local_ip4->addr, 4); + memset(&input[16], 0, 10); + input[26] = 0xff; + input[27] = 0xff; + SMEMCPY(&input[28], &remote_ip4->addr, 4); + } +#endif /* LWIP_IPV4 */ + + input[32] = (u8_t)(local_port >> 8); + input[33] = (u8_t)(local_port & 0xff); + input[34] = (u8_t)(remote_port >> 8); + input[35] = (u8_t)(remote_port & 0xff); + + /* The secret and padding are already filled in. */ + + /* + * Generate the hash using ROM MD5 APIs + * This hook is invoked in the context of TCP/IP (tiT) task and + * it is unlikely that its stack would be placed in SPIRAM. Hence + * even with SPIRAM enabled case and ESP32 revision < 3, using ROM + * APIs should not create any issues. + */ +#if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY + assert(!esp_ptr_external_ram(esp_cpu_get_sp())); +#endif + + md5_context_t ctx; + esp_rom_md5_init(&ctx); + esp_rom_md5_update(&ctx, input, sizeof(input)); + esp_rom_md5_final(output, &ctx); + + + /* Arbitrarily take the first 32 bits from the generated hash. */ + MEMCPY(&isn, output, sizeof(isn)); + + /* Add the current time in 4-microsecond units. */ + return isn + base_time + sys_now() * 250; +} + +#endif /* LWIP_HOOK_TCP_ISN */ diff --git a/components/lwip/port/if_index.c b/components/lwip/port/if_index.c new file mode 100644 index 000000000..d7dcf25e7 --- /dev/null +++ b/components/lwip/port/if_index.c @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lwip/if_api.h" + +unsigned int if_nametoindex(const char *ifname) +{ + return lwip_if_nametoindex(ifname); +} + +char *if_indextoname(unsigned int ifindex, char *ifname) +{ + return lwip_if_indextoname(ifindex, ifname); +} diff --git a/components/lwip/port/include/arpa/inet.h b/components/lwip/port/include/arpa/inet.h new file mode 100644 index 000000000..6687e0db9 --- /dev/null +++ b/components/lwip/port/include/arpa/inet.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INET_H_ +#define INET_H_ + +#include "lwip/inet.h" + +#endif /* INET_H_ */ diff --git a/components/lwip/port/include/debug/lwip_debug.h b/components/lwip/port/include/debug/lwip_debug.h new file mode 100644 index 000000000..d30d1a6e4 --- /dev/null +++ b/components/lwip/port/include/debug/lwip_debug.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef _LWIP_DEBUG_H +#define _LWIP_DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +void dbg_lwip_tcp_pcb_show(void); +void dbg_lwip_udp_pcb_show(void); +void dbg_lwip_tcp_rxtx_show(void); +void dbg_lwip_udp_rxtx_show(void); +void dbg_lwip_mem_cnt_show(void); + +#ifdef __cplusplus +} +#endif + +#endif // _LWIP_DEBUG_H diff --git a/components/lwip/port/include/lwip_default_hooks.h b/components/lwip/port/include/lwip_default_hooks.h new file mode 100644 index 000000000..da9b90101 --- /dev/null +++ b/components/lwip/port/include/lwip_default_hooks.h @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LWIP_ESP_DEFAULT_HOOKS_H_ +#define LWIP_ESP_DEFAULT_HOOKS_H_ +#include "lwip/ip_addr.h" +#include "lwip/arch.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/pbuf.h" +#include "netif/dhcp_state.h" + + +#ifdef ESP_IDF_LWIP_HOOK_FILENAME +#include ESP_IDF_LWIP_HOOK_FILENAME +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT +void lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes); +#endif +#if defined(CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM) || defined(CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT) +u32_t lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port); +#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn +#endif /* CONFIG_LWIP_HOOK_TCP_ISN... */ + +#if defined(CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM) || defined(CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT) +struct netif * +lwip_hook_ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest); + +#define LWIP_HOOK_IP6_ROUTE lwip_hook_ip6_route +#endif /* CONFIG_LWIP_HOOK_IP6_ROUTE... */ + +#if defined(CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM) || defined(CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT) +const ip6_addr_t *lwip_hook_nd6_get_gw(struct netif *netif, const ip6_addr_t *dest); + +#define LWIP_HOOK_ND6_GET_GW lwip_hook_nd6_get_gw +#endif /* CONFIG_LWIP_HOOK_ND6_GET_GATEWAY... */ + +#if defined(CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM) || defined(CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT) +const ip_addr_t *lwip_hook_ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest); + +#define LWIP_HOOK_IP6_SELECT_SRC_ADDR lwip_hook_ip6_select_source_address +#endif /* CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR... */ + +#if defined(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM) || defined(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT) +int lwip_hook_netconn_external_resolve(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err); + +#define LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE lwip_hook_netconn_external_resolve +#endif /* CONFIG_LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE... */ + +#if defined(CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM) +int lwip_hook_dns_external_resolve(const char *name, ip_addr_t *addr, dns_found_callback found, void *callback_arg, + u8_t addrtype, err_t *err); + +#define LWIP_HOOK_DNS_EXTERNAL_RESOLVE lwip_hook_dns_external_resolve +#endif /* CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM */ + + +#if defined(CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM) || defined(CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT) +int lwip_hook_ip6_input(struct pbuf *p, struct netif *inp); + +#define LWIP_HOOK_IP6_INPUT lwip_hook_ip6_input +#endif /* CONFIG_LWIP_HOOK_IP6_INPUT_CUSTIOM... */ + +#ifdef CONFIG_LWIP_IPV4 +struct netif * +ip4_route_src_hook(const ip4_addr_t *src,const ip4_addr_t *dest); + +struct dhcp; +struct netif; +struct dhcp_msg; +void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset); + +void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len); + +int dhcp_set_vendor_class_identifier(uint8_t len, const char * str); +int dhcp_get_vendor_specific_information(uint8_t len, char * str); +void dhcp_free_vendor_class_identifier(void); +#endif /* CONFIG_LWIP_IPV4 */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ESP_DEFAULT_HOOKS_H_ */ diff --git a/components/lwip/port/include/lwipopts.h b/components/lwip/port/include/lwipopts.h new file mode 100644 index 000000000..cc1346614 --- /dev/null +++ b/components/lwip/port/include/lwipopts.h @@ -0,0 +1,1685 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2015-2024 Espressif Systems (Shanghai) CO LTD + */ +#ifndef LWIP_HDR_ESP_LWIPOPTS_H +#define LWIP_HDR_ESP_LWIPOPTS_H + +#include "sdkconfig.h" +#include // For memcpy +#include // For malloc/free +#include +#include +#include +#include +#include +#include +#include "esp_task.h" +#include "esp_random.h" +#include "sdkconfig.h" +#include "sntp/sntp_get_set_time.h" +#include "sockets_ext.h" +#include "arch/sys_arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING 1 +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 1 +#else +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif +#define LOCK_TCPIP_CORE() do { sys_mutex_lock(&lock_tcpip_core); sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER); } while(0) +#define UNLOCK_TCPIP_CORE() do { sys_thread_tcpip(LWIP_CORE_LOCK_UNMARK_HOLDER); sys_mutex_unlock(&lock_tcpip_core); } while(0) +#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY +#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to lock TCPIP core functionality!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0) +#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */ + +#else +#define LWIP_TCPIP_CORE_LOCKING 0 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY +#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to run in TCPIP context!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0) +#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */ +#endif /* CONFIG_LWIP_TCPIP_CORE_LOCKING */ + +#define LWIP_MARK_TCPIP_THREAD() sys_thread_tcpip(LWIP_CORE_MARK_TCPIP_TASK) + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#define MEMCPY(dst,src,len) memcpy(dst,src,len) + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#define SMEMCPY(dst,src,len) memcpy(dst,src,len) + +#define LWIP_RAND esp_random + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#define MEM_LIBC_MALLOC 1 + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#define MEMP_MEM_MALLOC 1 + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT 4 + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETCONN CONFIG_LWIP_MAX_SOCKETS + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#define MEMP_NUM_RAW_PCB CONFIG_LWIP_MAX_RAW_PCBS + +/** + * MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB CONFIG_LWIP_MAX_ACTIVE_TCP + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB_LISTEN CONFIG_LWIP_MAX_LISTENING_TCP + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB CONFIG_LWIP_MAX_UDP_PCBS + +/* + -------------------------------- + ---------- ARP options ------- + -------------------------------- +*/ +/** + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. + */ +#define ARP_QUEUEING 1 + +#ifdef CONFIG_LWIP_DHCPS_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 +#else +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#ifdef CONFIG_LWIP_IPV4 +#define LWIP_IPV4 1 +#else +#define LWIP_IPV4 0 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP4 packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifdef CONFIG_LWIP_IP4_REASSEMBLY +#define IP_REASSEMBLY 1 +#else +#define IP_REASSEMBLY 0 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP4 packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifdef CONFIG_LWIP_IP4_FRAG +#define IP_FRAG 1 +#else +#define IP_FRAG 0 +#endif + +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifdef CONFIG_LWIP_IP_FORWARD +#define IP_FORWARD 1 +#else +#define IP_FORWARD 0 +#endif + +/** + * IP_NAPT==1: Enables IPv4 Network Address and Port Translation. + * Note that CONFIG_LWIP_IP_FORWARD option need to be enabled in + * system configuration for the NAPT to work on ESP platform + */ +#ifdef CONFIG_LWIP_IPV4_NAPT +#define IP_NAPT 1 + +#ifdef CONFIG_LWIP_IPV4_NAPT_PORTMAP +#define IP_NAPT_PORTMAP 1 +#else +#define IP_NAPT_PORTMAP 0 +#endif + +#else +#define IP_NAPT 0 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#define IP_REASS_MAXAGE 3 + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#define IP_REASS_MAX_PBUFS CONFIG_LWIP_IP_REASS_MAX_PBUFS + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#define IP_DEFAULT_TTL CONFIG_LWIP_IP_DEFAULT_TTL + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifdef CONFIG_LWIP_ICMP +#define LWIP_ICMP 1 +#else +#define LWIP_ICMP 0 +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifdef CONFIG_LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING 1 +#else +#define LWIP_BROADCAST_PING 0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifdef CONFIG_LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING 1 +#else +#define LWIP_MULTICAST_PING 0 +#endif + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#define LWIP_RAW 1 + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +#if CONFIG_LWIP_IPV4 +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP 1 + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifdef CONFIG_LWIP_DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK 1 +#else +#define DHCP_DOES_ARP_CHECK 0 +#endif + +/** + * LWIP_DHCP_GETS_NTP==1: Request NTP servers with discover/select. For each + * response packet, an callback is called, which has to be provided by the port: + * void dhcp_set_ntp_servers(u8_t num_ntp_servers, ip_addr_t* ntp_server_addrs); +*/ +#ifdef CONFIG_LWIP_DHCP_GET_NTP_SRV +#define LWIP_DHCP_GET_NTP_SRV 1 +#else +#define LWIP_DHCP_GET_NTP_SRV 0 +#endif + +/** + * ESP specific option only applicable if ESP_DHCP=1 + * LWIP_DHCP_DISABLE_CLIENT_ID==1: Do not add option 61 (client-id) to DHCP packets + * + */ +#ifdef CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID +#define ESP_DHCP_DISABLE_CLIENT_ID 1 +#else +#define ESP_DHCP_DISABLE_CLIENT_ID 0 +#endif + +/** + * ESP specific option only applicable if ESP_DHCP=1 + * CONFIG_LWIP_DHCP_RESTORE_LAST_IP==1: Last valid IP address obtained from DHCP server + * is restored after reset/power-up. + */ +#ifdef CONFIG_LWIP_DHCP_RESTORE_LAST_IP +/* + * Make the post-init hook check if we could restore the previously bound address + * - if yes reset the state to bound and mark result as ERR_OK (which skips discovery state) + * - if no, return false to continue normally to the discovery state + */ +#define LWIP_HOOK_DHCP_POST_INIT(netif, result) \ + (dhcp_ip_addr_restore(netif) ? ( dhcp_set_state(dhcp, DHCP_STATE_BOUND), \ + dhcp_network_changed(netif), \ + (result) = ERR_OK , \ + true ) : \ + false) +#else +#define LWIP_HOOK_DHCP_PRE_DISCOVERY(netif, result) (false) +#endif /* CONFIG_LWIP_DHCP_RESTORE_LAST_IP */ + +/** + * The maximum of NTP servers requested + */ +#define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS + +/** + * CONFIG_LWIP_DHCP_OPTIONS_LEN: The total length of outgoing DHCP option msg. If you have many options + * and options value is too long, you can configure the length according to your requirements + */ +#define DHCP_OPTIONS_LEN CONFIG_LWIP_DHCP_OPTIONS_LEN + +/** + * LWIP_DHCP_DISABLE_VENDOR_CLASS_ID==1: Do not add option 60 (Vendor Class Identifier) to DHCP packets + */ +#define ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID + +#define DHCP_DEFINE_CUSTOM_TIMEOUTS 1 +#define DHCP_COARSE_TIMER_SECS CONFIG_LWIP_DHCP_COARSE_TIMER_SECS +#define DHCP_NEXT_TIMEOUT_THRESHOLD (3) +/* Since for embedded devices it's not that hard to miss a discover packet, so lower + * the discover and request retry backoff time from (2,4,8,16,32,60,60)s to (500m,1,2,4,4,4,4)s. + */ +#define DHCP_REQUEST_TIMEOUT_SEQUENCE(tries) ((uint16_t)(((tries) < 5 ? 1 << (tries) : 16) * 250)) + +static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) +{ + uint32_t timeout = lease; + if (timeout == 0) { + timeout = min; + } + timeout = (timeout + DHCP_COARSE_TIMER_SECS - 1) / DHCP_COARSE_TIMER_SECS; + return timeout; +} + +#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T0_LEASE(dhcp) \ + timeout_from_offered((dhcp)->offered_t0_lease, 120) +#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T1_RENEW(dhcp) \ + timeout_from_offered((dhcp)->offered_t1_renew, (dhcp)->t0_timeout>>1 /* 50% */ ) +#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T2_REBIND(dhcp) \ + timeout_from_offered((dhcp)->offered_t2_rebind, ((dhcp)->t0_timeout/8)*7 /* 87.5% */ ) + +#define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) \ + do { LWIP_UNUSED_ARG(msg); \ + dhcp_parse_extra_opts(dhcp, state, option, len, pbuf, offset); \ + } while(0) + +#define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) \ + dhcp_append_extra_opts(netif, state, msg, options_len_ptr); + +#endif /* CONFIG_LWIP_IPV4 */ +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifdef CONFIG_LWIP_AUTOIP +#define LWIP_AUTOIP 1 + +/** +* LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on +* the same interface at the same time. +*/ +#define LWIP_DHCP_AUTOIP_COOP 1 + +/** +* LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes +* that should be sent before falling back on AUTOIP. This can be set +* as low as 1 to get an AutoIP address very quickly, but you should +* be prepared to handle a changing IP address when DHCP overrides +* AutoIP. +*/ +#define LWIP_DHCP_AUTOIP_COOP_TRIES CONFIG_LWIP_AUTOIP_TRIES + +/** + * ESP specific option only applicable if ESP_DHCP=1 + * LWIP_AUTOIP_MAX_CONFLICTS: Defines max conflicts before rate limiting + */ +#define LWIP_AUTOIP_MAX_CONFLICTS CONFIG_LWIP_AUTOIP_MAX_CONFLICTS + +/** + * ESP specific option only applicable if ESP_DHCP=1 + * LWIP_AUTOIP_RATE_LIMIT_INTERVAL: Delay in seconds between successive attempts + */ +#define LWIP_AUTOIP_RATE_LIMIT_INTERVAL CONFIG_LWIP_AUTOIP_RATE_LIMIT_INTERVAL + +#endif /* CONFIG_LWIP_AUTOIP */ + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#define LWIP_IGMP 1 + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#define LWIP_DNS 1 + +/** The maximum number of IP addresses per host + */ +#define DNS_MAX_HOST_IP CONFIG_LWIP_DNS_MAX_HOST_IP + +/** The maximum of DNS servers + */ +#define DNS_MAX_SERVERS CONFIG_LWIP_DNS_MAX_SERVERS + +/** ESP specific option only applicable if ESP_DNS=1 + * + * The last server can be initialized automatically by defining + * FALLBACK_DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*' + */ +#define DNS_FALLBACK_SERVER_INDEX (DNS_MAX_SERVERS - 1) + +#ifdef CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT +#define FALLBACK_DNS_SERVER_ADDRESS(address) \ + do { ip_addr_t *server_dns = address; \ + char server_ip[] = CONFIG_LWIP_FALLBACK_DNS_SERVER_ADDRESS; \ + ipaddr_aton(server_ip, server_dns); \ + } while (0) +#endif /* CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT */ + +/** + * LWIP_DNS_SUPPORT_MDNS_QUERIES==1: Enable mDNS queries in hostname resolution. + * This option is set via menuconfig. + */ +#ifdef CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 +#else +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 0 +#endif + +/** + * LWIP_DNS_SETSERVER_WITH_NETIF: If this is turned on, the dns_setserver_with_netif() is enabled and called + * from all internal modules (instead of dns_setserver()) allowing to setup a user callback to collect DNS server + * information acquired by the related network interface. + */ +#ifdef CONFIG_LWIP_DNS_SETSERVER_WITH_NETIF +#define LWIP_DNS_SETSERVER_WITH_NETIF 1 +#else +#define LWIP_DNS_SETSERVER_WITH_NETIF 0 +#endif + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#define LWIP_UDP 1 + +/** + * LWIP_NETBUF_RECVINFO==1: Enable IP_PKTINFO option. + * This option is set via menuconfig. + */ +#ifdef CONFIG_LWIP_NETBUF_RECVINFO +#define LWIP_NETBUF_RECVINFO 1 +#else +#define LWIP_NETBUF_RECVINFO 0 +#endif + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#define LWIP_TCP 1 + +/** + * TCP_WND: The size of a TCP window. This must be at least + * (2 * TCP_MSS) for things to work well. + * ATTENTION: when using TCP_RCV_SCALE, TCP_WND is the total size + * with scaling applied. Maximum window value in the TCP header + * will be TCP_WND >> TCP_RCV_SCALE + */ +#define TCP_WND CONFIG_LWIP_TCP_WND_DEFAULT + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#define TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#define TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifdef CONFIG_LWIP_TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 1 +#else +#define TCP_QUEUE_OOSEQ 0 +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs + * queued on ooseq per pcb + */ +#if TCP_QUEUE_OOSEQ +#define TCP_OOSEQ_MAX_PBUFS CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS +#endif + +/** + * TCP_OOSEQ_TIMEOUT: Timeout for each pbuf queued in TCP OOSEQ, in RTOs. + */ +#if TCP_QUEUE_OOSEQ +#define TCP_OOSEQ_TIMEOUT CONFIG_LWIP_TCP_OOSEQ_TIMEOUT +#endif + +/** + * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). + */ +#ifdef CONFIG_LWIP_TCP_SACK_OUT +#define LWIP_TCP_SACK_OUT 1 +#else +#define LWIP_TCP_SACK_OUT 0 +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#define TCP_MSS CONFIG_LWIP_TCP_MSS + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes). + * To achieve good performance, this should be at least 2 * TCP_MSS. + */ +#define TCP_SND_BUF CONFIG_LWIP_TCP_SND_BUF_DEFAULT + + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#define TCP_LISTEN_BACKLOG 1 + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time + */ +#ifdef CONFIG_LWIP_TCP_OVERSIZE_MSS +#define TCP_OVERSIZE TCP_MSS +#endif +#ifdef CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS +#define TCP_OVERSIZE (TCP_MSS/4) +#endif +#ifdef CONFIG_LWIP_TCP_OVERSIZE_DISABLE +#define TCP_OVERSIZE 0 +#endif +#ifndef TCP_OVERSIZE +#error "One of CONFIG_TCP_OVERSIZE_xxx options should be set by sdkconfig" +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + * events (accept, sent, etc) that happen in the system. + * LWIP_CALLBACK_API==1: The PCB callback function is called directly + * for the event. This is the default. + */ +#define LWIP_EVENT_API 0 +#define LWIP_CALLBACK_API 1 + +/** + * TCP_TMR_INTERVAL: TCP timer interval + */ +#define TCP_TMR_INTERVAL CONFIG_LWIP_TCP_TMR_INTERVAL + +/** + * TCP_MSL: The maximum segment lifetime in milliseconds + */ +#define TCP_MSL CONFIG_LWIP_TCP_MSL + +/** + * TCP_FIN_WAIT_TIMEOUT: The maximum FIN segment lifetime in milliseconds + */ +#define TCP_FIN_WAIT_TIMEOUT CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT + +/** + * LWIP_WND_SCALE and TCP_RCV_SCALE: + * Set LWIP_WND_SCALE to 1 to enable window scaling. + * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the + * range of [0..14]). + * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large + * send window while having a small receive window only. + */ +#ifdef CONFIG_LWIP_WND_SCALE +#define LWIP_WND_SCALE 1 +#define TCP_RCV_SCALE CONFIG_LWIP_TCP_RCV_SCALE +#else +#define LWIP_WND_SCALE 0 +#define TCP_RCV_SCALE 0 +#endif /* CONFIG_LWIP_WND_SCALE */ + +/** + * ESP specific option only applicable if ESP_LWIP=1 + * LWIP_TCP_RTO_TIME: TCP rto time. + * Default is 3 second. + */ +#define LWIP_TCP_RTO_TIME CONFIG_LWIP_TCP_RTO_TIME + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ + +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#define LWIP_NETIF_HOSTNAME 1 + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifdef CONFIG_LWIP_NETIF_API +#define LWIP_NETIF_API 1 +#else +#define LWIP_NETIF_API 0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#ifdef CONFIG_LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK 1 +#else +#define LWIP_NETIF_STATUS_CALLBACK 0 +#endif + +/** + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * for several netif related event that supports multiple subscribers. + * + * This ext-callback is used by ESP-NETIF with lwip-orig (upstream version) + * to provide netif related events on IP4/IP6 address/status changes + */ +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP *tries* to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * ATTENTION: a driver should *NOT* rely on getting single pbufs but check TX + * pbufs for being in one piece. If not, @ref pbuf_clone can be used to get + * a single pbuf: + * if (p->next != NULL) { + * struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); + * if (q == NULL) { + * return ERR_MEM; + * } + * p = q; ATTENTION: do NOT free the old 'p' as the ref belongs to the caller! + * } + */ +#define LWIP_NETIF_TX_SINGLE_PBUF 1 + +/** + * LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store + * data in client_data member array of struct netif (max. 256). + */ +#ifndef CONFIG_LWIP_NUM_NETIF_CLIENT_DATA +#define CONFIG_LWIP_NUM_NETIF_CLIENT_DATA 0 +#endif +#if defined(CONFIG_ESP_NETIF_BRIDGE_EN) || defined(CONFIG_LWIP_PPP_SUPPORT) +/* + * If special lwip interfaces (like bridge, ppp) enabled + * `netif->state` is used internally and we must store esp-netif ptr + * in `netif->client_data` + */ +#define LWIP_ESP_NETIF_DATA (1) +#else +#define LWIP_ESP_NETIF_DATA (0) +#endif + +#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_ESP_NETIF_DATA + CONFIG_LWIP_NUM_NETIF_CLIENT_DATA) + +/** + * BRIDGEIF_MAX_PORTS: this is used to create a typedef used for forwarding + * bit-fields: the number of bits required is this + 1 (for the internal/cpu port) + */ +#ifdef CONFIG_LWIP_BRIDGEIF_MAX_PORTS +#define BRIDGEIF_MAX_PORTS CONFIG_LWIP_BRIDGEIF_MAX_PORTS +#endif + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1). + * This is only needed when no real netifs are available. If at least one other +*/ +#ifdef CONFIG_LWIP_NETIF_LOOPBACK +#define LWIP_HAVE_LOOPIF 1 + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#define LWIP_NETIF_LOOPBACK 1 + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#define LWIP_LOOPBACK_MAX_PBUFS CONFIG_LWIP_LOOPBACK_MAX_PBUFS +#else +#define LWIP_HAVE_LOOPIF 0 +#endif + +/* + ------------------------------------ + ---------- SLIPIF options ---------- + ------------------------------------ +*/ + +#ifdef CONFIG_LWIP_SLIP_SUPPORT +/** + * Enable SLIP receive from ISR functions and disable Rx thread + * + * This is the only supported mode of lwIP SLIP interface, so that + * - incoming packets are queued into pbufs + * - no thread is created from lwIP + * meaning it is the application responsibility to read data + * from IO driver and feed them to the slip interface + */ +#define SLIP_RX_FROM_ISR 1 +#define SLIP_USE_RX_THREAD 0 + +/** + * SLIP_DEBUG: Enable debugging for SLIP. + */ +#ifdef CONFIG_LWIP_SLIP_DEBUG_ON +#define SLIP_DEBUG LWIP_DBG_ON +#else +#define SLIP_DEBUG LWIP_DBG_OFF +#endif +#endif /* CONFIG_LWIP_SLIP_SUPPORT */ + +/* + ------------------------------------ + ---------- Thread options ---------- + ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#define TCPIP_THREAD_NAME "tiT" + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define TCPIP_THREAD_STACKSIZE ESP_TASK_TCPIP_STACK + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define TCPIP_THREAD_PRIO ESP_TASK_TCPIP_PRIO + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#define TCPIP_MBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#define DEFAULT_ACCEPTMBOX_SIZE CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define DEFAULT_THREAD_STACKSIZE TCPIP_THREAD_STACKSIZE + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#define DEFAULT_THREAD_PRIO TCPIP_THREAD_PRIO + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_RAW_RECVMBOX_SIZE 6 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 1 + +/** LWIP_NETCONN_SEM_PER_THREAD==1: Use one (thread-local) semaphore per + * thread calling socket/netconn functions instead of allocating one + * semaphore per netconn (and per select etc.) + * ATTENTION: a thread-local semaphore for API calls is needed: + * - LWIP_NETCONN_THREAD_SEM_GET() returning a sys_sem_t* + * - LWIP_NETCONN_THREAD_SEM_ALLOC() creating the semaphore + * - LWIP_NETCONN_THREAD_SEM_FREE() freeing the semaphore + * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). + * Ports may call these for threads created with sys_thread_new(). + */ +#define LWIP_NETCONN_SEM_PER_THREAD 1 + +/** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, + * writing from a 2nd thread and closing from a 3rd thread at the same time. + * ATTENTION: This is currently really alpha! Some requirements: + * - LWIP_NETCONN_SEM_PER_THREAD==1 is required to use one socket/netconn from + * multiple threads at once + * - sys_mbox_free() has to unblock receive tasks waiting on recvmbox/acceptmbox + * and prevent a task pending on this during/after deletion + */ +#define LWIP_NETCONN_FULLDUPLEX 1 + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 1 + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names through defines. + * LWIP_COMPAT_SOCKETS==2: Same as ==1 but correctly named functions are created. + * While this helps code completion, it might conflict with existing libraries. + * (only used if you use sockets.c) + */ +#define LWIP_COMPAT_SOCKETS 0 + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + * + * POSIX I/O functions are mapped to LWIP via the VFS layer + * (see port/vfs_lwip.c) + */ +/** + */ +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 + +/** + * LWIP_SOCKET_OFFSET==n: Increases the file descriptor number created by LwIP with n. + * + * FD_SETSIZE from sys/types.h is the maximum number of supported file + * descriptors and CONFIG_LWIP_MAX_SOCKETS defines the number of sockets; + * LWIP_SOCKET_OFFSET is configured to use the largest numbers of file + * descriptors for sockets. File descriptors from 0 to LWIP_SOCKET_OFFSET-1 + * are non-socket descriptors and from LWIP_SOCKET_OFFSET to FD_SETSIZE are + * socket descriptors. + */ +#define LWIP_SOCKET_OFFSET (FD_SETSIZE - CONFIG_LWIP_MAX_SOCKETS) + +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#define LWIP_SO_SNDTIMEO 1 + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#define LWIP_SO_RCVTIMEO 1 + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#define LWIP_TCP_KEEPALIVE 1 + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + * This option is set via menuconfig. + */ +#ifdef CONFIG_LWIP_SO_LINGER +#define LWIP_SO_LINGER 1 +#else +#define LWIP_SO_LINGER 0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + * This option is set via menuconfig. + */ +#ifdef CONFIG_LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF 1 +#else +#define LWIP_SO_RCVBUF 0 +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + * This option is set via menuconfig. + */ +#ifdef CONFIG_LWIP_SO_REUSE +#define SO_REUSE 1 +#else +#define SO_REUSE 0 +#endif + +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifdef CONFIG_LWIP_SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 1 +#else +#define SO_REUSE_RXTOALL 0 +#endif + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ +#define LWIP_TIMEVAL_PRIVATE 0 + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ + +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifdef CONFIG_LWIP_STATS +#define LWIP_STATS 1 +#define ESP_STATS_MEM 1 + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#define LWIP_STATS_DISPLAY 1 +#else +#define LWIP_STATS 0 +#define ESP_STATS_MEM 0 +#endif /* CONFIG_LWIP_STATS */ + +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ + +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifdef CONFIG_LWIP_PPP_SUPPORT +#define PPP_SUPPORT 1 + +/** + * PPP_IPV6_SUPPORT == 1: Enable IPV6 support for local link + * between modem and lwIP stack. + * Some modems do not support IPV6 addressing in local link and + * the only option available is to disable IPV6 address negotiation. + */ +#define PPP_IPV6_SUPPORT CONFIG_LWIP_PPP_ENABLE_IPV6 + +/** + * PPP_NOTIFY_PHASE==1: Support PPP notify phase. + */ +#define PPP_NOTIFY_PHASE CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#define PAP_SUPPORT CONFIG_LWIP_PPP_PAP_SUPPORT + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#define CHAP_SUPPORT CONFIG_LWIP_PPP_CHAP_SUPPORT + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. + */ +#define MSCHAP_SUPPORT CONFIG_LWIP_PPP_MSCHAP_SUPPORT + +/** + * CCP_SUPPORT==1: Support CCP. + */ +#define MPPE_SUPPORT CONFIG_LWIP_PPP_MPPE_SUPPORT + +/** + * PPP_SERVER==1: Enable PPP server support (waiting for incoming PPP session). + */ +#define PPP_SERVER CONFIG_LWIP_PPP_SERVER_SUPPORT + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#define VJ_SUPPORT CONFIG_LWIP_PPP_VJ_HEADER_COMPRESSION + +/** + * PPP_MAXIDLEFLAG: Max Xmit idle time (in ms) before resend flag char. + * TODO: If PPP_MAXIDLEFLAG > 0 and next package is send during PPP_MAXIDLEFLAG time, + * then 0x7E is not added at the beginning of PPP package but 0x7E termination + * is always at the end. This behaviour brokes PPP dial with GSM (PPPoS). + * The PPP package should always start and end with 0x7E. + */ + +#define PPP_MAXIDLEFLAG 0 + +#ifdef CONFIG_LWIP_ENABLE_LCP_ECHO +/** + * LCP_ECHOINTERVAL: Interval in seconds between keepalive LCP echo requests, 0 to disable. + */ +#define LCP_ECHOINTERVAL CONFIG_LWIP_LCP_ECHOINTERVAL + +/** + * LCP_MAXECHOFAILS: Number of consecutive unanswered echo requests before failure is indicated. + */ +#define LCP_MAXECHOFAILS CONFIG_LWIP_LCP_MAXECHOFAILS +#endif /* CONFIG_LWIP_ENABLE_LCP_ECHO */ + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifdef CONFIG_LWIP_PPP_DEBUG_ON +#define PPP_DEBUG LWIP_DBG_ON +#define PRINTPKT_SUPPORT 1 +#define PPP_PROTOCOLNAME 1 +#else +#define PPP_DEBUG LWIP_DBG_OFF +#endif /* CONFIG_LWIP_PPP_DEBUG_ON */ +#else +#define PPP_SUPPORT 0 +#endif /* CONFIG_LWIP_PPP_SUPPORT */ + +/** + * LWIP_USE_EXTERNAL_MBEDTLS: Use external mbed TLS library for crypto implementation used in PPP AUTH + */ +#ifdef CONFIG_LWIP_USE_EXTERNAL_MBEDTLS +#define LWIP_USE_EXTERNAL_MBEDTLS 1 +#else +#define LWIP_USE_EXTERNAL_MBEDTLS 0 +#endif + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ + +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifdef CONFIG_LWIP_CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 1 +#else +#define CHECKSUM_CHECK_IP 0 +#endif + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifdef CONFIG_LWIP_CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 1 +#else +#define CHECKSUM_CHECK_UDP 0 +#endif + +/** + * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. + */ +#ifdef CONFIG_LWIP_CHECKSUM_CHECK_ICMP +#define CHECKSUM_CHECK_ICMP 1 +#else +#define CHECKSUM_CHECK_ICMP 0 +#endif + +/* + --------------------------------------- + ---------- IPv6 options --------------- + --------------------------------------- +*/ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#ifdef CONFIG_LWIP_IPV6 +#define LWIP_IPV6 1 +#else +#define LWIP_IPV6 0 +#endif + +/** + * LWIP_ND6==1: Enable ND6 protocol in IPv6 + */ +#ifdef CONFIG_LWIP_ND6 +#define LWIP_ND6 1 +#else +#define LWIP_ND6 0 +#endif + +/** + * LWIP_FORCE_ROUTER_FORWARDING==1: the router flag in NA packet will always set to 1, + * otherwise, never set router flag for NA packets. + */ +#ifdef CONFIG_LWIP_FORCE_ROUTER_FORWARDING +#define LWIP_FORCE_ROUTER_FORWARDING 1 +#else +#define LWIP_FORCE_ROUTER_FORWARDING 0 +#endif + +/** + * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. + */ +#define LWIP_IPV6_NUM_ADDRESSES CONFIG_LWIP_IPV6_NUM_ADDRESSES + +/** + * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs + */ +#ifdef CONFIG_LWIP_IPV6_FORWARD +#define LWIP_IPV6_FORWARD 1 +#else +#define LWIP_IPV6_FORWARD 0 +#endif + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IP6 packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP6_REASSEMBLY. + */ +#ifdef CONFIG_LWIP_IP6_FRAG +#define LWIP_IPV6_FRAG 1 +#else +#define LWIP_IPV6_FRAG 0 +#endif + +/** + * LWIP_IPV6_REASS==1: reassemble incoming IP6 packets that fragmented. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via LWIP_IP6_FRAG. + */ +#ifdef CONFIG_LWIP_IP6_REASSEMBLY +#define LWIP_IPV6_REASS 1 +#else +#define LWIP_IPV6_REASS 0 +#endif + +/** + * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. + */ +#ifdef CONFIG_LWIP_IPV6_AUTOCONFIG +#define ESP_IPV6_AUTOCONFIG 1 +#else +#define ESP_IPV6_AUTOCONFIG 0 +#endif + +/** + * LWIP_ND6_RDNSS_MAX_DNS_SERVERS > 0: Use IPv6 Router Advertisement Recursive + * DNS Server Option (as per RFC 6106) to copy a defined maximum number of DNS + * servers to the DNS module. + */ +#define LWIP_ND6_RDNSS_MAX_DNS_SERVERS CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS + +/** + * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful/stateless address autoconfiguration. + */ +#ifdef CONFIG_LWIP_IPV6_DHCP6 +#define LWIP_IPV6_DHCP6 1 +#else +#define LWIP_IPV6_DHCP6 0 +#endif + +/** + * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. + */ +#define MEMP_NUM_ND6_QUEUE CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE + +/** + * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache + */ +#define LWIP_ND6_NUM_NEIGHBORS CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS + +/* + --------------------------------------- + ---------- Hook options --------------- + --------------------------------------- +*/ +#ifdef LWIP_HOOK_FILENAME +#warning LWIP_HOOK_FILENAME is used for IDF default hooks. Please use ESP_IDF_LWIP_HOOK_FILENAME to insert additional hook +#endif +#define LWIP_HOOK_FILENAME "lwip_default_hooks.h" +#define LWIP_HOOK_IP4_ROUTE_SRC ip4_route_src_hook +#if LWIP_NETCONN_FULLDUPLEX +#define LWIP_DONE_SOCK(sock) done_socket(sock) +#else +#define LWIP_DONE_SOCK(sock) ((void)1) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + +#define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) \ + lwip_getsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false + +#define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) \ + lwip_setsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DEBUG: Enable lwip debugging in other modules. + */ +#ifdef CONFIG_LWIP_DEBUG +#define LWIP_DEBUG LWIP_DBG_ON +#else +#undef LWIP_DEBUG +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifdef CONFIG_LWIP_ETHARP_DEBUG +#define ETHARP_DEBUG LWIP_DBG_ON +#else +#define ETHARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifdef CONFIG_LWIP_NETIF_DEBUG +#define NETIF_DEBUG LWIP_DBG_ON +#else +#define NETIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifdef CONFIG_LWIP_PBUF_DEBUG +#define PBUF_DEBUG LWIP_DBG_ON +#else +#define PBUF_DEBUG LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifdef CONFIG_LWIP_API_LIB_DEBUG +#define API_LIB_DEBUG LWIP_DBG_ON +#else +#define API_LIB_DEBUG LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifdef CONFIG_LWIP_SOCKETS_DEBUG +#define SOCKETS_DEBUG LWIP_DBG_ON +#else +#define SOCKETS_DEBUG LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifdef CONFIG_LWIP_ICMP_DEBUG +#define ICMP_DEBUG LWIP_DBG_ON +#else +#define ICMP_DEBUG LWIP_DBG_OFF +#endif + +#ifdef CONFIG_LWIP_ICMP6_DEBUG +#define ICMP6_DEBUG LWIP_DBG_ON +#else +#define ICMP6_DEBUG LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifdef CONFIG_LWIP_DHCP_DEBUG +#define DHCP_DEBUG LWIP_DBG_ON +#else +#define DHCP_DEBUG LWIP_DBG_OFF +#endif + +#ifdef CONFIG_LWIP_DHCP_STATE_DEBUG +#define ESP_DHCP_DEBUG LWIP_DBG_ON +#else +#define ESP_DHCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifdef CONFIG_LWIP_IP_DEBUG +#define IP_DEBUG LWIP_DBG_ON +#else +#define IP_DEBUG LWIP_DBG_OFF +#endif + +/** + * IP6_DEBUG: Enable debugging for IP6. + */ +#ifdef CONFIG_LWIP_IP6_DEBUG +#define IP6_DEBUG LWIP_DBG_ON +#else +#define IP6_DEBUG LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifdef CONFIG_LWIP_TCP_DEBUG +#define TCP_DEBUG LWIP_DBG_ON +#else +#define TCP_DEBUG LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging for UDP. + */ +#ifdef CONFIG_LWIP_UDP_DEBUG +#define UDP_DEBUG LWIP_DBG_ON +#else +#define UDP_DEBUG LWIP_DBG_OFF +#endif + +/** + * SNTP_DEBUG: Enable debugging for SNTP. + */ +#ifdef CONFIG_LWIP_SNTP_DEBUG +#define SNTP_DEBUG LWIP_DBG_ON +#else +#define SNTP_DEBUG LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifdef CONFIG_LWIP_DNS_DEBUG +#define DNS_DEBUG LWIP_DBG_ON +#else +#define DNS_DEBUG LWIP_DBG_OFF +#endif + +/** + * NAPT_DEBUG: Enable debugging for NAPT. + */ +#ifdef CONFIG_LWIP_NAPT_DEBUG +#define NAPT_DEBUG LWIP_DBG_ON +#else +#define NAPT_DEBUG LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#define MEMP_DEBUG LWIP_DBG_OFF + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#define TCPIP_DEBUG LWIP_DBG_OFF + +/** + * TCP_OOSEQ_DEBUG: Enable debugging in tcpin.c for OOSEQ. + */ +#define TCP_OOSEQ_DEBUG LWIP_DBG_OFF + +/** + * BRIDGEIF_DEBUG: Enable generic debugging for bridge. + */ +#ifdef CONFIG_LWIP_BRIDGEIF_DEBUG +#define BRIDGEIF_DEBUG LWIP_DBG_ON +#endif + +/** + * BRIDGEIF_FDB_DEBUG: Enable debugging for bridge FDB. + */ +#ifdef CONFIG_LWIP_BRIDGEIF_FDB_DEBUG +#define BRIDGEIF_FDB_DEBUG LWIP_DBG_ON +#endif + +/** + * BRIDGEIF_FW_DEBUG: Enable debugging for bridge forwarding. + */ +#ifdef CONFIG_LWIP_BRIDGEIF_FW_DEBUG +#define BRIDGEIF_FW_DEBUG LWIP_DBG_ON +#endif + +/* + -------------------------------------- + ------------ SNTP options ------------ + -------------------------------------- +*/ +/** + * Max number of SNTP servers handled (default equal to LWIP_DHCP_MAX_NTP_SERVERS) + */ +#ifdef CONFIG_LWIP_SNTP_MAX_SERVERS +#define SNTP_MAX_SERVERS CONFIG_LWIP_SNTP_MAX_SERVERS +#endif /* CONFIG_LWIP_SNTP_MAX_SERVERS */ + +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#define SNTP_SERVER_DNS 1 + +/** + * It disables a check of SNTP_UPDATE_DELAY it is done in sntp_set_sync_interval + */ +#define SNTP_SUPPRESS_DELAY_CHECK + +#define SNTP_UPDATE_DELAY (sntp_get_sync_interval()) +#define SNTP_SET_SYSTEM_TIME_US(sec, us) (sntp_set_system_time(sec, us)) +#define SNTP_GET_SYSTEM_TIME(sec, us) (sntp_get_system_time(&(sec), &(us))) + +/** + * Configuring SNTP startup delay + */ +#ifdef CONFIG_LWIP_SNTP_STARTUP_DELAY +#define SNTP_STARTUP_DELAY 1 +#ifdef CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY +#define SNTP_STARTUP_DELAY_FUNC (LWIP_RAND() % CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY) +#endif /* CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY */ +#else +#define SNTP_STARTUP_DELAY 0 +#endif /* SNTP_STARTUP_DELAY */ + +/* + --------------------------------------- + --------- ESP specific options -------- + --------------------------------------- +*/ +/** + * ESP_LWIP_IGMP_TIMERS_ONDEMAND==1: Start IGMP timers only if used + * ESP_LWIP_MLD6_TIMERS_ONDEMAND==1: Start MLD6 timers only if used + * Timers will only be activated when joining groups/receiving queries + */ +#ifdef CONFIG_LWIP_TIMERS_ONDEMAND +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 1 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 1 +#define ESP_LWIP_DHCP_FINE_TIMERS_ONDEMAND 1 +#define ESP_LWIP_DNS_TIMERS_ONDEMAND 1 +#if IP_REASSEMBLY +#define ESP_LWIP_IP4_REASSEMBLY_TIMERS_ONDEMAND 1 +#endif /* IP_REASSEMBLY */ +#if LWIP_IPV6_REASS +#define ESP_LWIP_IP6_REASSEMBLY_TIMERS_ONDEMAND 1 +#endif /* LWIP_IPV6_REASS */ +#else +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 0 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 0 +#define ESP_LWIP_DHCP_FINE_TIMERS_ONDEMAND 0 +#define ESP_LWIP_DNS_TIMERS_ONDEMAND 0 +#if IP_REASSEMBLY +#define ESP_LWIP_IP4_REASSEMBLY_TIMERS_ONDEMAND 0 +#endif /* IP_REASSEMBLY */ +#if LWIP_IPV6_REASS +#define ESP_LWIP_IP6_REASSEMBLY_TIMERS_ONDEMAND 0 +#endif /* LWIP_IPV6_REASS */ +#endif + +/** + * ESP_GRATUITOUS_ARP==1: This option allows to send gratuitous ARP periodically. + */ +#ifdef CONFIG_LWIP_ESP_GRATUITOUS_ARP +#define ESP_GRATUITOUS_ARP 1 +#define ESP_GRATUITOUS_ARP_INTERVAL (CONFIG_LWIP_GARP_TMR_INTERVAL*1000UL) +#else +#define ESP_GRATUITOUS_ARP 0 +#endif + +/** + * ESP_MLDV6_REPORT==1: This option allows to send mldv6 report periodically. + */ +#ifdef CONFIG_LWIP_ESP_MLDV6_REPORT +#define ESP_MLDV6_REPORT 1 +#else +#define ESP_MLDV6_REPORT 0 +#endif + +#define ESP_LWIP 1 +#define ESP_LWIP_ARP 1 +#define ESP_PER_SOC_TCP_WND 0 +#define ESP_THREAD_SAFE 1 +#define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF +#define ESP_DHCP 1 +#define ESP_DNS 1 +#define ESP_STATS_TCP 0 +#define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__) +#define ESP_PING 1 +#define ESP_HAS_SELECT 1 +#define ESP_IP4_ROUTE 1 +#define ESP_AUTO_IP 1 +#define ESP_PBUF 1 +#define ESP_PPP 1 +#define ESP_IPV6 LWIP_IPV6 +#define ESP_SOCKET 1 +#define ESP_LWIP_SELECT 1 +#define ESP_LWIP_LOCK 1 +#define ESP_THREAD_PROTECTION 1 +#define LWIP_SUPPORT_CUSTOM_PBUF 1 +#define ESP_LWIP_FALLBACK_DNS_PREFER_IPV4 0 + +/* + ----------------------------------------- + ---------- DHCP Server options ---------- + ----------------------------------------- +*/ +/** + * ESP_DHCPS==1: Enable the DHCP server + */ +#ifdef CONFIG_LWIP_DHCPS +#define ESP_DHCPS 1 +#define ESP_DHCPS_TIMER 0 +#else +#define ESP_DHCPS 0 +#define ESP_DHCPS_TIMER 0 +#endif /* CONFIG_LWIP_DHCPS */ + + +#if LWIP_NETCONN_SEM_PER_THREAD +#if ESP_THREAD_SAFE +#define LWIP_NETCONN_THREAD_SEM_GET() sys_thread_sem_get() +#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_thread_sem_init() +#define LWIP_NETCONN_THREAD_SEM_FREE() sys_thread_sem_deinit() +#endif +#endif + +/** + * If CONFIG_ALLOC_MEMORY_IN_SPIRAM_FIRST is enabled, Try to + * allocate memory for lwip in SPIRAM firstly. If failed, try to allocate + * internal memory then. + */ +#if CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP +#define mem_clib_malloc(size) heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) +#define mem_clib_calloc(n, size) heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL) +#else /* !CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP */ +#define mem_clib_malloc malloc +#define mem_clib_calloc calloc +#endif /* CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP */ + + +/* + * Check if the lwIP configuration is sane + */ +#if !LWIP_IPV4 && !LWIP_IPV6 +#error "Please enable at least one IP stack (either IPv4 or IPv6 or both)" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_ESP_LWIPOPTS_H */ diff --git a/components/lwip/port/include/netdb.h b/components/lwip/port/include/netdb.h new file mode 100644 index 000000000..f7c0eedeb --- /dev/null +++ b/components/lwip/port/include/netdb.h @@ -0,0 +1,29 @@ +/** + * @file + * This file is a posix wrapper for lwip/netdb.h. + */ + +/* + * SPDX-FileCopyrightText: 2001-2004 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + */ + +#include "lwip/netdb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ESP_PLATFORM +int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, + char *host, socklen_t hostlen, + char *serv, socklen_t servlen, int flags); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/port/include/netif/dhcp_state.h b/components/lwip/port/include/netif/dhcp_state.h new file mode 100644 index 000000000..0ebb78ab1 --- /dev/null +++ b/components/lwip/port/include/netif/dhcp_state.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LWIP_ESP_DHCP_STATE_H +#define LWIP_ESP_DHCP_STATE_H + +#include +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool dhcp_ip_addr_restore(struct netif *netif); + +void dhcp_ip_addr_store(struct netif *netif); + +void dhcp_ip_addr_erase(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ESP_DHCP_STATE_H */ diff --git a/components/lwip/port/include/netinet/in.h b/components/lwip/port/include/netinet/in.h new file mode 100644 index 000000000..808f36b51 --- /dev/null +++ b/components/lwip/port/include/netinet/in.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef IN_H_ +#define IN_H_ + +#include "lwip/inet.h" + +#define IN6_IS_ADDR_MULTICAST(a) IN_MULTICAST(a) + +#endif /* IN_H_ */ diff --git a/components/lwip/port/include/netinet/tcp.h b/components/lwip/port/include/netinet/tcp.h new file mode 100644 index 000000000..d832864dc --- /dev/null +++ b/components/lwip/port/include/netinet/tcp.h @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2015-2016 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020 Francesco Giancane + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#include "lwip/tcp.h" + +#endif /* _NETINET_TCP_H */ diff --git a/components/lwip/port/include/sntp/sntp_get_set_time.h b/components/lwip/port/include/sntp/sntp_get_set_time.h new file mode 100644 index 000000000..c032aa170 --- /dev/null +++ b/components/lwip/port/include/sntp/sntp_get_set_time.h @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SNTP_GET_SET_TIME_H__ +#define __SNTP_GET_SET_TIME_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Declarations of functions used in lwipopts.h to redefine + * default sntp macros, such as: + * - SNTP_UPDATE_DELAY() + * - SNTP_SET_SYSTEM_TIME_US() + * - SNTP_GET_SYSTEM_TIME() + */ + +/* + * @brief Get the sync interval of SNTP operation + * Full definition is provided in IDF's layer in esp_sntp.c + */ +uint32_t sntp_get_sync_interval(void); + +/** + * @brief system time setter used in the sntp module + * @note The lwip sntp uses u32_t types for sec and us arguments + */ +void sntp_set_system_time(uint32_t sec, uint32_t us); + +/** + * @brief system time getter used in the sntp module + * @note The lwip sntp uses u32_t types for sec and us arguments + */ +void sntp_get_system_time(uint32_t* sec, uint32_t* us); + +#ifdef __cplusplus +} +#endif + +#endif //__SNTP_GET_SET_TIME_H__ diff --git a/components/lwip/port/include/sockets_ext.h b/components/lwip/port/include/sockets_ext.h new file mode 100644 index 000000000..b4ef6199c --- /dev/null +++ b/components/lwip/port/include/sockets_ext.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPV6_MULTICAST_IF 0x300 +#define IPV6_MULTICAST_HOPS 0x301 +#define IPV6_MULTICAST_LOOP 0x302 + +struct lwip_sock; + +bool lwip_setsockopt_impl_ext(struct lwip_sock* sock, int level, int optname, const void *optval, uint32_t optlen, int *err); +bool lwip_getsockopt_impl_ext(struct lwip_sock* sock, int level, int optname, void *optval, uint32_t *optlen, int *err); +#ifdef __cplusplus +} +#endif diff --git a/components/lwip/port/linux/include/arch/cc.h b/components/lwip/port/linux/include/arch/cc.h new file mode 100644 index 000000000..10be65f3e --- /dev/null +++ b/components/lwip/port/linux/include/arch/cc.h @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD + */ +#ifndef LWIP_ARCH_CC_H +#define LWIP_ARCH_CC_H + +/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */ +#if defined __ANDROID__ +#define LWIP_UNIX_ANDROID +#elif defined __linux__ +#define LWIP_UNIX_LINUX +#elif defined __APPLE__ +#define LWIP_UNIX_MACH +#elif defined __OpenBSD__ +#define LWIP_UNIX_OPENBSD +#elif defined __CYGWIN__ +#define LWIP_UNIX_CYGWIN +#elif defined __GNU__ +#define LWIP_UNIX_HURD +#endif + +#define LWIP_TIMEVAL_PRIVATE 0 +#include +#include + +#define LWIP_ERRNO_INCLUDE + +#if defined(LWIP_UNIX_LINUX) || defined(LWIP_UNIX_HURD) +#define LWIP_ERRNO_STDINCLUDE 1 +#endif + +/* different handling for unit test, normally not needed */ +#ifdef LWIP_NOASSERT_ON_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ + handler;}} while(0) +#endif + +#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET) +typedef __kernel_fd_set fd_set; +#endif + +#if defined(LWIP_UNIX_MACH) +/* sys/types.h and signal.h bring in Darwin byte order macros. pull the + header here and disable LwIP's version so that apps still can get + the macros via LwIP headers and use system headers */ +#include +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#endif + +struct sio_status_s; +typedef struct sio_status_s sio_status_t; +#define sio_fd_t sio_status_t* +#define __sio_fd_t_defined + +typedef unsigned int sys_prot_t; + +#endif /* LWIP_ARCH_CC_H */ diff --git a/components/lwip/port/linux/include/arch/vfs_lwip.h b/components/lwip/port/linux/include/arch/vfs_lwip.h new file mode 100644 index 000000000..c9899b7dd --- /dev/null +++ b/components/lwip/port/linux/include/arch/vfs_lwip.h @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +static inline void esp_vfs_lwip_sockets_register(void) {} diff --git a/components/lwip/port/linux/include/net/if.h b/components/lwip/port/linux/include/net/if.h new file mode 100644 index 000000000..e7bc2a3ab --- /dev/null +++ b/components/lwip/port/linux/include/net/if.h @@ -0,0 +1,6 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once diff --git a/components/lwip/port/linux/include/sys/fcntl.h b/components/lwip/port/linux/include/sys/fcntl.h new file mode 100644 index 000000000..f2b5d8737 --- /dev/null +++ b/components/lwip/port/linux/include/sys/fcntl.h @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "sdkconfig.h" + +#ifdef LWIP_HDR_LINUX_SYS_SOCKETS_H +// only if we prefer linux system sockets, include from system paths +#include_next +#elif CONFIG_IDF_TARGET_LINUX +// need to declare, as on linux we bypass IDF vfs and wrap posix io functions +extern int fcntl(int s, int cmd, ...); +#endif +// ignore otherwise (typically included from lwipopts.h) since lwip provides all necessary definitions diff --git a/components/lwip/port/linux/include/sys/socket.h b/components/lwip/port/linux/include/sys/socket.h new file mode 100644 index 000000000..c7437e042 --- /dev/null +++ b/components/lwip/port/linux/include/sys/socket.h @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#ifdef LWIP_HDR_LINUX_SYS_SOCKETS_H +/* only if we prefer linux system sockets, include from system paths */ +#include_next +#else +/* Include lwip sockets by default */ +#include "lwip/sockets.h" +#endif /* LWIP_HDR_LINUX_SYS_SOCKETS_H */ diff --git a/components/lwip/port/linux/vfs_lwip.c b/components/lwip/port/linux/vfs_lwip.c new file mode 100644 index 000000000..116f8bc69 --- /dev/null +++ b/components/lwip/port/linux/vfs_lwip.c @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +extern int __real_fcntl(int s, int cmd, ...); +extern int __real_close(int s); +extern ssize_t __real_write (int fd, const void *buf, size_t n); +extern ssize_t __real_read (int fd, void *buf, size_t n); +extern int __real_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval); + +ssize_t __wrap_write (int fd, const void *buf, size_t n) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_write(fd, buf, n); +#endif + return __real_write(fd, buf, n); +} + +ssize_t __wrap_read (int fd, void *buf, size_t n) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_read(fd, buf, n); +#endif + return __real_read(fd, buf, n); +} + +int __wrap_select (int fd, fd_set * rds, fd_set * wfds, fd_set *efds, struct timeval *tval) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_select(fd, rds, wfds, efds, tval); +#endif + return __real_select(fd, rds, wfds, efds, tval); +} + +int __wrap_fcntl(int fd, int cmd, ...) +{ + va_list args; +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) { + va_start(args, cmd); + int arg = va_arg(args, int); + va_end(args); + return lwip_fcntl(fd, cmd, arg); + } +#endif + + return __real_fcntl(fd, cmd, args); +} + +int __wrap_close(int fd) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_close(fd); +#endif + return __real_close(fd); +} diff --git a/components/lwip/port/sockets_ext.c b/components/lwip/port/sockets_ext.c new file mode 100644 index 000000000..79bab7f11 --- /dev/null +++ b/components/lwip/port/sockets_ext.c @@ -0,0 +1,108 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lwip/sockets.h" +#include "lwip/priv/sockets_priv.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" + +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ + if (((optlen) < sizeof(opttype)) || ((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { *err=EINVAL; goto exit; } }while(0) + +#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ + if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { *err=ENOPROTOOPT; goto exit; } } while(0) + + +bool lwip_setsockopt_impl_ext(struct lwip_sock* sock, int level, int optname, const void *optval, socklen_t optlen, int *err) +{ +#if LWIP_IPV6 + if (level != IPPROTO_IPV6) +#endif /* LWIP_IPV6 */ + { + return false; + } + +#if LWIP_IPV6 + switch (optname) { + default: + return false; + case IPV6_MULTICAST_IF: /* NB: like IP_MULTICAST_IF, this takes an IP not an index */ + { + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + udp_set_multicast_netif_index(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval)); + } + break; + case IPV6_MULTICAST_HOPS: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval)); + break; + case IPV6_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); + if (*(const u8_t*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); + } + break; + } +exit: + return true; +#endif /* LWIP_IPV6 */ +} + +bool lwip_getsockopt_impl_ext(struct lwip_sock* sock, int level, int optname, void *optval, uint32_t *optlen, int *err) +{ +#if LWIP_IPV6 + if (level != IPPROTO_IPV6) +#endif /* LWIP_IPV6 */ + { + return false; + } + +#if LWIP_IPV6 + switch (optname) { + default: + return false; + case IPV6_MULTICAST_IF: /* NB: like IP_MULTICAST_IF, this returns an IP not an index */ + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + *err = ENOPROTOOPT; + goto exit; + } + *(u8_t*)optval = udp_get_multicast_netif_index(sock->conn->pcb.udp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt_ext(IPPROTO_IPV6, IPV6_MULTICAST_IF) = 0x%"X32_F"\n", + *(u32_t *)optval)); + break; + case IPV6_MULTICAST_HOPS: + printf("IPV6_MULTICAST_HOPS\n"); + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { + *err = ENOPROTOOPT; + goto exit; + } + *(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt_ext(IPPROTO_IPV6, IP_MULTICAST_LOOP) = %d\n", + *(int *)optval)); + break; + case IPV6_MULTICAST_LOOP: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); + if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t*)optval = 1; + } else { + *(u8_t*)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt_ext(IPPROTO_IPV6, IP_MULTICAST_LOOP) = %d\n", + *(int *)optval)); + break; + } +exit: + return true; +#endif /* LWIP_IPV6 */ +} diff --git a/components/lwip/sdkconfig.rename b/components/lwip/sdkconfig.rename new file mode 100644 index 000000000..28f675529 --- /dev/null +++ b/components/lwip/sdkconfig.rename @@ -0,0 +1,37 @@ +# sdkconfig replacement configurations for deprecated options formatted as +# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION + +CONFIG_L2_TO_L3_COPY CONFIG_LWIP_L2_TO_L3_COPY +CONFIG_ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP +CONFIG_GARP_TMR_INTERVAL CONFIG_LWIP_GARP_TMR_INTERVAL +CONFIG_TCPIP_RECVMBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE + +# TCP +CONFIG_TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX +CONFIG_TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX +CONFIG_TCP_MSS CONFIG_LWIP_TCP_MSS +CONFIG_TCP_MSL CONFIG_LWIP_TCP_MSL +CONFIG_TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT +CONFIG_TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT +CONFIG_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE +CONFIG_TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ +CONFIG_TCP_OVERSIZE CONFIG_LWIP_TCP_OVERSIZE +CONFIG_TCP_OVERSIZE_MSS CONFIG_LWIP_TCP_OVERSIZE_MSS +CONFIG_TCP_OVERSIZE_QUARTER_MSS CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS +CONFIG_TCP_OVERSIZE_DISABLE CONFIG_LWIP_TCP_OVERSIZE_DISABLE + +# UDP +CONFIG_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE + +CONFIG_TCPIP_TASK_STACK_SIZE CONFIG_LWIP_TCPIP_TASK_STACK_SIZE +CONFIG_TCPIP_TASK_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY +CONFIG_TCPIP_TASK_AFFINITY_CPU0 CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 +CONFIG_TCPIP_TASK_AFFINITY_CPU1 CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 +CONFIG_PPP_SUPPORT CONFIG_LWIP_PPP_SUPPORT +CONFIG_PPP_NOTIFY_PHASE_SUPPORT CONFIG_LWIP_PPP_NOTIFY_PHASE_SUPPORT +CONFIG_PPP_PAP_SUPPORT CONFIG_LWIP_PPP_PAP_SUPPORT +CONFIG_PPP_CHAP_SUPPORT CONFIG_LWIP_PPP_CHAP_SUPPORT +CONFIG_PPP_MSCHAP_SUPPORT CONFIG_LWIP_PPP_MSCHAP_SUPPORT +CONFIG_PPP_MPPE_SUPPORT CONFIG_LWIP_PPP_MPPE_SUPPORT +CONFIG_PPP_DEBUG_ON CONFIG_LWIP_PPP_DEBUG_ON diff --git a/components/lwip/test_apps/.build-test-rules.yml b/components/lwip/test_apps/.build-test-rules.yml new file mode 100644 index 000000000..a72b0116d --- /dev/null +++ b/components/lwip/test_apps/.build-test-rules.yml @@ -0,0 +1,6 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/lwip/test_apps: + disable_test: + - if: IDF_TARGET != "esp32" + reason: running this test for one target only is enough to be sufficiently confident about no regression in lwip diff --git a/components/lwip/test_apps/CMakeLists.txt b/components/lwip/test_apps/CMakeLists.txt new file mode 100644 index 000000000..88bcd73ec --- /dev/null +++ b/components/lwip/test_apps/CMakeLists.txt @@ -0,0 +1,8 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lwip_test) diff --git a/components/lwip/test_apps/README.md b/components/lwip/test_apps/README.md new file mode 100644 index 000000000..9a7824d8e --- /dev/null +++ b/components/lwip/test_apps/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/lwip/test_apps/main/CMakeLists.txt b/components/lwip/test_apps/main/CMakeLists.txt new file mode 100644 index 000000000..d9527a3cf --- /dev/null +++ b/components/lwip/test_apps/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "lwip_test.c" + REQUIRES test_utils + INCLUDE_DIRS "." + PRIV_REQUIRES unity lwip test_utils) diff --git a/components/lwip/test_apps/main/lwip_test.c b/components/lwip/test_apps/main/lwip_test.c new file mode 100644 index 000000000..3ada89a99 --- /dev/null +++ b/components/lwip/test_apps/main/lwip_test.c @@ -0,0 +1,334 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "test_utils.h" +#include "unity.h" +#include "unity_fixture.h" + +#include "soc/soc_caps.h" + +#include "lwip/inet.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "lwip/tcpip.h" +#include "lwip/prot/iana.h" +#include "ping/ping_sock.h" +#include "dhcpserver/dhcpserver.h" +#include "dhcpserver/dhcpserver_options.h" +#include "esp_sntp.h" + +#define ETH_PING_END_BIT BIT(1) +#define ETH_PING_DURATION_MS (5000) +#define ETH_PING_END_TIMEOUT_MS (ETH_PING_DURATION_MS * 2) +#define TEST_ICMP_DESTINATION_DOMAIN_NAME "127.0.0.1" + + +TEST_GROUP(lwip); + +TEST_SETUP(lwip) +{ +} + +TEST_TEAR_DOWN(lwip) +{ +} + +static void test_on_ping_success(esp_ping_handle_t hdl, void *args) +{ + uint8_t ttl; + uint16_t seqno; + uint32_t elapsed_time, recv_len; + ip_addr_t target_addr; + esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl)); + esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr)); + esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len)); + esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time)); + printf("%" PRId32 "bytes from %s icmp_seq=%d ttl=%d time=%" PRId32 " ms\n", + recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time); +} + +static void test_on_ping_timeout(esp_ping_handle_t hdl, void *args) +{ + uint16_t seqno; + ip_addr_t target_addr; + esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno)); + esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr)); + printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno); +} + +static void test_on_ping_end(esp_ping_handle_t hdl, void *args) +{ + EventGroupHandle_t eth_event_group = (EventGroupHandle_t)args; + uint32_t transmitted; + uint32_t received; + uint32_t total_time_ms; + + esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted)); + esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received)); + esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); + printf("%" PRId32 " packets transmitted, %" PRId32 " received, time %" PRId32 "ms\n", transmitted, received, total_time_ms); + if (transmitted == received) { + xEventGroupSetBits(eth_event_group, ETH_PING_END_BIT); + } +} + +TEST(lwip, localhost_ping_test) +{ + EventBits_t bits; + EventGroupHandle_t eth_event_group = xEventGroupCreate(); + TEST_ASSERT(eth_event_group != NULL); + test_case_uses_tcpip(); + + // Parse IP address: Destination is a localhost address, so we don't need any interface (esp-netif/driver) + ip_addr_t target_addr; + struct addrinfo hint; + struct addrinfo *res = NULL; + memset(&hint, 0, sizeof(hint)); + memset(&target_addr, 0, sizeof(target_addr)); + /* convert URL to IP */ + TEST_ASSERT(getaddrinfo(TEST_ICMP_DESTINATION_DOMAIN_NAME, NULL, &hint, &res) == 0); + struct in_addr addr4 = ((struct sockaddr_in *)(res->ai_addr))->sin_addr; + inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4); + freeaddrinfo(res); + + esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); + ping_config.timeout_ms = 2000; + ping_config.target_addr = target_addr; + ping_config.count = 0; // ping in infinite mode + /* set callback functions */ + esp_ping_callbacks_t cbs; + cbs.on_ping_success = test_on_ping_success; + cbs.on_ping_timeout = test_on_ping_timeout; + cbs.on_ping_end = test_on_ping_end; + cbs.cb_args = eth_event_group; + + esp_ping_handle_t ping; + TEST_ESP_OK(esp_ping_new_session(&ping_config, &cbs, &ping)); + /* start ping */ + TEST_ESP_OK(esp_ping_start(ping)); + /* ping for a while */ + vTaskDelay(pdMS_TO_TICKS(ETH_PING_DURATION_MS)); + /* stop ping */ + TEST_ESP_OK(esp_ping_stop(ping)); + /* wait for end of ping */ + bits = xEventGroupWaitBits(eth_event_group, ETH_PING_END_BIT, true, true, pdMS_TO_TICKS(ETH_PING_END_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_PING_END_BIT) == ETH_PING_END_BIT); + /* restart ping */ + TEST_ESP_OK(esp_ping_start(ping)); + vTaskDelay(pdMS_TO_TICKS(ETH_PING_DURATION_MS)); + TEST_ESP_OK(esp_ping_stop(ping)); + bits = xEventGroupWaitBits(eth_event_group, ETH_PING_END_BIT, true, true, pdMS_TO_TICKS(ETH_PING_END_TIMEOUT_MS)); + TEST_ASSERT((bits & ETH_PING_END_BIT) == ETH_PING_END_BIT); + /* de-initialize ping process */ + TEST_ESP_OK(esp_ping_delete_session(ping)); + + vEventGroupDelete(eth_event_group); +} + +TEST(lwip, dhcp_server_init_deinit) +{ + dhcps_t *dhcps = dhcps_new(); + TEST_ASSERT_NOT_NULL(dhcps); + ip4_addr_t ip = { .addr = IPADDR_ANY }; + TEST_ASSERT(dhcps_start(dhcps, NULL, ip) == ERR_ARG); + TEST_ASSERT(dhcps_stop(dhcps, NULL) == ERR_ARG); + dhcps_delete(dhcps); +} + +struct dhcps_api { + EventGroupHandle_t event; + ip4_addr_t netmask; + ip4_addr_t ip; + err_t ret_start; + err_t ret_stop; +}; + +static void dhcps_test_net_classes_api(void* ctx) +{ + struct netif *netif; + struct dhcps_api *api = ctx; + + NETIF_FOREACH(netif) { + if (netif->name[0] == 'l' && netif->name[1] == 'o') { + break; + } + } + TEST_ASSERT_NOT_NULL(netif); + + dhcps_t *dhcps = dhcps_new(); + dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&api->netmask, sizeof(api->netmask)); + api->ret_start = dhcps_start(dhcps, netif, api->ip); + api->ret_stop = dhcps_stop(dhcps, netif); + dhcps_delete(dhcps); + xEventGroupSetBits(api->event, 1); +} + +static void dhcps_test_net_classes(uint32_t ip, uint32_t mask, bool pass) +{ + + struct dhcps_api api = { + .ret_start = ERR_IF, + .ret_stop = ERR_IF, + .ip = {.addr = PP_HTONL(ip)}, + .netmask = {.addr = PP_HTONL(mask)}, + .event = xEventGroupCreate() + }; + + tcpip_callback(dhcps_test_net_classes_api, &api); + xEventGroupWaitBits(api.event, 1, true, true, pdMS_TO_TICKS(5000)); + vEventGroupDelete(api.event); + err_t ret_start_expected = pass ? ERR_OK : ERR_ARG; + TEST_ASSERT(api.ret_start == ret_start_expected); + TEST_ASSERT(api.ret_stop == ERR_OK); + +} + +TEST(lwip, dhcp_server_start_stop_localhost) +{ + test_case_uses_tcpip(); + + // Class A: IP: 127.0.0.1, Mask: 255.0.0.0 + dhcps_test_net_classes(0x7f000001, 0xFF000000, true); + + // Class B: IP: 128.1.1.1, Mask: 255.255.0.0 + dhcps_test_net_classes(0x80010101, 0xFFFF0000, true); + + // Class C: IP: 192.168.1.1, Mask: 255.255.255.0 + dhcps_test_net_classes(0xC0A80101, 0xFFFFFF00, true); + + // Class C: IP: 192.168.4.1, Mask: 255.255.0.0 + dhcps_test_net_classes(0xC0A80401, 0xFFFF0000, true); + + // Class C: IP: 192.168.4.1, Mask: 255.0.0.0 + dhcps_test_net_classes(0xC0A80401, 0xFF000000, true); + + // Class A: IP: 127.0.0.1, with inaccurate Mask: 255.248.255.0 + // expect dhcps_start() to fail + dhcps_test_net_classes(0x7f000001, 0xFFF8FF00, false); + + // Class C: IP: 192.168.200.8, with inaccurate Mask: 255.255.255.248 + // expect dhcps_start() to fail + dhcps_test_net_classes(0xC0A8C808, 0xFFFFFFF8, false); +} + + +int test_sntp_server_create(void) +{ + struct sockaddr_in dest_addr_ip4; + int sock = -1; + dest_addr_ip4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + dest_addr_ip4.sin_family = AF_INET; + dest_addr_ip4.sin_port = htons(LWIP_IANA_PORT_SNTP); + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + TEST_ASSERT_GREATER_OR_EQUAL(0, sock); + int reuse_en = 1; + TEST_ASSERT_GREATER_OR_EQUAL(0, setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_en, sizeof(reuse_en))); + TEST_ASSERT_GREATER_OR_EQUAL(0, bind(sock, (struct sockaddr*) &dest_addr_ip4, sizeof(dest_addr_ip4))); + return sock; +} + +bool test_sntp_server_reply_with_time(int sock, int year, bool msb_flag) +{ + struct sntp_timestamp { + uint32_t seconds; + uint32_t fraction; + }; + const int SNTP_MSG_LEN = 48; + const int SNTP_MODE_CLIENT = 0x03; + const int SNTP_MODE_SERVER = 0x04; + const int SNTP_MODE_MASK = 0x07; + const int SNTP_OFFSET_STRATUM = 1; + + char rx_buffer[SNTP_MSG_LEN]; + struct sockaddr_storage source_addr; + socklen_t socklen = sizeof(source_addr); + + int len = recvfrom(sock, rx_buffer, SNTP_MSG_LEN, 0, (struct sockaddr *)&source_addr, &socklen); + if (len == SNTP_MSG_LEN && source_addr.ss_family == PF_INET && (SNTP_MODE_MASK & rx_buffer[0]) == SNTP_MODE_CLIENT) { + // modify the client's request to act as a server's response with the injected *xmit* timestamp + rx_buffer[0] &= ~SNTP_MODE_CLIENT; + rx_buffer[0] |= SNTP_MODE_SERVER; + rx_buffer[SNTP_OFFSET_STRATUM] = 0x1; + // set the desired timestamp + struct sntp_timestamp *timestamp = (struct sntp_timestamp *)(rx_buffer + SNTP_MSG_LEN - sizeof(struct sntp_timestamp)); // xmit is the last timestamp in the datagram + int64_t seconds_since_1900 = (365*24*60*60 /* seconds per year */ + 24*60*60/4 /* ~ seconds per leap year */ )*(year-1900); + // apply the MSB convention (set: 1968-2036, cleared: 2036-2104) + timestamp->seconds = htonl( (msb_flag ? 0x80000000 : 0) | (0xFFFFFFFF & seconds_since_1900) ); + len = sendto(sock, rx_buffer, SNTP_MSG_LEN, 0, (struct sockaddr *)&source_addr, sizeof(source_addr)); + if (len == SNTP_MSG_LEN) { + return true; + } + } + return false; +} + +void test_sntp_timestamps(int year, bool msb_flag) +{ + int sock = test_sntp_server_create(); + + // init and start the SNTP + esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "127.0.0.1"); + esp_sntp_init(); + // wait until time sync + int retry = 0; + while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) { + TEST_ASSERT_TRUE(test_sntp_server_reply_with_time(sock, year, msb_flag)); // post the SNTP server's reply + retry++; + TEST_ASSERT_LESS_THAN(3, retry); + } + + // check time and assert the year + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + TEST_ASSERT_EQUAL(year, 1900 + timeinfo.tm_year); + + // Check that the server 0 was reachable + TEST_ASSERT_EQUAL(1, esp_sntp_getreachability(0)); + // close the SNTP and the fake server + esp_sntp_stop(); + + // Test some other SNTP APIs + TEST_ASSERT_EQUAL(0, esp_sntp_getreachability(0)); + TEST_ASSERT_EQUAL(ESP_SNTP_OPMODE_POLL, esp_sntp_getoperatingmode()); + const ip_addr_t *server_ip = esp_sntp_getserver(0); + TEST_ASSERT_EQUAL(PP_HTONL(IPADDR_LOOPBACK), server_ip->u_addr.ip4.addr); + close(sock); +} + +TEST(lwip, sntp_client_time_2015) +{ + test_case_uses_tcpip(); + test_sntp_timestamps(2015, true); // NTP timestamp MSB is set for time before 2036 +} + +TEST(lwip, sntp_client_time_2048) +{ + test_case_uses_tcpip(); + test_sntp_timestamps(2048, false); // NTP timestamp MSB is cleared for time after 2036 +} + +TEST_GROUP_RUNNER(lwip) +{ + RUN_TEST_CASE(lwip, localhost_ping_test) + RUN_TEST_CASE(lwip, dhcp_server_init_deinit) + RUN_TEST_CASE(lwip, dhcp_server_start_stop_localhost) + RUN_TEST_CASE(lwip, sntp_client_time_2015) + RUN_TEST_CASE(lwip, sntp_client_time_2048) +} + +void app_main(void) +{ + UNITY_MAIN(lwip); +} diff --git a/components/lwip/test_apps/pytest_lwip.py b/components/lwip/test_apps/pytest_lwip.py new file mode 100644 index 000000000..3640dce3f --- /dev/null +++ b/components/lwip/test_apps/pytest_lwip.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.generic +def test_lwip(dut: Dut) -> None: + dut.expect_unity_test_output() diff --git a/components/lwip/test_apps/sdkconfig.ci.lwip_debug b/components/lwip/test_apps/sdkconfig.ci.lwip_debug new file mode 100644 index 000000000..40fa677f3 --- /dev/null +++ b/components/lwip/test_apps/sdkconfig.ci.lwip_debug @@ -0,0 +1,25 @@ +# Included for build test with LWIP debug enabled. + +CONFIG_LWIP_IP_FORWARD=y +CONFIG_LWIP_IPV4_NAPT=y +CONFIG_LWIP_DEBUG=y +CONFIG_LWIP_DEBUG_ESP_LOG=y +CONFIG_LWIP_NETIF_DEBUG=y +CONFIG_LWIP_PBUF_DEBUG=y +CONFIG_LWIP_ETHARP_DEBUG=y +CONFIG_LWIP_API_LIB_DEBUG=y +CONFIG_LWIP_SOCKETS_DEBUG=y +CONFIG_LWIP_IP_DEBUG=y +CONFIG_LWIP_ICMP_DEBUG=y +CONFIG_LWIP_DHCP_STATE_DEBUG=y +CONFIG_LWIP_DHCP_DEBUG=y +CONFIG_LWIP_IP6_DEBUG=y +CONFIG_LWIP_ICMP6_DEBUG=y +CONFIG_LWIP_TCP_DEBUG=y +CONFIG_LWIP_UDP_DEBUG=y +CONFIG_LWIP_SNTP_DEBUG=y +CONFIG_LWIP_DNS_DEBUG=y +CONFIG_LWIP_NAPT_DEBUG=y +CONFIG_LWIP_BRIDGEIF_DEBUG=y +CONFIG_LWIP_BRIDGEIF_FDB_DEBUG=y +CONFIG_LWIP_BRIDGEIF_FW_DEBUG=y diff --git a/components/lwip/test_apps/sdkconfig.defaults b/components/lwip/test_apps/sdkconfig.defaults new file mode 100644 index 000000000..9b9de5f06 --- /dev/null +++ b/components/lwip/test_apps/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_UNITY_ENABLE_FIXTURE=y +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/configs/builds.json b/configs/builds.json index e34813cfa..ddfb8e4f8 100644 --- a/configs/builds.json +++ b/configs/builds.json @@ -4,7 +4,7 @@ "file":"libspi_flash.a", "src":"build/esp-idf/spi_flash/libspi_flash.a", "out":"lib/libspi_flash.a", - "targets":["esp32","esp32c2","esp32c3","esp32s2","esp32s3","esp32c6","esp32h2"] + "targets":["esp32","esp32c2","esp32c3","esp32s2","esp32s3","esp32c6","esp32h2","esp32p4"] }, { "file":"libesp_psram.a", @@ -44,6 +44,20 @@ } ], "targets":[ + { + "target": "esp32p4", + "features":["qio_ram"], + "idf_libs":["qio","80m"], + "bootloaders":[ + ["qio","80m"], + ["dio","80m"], + ["qio","40m"], + ["dio","40m"] + ], + "mem_variants":[ + ["dio","80m"] + ] + }, { "target": "esp32c2", "skip": 1, @@ -143,8 +157,7 @@ ["qio","80m","opi_ram"], ["dio","80m","qio_ram"], ["dio","80m","opi_ram"], - ["opi","80m","opi_ram"], - ["opi","80m","qio_ram"] + ["opi","80m","opi_ram"] ] } ] diff --git a/configs/defconfig.common b/configs/defconfig.common index 47310528c..95be49f7f 100644 --- a/configs/defconfig.common +++ b/configs/defconfig.common @@ -1,3 +1,18 @@ +# CONFIG_LWIP_DEBUG=y +# CONFIG_LWIP_DEBUG_ESP_LOG is not set +# CONFIG_LWIP_TCP_DEBUG=y +# CONFIG_MBEDTLS_DEBUG=y +CONFIG_LWIP_TCPIP_CORE_LOCKING=y +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=8192 +# CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN is not set (default 4096) +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=8192 +CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH=y +CONFIG_MBEDTLS_HAVE_TIME=y +CONFIG_IDF_EXPERIMENTAL_FEATURES + +CONFIG_LWIP_LOCAL_HOSTNAME="tasmota" + CONFIG_AUTOSTART_ARDUINO=y # CONFIG_WS2812_LED_ENABLE is not set CONFIG_ARDUHAL_ESP_LOG=y @@ -44,6 +59,10 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y # CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION is not set CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y +CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y +CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y CONFIG_HEAP_POISONING_LIGHT=y CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_WS_SUPPORT=y @@ -85,8 +104,8 @@ CONFIG_MBEDTLS_ECJPAKE_C=y CONFIG_MBEDTLS_HKDF_C=y CONFIG_MBEDTLS_CAMELLIA_C=y CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER=y -# CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN is not set CONFIG_MBEDTLS_SSL_PROTO_DTLS=y +CONFIG_MBEDTLS_CMAC_C=y CONFIG_OPENSSL_ASSERT_DO_NOTHING=y CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=2048 CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y diff --git a/configs/defconfig.esp32c6 b/configs/defconfig.esp32c6 index c39022997..07621cf07 100644 --- a/configs/defconfig.esp32c6 +++ b/configs/defconfig.esp32c6 @@ -35,6 +35,9 @@ CONFIG_OPENTHREAD_NETWORK_MASTERKEY="00112233445566778899aabbccddeeff" CONFIG_OPENTHREAD_NETWORK_PSKC="104810e2315100afd6bc9215a6bfac53" # end of OpenThread +# Matter shall use only WiFi +CONFIG_ENABLE_MATTER_OVER_THREAD=n + # # Zigbee # diff --git a/configs/defconfig.esp32p4 b/configs/defconfig.esp32p4 new file mode 100644 index 000000000..eaa692910 --- /dev/null +++ b/configs/defconfig.esp32p4 @@ -0,0 +1,15 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_SPEED_200M=y +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set +CONFIG_LWIP_TCP_SACK_OUT=y + +CONFIG_SLAVE_IDF_TARGET_ESP32C6=y +CONFIG_ESP_SDIO_BUS_WIDTH=4 +CONFIG_ESP_SDIO_CLOCK_FREQ_KHZ=40000 +CONFIG_ESP_SDIO_PIN_CMD=19 +CONFIG_ESP_SDIO_PIN_CLK=18 +CONFIG_ESP_SDIO_PIN_D0=14 +CONFIG_ESP_SDIO_PIN_D1=15 +CONFIG_ESP_SDIO_PIN_D2=16 +CONFIG_ESP_SDIO_PIN_D3=17 diff --git a/main/idf_component.yml b/main/idf_component.yml index 714b3f0d6..c6bb97f46 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,6 +1,6 @@ dependencies: # Required IDF version - idf: ">=5.1" + idf: ">=5.3" espressif/esp32-camera: version: "master" git: https://github.com/espressif/esp32-camera.git @@ -12,12 +12,6 @@ dependencies: require: public rules: - if: "target not in [esp32c2]" - # espressif/esp-dl: - # version: "af7808ba09448ce82c704455975d4cf1e4305fd7" - # git: https://github.com/espressif/esp-dl.git - # require: public - # rules: - # - if: "target in [esp32s3, esp32s2, esp32]" espressif/esp-sr: version: ">=1.4.2" rules: @@ -26,45 +20,4 @@ dependencies: version: "^1.3.0" require: public rules: - - if: "target not in [esp32c2, esp32h2]" - - # esp-sr: "^1.3.1" - # esp32-camera: "^2.0.4" - # esp-dl: - # git: https://github.com/espressif/esp-dl.git - # espressif/esp_rainmaker: - # path: components/esp_rainmaker - # git: https://github.com/espressif/esp-rainmaker.git - - # # Defining a dependency from the registry: - # # https://components.espressif.com/component/example/cmp - # example/cmp: "^3.3.3" # Automatically update minor releases - # - # # Other ways to define dependencies - # - # # For components maintained by Espressif only name can be used. - # # Same as `espressif/cmp` - # component: "~1.0.0" # Automatically update bugfix releases - # - # # Or in a longer form with extra parameters - # component2: - # version: ">=2.0.0" - # - # # For transient dependencies `public` flag can be set. - # # `public` flag doesn't have an effect for the `main` component. - # # All dependencies of `main` are public by default. - # public: true - # - # # For components hosted on non-default registry: - # service_url: "https://componentregistry.company.com/" - # - # # For components in git repository: - # test_component: - # path: test_component - # git: ssh://git@gitlab.com/user/components.git - # - # # For test projects during component development - # # components can be used from a local directory - # # with relative or absolute path - # some_local_component: - # path: ../../projects/component + - if: "target not in [esp32c2, esp32h2, esp32p4]" diff --git a/patches/esp32c6_provisioning_bluedroid.diff b/patches/esp32c6_provisioning_bluedroid.diff deleted file mode 100644 index 98371b8aa..000000000 --- a/patches/esp32c6_provisioning_bluedroid.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c -index 8a4ae0f3d9..cd6421c6e5 100644 ---- a/components/protocomm/src/simple_ble/simple_ble.c -+++ b/components/protocomm/src/simple_ble/simple_ble.c -@@ -225,7 +225,7 @@ esp_err_t simple_ble_start(simple_ble_cfg_t *cfg) - #ifdef CONFIG_BTDM_CTRL_MODE_BTDM - ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); --#elif defined CONFIG_BTDM_CTRL_MODE_BLE_ONLY || CONFIG_BT_CTRL_MODE_EFF -+#elif defined CONFIG_BTDM_CTRL_MODE_BLE_ONLY || CONFIG_BT_CTRL_MODE_EFF || CONFIG_IDF_TARGET_ESP32C6 - ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); - #else - ESP_LOGE(TAG, "Configuration mismatch. Select BLE Only or BTDM mode from menuconfig"); diff --git a/patches/mmu_map.diff b/patches/mmu_map.diff deleted file mode 100644 index 3bf56005a..000000000 --- a/patches/mmu_map.diff +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c -index b7d927f8fe..6a8c4635f0 100644 ---- a/components/esp_mm/esp_mmu_map.c -+++ b/components/esp_mm/esp_mmu_map.c -@@ -315,6 +315,19 @@ esp_err_t esp_mmu_map_reserve_block_with_caps(size_t size, mmu_mem_caps_t caps, - s_mmu_ctx.mem_regions[found_region_id].max_slot_size -= aligned_size; - ESP_EARLY_LOGV(TAG, "found laddr is 0x%x", laddr); - -+ mem_block_t *mem_block = NULL; -+ mem_region_t *region = &s_mmu_ctx.mem_regions[found_region_id]; -+ TAILQ_FOREACH(mem_block, ®ion->mem_block_head, entries) { -+ if (mem_block == TAILQ_FIRST(®ion->mem_block_head) || mem_block == TAILQ_LAST(®ion->mem_block_head, mem_block_head_)) { -+ TAILQ_REMOVE(®ion->mem_block_head, mem_block, entries); -+ } else { -+ // probably the reservation of MMU region should be disallowed for this case - already some MMU mappings exist? -+ // assert/abort -+ ESP_EARLY_LOGE(TAG, "already some MMU mappings exist?"); -+ abort(); -+ } -+ } -+ - uint32_t vaddr = 0; - if (caps & MMU_MEM_CAP_EXEC) { - vaddr = mmu_ll_laddr_to_vaddr(laddr, MMU_VADDR_INSTRUCTION); diff --git a/tools/add_sdk_json.py b/tools/add_sdk_json.py index d2deb4a87..7b12289bb 100644 --- a/tools/add_sdk_json.py +++ b/tools/add_sdk_json.py @@ -66,7 +66,7 @@ def add_system(systems, host, url, filename, sha, size): dep_skip = False for dep in farray['packages'][0]['platforms'][0]['toolsDependencies']: if dep['name'] == tool_name: - if dep['version'] == tool_version: + if dep['version'] == tool_version and not tool_name.startswith('esp32-arduino-libs'): print('Skipping {0}. Same version {1}'.format(tool_name, tool_version)) dep_skip = True break diff --git a/tools/archive-build.sh b/tools/archive-build.sh index f973a42ef..f0776804a 100755 --- a/tools/archive-build.sh +++ b/tools/archive-build.sh @@ -1,12 +1,70 @@ #!/bin/bash -IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD || echo "") -IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD || echo "") idf_version_string=${IDF_BRANCH//\//_}"-$IDF_COMMIT" -archive_path="dist/arduino-esp32-libs-$1-$idf_version_string.tar.gz" +archive_path="dist/arduino-esp32-libs-$TARGET-$idf_version_string.tar.gz" +build_archive_path="dist/arduino-esp32-build-$TARGET-$idf_version_string.tar.gz" +pio_archive_path="dist/framework-arduinoespressif32-$TARGET-$idf_version_string.tar.gz" +pio_zip_archive_path="dist/framework-arduinoespressif32-$TARGET-$idf_version_string.zip" +libs_archive_path="dist/framework-arduinoespressif32-libs-$TARGET-$idf_version_string" +libs_zip_archive_path="$libs_archive_path.zip" +libs_tar_archive_path="$libs_archive_path.tar.gz" -mkdir -p dist && rm -rf "$archive_path" -if [ -d "out" ]; then - cd out && tar zcf "../$archive_path" * && cd .. -fi +mkdir -p dist && rm -rf "$archive_path" "$build_archive_path" + +cd out +echo "Creating PlatformIO Tasmota framework-arduinoespressif32" +mkdir -p arduino-esp32/cores/esp32 +mkdir -p arduino-esp32/tools/partitions +cp -rf ../components/arduino/tools arduino-esp32 +cp -rf ../components/arduino/cores arduino-esp32 +cp -rf ../components/arduino/libraries arduino-esp32 +cp -rf ../components/arduino/variants arduino-esp32 +cp -f ../components/arduino/CMa* arduino-esp32 +cp -f ../components/arduino/idf* arduino-esp32 +cp -f ../components/arduino/Kco* arduino-esp32 +cp -f ../components/arduino/pac* arduino-esp32 +# rm -rf arduino-esp32/docs +# rm -rf arduino-esp32/tests +# rm -rf arduino-esp32/idf_component_examples +# rm -rf arduino-esp32/libraries/RainMaker +# rm -rf arduino-esp32/libraries/Insights +# rm -rf arduino-esp32/libraries/ESP_I2S +# rm -rf arduino-esp32/libraries/SPIFFS +# rm -rf arduino-esp32/libraries/BLE +# rm -rf arduino-esp32/libraries/SimpleBLE +# rm -rf arduino-esp32/libraries/BluetoothSerial +# rm -rf arduino-esp32/libraries/WiFiProv +# rm -rf arduino-esp32/libraries/WiFiClientSecure +# rm -rf arduino-esp32/libraries/NetworkClientSecure +# rm -rf arduino-esp32/libraries/ESP_SR +# rm -rf arduino-esp32/libraries/ESP_NOW +# rm -rf arduino-esp32/libraries/TFLiteMicro +# rm -rf arduino-esp32/libraries/ESP32 +rm -rf arduino-esp32/package +rm -rf arduino-esp32/tools/esp32-arduino-libs +rm -rf arduino-esp32/tools/*.exe +rm -rf arduino-esp32/tools/esptool.py +rm -rf arduino-esp32/tools/get.py +rm -rf arduino-esp32/tools/ide-debug +rm -rf arduino-esp32/tools/gen_insights_package.py +rm -rf arduino-esp32/platform.txt +rm -rf arduino-esp32/programmers.txt +rm -rf arduino-esp32/boards.txt +rm -rf arduino-esp32/package.json +rm -rf arduino-esp32/*.md +cp -Rf tools/esp32-arduino-libs arduino-esp32/tools/ +cp ../package.json arduino-esp32/package.json +cp ../core_version.h arduino-esp32/cores/esp32/core_version.h +mv arduino-esp32/ framework-arduinoespressif32/ +cd framework-arduinoespressif32/libraries +rm -rf **/examples +cd ../tools/esp32-arduino-libs +#rm -rf **/flags +cd ../../../ +# If the framework is needed as tar.gz uncomment next line +# tar --exclude=.* -zcf ../$pio_archive_path framework-arduinoespressif32/ +mv framework-arduinoespressif32/tools/esp32-arduino-libs framework-arduinoespressif32-libs + +7z a -mx=9 -tzip -xr'!.*' ../$pio_zip_archive_path framework-arduinoespressif32/ +7z a -mx=9 -tzip -xr'!.*' ../$libs_zip_archive_path framework-arduinoespressif32-libs/ diff --git a/tools/config.sh b/tools/config.sh index 2988a1517..53c31f888 100755 --- a/tools/config.sh +++ b/tools/config.sh @@ -6,11 +6,12 @@ if [ -z $IDF_PATH ]; then fi if [ -z $IDF_BRANCH ]; then - IDF_BRANCH="release/v5.1" + export IDF_BRANCH="release/v5.3" fi +# Arduino branch to use if [ -z $AR_PR_TARGET_BRANCH ]; then - AR_PR_TARGET_BRANCH="master" + AR_PR_TARGET_BRANCH="release/v3.1.x" fi if [ -z $IDF_TARGET ]; then @@ -27,6 +28,12 @@ fi # Owner of the target ESP32 Arduino repository AR_USER="espressif" +# IDF commit to use +#IDF_COMMIT="" + +# Arduino commit to use +#AR_COMMIT="" + # The full name of the repository AR_REPO="$AR_USER/arduino-esp32" IDF_REPO="$AR_USER/esp-idf" @@ -52,9 +59,21 @@ AR_SDK="$AR_TOOLS/esp32-arduino-libs/$IDF_TARGET" PIO_SDK="FRAMEWORK_SDK_DIR, \"$IDF_TARGET\"" TOOLS_JSON_OUT="$AR_TOOLS/esp32-arduino-libs" +if [ "$IDF_COMMIT" ]; then + export IDF_COMMIT +fi + if [ -d "$IDF_PATH" ]; then export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) - export IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) +fi + +echo "Using IDF branch $IDF_BRANCH" +echo "Using IDF commit $IDF_COMMIT" + +if [ "$AR_COMMIT" ]; then + echo "Using Arduino commit $AR_COMMIT" +else + export AR_COMMIT=$(git -C "$AR_COMPS/arduino" rev-parse --short HEAD || echo "") fi function get_os(){ @@ -84,6 +103,7 @@ function get_os(){ AR_OS=`get_os` export SED="sed" +export AWK="awk" export SSTAT="stat -c %s" if [[ "$AR_OS" == "macos" ]]; then @@ -96,6 +116,7 @@ if [[ "$AR_OS" == "macos" ]]; then exit 1 fi export SED="gsed" + export AWK="gawk" export SSTAT="stat -f %z" fi diff --git a/tools/docker/README.md b/tools/docker/README.md index 109665c4a..d6a213129 100644 --- a/tools/docker/README.md +++ b/tools/docker/README.md @@ -24,7 +24,7 @@ Multiple tags of this image are maintained: ## Basic Usage ```bash -docker run --rm -it -e "TERM=xterm-256color" -v :/arduino-esp32 espressif/esp32-arduino-lib-builder:latest +docker run --rm -it -e "TERM=xterm-256color" -v :/arduino-esp32 espressif/esp32-arduino-lib-builder:release-v5.3 ``` The above command explained: @@ -35,18 +35,16 @@ The above command explained: - `-t`: Allocates a pseudo-TTY. - `-e "TERM=xterm-256color"`: Optional. Sets the terminal type to `xterm-256color` to display colors correctly. - `-v :/arduino-esp32`: Optional. Mounts the Arduino Core for ESP32 repository at `/arduino-esp32` inside the container. Replace `` with the path to the repository on the host machine. If not provided, the container will not copy the compiled libraries to the host machine. - - `espressif/esp32-arduino-lib-builder:latest`: The Docker image to use. + - `espressif/esp32-arduino-lib-builder:release-v5.3`: The Docker image to use. After running the above command, you will be inside the container and can build the libraries using the user interface. By default the docker container will run the user interface script. If you want to run a specific command, you can pass it as an argument to the docker run command. For example, to run a terminal inside the container, you can run: ```bash -docker run -it espressif/esp32-arduino-lib-builder:latest /bin/bash +docker run -it espressif/esp32-arduino-lib-builder:release-v5.3 /bin/bash ``` ## Documentation - - -For more information about this image and the detailed usage instructions, please refer to the Arduino Core for ESP32 documentation. +For more information about this image and the detailed usage instructions, please refer to the [Arduino Core for ESP32 documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/lib_builder.html#docker-image). diff --git a/tools/docker/run.ps1 b/tools/docker/run.ps1 index 4c49ac505..5ecb01a64 100644 --- a/tools/docker/run.ps1 +++ b/tools/docker/run.ps1 @@ -1,5 +1,8 @@ # This is an example of how to run the docker container. # This script is not part of the container, it is meant to be run on the host machine. +# Note that this file will build the release/v5.3 branch. For other branches, change the tag accordingly. +# You can check the available tags at https://hub.docker.com/r/espressif/esp32-arduino-lib-builder/tags +# As this script is unsigned, you may need to run `Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass` before running it. # Usage: .\run.ps1 # Exit on error @@ -58,4 +61,4 @@ if ($env:LIBBUILDER_GIT_SAFE_DIR) { } Write-Output "Running: docker run $($DOCKER_ARGS -join ' ') espressif/esp32-arduino-lib-builder" -docker run @($DOCKER_ARGS) espressif/esp32-arduino-lib-builder +docker run @($DOCKER_ARGS) espressif/esp32-arduino-lib-builder:release-v5.3 diff --git a/tools/docker/run.sh b/tools/docker/run.sh index 59e967363..c7f97a6f5 100755 --- a/tools/docker/run.sh +++ b/tools/docker/run.sh @@ -2,6 +2,8 @@ # This is an example of how to run the docker container. # This script is not part of the container, it is meant to be run on the host machine. +# Note that this file will build the release/v5.3 branch. For other branches, change the tag accordingly. +# You can check the available tags at https://hub.docker.com/r/espressif/esp32-arduino-lib-builder/tags # Usage: ./run.sh if ! [ -x "$(command -v docker)" ]; then @@ -31,4 +33,4 @@ if [ -n "$LIBBUILDER_GIT_SAFE_DIR" ]; then fi echo "Running: docker run ${DOCKER_ARGS[@]} espressif/esp32-arduino-lib-builder" -docker run ${DOCKER_ARGS[@]} espressif/esp32-arduino-lib-builder +docker run ${DOCKER_ARGS[@]} espressif/esp32-arduino-lib-builder:release-v5.3 diff --git a/tools/gen_pio_frmwk_manifest.py b/tools/gen_pio_frmwk_manifest.py new file mode 100644 index 000000000..b1aa19923 --- /dev/null +++ b/tools/gen_pio_frmwk_manifest.py @@ -0,0 +1,89 @@ +import argparse +import json +import os +import re +import sys +import datetime + +MANIFEST_DATA = { + "name": "framework-arduinoespressif32-libs", + "description": "Precompiled libraries for Arduino Wiring-based Framework for the Espressif ESP32 series of SoCs", + "keywords": ["framework", "arduino", "espressif", "esp32"], + "license": "LGPL-2.1-or-later", + "repository": { + "type": "git", + "url": "https://github.com/hamzahajeir/esp32-arduino-lib-builder", + }, +} + + +def convert_version(version_string): + """A helper function that converts a custom IDF version string + extracted from a Git repository to a suitable SemVer alternative. For example: + 'release/v5.1' becomes '5.1.0', + 'v7.7.7' becomes '7.7.7' + """ + + regex_pattern = ( + r"v(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.*(?P0|[1-9]\d*)*" + ) + match = re.search(regex_pattern, version_string) + if not match: + sys.stderr.write( + f"Failed to find a regex match for '{regex_pattern}' in '{version_string}'\n" + ) + return "" + + major, minor, patch = match.groups() + if not patch: + patch = "0" + + return ".".join((major, minor, patch)) + + +def main(dst_dir, version_string, commit_hash): + + converted_version = convert_version(version_string) + if not converted_version: + sys.stderr.write(f"Failed to convert version '{version_string}'\n") + return -1 + + manifest_file_path = os.path.join(dst_dir, "package.json") + build_date = datetime.date.today() + with open(manifest_file_path, "w", encoding="utf8") as fp: + MANIFEST_DATA["version"] = f"{converted_version}+sha.{commit_hash}" + MANIFEST_DATA["date"] = f"{build_date}" + json.dump(MANIFEST_DATA, fp, indent=2) + + print( + f"Generated PlatformIO framework manifest file '{manifest_file_path}' with '{converted_version}' version" + ) + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-o", + "--dst-dir", + dest="dst_dir", + required=True, + help="Destination folder where the 'package.json' manifest will be located", + ) + parser.add_argument( + "-s", + "--version-string", + dest="version_string", + required=True, + help="ESP-IDF version string used for compiling libraries", + ) + parser.add_argument( + "-c", + "--commit-hash", + dest="commit_hash", + required=True, + help="ESP-IDF revision in form of a commit hash", + ) + args = parser.parse_args() + + sys.exit(main(args.dst_dir, args.version_string, args.commit_hash)) diff --git a/tools/gen_pio_lib_manifest.py b/tools/gen_pio_lib_manifest.py new file mode 100644 index 000000000..389e79775 --- /dev/null +++ b/tools/gen_pio_lib_manifest.py @@ -0,0 +1,86 @@ +import argparse +import json +import os +import re +import sys + +MANIFEST_DATA = { + "name": "framework-arduinoespressif32-libs", + "description": "Precompiled libraries for Arduino Wiring-based Framework for the Espressif ESP32 series of SoCs", + "keywords": ["framework", "arduino", "espressif", "esp32"], + "license": "LGPL-2.1-or-later", + "repository": { + "type": "git", + "url": "https://github.com/hamzahajeir/esp32-arduino-libs", + }, +} + + +def convert_version(version_string): + """A helper function that converts a custom IDF version string + extracted from a Git repository to a suitable SemVer alternative. For example: + 'release/v5.1' becomes '5.1.0', + 'v7.7.7' becomes '7.7.7' + """ + + regex_pattern = ( + r"v(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.*(?P0|[1-9]\d*)*" + ) + match = re.search(regex_pattern, version_string) + if not match: + sys.stderr.write( + f"Failed to find a regex match for '{regex_pattern}' in '{version_string}'\n" + ) + return "" + + major, minor, patch = match.groups() + if not patch: + patch = "0" + + return ".".join((major, minor, patch)) + + +def main(dst_dir, version_string, commit_hash): + + converted_version = convert_version(version_string) + if not converted_version: + sys.stderr.write(f"Failed to convert version '{version_string}'\n") + return -1 + + manifest_file_path = os.path.join(dst_dir, "package.json") + with open(manifest_file_path, "w", encoding="utf8") as fp: + MANIFEST_DATA["version"] = f"{converted_version}+sha.{commit_hash}" + json.dump(MANIFEST_DATA, fp, indent=2) + + print( + f"Generated PlatformIO libraries manifest file '{manifest_file_path}' with '{converted_version}' version" + ) + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-o", + "--dst-dir", + dest="dst_dir", + required=True, + help="Destination folder where the 'package.json' manifest will be located", + ) + parser.add_argument( + "-s", + "--version-string", + dest="version_string", + required=True, + help="ESP-IDF version string used for compiling libraries", + ) + parser.add_argument( + "-c", + "--commit-hash", + dest="commit_hash", + required=True, + help="ESP-IDF revision in form of a commit hash", + ) + args = parser.parse_args() + + sys.exit(main(args.dst_dir, args.version_string, args.commit_hash)) diff --git a/tools/gen_platformio_manifest.py b/tools/gen_platformio_manifest.py index f02218826..b1aa19923 100644 --- a/tools/gen_platformio_manifest.py +++ b/tools/gen_platformio_manifest.py @@ -3,6 +3,7 @@ import os import re import sys +import datetime MANIFEST_DATA = { "name": "framework-arduinoespressif32-libs", @@ -11,7 +12,7 @@ "license": "LGPL-2.1-or-later", "repository": { "type": "git", - "url": "https://github.com/espressif/esp32-arduino-lib-builder", + "url": "https://github.com/hamzahajeir/esp32-arduino-lib-builder", }, } @@ -48,12 +49,14 @@ def main(dst_dir, version_string, commit_hash): return -1 manifest_file_path = os.path.join(dst_dir, "package.json") + build_date = datetime.date.today() with open(manifest_file_path, "w", encoding="utf8") as fp: MANIFEST_DATA["version"] = f"{converted_version}+sha.{commit_hash}" + MANIFEST_DATA["date"] = f"{build_date}" json.dump(MANIFEST_DATA, fp, indent=2) print( - f"Generated PlatformIO manifest file '{manifest_file_path}' with '{converted_version}' version" + f"Generated PlatformIO framework manifest file '{manifest_file_path}' with '{converted_version}' version" ) return 0 diff --git a/tools/gen_tools_json.py b/tools/gen_tools_json.py index f0fc67579..802efa4f2 100644 --- a/tools/gen_tools_json.py +++ b/tools/gen_tools_json.py @@ -35,7 +35,7 @@ def replace_if_xz(system): # let's get the checksum file from the release release_manifest_url = "" # parse the download url to extract all info needed for the checksum file url - urlx = re.findall("^https://github.com/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/releases/download/([a-zA-Z0-9_\-.]+)/([a-zA-Z0-9_\-.]+)$", new_url) + urlx = re.findall("^https://github.com/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)/releases/download/([a-zA-Z0-9_\\-.]+)/([a-zA-Z0-9_\-.]+)$", new_url) if urlx and len(urlx) > 0: (owner, proj, version, filename) = urlx[0] release_manifest_url = "https://github.com/%s/%s/releases/download/%s/%s-%s-checksum.sha256" % (owner, proj, version, proj, version) @@ -59,7 +59,7 @@ def replace_if_xz(system): "files": [] } release_manifest_contents = requests.get(release_manifest_url).text - x = re.findall("\s([a-zA-Z0-9_\-.]+):\s([0-9]+)\s[a-z]+\\n([a-f0-9]+)\s\*.*", release_manifest_contents) + x = re.findall("\s([a-zA-Z0-9_\-.]+):\s([0-9]+)\s[a-z]+\\n([a-f0-9]+)\\s\*.*", release_manifest_contents) if x and len(x) > 0: for line in x: (filename, size, checksum) = line @@ -107,7 +107,7 @@ def replace_if_xz(system): out_path = args.out_path; # settings - arduino_tools = ["xtensa-esp32-elf","xtensa-esp32s2-elf","xtensa-esp32s3-elf","xtensa-esp-elf-gdb","riscv32-esp-elf","riscv32-esp-elf-gdb","openocd-esp32"] + arduino_tools = ["xtensa-esp-elf","xtensa-esp-elf-gdb","riscv32-esp-elf","riscv32-esp-elf-gdb","openocd-esp32"] # code start farray = {"packages":[{"platforms":[{"toolsDependencies":[]}],"tools":[]}]} diff --git a/tools/install-arduino.sh b/tools/install-arduino.sh index 1a0ba4d39..1cc05f9d6 100755 --- a/tools/install-arduino.sh +++ b/tools/install-arduino.sh @@ -5,9 +5,38 @@ source ./tools/config.sh # # CLONE/UPDATE ARDUINO # -echo "Updating ESP32 Arduino..." +if [ "$AR_BRANCH" ]; then + echo "Installing Arduino from branch '$AR_BRANCH'" + if [ ! -d "$AR_COMPS/arduino" ]; then + # for using a branch we need no full clone + git clone -b "$AR_BRANCH" --recursive --depth 1 --shallow-submodule $AR_REPO_URL "$AR_COMPS/arduino" + else + # update existing branch + cd "$AR_COMPS/arduino" + git pull + git reset --hard $AR_BRANCH + # -ff is for cleaning untracked files as well as submodules + git clean -ffdx + cd - + fi +fi + if [ ! -d "$AR_COMPS/arduino" ]; then + # we need a full clone since no branch was set + echo "Full cloning of ESP32 Arduino repo '$AR_REPO_URL'" git clone $AR_REPO_URL "$AR_COMPS/arduino" +else + if [ "$AR_BRANCH" ]; then + echo "ESP32 Arduino is up to date" + else + # update existing branch + echo "Updating ESP32 Arduino" + cd "$AR_COMPS/arduino" + git pull + # -ff is for cleaning untracked files as well as submodules + git clean -ffdx + cd - + fi fi if [ -z $AR_BRANCH ]; then @@ -39,10 +68,28 @@ if [ -z $AR_BRANCH ]; then fi fi -if [ "$AR_BRANCH" ]; then - echo "AR_BRANCH='$AR_BRANCH'" - git -C "$AR_COMPS/arduino" fetch --all && \ - git -C "$AR_COMPS/arduino" checkout "$AR_BRANCH" && \ - git -C "$AR_COMPS/arduino" pull --ff-only -fi if [ $? -ne 0 ]; then exit 1; fi + +# +# remove code and libraries not needed/wanted for Tasmota framework +# +rm -rf "$AR_COMPS/arduino/docs" +rm -rf "$AR_COMPS/arduino/idf_component_examples" +# rm -rf "$AR_COMPS/arduino/package" +rm -rf "$AR_COMPS/arduino/tests" +# rm -rf "$AR_COMPS/arduino/cores/esp32/chip-debug-report.cpp" +# rm -rf "$AR_COMPS/arduino/cores/esp32/chip-debug-report.h" +# rm -rf "$AR_COMPS/arduino/libraries/RainMaker" +# rm -rf "$AR_COMPS/arduino/libraries/Insights" +# rm -rf "$AR_COMPS/arduino/libraries/ESP_I2S" +# rm -rf "$AR_COMPS/arduino/libraries/SPIFFS" +# rm -rf "$AR_COMPS/arduino/libraries/BLE" +# rm -rf "$AR_COMPS/arduino/libraries/SimpleBLE" +# rm -rf "$AR_COMPS/arduino/libraries/BluetoothSerial" +# rm -rf "$AR_COMPS/arduino/libraries/WiFiProv" +# rm -rf "$AR_COMPS/arduino/libraries/WiFiClientSecure" +# rm -rf "$AR_COMPS/arduino/libraries/NetworkClientSecure" +# rm -rf "$AR_COMPS/arduino/libraries/ESP32" +# rm -rf "$AR_COMPS/arduino/libraries/ESP_SR" +# rm -rf "$AR_COMPS/arduino/libraries/ESP_NOW" +# rm -rf "$AR_COMPS/arduino/libraries/TFLiteMicro" \ No newline at end of file diff --git a/tools/install-esp-idf.sh b/tools/install-esp-idf.sh index bd3d07985..5286375ff 100755 --- a/tools/install-esp-idf.sh +++ b/tools/install-esp-idf.sh @@ -10,15 +10,44 @@ fi # # CLONE ESP-IDF # +if [ "$IDF_TAG" ] || [ "$IDF_COMMIT" ]; then + if [ ! -d "$IDF_PATH" ]; then + # full clone needed to check out tag or commit + echo "ESP-IDF is not installed! Installing with full clone from $IDF_REPO_URL branch $IDF_BRANCH" + git clone $IDF_REPO_URL -b $IDF_BRANCH + idf_was_installed="1" + else + # update local clone + echo "ESP-IDF is installed, updating..." + cd $IDF_PATH + git pull + git reset --hard $IDF_BRANCH + git submodule update + # -ff is for cleaning untracked files as well as submodules + git clean -ffdx + cd - + idf_was_installed="1" + fi +fi if [ ! -d "$IDF_PATH" ]; then - echo "ESP-IDF is not installed! Installing local copy" - git clone $IDF_REPO_URL -b $IDF_BRANCH - idf_was_installed="1" + # for using a branch we need no full clone + echo "ESP-IDF is not installed! Installing branch $IDF_BRANCH from $IDF_REPO_URL" + git clone -b $IDF_BRANCH --recursive --depth 1 --shallow-submodule $IDF_REPO_URL + idf_was_installed="1" +else + # update existing branch + echo "ESP-IDF is already installed, updating branch $IDF_BRANCH" + cd $IDF_PATH + git pull + git reset --hard $IDF_BRANCH + git submodule update --depth 1 + # -ff is for cleaning untracked files as well as submodules + git clean -ffdx + cd - + idf_was_installed="1" fi -git -C "$IDF_PATH" fetch --all --tags - if [ "$IDF_TAG" ]; then git -C "$IDF_PATH" checkout "tags/$IDF_TAG" idf_was_installed="1" @@ -34,16 +63,24 @@ fi if [ ! -x $idf_was_installed ] || [ ! -x $commit_predefined ]; then git -C $IDF_PATH submodule update --init --recursive $IDF_PATH/install.sh - export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) - export IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) - # Temporarily patch the ESP32-S2 I2C LL driver to keep the clock source + # 1) Temporarily patch the ESP32-S2 I2C LL driver to keep the clock source + # 2) Temporarily fix for mmu map and late init of psram https://github.com/espressif/arduino-esp32/issues/9936 cd $IDF_PATH patch -p1 -N -i $AR_PATCHES/esp32s2_i2c_ll_master_init.diff - patch -p1 -N -i $AR_PATCHES/mmu_map.diff patch -p1 -N -i $AR_PATCHES/lwip_max_tcp_pcb.diff - patch -p1 -N -i $AR_PATCHES/esp32c6_provisioning_bluedroid.diff cd - + + # Get the exact IDF version from file "version.txt" + cd $IDF_PATH + IDF_VERSION=$(