diff --git a/.github/test-spec.yml b/.github/test-spec.yml new file mode 100644 index 000000000000..7c4d93cd0381 --- /dev/null +++ b/.github/test-spec.yml @@ -0,0 +1,208 @@ +# This is the Jenkins ci variant of the .github/labler.yaml +"CI-iot-zephyr-lwm2m-test": + - "drivers/console/**/*" + - "drivers/flash/**/*" + - "subsys/dfu/boot/**/*" + - "subsys/net/ip/**/*" + - "subsys/net/lib/http/**/*" + - "subsys/net/lib/lwm2m//**/*" + - "subsys/net/**/*" + +"CI-iot-samples-test": + - "boards/arm/nrf9160dk_nrf9160/**/*" + - "dts/arm/nordic/nrf9160*" + - "include/net/**/*" + - "subsys/net/lib/**/*" + +"CI-iot-libraries-test": + - "boards/arm/nrf9160dk_nrf9160/**/*" + - "dts/arm/nordic/nrf9160*" + - "include/net/socket_ncs.h" + - "subsys/testsuite/ztest/**/*" + +"CI-lwm2m-test": +# Not necessary to run tests on changes to this repo. + +"CI-boot-dfu-test": + - "subsys/mgmt/mcumgr/**/*" + - "subsys/dfu/**/*" + - "include/mgmt/mcumgr/**/*" + - "include/dfu/**/*" + - "samples/subsys/mgmt/mcumgr/smp_svr/**/*" + +"CI-tfm-test": + - "boards/arm/nrf5340dk_nrf5340/**/*" + - "boards/arm/nrf9160dk_nrf9160/**/*" + - "drivers/entropy/*" + - "dts/arm/nordic/nrf5340*" + - "dts/arm/nordic/nrf9160*" + - "modules/trusted-firmware-m/**/*" + - "samples/tfm_integration/**/*" + +"CI-ble-test": + - "**/*" + +"CI-mesh-test": + - "subsys/bluetooth/mesh/**/*" + - "include/bluetooth/mesh/**/*" + - "samples/bluetooth/mesh/**/*" + - "samples/bluetooth/mesh_demo/**/*" + - "samples/bluetooth/mesh_provisioner/**/*" + - "tests/bluetooth/mesh/**/*" + - "tests/bluetooth/mesh_shell/**/*" + +"CI-zigbee-test": + - "subsys/mgmt/mcumgr/**/*" + - "subsys/dfu/**/*" + - "include/mgmt/mcumgr/**/*" + - "include/dfu/**/*" + +"CI-thingy91-test": + - "boards/arm/nrf9160dk_nrf9160/**/*" + - "arch/x86/core/**/*" + - "arch/x86/include/**/*" + - "drivers/console/**/*" + - "drivers/ethernet/**/*" + - "drivers/flash/**/*" + - "drivers/hwinfo/**/*" + - "drivers/interrupt_controller/**/*" + - "drivers/net/**/*" + - "drivers/serial/**/*" + - "drivers/timer/**/*" + - "include/**/*" + - "kernel/**/*" + - "lib/libc/common/source/stdlib/**/*" + - "lib/libc/newlib/**/*" + - "lib/libc/picolibc/**/*" + - "lib/os/**/*" + - "lib/posix/**/*" + - "misc/**/*" + - "modules/mbedtls/**/*" + - "soc/x86/ia32/**/*" + - "subsys/fs/fcb/**/*" + - "subsys/logging/**/*" + - "subsys/net/**/*" + - "subsys/random/**/*" + - "subsys/settings/include/**/*" + - "subsys/settings/src/**/*" + - "subsys/stats/**/*" + - "subsys/storage/flash_map/**/*" + - "subsys/storage/stream/**/*" + - "subsys/tracing/**/*" + +"CI-desktop-test": + - "**/*" + +"CI-crypto-test": + - "boards/arm/nrf52840dk_nrf52840/**/*" + - "boards/arm/nrf5340dk_nrf5340/**/*" + - "boards/arm/nrf9160dk_nrf9160/**/*" + - "drivers/entropy/*" + - "drivers/serial/**/*" + - "dts/arm/nordic/nrf52840*" + - "dts/arm/nordic/nrf5340*" + - "dts/arm/nordic/nrf9160*" + - "include/drivers/serial/**/*" + - "modules/mbedtls/**/*" + +"CI-fem-test": + - "**/*" + +"CI-rs-test": + - "**/*" + +"CI-homekit-test": + - "include/dfu/**/*" + - "include/mgmt/mcumgr/**/*" + - "soc/arm/nordic_nrf/**/*" + - "subsys/dfu/**/*" + - "subsys/settings/**/*" + - "subsys/net/lib/openthread/**/*" + - "subsys/mgmt/mcumgr/**/*" + - "samples/bluetooth/hci_rpmsg/**/*" + - "samples/subsys/mgmt/mcumgr/smp_svr/**/*" + - any: + - "subsys/bluetooth/**/*" + - "!subsys/bluetooth/mesh/**/*" + +"CI-thread-test": + - "**/*" + +"CI-nfc-test": + - "**/*" + +"CI-matter-test": + - "include/dfu/**/*" + - "include/mgmt/mcumgr/**/*" + - "soc/arm/nordic_nrf/**/*" + - "subsys/dfu/**/*" + - "subsys/settings/**/*" + - "subsys/net/**/*" + - "subsys/mgmt/mcumgr/**/*" + - "drivers/net/**/*" + - "samples/bluetooth/hci_rpmsg/**/*" + - any: + - "subsys/bluetooth/**/*" + - "!subsys/bluetooth/mesh/**/*" + - "!subsys/bluetooth/audio/**/*" + +"CI-find-my-test": + - "**/*" + +"CI-gazell-test": + - "**/*" + +"CI-rpc-test": + - "**/*" + +"CI-modemshell-test": + - "include/net/**/*" + - "include/posix/**/*" + - "include/shell/**/*" + - "drivers/net/**/*" + - "drivers/serial/**/*" + - "drivers/wifi/**/*" + - "subsys/shell/**/*" + - "subsys/net/**/*" + - "subsys/settings/**/*" + +"CI-positioning-test": + - "include/net/**/*" + - "include/posix/**/*" + - "drivers/net/**/*" + - "drivers/wifi/**/*" + - "subsys/net/**/*" + - "subsys/settings/**/*" + +"CI-cloud-test": + - "include/zephyr/dfu/**/*" + - "include/zephyr/net/**/*" + - "include/zephyr/posix/**/*" + - "include/zephyr/settings/**/*" + - "drivers/led/**/*" + - "drivers/net/**/*" + - "drivers/sensor/**/*" + - "drivers/serial/**/*" + - "drivers/wifi/**/*" + - "lib/posix/**/*" + - "soc/arm/nordic_nrf/**/*" + - "subsys/dfu/**/*" + - "subsys/net/**/*" + - "subsys/settings/**/*" + +"CI-wifi": + - "subsys/net/l2/wifi/**/*" + - "subsys/net/l2/ethernet/**/*" + +"CI-sidewalk-test": + - "include/dfu/**/*" + - "include/mgmt/mcumgr/**/*" + - "soc/arm/nordic_nrf/**/*" + - "subsys/dfu/**/*" + - "subsys/settings/**/*" + - "subsys/mgmt/mcumgr/**/*" + - "samples/bluetooth/hci_rpmsg/**/*" + - any: + - "subsys/bluetooth/**/*" + - "!subsys/bluetooth/mesh/**/*" + - "!subsys/bluetooth/audio/**/*" diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 9108d31b45b8..402cbae9f951 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -8,8 +8,7 @@ concurrency: jobs: clang-build: - if: github.repository_owner == 'zephyrproject-rtos' - runs-on: zephyr-runner-linux-x64-4xlarge + runs-on: ubuntu-latest container: image: ghcr.io/zephyrproject-rtos/ci:v0.26.4 options: '--entrypoint /bin/bash' @@ -19,11 +18,13 @@ jobs: fail-fast: false matrix: platform: ["native_posix"] + subset: [1, 2, 3, 4, 5] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.1 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} + MATRIX_SIZE: 5 outputs: report_needed: ${{ steps.twister.outputs.report_needed }} steps: @@ -85,7 +86,7 @@ jobs: id: cache-ccache uses: zephyrproject-rtos/action-s3-cache@v1.2.0 with: - key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.platform }}-ccache + key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.subset }}-ccache path: /github/home/.cache/ccache aws-s3-bucket: ccache.zephyrproject.org aws-access-key-id: ${{ vars.AWS_CCACHE_ACCESS_KEY_ID }} @@ -98,6 +99,16 @@ jobs: test -d github/home/.cache/ccache && rm -rf /github/home/.cache/ccache && mv github/home/.cache/ccache /github/home/.cache/ccache ccache -M 10G -s + - name: Build test plan with Twister + id: twister_test_plan + run: | + export ZEPHYR_BASE=${PWD} + export ZEPHYR_TOOLCHAIN_VARIANT=llvm + + # check if we need to run a full twister or not based on files changed + python3 ./scripts/ci/test_plan.py -p native_posix -c origin/${BASE_REF}.. + + - name: Run Tests with Twister id: twister run: | @@ -111,7 +122,7 @@ jobs: if [ -s testplan.json ]; then echo "report_needed=1" >> $GITHUB_OUTPUT # Full twister but with options based on changes - ./scripts/twister --force-color --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 + ./scripts/twister --inline-logs -M -N -v --load-tests testplan.json --retry-failed 2 --subset ${{matrix.subset}}/${MATRIX_SIZE} else # if nothing is run, skip reporting step echo "report_needed=0" >> $GITHUB_OUTPUT @@ -126,7 +137,7 @@ jobs: if: always() && steps.twister.outputs.report_needed != 0 uses: actions/upload-artifact@v3 with: - name: Unit Test Results (Subset ${{ matrix.platform }}) + name: Unit Test Results (Subset ${{ matrix.subset }}) path: twister-out/twister.xml clang-build-results: diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index f84faff3e4af..002179b67406 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -38,8 +38,12 @@ jobs: git config --global user.name "Your Name" git remote -v # Ensure there's no merge commits in the PR - [[ "$(git rev-list --merges --count origin/${BASE_REF}..)" == "0" ]] || \ - (echo "::error ::Merge commits not allowed, rebase instead";false) + #[[ "$(git rev-list --merges --count origin/${BASE_REF}..)" == "0" ]] || \ + #(echo "::error ::Merge commits not allowed, rebase instead";false) + # Sauce tag checks before rebasing + git rev-list --first-parent origin/${BASE_REF}..HEAD | tr '\n' ',' | \ + xargs gitlint -c ncs-sauce-tags.enable=true \ + -c title-starts-with-subsystem.regex=".*" --commits git rebase origin/${BASE_REF} # debug git log --pretty=oneline | head -n 10 @@ -56,7 +60,7 @@ jobs: # debug ls -la git log --pretty=oneline | head -n 10 - ./scripts/ci/check_compliance.py --annotate -e KconfigBasic \ + ./scripts/ci/check_compliance.py --annotate -e KconfigBasic -e Kconfig \ -c origin/${BASE_REF}.. - name: upload-results diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 466f9c8afbda..4510e21505f9 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -22,7 +22,7 @@ on: - 'west.yml' - '.github/workflows/doc-build.yml' - 'scripts/dts/**' - - 'scripts/requirements-doc.txt' + - 'doc/requirements.txt' env: # NOTE: west docstrings will be extracted from the version listed here @@ -57,12 +57,12 @@ jobs: uses: actions/cache@v3 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('doc/requirements.txt') }} - name: install-pip run: | sudo pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r doc/requirements.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} @@ -84,7 +84,7 @@ jobs: DOC_TARGET="html" fi - DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -W -t publish" make -C doc ${DOC_TARGET} + DOC_TAG=${DOC_TAG} SPHINXOPTS_EXTRA="-q -t publish" make -C doc ${DOC_TARGET} - name: compress-docs run: | @@ -136,7 +136,7 @@ jobs: uses: actions/cache@v3 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('doc/requirements.txt') }} - name: setup-venv run: | @@ -147,7 +147,7 @@ jobs: - name: install-pip run: | pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r doc/requirements.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} diff --git a/.gitlint b/.gitlint index b8d25ce49b92..8a33f140b2ab 100644 --- a/.gitlint +++ b/.gitlint @@ -16,7 +16,7 @@ debug = false extra-path=scripts/gitlint [title-max-length-no-revert] -line-length=75 +line-length=120 [body-min-line-count] min-line-count=1 @@ -42,7 +42,7 @@ words=wip [max-line-length-with-exceptions] # B1 = body-max-line-length -line-length=75 +line-length=120 [body-min-length] min-length=3 diff --git a/CMakeLists.txt b/CMakeLists.txt index f6b06937f873..66eb7bbbd475 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -480,8 +480,9 @@ if(CONFIG_USERSPACE) endif() get_property(TOPT GLOBAL PROPERTY TOPT) -set_ifndef( TOPT -Wl,-T) # clang doesn't pick -T for some reason and complains, - # while -Wl,-T works for both, gcc and clang +get_property(COMPILER_TOPT TARGET compiler PROPERTY linker_script) +set_ifndef( TOPT "${COMPILER_TOPT}") +set_ifndef( TOPT -Wl,-T) # Use this if the compiler driver doesn't set a value if(CONFIG_HAVE_CUSTOM_LINKER_SCRIPT) set(LINKER_SCRIPT ${APPLICATION_SOURCE_DIR}/${CONFIG_CUSTOM_LINKER_SCRIPT}) @@ -1429,6 +1430,7 @@ toolchain_ld_link_elf( target_byproducts(TARGET ${ZEPHYR_LINK_STAGE_EXECUTABLE} BYPRODUCTS ${PROJECT_BINARY_DIR}/${ZEPHYR_LINK_STAGE_EXECUTABLE}.map ) +set(BYPRODUCT_KERNEL_ELF_NAME "${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" CACHE FILEPATH "Kernel elf file" FORCE) set_property(TARGET ${ZEPHYR_LINK_STAGE_EXECUTABLE} PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/${ZEPHYR_CURRENT_LINKER_CMD} @@ -1576,6 +1578,7 @@ if(CONFIG_BUILD_OUTPUT_HEX OR BOARD_FLASH_RUNNER STREQUAL openocd) ${KERNEL_HEX_NAME} # ${out_hex_byprod} # Is this needed ? ) + set(BYPRODUCT_KERNEL_HEX_NAME "${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME}" CACHE FILEPATH "Kernel hex file" FORCE) endif() endif() @@ -1598,6 +1601,7 @@ if(CONFIG_BUILD_OUTPUT_BIN) ${KERNEL_BIN_NAME} # ${out_hex_byprod} # Is this needed ? ) + set(BYPRODUCT_KERNEL_BIN_NAME "${PROJECT_BINARY_DIR}/${KERNEL_BIN_NAME}" CACHE FILEPATH "Kernel binary file" FORCE) endif() endif() @@ -1630,6 +1634,7 @@ if(CONFIG_BUILD_OUTPUT_BIN AND CONFIG_BUILD_OUTPUT_UF2) post_build_byproducts ${KERNEL_UF2_NAME} ) + set(BYPRODUCT_KERNEL_UF2_NAME "${PROJECT_BINARY_DIR}/${KERNEL_UF2_NAME}" CACHE FILEPATH "Kernel uf2 file" FORCE) endif() if(CONFIG_BUILD_OUTPUT_META) @@ -1681,6 +1686,7 @@ if(CONFIG_BUILD_OUTPUT_S19) # ${out_S19_byprod} # Is this needed ? ) + set(BYPRODUCT_KERNEL_S19_NAME "${PROJECT_BINARY_DIR}/${KERNEL_S19_NAME}" CACHE FILEPATH "Kernel s19 file" FORCE) endif() endif() @@ -1764,6 +1770,7 @@ if(CONFIG_BUILD_OUTPUT_EXE) post_build_byproducts ${KERNEL_EXE_NAME} ) + set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) endif() if(CONFIG_BUILD_OUTPUT_INFO_HEADER) diff --git a/CODEOWNERS b/CODEOWNERS index 176da459cc0b..4a53d28066db 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -14,6 +14,7 @@ # * @galak @nashif /.github/ @nashif @stephanosio +/.github/test-spec.yml @nrfconnect/ncs-test-leads /.github/workflows/ @galak @nashif /MAINTAINERS.yml @MaureenHelm /arch/arc/ @abrodkin @ruuddw @evgeniy-paltsev diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000000..3b9cf0022399 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,5 @@ +@Library("CI_LIB") _ + +def pipeline = new ncs.sdk_zephyr.Main() + +pipeline.run(JOB_NAME) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7bafdc0be0e1..677f9000042f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -591,7 +591,6 @@ Documentation: - doc/images/Zephyr-Kite-in-tree.png - doc/index-tex.rst - doc/index.rst - - doc/kconfig.rst - doc/known-warnings.txt - doc/templates/sample.tmpl - doc/templates/board.tmpl diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ec82b1e50ee1..e17cf3f9b310 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -53,6 +53,22 @@ config ARM_ON_ENTER_CPU_IDLE_HOOK If needed, this hook can be used to prevent the CPU from actually entering sleep by skipping the WFE/WFI instruction. +config ARM_ON_EXIT_CPU_IDLE + bool + help + Enables a possibility to inject SoC-specific code just after WFI/WFE + instructions of the cpu idle implementation. + + Enabling this option requires that the SoC provides a soc_cpu_idle.h + header file which defines SOC_ON_EXIT_CPU_IDLE macro guarded by + _ASMLANGUAGE. + + The SOC_ON_EXIT_CPU_IDLE macro is expanded just after + WFI/WFE instructions before any memory access is performed. The purpose + of the SOC_ON_EXIT_CPU_IDLE is to perform an action that mitigate issues + observed on some SoCs caused by a memory access following WFI/WFE + instructions. + rsource "core/aarch32/Kconfig" rsource "core/aarch32/Kconfig.vfp" diff --git a/arch/arm/core/aarch32/cpu_idle.S b/arch/arm/core/aarch32/cpu_idle.S index 90f51f476b56..8164959ab291 100644 --- a/arch/arm/core/aarch32/cpu_idle.S +++ b/arch/arm/core/aarch32/cpu_idle.S @@ -13,6 +13,10 @@ #include #include +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) +#include +#endif + _ASM_FILE_PROLOGUE GTEXT(z_arm_cpu_idle_init) @@ -64,6 +68,11 @@ SECTION_FUNC(TEXT, z_arm_cpu_idle_init) dsb \wait_instruction +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) + /* Inline the macro provided by SoC-specific code */ + SOC_ON_EXIT_CPU_IDLE +#endif /* CONFIG_ARM_ON_EXIT_CPU_IDLE */ + #if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK) _skip_\@: #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) diff --git a/boards/arm/actinius_icarus/Kconfig.defconfig b/boards/arm/actinius_icarus/Kconfig.defconfig index 6994aac280d6..3b8093275da3 100644 --- a/boards/arm/actinius_icarus/Kconfig.defconfig +++ b/boards/arm/actinius_icarus/Kconfig.defconfig @@ -8,6 +8,21 @@ if BOARD_ACTINIUS_ICARUS || BOARD_ACTINIUS_ICARUS_NS config BOARD default "actinius_icarus" +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_ACTINIUS_ICARUS_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + source "boards/common/actinius/Kconfig" # For the secure version of the board the firmware is linked at the beginning diff --git a/boards/arm/actinius_icarus_bee/Kconfig.defconfig b/boards/arm/actinius_icarus_bee/Kconfig.defconfig index 309a45a61d42..7b733d910d9f 100644 --- a/boards/arm/actinius_icarus_bee/Kconfig.defconfig +++ b/boards/arm/actinius_icarus_bee/Kconfig.defconfig @@ -8,6 +8,21 @@ if BOARD_ACTINIUS_ICARUS_BEE || BOARD_ACTINIUS_ICARUS_BEE_NS config BOARD default "actinius_icarus_bee" +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_ACTINIUS_ICARUS_BEE_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + source "boards/common/actinius/Kconfig" # For the secure version of the board the firmware is linked at the beginning diff --git a/boards/arm/actinius_icarus_som/Kconfig.defconfig b/boards/arm/actinius_icarus_som/Kconfig.defconfig index 473acfea29fe..cc92427d24c8 100644 --- a/boards/arm/actinius_icarus_som/Kconfig.defconfig +++ b/boards/arm/actinius_icarus_som/Kconfig.defconfig @@ -8,6 +8,21 @@ if BOARD_ACTINIUS_ICARUS_SOM || BOARD_ACTINIUS_ICARUS_SOM_NS config BOARD default "actinius_icarus_som" +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_ACTINIUS_ICARUS_SOM_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + source "boards/common/actinius/Kconfig" # For the secure version of the board the firmware is linked at the beginning diff --git a/boards/arm/circuitdojo_feather_nrf9160/Kconfig.defconfig b/boards/arm/circuitdojo_feather_nrf9160/Kconfig.defconfig index 73648be3ef17..f37bfbf84fb4 100644 --- a/boards/arm/circuitdojo_feather_nrf9160/Kconfig.defconfig +++ b/boards/arm/circuitdojo_feather_nrf9160/Kconfig.defconfig @@ -9,6 +9,21 @@ if BOARD_CIRCUITDOJO_FEATHER_NRF9160 || BOARD_CIRCUITDOJO_FEATHER_NRF9160_NS config BOARD default "circuitdojo_feather_nrf9160" +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_CIRCUITDOJO_FEATHER_NRF9160_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + # For the secure version of the board the firmware is linked at the beginning # of the flash, or into the code-partition defined in DT if it is intended to # be loaded by MCUboot. If the secure firmware is to be combined with a non- diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.defconfig b/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.defconfig index 8ae5b832d895..3d98b1b4cb4b 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.defconfig +++ b/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.defconfig @@ -9,6 +9,21 @@ if BOARD_SPARKFUN_THING_PLUS_NRF9160 || BOARD_SPARKFUN_THING_PLUS_NRF9160_NS config BOARD default "sparkfun_thing_plus_nrf9160" +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_SPARKFUN_THING_PLUS_NRF9160_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + # For the secure version of the board the firmware is linked at the beginning # of the flash, or into the code-partition defined in DT if it is intended to # be loaded by MCUboot. If the secure firmware is to be combined with a non- diff --git a/boards/arm/thingy53_nrf5340/Kconfig.defconfig b/boards/arm/thingy53_nrf5340/Kconfig.defconfig index e4d9e63b7f17..c79eb908c215 100644 --- a/boards/arm/thingy53_nrf5340/Kconfig.defconfig +++ b/boards/arm/thingy53_nrf5340/Kconfig.defconfig @@ -8,6 +8,27 @@ if BOARD_THINGY53_NRF5340_CPUAPP || BOARD_THINGY53_NRF5340_CPUAPP_NS config BOARD default "thingy53_nrf5340_cpuapp" +config BOOTLOADER_MCUBOOT + default y if !MCUBOOT + +config BOARD_ENABLE_CPUNET + default y if !MCUBOOT + +# By default, if we build for a Non-Secure version of the board, +# enable building with TF-M as the Secure Execution Environment. +config BUILD_WITH_TFM + default y if BOARD_THINGY53_NRF5340_CPUAPP_NS + +if BUILD_WITH_TFM + +# By default, if we build with TF-M, instruct build system to +# flash the combined TF-M (Secure) & Zephyr (Non Secure) image +config TFM_FLASH_MERGED_BINARY + bool + default y + +endif # BUILD_WITH_TFM + # Code Partition: # # For the secure version of the board the firmware is linked at the beginning @@ -135,6 +156,12 @@ endif # LOG endif # BOARD_SERIAL_BACKEND_CDC_ACM +# By default, a USB CDC ACM instance is already enabled in the board's DTS. +# It is not necessary for nRF Connect SDK to add another instance if MCUBoot +# bootloader is built as a child image. +config MCUBOOT_USB_SUPPORT + default n + endif # BOARD_THINGY53_NRF5340_CPUAPP || BOARD_THINGY53_NRF5340_CPUAPP_NS if BOARD_THINGY53_NRF5340_CPUNET diff --git a/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp.yml b/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp.yml new file mode 100644 index 000000000000..7a48d51ec334 --- /dev/null +++ b/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp.yml @@ -0,0 +1,55 @@ +app: + address: 0x10200 + region: flash_primary + size: 0xdfe00 +mcuboot: + address: 0x0 + region: flash_primary + size: 0x10000 +mcuboot_pad: + address: 0x10000 + region: flash_primary + size: 0x200 +mcuboot_primary: + address: 0x10000 + orig_span: &id001 + - mcuboot_pad + - app + region: flash_primary + size: 0xe0000 + span: *id001 +mcuboot_primary_app: + address: 0x10200 + orig_span: &id002 + - app + region: flash_primary + size: 0xdfe00 + span: *id002 +settings_storage: + address: 0xf0000 + region: flash_primary + size: 0x10000 +mcuboot_primary_1: + address: 0x0 + size: 0x40000 + device: flash_ctrl + region: ram_flash +mcuboot_secondary: + address: 0x00000 + size: 0xe0000 + device: MX25R64 + region: external_flash +mcuboot_secondary_1: + address: 0xe0000 + size: 0x40000 + device: MX25R64 + region: external_flash +external_flash: + address: 0x120000 + size: 0x6e0000 + device: MX25R64 + region: external_flash +pcd_sram: + address: 0x20000000 + size: 0x2000 + region: sram_primary diff --git a/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp_ns.yml b/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp_ns.yml new file mode 100644 index 000000000000..70ffe6d9c124 --- /dev/null +++ b/boards/arm/thingy53_nrf5340/pm_static_thingy53_nrf5340_cpuapp_ns.yml @@ -0,0 +1,73 @@ +mcuboot: + address: 0x0 + region: flash_primary + size: 0x10000 +mcuboot_pad: + address: 0x10000 + region: flash_primary + size: 0x200 +tfm_secure: + address: 0x10000 + size: 0xc000 + span: [mcuboot_pad, tfm] +tfm_nonsecure: + address: 0x1c000 + size: 0xd4000 + span: [app] +tfm: + address: 0x10200 + region: flash_primary + size: 0xbe00 +app: + address: 0x1c000 + region: flash_primary + size: 0xd4000 +mcuboot_primary: + address: 0x10000 + orig_span: &id001 + - mcuboot_pad + - tfm + - app + region: flash_primary + size: 0xe0000 + span: *id001 +mcuboot_primary_app: + address: 0x10200 + orig_span: &id002 + - tfm + - app + region: flash_primary + size: 0xdfe00 + span: *id002 +nonsecure_storage: + address: 0xf0000 + size: 0x10000 + span: [settings_storage] +settings_storage: + address: 0xf0000 + region: flash_primary + size: 0x10000 +mcuboot_primary_1: + address: 0x0 + size: 0x40000 + device: flash_ctrl + region: ram_flash +mcuboot_secondary: + address: 0x00000 + size: 0xe0000 + device: MX25R64 + region: external_flash +mcuboot_secondary_1: + address: 0xe0000 + size: 0x40000 + device: MX25R64 + region: external_flash +external_flash: + address: 0x120000 + size: 0x6e0000 + device: MX25R64 + region: external_flash +pcd_sram: + address: 0x20000000 + size: 0x2000 + region: sram_primary diff --git a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi index c61a68f06565..e6ff6e1f6698 100644 --- a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi +++ b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_common.dtsi @@ -15,6 +15,7 @@ zephyr,bt-hci-rpmsg-ipc = &ipc0; nordic,802154-spinel-ipc = &ipc0; zephyr,ieee802154 = &ieee802154; + nordic,pm-ext-flash = &mx25r64; }; buttons { diff --git a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts index 6542d47d28e4..fedf35c8b3e1 100644 --- a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts +++ b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts @@ -63,6 +63,20 @@ supply-voltage-mv = <3000>; }; + edge_connector: connector { + compatible = "nordic-thingy53-edge-connector"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <8 0 &gpio0 5 0>, /* P8, P0.05/AIN1 */ + <9 0 &gpio0 4 0>, /* P9, P0.04/AIN0 */ + <15 0 &gpio0 8 0>, /* P15, P0.08/TRACEDATA3 */ + <16 0 &gpio0 9 0>, /* P16, P0.09/TRACEDATA2 */ + <17 0 &gpio0 10 0>, /* P17, P0.10/TRACEDATA1 */ + <18 0 &gpio0 11 0>, /* P18, P0.11/TRACEDATA0 */ + <19 0 &gpio0 12 0>; /* P19, P0.12/TRACECLK */ + }; + aliases { sw0 = &button0; sw1 = &button1; diff --git a/boards/posix/native_posix/irq_handler.c b/boards/posix/native_posix/irq_handler.c index 2c962fc79ca5..785851aa524b 100644 --- a/boards/posix/native_posix/irq_handler.c +++ b/boards/posix/native_posix/irq_handler.c @@ -105,7 +105,7 @@ void posix_irq_handler(void) */ if (may_swap && (hw_irq_ctrl_get_cur_prio() == 256) - && (_kernel.ready_q.cache != _current)) { + && (_kernel.ready_q.cache) && (_kernel.ready_q.cache != _current)) { (void)z_swap_irqlock(irq_lock); } diff --git a/boards/posix/nrf52_bsim/irq_handler.c b/boards/posix/nrf52_bsim/irq_handler.c index c14d197daa88..497ba37e57de 100644 --- a/boards/posix/nrf52_bsim/irq_handler.c +++ b/boards/posix/nrf52_bsim/irq_handler.c @@ -126,7 +126,7 @@ void posix_irq_handler(void) if (may_swap && (hw_irq_ctrl_get_cur_prio() == 256) && (CPU_will_be_awaken_from_WFE == false) - && (_kernel.ready_q.cache != _current)) { + && (_kernel.ready_q.cache) && (_kernel.ready_q.cache != _current)) { z_swap_irqlock(irq_lock); } diff --git a/cmake/compiler/clang/compiler_flags.cmake b/cmake/compiler/clang/compiler_flags.cmake index 7a3fbdc1c3a8..12868539d2f7 100644 --- a/cmake/compiler/clang/compiler_flags.cmake +++ b/cmake/compiler/clang/compiler_flags.cmake @@ -23,6 +23,9 @@ set_compiler_property(PROPERTY diagnostic -fcolor-diagnostics) # clang flag to save temporary object files set_compiler_property(PROPERTY save_temps -save-temps) +# clang doesn't handle the -T flag +set_compiler_property(PROPERTY linker_script -Wl,-T) + ####################################################### # This section covers flags related to warning levels # ####################################################### diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 4614866b2ce0..5f15d1b80074 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -106,6 +106,9 @@ set_compiler_property(PROPERTY debug) # Flags to save temporary object files set_compiler_property(PROPERTY save_temps) +# Flag to specify linker script +set_compiler_property(PROPERTY linker_script) + set_compiler_property(PROPERTY no_common) # Flags for imacros. The specific header must be appended by user. diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index f2c2845923bf..cca947e3d0fa 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -182,6 +182,9 @@ set_compiler_property(PROPERTY debug -g) # Flags to save temporary object files set_compiler_property(PROPERTY save_temps -save-temps=obj) +# Flag to specify linker script +set_compiler_property(PROPERTY linker_script -T) + # Flags to not track macro expansion set_compiler_property(PROPERTY no_track_macro_expansion -ftrack-macro-expansion=0) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index f551466a4113..3b29069ca354 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -114,15 +114,24 @@ function(zephyr_mcuboot_tasks) list(APPEND unconfirmed_args --bin --sbin ${output}.signed.bin) list(APPEND byproducts ${output}.signed.bin) zephyr_runner_file(bin ${output}.signed.bin) + set(BYPRODUCT_KERNEL_SIGNED_BIN_NAME "${output}.signed.bin" + CACHE FILEPATH "Signed kernel bin file" FORCE + ) if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) list(APPEND confirmed_args --bin --sbin ${output}.signed.confirmed.bin) list(APPEND byproducts ${output}.signed.confirmed.bin) + set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_BIN_NAME "${output}.signed.confirmed.bin" + CACHE FILEPATH "Signed and confirmed kernel bin file" FORCE + ) endif() if(NOT "${keyfile_enc}" STREQUAL "") list(APPEND encrypted_args --bin --sbin ${output}.signed.encrypted.bin) list(APPEND byproducts ${output}.signed.encrypted.bin) + set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_BIN_NAME "${output}.signed.encrypted.bin" + CACHE FILEPATH "Signed and encrypted kernel bin file" FORCE + ) endif() endif() @@ -131,15 +140,24 @@ function(zephyr_mcuboot_tasks) list(APPEND unconfirmed_args --hex --shex ${output}.signed.hex) list(APPEND byproducts ${output}.signed.hex) zephyr_runner_file(hex ${output}.signed.hex) + set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex" + CACHE FILEPATH "Signed kernel hex file" FORCE + ) if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) list(APPEND confirmed_args --hex --shex ${output}.signed.confirmed.hex) list(APPEND byproducts ${output}.signed.confirmed.hex) + set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_HEX_NAME "${output}.signed.confirmed.hex" + CACHE FILEPATH "Signed and confirmed kernel hex file" FORCE + ) endif() if(NOT "${keyfile_enc}" STREQUAL "") list(APPEND encrypted_args --hex --shex ${output}.signed.encrypted.hex) list(APPEND byproducts ${output}.signed.encrypted.hex) + set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_HEX_NAME "${output}.signed.encrypted.hex" + CACHE FILEPATH "Signed and encrypted kernel hex file" FORCE + ) endif() endif() diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index 7e65c9cd186d..28ee922d40b0 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -242,3 +242,7 @@ if("${CMAKE_EXTRA_GENERATOR}" STREQUAL "Eclipse CDT4") include(${ZEPHYR_BASE}/cmake/ide/eclipse_cdt4_generator_amendment.cmake) eclipse_cdt4_generator_amendment(1) endif() + +if(ZEPHYR_NRF_MODULE_DIR) + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/partition_manager.cmake) +endif() diff --git a/cmake/modules/snippets.cmake b/cmake/modules/snippets.cmake index 550d236a2f4a..6f8950c5f64a 100644 --- a/cmake/modules/snippets.cmake +++ b/cmake/modules/snippets.cmake @@ -59,6 +59,7 @@ function(zephyr_process_snippets) # Set SNIPPET_ROOT. list(APPEND SNIPPET_ROOT ${APPLICATION_SOURCE_DIR}) list(APPEND SNIPPET_ROOT ${ZEPHYR_BASE}) + list(APPEND SNIPPET_ROOT ${ZEPHYR_NRF_MODULE_DIR}) unset(real_snippet_root) foreach(snippet_dir ${SNIPPET_ROOT}) # The user might have put a symbolic link in here, for example. diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 7c03af46d8c0..5cfce578a4a9 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -12,13 +12,15 @@ message(STATUS "Zephyr base: ${ZEPHYR_BASE}") #------------------------------------------------------------------------------- # Options -set(SPHINXOPTS "-j auto" CACHE STRING "Default Sphinx Options") +set(SPHINXOPTS "-j auto -W --keep-going -T" CACHE STRING "Default Sphinx Options") +set(SPHINXOPTS_EXTRA "" CACHE STRING "Extra Sphinx Options (added to defaults)") set(LATEXMKOPTS "-halt-on-error -no-shell-escape" CACHE STRING "Default latexmk options") set(DT_TURBO_MODE OFF CACHE BOOL "Enable DT turbo mode") set(DOC_TAG "development" CACHE STRING "Documentation tag") set(DTS_ROOTS "${ZEPHYR_BASE}" CACHE STRING "DT bindings root folders") separate_arguments(SPHINXOPTS) +separate_arguments(SPHINXOPTS_EXTRA) separate_arguments(LATEXMKOPTS) #------------------------------------------------------------------------------- @@ -145,6 +147,7 @@ add_doc_target( -w ${DOCS_BUILD_DIR}/html.log -t ${DOC_TAG} ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_HTML_DIR} USES_TERMINAL @@ -173,6 +176,7 @@ add_doc_target( -t ${DOC_TAG} -t svgconvert ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_LATEX_DIR} USES_TERMINAL @@ -223,6 +227,7 @@ add_doc_target( -w ${DOCS_BUILD_DIR}/linkcheck.log -t ${DOC_TAG} ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_LINKCHECK_DIR} USES_TERMINAL diff --git a/doc/Makefile b/doc/Makefile index c9ae0e700978..321a1b92cc40 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -4,7 +4,8 @@ BUILDDIR ?= _build DOC_TAG ?= development -SPHINXOPTS ?= -j auto +SPHINXOPTS ?= -j auto -W --keep-going -T +SPHINXOPTS_EXTRA ?= LATEXMKOPTS ?= -halt-on-error -no-shell-escape DT_TURBO_MODE ?= 0 @@ -26,6 +27,7 @@ configure: -S. \ -DDOC_TAG=${DOC_TAG} \ -DSPHINXOPTS="${SPHINXOPTS}" \ + -DSPHINXOPTS_EXTRA="${SPHINXOPTS_EXTRA}" \ -DLATEXMKOPTS="${LATEXMKOPTS}" \ -DDT_TURBO_MODE=${DT_TURBO_MODE} diff --git a/doc/_extensions/zephyr/warnings_filter.py b/doc/_extensions/zephyr/warnings_filter.py index 650a76134b21..9239776ff793 100644 --- a/doc/_extensions/zephyr/warnings_filter.py +++ b/doc/_extensions/zephyr/warnings_filter.py @@ -24,7 +24,7 @@ import logging import re -from typing import Dict, Any, List +from typing import Dict, Any, List, Optional from sphinx.application import Sphinx from sphinx.util.logging import NAMESPACE @@ -41,6 +41,7 @@ class WarningsFilter(logging.Filter): silent: If true, warning is hidden, otherwise it is shown as INFO. name: Filter name. """ + def __init__(self, expressions: List[str], silent: bool, name: str = "") -> None: super().__init__(name) @@ -52,7 +53,8 @@ def filter(self, record: logging.LogRecord) -> bool: return True for expression in self._expressions: - if re.match(expression, record.msg): + # The message isn't always a string so we convert it before regexing as we can only regex strings + if expression.match(str(record.msg)): if self._silent: return False else: @@ -63,6 +65,21 @@ def filter(self, record: logging.LogRecord) -> bool: return True +class Expression: + """ + Encapsulate a log filter pattern and track if it ever matches a log line. + """ + + def __init__(self, pattern): + self.pattern = pattern + self.matched = False + + def match(self, str): + matches = bool(re.match(self.pattern, str)) + self.matched = matches or self.matched + return matches + + def configure(app: Sphinx) -> None: """Entry point. @@ -74,8 +91,10 @@ def configure(app: Sphinx) -> None: with open(app.config.warnings_filter_config) as f: expressions = list() for line in f.readlines(): - if not line.startswith("#"): - expressions.append(line.rstrip()) + if line.strip() and not line.startswith("#"): + expressions.append(Expression(line.rstrip())) + + app.env.warnings_filter_expressions = expressions # install warnings filter to all the Sphinx logger handlers filter = WarningsFilter(expressions, app.config.warnings_filter_silent) @@ -84,11 +103,28 @@ def configure(app: Sphinx) -> None: handler.filters.insert(0, filter) +def finished(app: Sphinx, exception: Optional[Exception]): + """ + Prints out any patterns that have not matched a log line to allow us to clean up any that are not used. + """ + if exception: + # Early exit if there has been an exception as matching data is only + # valid for complete builds + return + + expressions = app.env.warnings_filter_expressions + + for expression in expressions: + if not expression.matched: + logging.warning(f"Unused expression: {expression.pattern}") + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("warnings_filter_config", "", "") app.add_config_value("warnings_filter_silent", True, "") app.connect("builder-inited", configure) + app.connect("build-finished", finished) return { "version": __version__, diff --git a/doc/build/index.rst b/doc/build/index.rst index 75be277c7219..4a3e76be3073 100644 --- a/doc/build/index.rst +++ b/doc/build/index.rst @@ -14,3 +14,4 @@ Build and Configuration Systems snippets/index.rst zephyr_cmake_package.rst sysbuild/index.rst + version/index.rst diff --git a/doc/build/kconfig/setting.rst b/doc/build/kconfig/setting.rst index 2fd78ff463b9..5f37e831e9e0 100644 --- a/doc/build/kconfig/setting.rst +++ b/doc/build/kconfig/setting.rst @@ -7,8 +7,7 @@ The :ref:`menuconfig and guiconfig interfaces ` can be used to test out configurations during application development. This page explains how to make settings permanent. -All Kconfig options can be searched in the :ref:`Kconfig search page -`. +All Kconfig options can be searched in the Kconfig search page. .. note:: @@ -115,8 +114,7 @@ Assignments in configuration files are only respected if the dependencies for the symbol are satisfied. A warning is printed otherwise. To figure out what the dependencies of a symbol are, use one of the :ref:`interactive configuration interfaces ` (you can jump directly to a symbol with -:kbd:`/`), or look up the symbol in the :ref:`Kconfig search page -`. +:kbd:`/`), or look up the symbol in the Kconfig search page. .. _initial-conf: diff --git a/doc/build/version/index.rst b/doc/build/version/index.rst new file mode 100644 index 000000000000..de4e713c6b60 --- /dev/null +++ b/doc/build/version/index.rst @@ -0,0 +1,164 @@ +.. _app-version-details: + +Application version management +****************************** + +Zephyr supports an application version management system for applications which is built around the +system that Zephyr uses for its own version system management. This allows applications to define a +version file and have application (or module) code include the auto-generated file and be able to +access it, just as they can with the kernel version. This version information is available from +multiple scopes, including: + +* Code (C/C++) +* Kconfig +* CMake + +which makes it a very versatile system for lifecycle management of applications. In addition, it +can be used when building applications which target supported bootloaders (e.g. MCUboot) allowing +images to be signed with correct version of the application automatically - no manual signing +steps are required. + +VERSION file +============ + +Application version information is set on a per-application basis in a file named :file:`VERSION`, +which must be placed at the base directory of the application, where the CMakeLists.txt file is +located. This is a simple text file which contains the various version information fields, each on +a newline. The basic ``VERSION`` file has the following structure: + +.. code-block:: none + + VERSION_MAJOR = + VERSION_MINOR = + PATCHLEVEL = + VERSION_TWEAK = + EXTRAVERSION = + +Each field and the values it supports is described below (note that there may be further +restrictions depending upon what the version is used for, e.g. bootloaders might only support some +of these fields or might place limits on the maximum values of fields): + ++---------------+----------------------------------------+ +| Field | Data type | ++---------------+----------------------------------------+ +| VERSION_MAJOR | Numerical | ++---------------+----------------------------------------+ +| VERSION_MINOR | Numerical | ++---------------+----------------------------------------+ +| PATCHLEVEL | Numerical | ++---------------+----------------------------------------+ +| VERSION_TWEAK | Numerical | ++---------------+----------------------------------------+ +| EXTRAVERSION | Alphanumerical (Lowercase a-z and 0-9) | ++---------------+----------------------------------------+ + +When an application is configured using CMake, the version file will be automatically processed, +and will be checked automatically each time the version is changed, so CMake does not need to be +manually re-ran for changes to this file. + +For the sections below, examples are provided for the following :file:`VERSION` file: + +.. code-block:: none + + VERSION_MAJOR = 1 + VERSION_MINOR = 2 + PATCHLEVEL = 3 + VERSION_TWEAK = 4 + EXTRAVERSION = unstable + +Use in code +=========== + +To use the version information in application code, the version file must be included, then the +fields can be freely used. The include file name is :file:`app_version.h` (no path is needed), the +following defines are available: + ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| Define | Type | Field(s) | Example | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APPVERSION | Numerical | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_NUMBER | Numerical | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` |br| | | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_BUILD_VERSION | String (unquoted) | None (value of ``git describe --abbrev=12 --always`` | v3.3.0-18-g2c85d9224fca | +| | | from application repository) | | ++--------------------+-------------------+------------------------------------------------------+-------------------------+ + +Use in Kconfig +============== + +The following variables are available for usage in Kconfig files: + ++------------------+-----------+-------------------------+----------------+ +| Variable | Type | Field(s) | Example | ++------------------+-----------+-------------------------+----------------+ +| $(VERSION_MAJOR) | Numerical | ``VERSION_MAJOR`` | 1 | ++------------------+-----------+-------------------------+----------------+ +| $(VERSION_MINOR) | Numerical | ``VERSION_MINOR`` | 2 | ++------------------+-----------+-------------------------+----------------+ +| $(PATCHLEVEL) | Numerical | ``PATCHLEVEL`` | 3 | ++------------------+-----------+-------------------------+----------------+ +| $(VERSION_TWEAK) | Numerical | ``VERSION_TWEAK`` | 4 | ++------------------+-----------+-------------------------+----------------+ +| $(APPVERSION) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++------------------+-----------+-------------------------+----------------+ + +Use in CMake +============ + +The following variable are available for usage in CMake files: + ++--------------------+-----------------+---------------------------------------------------+----------------+ +| Variable | Type | Field(s) | Example | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APPVERSION | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_VERSION_NUMBER | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++--------------------+-----------------+---------------------------------------------------+----------------+ +| APP_VERSION_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++--------------------+-----------------+---------------------------------------------------+----------------+ + +Use in MCUboot-supported applications +===================================== + +No additional configuration needs to be done to the target application so long as it is configured +to support MCUboot and a signed image is generated, the version information will be automatically +included in the image data. + +The format used for signing is ``VERSION_MAJOR`` . ``VERSION_MINOR`` . ``PATCHLEVEL``, the tweak +version field is not currently used. diff --git a/doc/conf.py b/doc/conf.py index 79f2f51b9b59..ef6bbf197511 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -72,6 +72,7 @@ "sphinx.ext.extlinks", "sphinx.ext.autodoc", "sphinx.ext.graphviz", + "sphinxcontrib.jquery", "zephyr.application", "zephyr.html_redirects", "zephyr.kconfig", diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index d954348841dd..1eb691b96c8a 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -21,4 +21,5 @@ Read more about Bluetooth mesh on the mesh/proxy.rst mesh/heartbeat.rst mesh/cfg.rst + mesh/statistic.rst mesh/shell.rst diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 7a3f2e1b291e..83a0d045d455 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -1687,3 +1687,18 @@ The Solicitation PDU RPL Client model is an optional mesh subsystem that can be * ``RngStart``: Start address of the SSRC range. * ``Ackd``: This argument decides on whether an acknowledged or unacknowledged message will be sent. * ``RngLen``: Range length for the SSRC addresses to be cleared from the solicitiation RPL list. This parameter is optional; if absent, only a single SSRC address will be cleared. + + +Frame statistic +=============== + +``mesh stat get`` +----------------- + + Get the frame statistic. The command prints numbers of received frames, as well as numbers of planned and succeeded transmission attempts. + + +``mesh stat clear`` +------------------- + + Clear all statistics collected before. diff --git a/doc/connectivity/bluetooth/api/mesh/statistic.rst b/doc/connectivity/bluetooth/api/mesh/statistic.rst new file mode 100644 index 000000000000..bf974b9ae91c --- /dev/null +++ b/doc/connectivity/bluetooth/api/mesh/statistic.rst @@ -0,0 +1,19 @@ +.. _bluetooth_mesh_stat: + +Frame statistic +############### + +The frame statistic API allows monitoring the number of received frames over +different interfaces, and the number of planned and succeeded transmission and +relaying attempts. + +The API helps the user to estimate the efficiency of the advertiser configuration +parameters and the scanning ability of the device. The number of the monitored +parameters can be easily extended by customer values. + +An application can read out and clean up statistics at any time. + +API reference +************* + +.. doxygengroup:: bt_mesh_stat diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 0ee4eb01d429..6d26205511e3 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -364,14 +364,44 @@ endpoint name. This is important as it needs to be unique per LwM2M server: (void)memset(&client, 0x0, sizeof(client)); lwm2m_rd_client_start(&client, "unique-endpoint-name", 0, rd_client_event); -Using LwM2M library with DTLS -***************************** +.. _lwm2m_security: -The Zephyr LwM2M library can be used with DTLS transport for secure -communication by selecting :kconfig:option:`CONFIG_LWM2M_DTLS_SUPPORT`. In the client -initialization we need to create a PSK and identity. These need to match -the security information loaded onto the LwM2M server. Normally, the -endpoint name is used to lookup the related security information: +LwM2M security modes +******************** + +The Zephyr LwM2M library can be used either without security or use DTLS to secure the communication channel. +When using DTLS with the LwM2M engine, PSK (Pre-Shared Key) and X.509 certificates are the security modes that can be used to secure the communication. +The engine uses LwM2M Security object (Id 0) to read the stored credentials and feed keys from the security object into +the TLS credential subsystem, see :ref:`secure sockets documentation `. +Enable the :kconfig:option:`CONFIG_LWM2M_DTLS_SUPPORT` Kconfig option to use the security. + +Depending on the selected mode, the security object must contain following data: + +PSK + Security Mode (Resource ID 2) set to zero (Pre-Shared Key mode). + Identity (Resource ID 3) contains PSK ID in binary form. + Secret key (Resource ID 5) contains the PSK key in binary form. + If the key or identity is provided as a hex string, it must be converted to binary before storing into the security object. + +X509 + When X509 certificates are used, set Security Mode (ID 2) to ``2`` (Certificate mode). + Identity (ID 3) is used to store the client certificate and Secret key (ID 5) must have a private key associated with the certificate. + Server Public Key resource (ID 4) must contain a server certificate or CA certificate used to sign the certificate chain. + If the :kconfig:option:`CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT` Kconfig option is enabled, certificates and private key can be entered in PEM format. + Otherwise, they must be in binary DER format. + +NoSec + When no security is used, set Security Mode (Resource ID 2) to ``3`` (NoSec). + +In all modes, Server URI resource (ID 0) must contain the full URI for the target server. +When DNS names are used, the DNS resolver must be enabled. + +LwM2M stack provides callbacks in the :c:struct:`lwm2m_ctx` structure. +They are used to feed keys from the LwM2M security object into the TLS credential subsystem. +By default, these callbacks can be left as NULL pointers, in which case default callbacks are used. +When an external TLS stack, or non-default socket options are required, you can overwrite the :c:func:`lwm2m_ctx.load_credentials` or :c:func:`lwm2m_ctx.set_socketoptions` callbacks. + +An example of setting up the security object for PSK mode: .. code-block:: c @@ -383,21 +413,26 @@ endpoint name is used to lookup the related security information: static const char client_identity[] = "Client_identity"; -Next we alter the ``Security`` object resources to include DTLS security -information. The server URL should begin with ``coaps://`` to indicate security -is required. Assign a 0 value (Pre-shared Key mode) to the ``Security Mode`` -resource. Lastly, set the client identity and PSK resources. + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); + lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_PSK); + /* Set the client identity as a string, but this could be binary as well */ + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), client_identity); + /* Set the client pre-shared key (PSK) */ + lwm2m_set_opaque(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), client_psk, sizeof(client_psk)); + +An example of setting up the security object for X509 certificate mode: .. code-block:: c - /* Use coaps:// for server URL protocol */ - lwm2m_set_string(&LWM2M_OBJ(0, 0, 0), "coaps://5.39.83.206"); - /* 0 = Pre-Shared Key mode */ - lwm2m_set_u8(&LWM2M_OBJ(0, 0, 2), 0); - /* Set the client identity */ - lwm2m_set_string(&LWM2M_OBJ(0, 0, 3), (char *)client_identity); - /* Set the client pre-shared key (PSK) */ - lwm2m_set_opaque(&LWM2M_OBJ(0, 0, 5), (void *)client_psk, sizeof(client_psk)); + static const char certificate[] = "-----BEGIN CERTIFICATE-----\nMIIB6jCCAY+gAw..."; + static const char key[] = "-----BEGIN EC PRIVATE KEY-----\nMHcCAQ..."; + static const char root_ca[] = "-----BEGIN CERTIFICATE-----\nMIIBaz..."; + + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); + lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_CERT); + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), certificate); + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), key); + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), root_ca); Before calling :c:func:`lwm2m_rd_client_start` assign the tls_tag # where the LwM2M library should store the DTLS information prior to connection (normally a diff --git a/doc/connectivity/networking/api/mqtt.rst b/doc/connectivity/networking/api/mqtt.rst index b1090c8d3947..dcc71e3320b8 100644 --- a/doc/connectivity/networking/api/mqtt.rst +++ b/doc/connectivity/networking/api/mqtt.rst @@ -149,6 +149,7 @@ additional configuration information: tls_config->sec_tag_list = m_sec_tags; tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags); tls_config->hostname = MQTT_BROKER_HOSTNAME; + tls_config->set_native_tls = true; In this sample code, the ``m_sec_tags`` array holds a list of tags, referencing TLS credentials that the MQTT library should use for authentication. We do not specify @@ -161,6 +162,8 @@ Note, that TLS credentials referenced by the ``m_sec_tags`` array must be registered in the system first. For more information on how to do that, refer to :ref:`secure sockets documentation `. +Finally, ``set_native_tls`` can be optionally set to enable native TLS support instead of offloading TLS operations to the modem. + An example of how to use TLS with MQTT is also present in :ref:`mqtt-publisher-sample`. diff --git a/doc/connectivity/networking/api/net_tech.rst b/doc/connectivity/networking/api/net_tech.rst index 3575db974b54..910ec4e0cce5 100644 --- a/doc/connectivity/networking/api/net_tech.rst +++ b/doc/connectivity/networking/api/net_tech.rst @@ -10,3 +10,4 @@ Networking Technologies ieee802154.rst thread.rst ppp.rst + wifi.rst diff --git a/doc/connectivity/networking/api/wifi.rst b/doc/connectivity/networking/api/wifi.rst new file mode 100644 index 000000000000..be29d9f8ddaa --- /dev/null +++ b/doc/connectivity/networking/api/wifi.rst @@ -0,0 +1,30 @@ +.. _wifi_mgmt: + +Wi-Fi Management +################ + +Overview +======== + +The Wi-Fi management API is used to manage Wi-Fi networks. It supports below modes: + +* IEEE802.11 Station (STA) +* IEEE802.11 Access Point (AP) + +Only personal mode security is supported with below types: + +* Open +* WPA2-PSK +* WPA3-PSK-256 +* WPA3-SAE + +The Wi-Fi management API is implemented in the `wifi_mgmt` module as a part of the networking L2 stack. +Currently, two types of Wi-Fi drivers are supported: + +* Networking or socket offloaded drivers +* Native L2 Ethernet drivers + +API Reference +************* + +.. doxygengroup:: wifi_mgmt diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index 5c885e9d287a..c339632fdf18 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -99,12 +99,20 @@ can be disabled if not needed. listen management events generated by core stack when for example IP address is added to the device, or network interface is coming up etc. +* **Wi-Fi Management API.** Applications can use Wi-Fi management API to + manage the interface, in example to connect to Wi-Fi network and to scan + available Wi-Fi networks. + +* **Wi-Fi Network Manager API.** Wi-Fi Network Managers can now register + themselves to the Wi-Fi stack. The Network Managers can then implement + the Wi-Fi Management API and manage the Wi-Fi interface. + * **Multiple Network Technologies.** The Zephyr OS can be configured to support multiple network technologies at the same time simply by enabling - them in Kconfig: for example, Ethernet and 802.15.4 support. Note that no - automatic IP routing functionality is provided between these technologies. - Applications can send data according to their needs to desired network - interface. + them in Kconfig: for example, Ethernet, Wi-Fi and 802.15.4 support. Note + that no automatic IP routing functionality is provided between these + technologies. Applications can send data according to their needs to desired + network interface. * **Minimal Copy Network Buffer Management.** It is possible to have minimal copy network data path. This means that the system tries to avoid copying diff --git a/doc/contribute/documentation/generation.rst b/doc/contribute/documentation/generation.rst index d7c8d6282bf4..3701e8601385 100644 --- a/doc/contribute/documentation/generation.rst +++ b/doc/contribute/documentation/generation.rst @@ -80,7 +80,7 @@ Our documentation processing has been tested to run with: * Graphviz 2.43 * Latexmk version 4.56 * All Python dependencies listed in the repository file - ``scripts/requirements-doc.txt`` + ``doc/requirements.txt`` In order to install the documentation tools, first install Zephyr as described in :ref:`getting_started`. Then install additional tools diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index 98a733062aeb..3fd971ad945f 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -45,6 +45,7 @@ Here are the files in a simple Zephyr application: ├── CMakeLists.txt ├── app.overlay ├── prj.conf + ├── VERSION └── src └── main.c @@ -77,6 +78,12 @@ These contents are: See :ref:`application-kconfig` below for more information. +* **VERSION**: A text file that contains several version information fields. + These fields let you manage the lifecycle of the application and automate + providing the application version when signing application images. + + See :ref:`app-version-details` for more information about this file and how to use it. + * **main.c**: A source code file. Applications typically contain source files written in C, C++, or assembly language. The Zephyr convention is to place them in a subdirectory of :file:`` named :file:`src`. @@ -190,11 +197,17 @@ following example, ``app`` is a Zephyr freestanding application: └── src/ └── main.c +.. _zephyr-creating-app: + Creating an Application *********************** -example-application -=================== +In Zephyr, you can either use a reference workspace application or create your application by hand. + +.. _zephyr-creating-app-from-example: + +Using a Reference Workspace Application +======================================= The `example-application`_ Git repository contains a reference :ref:`workspace application `. It is recommended to use it as a reference @@ -210,7 +223,7 @@ commonly-used features, such as: - A custom west :ref:`extension command ` Basic example-application Usage -=============================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The easiest way to get started with the example-application repository within an existing Zephyr workspace is to follow these steps: @@ -226,7 +239,7 @@ you are using an existing Zephyr workspace, you can use ``west build`` or any other west commands to build, flash, and debug. Advanced example-application Usage -================================== +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can also use the example-application repository as a starting point for building your own customized Zephyr-based software distribution. This lets you @@ -283,6 +296,8 @@ From now on, you can collaborate on the shared software by pushing changes to the repositories you are using and updating :file:`my-manifest-repo/west.yml` as needed to add and remove repositories, or change their contents. +.. _zephyr-creating-app-by-hand: + Creating an Application by Hand =============================== @@ -430,6 +445,8 @@ should know about. You can use a :ref:`cmake_build_config_package` to share common settings for these variables. +.. _zephyr-app-cmakelists: + Application CMakeLists.txt ************************** @@ -564,6 +581,8 @@ For example: ${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME} ${app_provision_hex}) +.. _zephyr-app-cmakecache: + CMakeCache.txt ************** @@ -621,9 +640,8 @@ started. See :ref:`setting_configuration_values` for detailed documentation on setting Kconfig configuration values. The :ref:`initial-conf` section on the same page -explains how the initial configuration is derived. See :ref:`kconfig-search` -for a complete list of configuration options. -See :ref:`hardening` for security information related with Kconfig options. +explains how the initial configuration is derived. See :ref:`hardening` for +security information related with Kconfig options. The other pages in the :ref:`Kconfig section of the manual ` are also worth going through, especially if you planning to add new configuration diff --git a/doc/kconfig.rst b/doc/kconfig.rst deleted file mode 100644 index 1123de2adbd9..000000000000 --- a/doc/kconfig.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -.. _kconfig-search: - -Kconfig Search -============== - -.. kconfig:search:: diff --git a/doc/known-warnings.txt b/doc/known-warnings.txt index 2ae3f98729c4..3ea22e16b675 100644 --- a/doc/known-warnings.txt +++ b/doc/known-warnings.txt @@ -1,17 +1,24 @@ # Each line should contain the regular expression of a known Sphinx warning # that should be filtered out -.*Duplicate C declaration.*\n.*'\.\. c:.*:: dma_config'.* + +# Function and (enum or struct) name .*Duplicate C declaration.*\n.*'\.\. c:.*:: flash_img_check'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: zsock_fd_set'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: net_if_mcast_monitor'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: fs_statvfs'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*dmic_trigger.*'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: uint16_t id'.* +.*Duplicate C declaration.*\n.*'\.\. c:.*:: dma_config'.* +.*Duplicate C declaration.*\n.*'\.\. c:.*:: net_if_mcast_monitor'.* + +# Struct and typedef name +.*Duplicate C declaration.*\n.*'\.\. c:.*:: zsock_fd_set'.* + +# Function and extern function .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_addr_mask_cmp.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_is_addr_bcast.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_addr_lookup.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv6_addr_lookup.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv6_maddr_lookup.*'.* + +# Common field names .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct in_addr.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct in6_addr.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct net_if.*'.* diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index c532ff873e5c..900908b533d8 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -232,6 +232,58 @@ Devicetree Libraries / Subsystems ********************** +* Management + + * Introduced MCUmgr client support with handlers for img_mgmt and os_mgmt. + + * Added response checking to MCUmgr's :c:enumerator:`MGMT_EVT_OP_CMD_RECV` + notification callback to allow applications to reject MCUmgr commands. + + * MCUmgr SMP version 2 error translation (to legacy MCUmgr error code) is now + supported in function handlers by setting ``mg_translate_error`` of + :c:struct:`mgmt_group` when registering a transport. See + :c:type:`smp_translate_error_fn` for function details. +* shell + + * Added an application shell module with helpers common to all applications. + + * Fixed an issue with MCUmgr img_mgmt group whereby the size of the upload in + the initial packet was not checked. + + * Fixed an issue with MCUmgr fs_mgmt group whereby some status codes were not + checked properly, this meant that the error returned might not be the + correct error, but would only occur in situations where an error was + already present. + + * Fixed an issue whereby the SMP response function did not check to see if + the initial zcbor map was created successfully. + + * Fixes an issue with MCUmgr shell_mgmt group whereby the length of a + received command was not properly checked. + + * Added optional mutex locking support to MCUmgr img_mgmt group, which can + be enabled with :kconfig:option:`CONFIG_MCUMGR_GRP_IMG_MUTEX`. + + * Added MCUmgr settings management group, which allows for manipulation of + zephyr settings from a remote device, see :ref:`mcumgr_smp_group_3` for + details. + + * Added :kconfig:option:`CONFIG_MCUMGR_GRP_IMG_ALLOW_CONFIRM_NON_ACTIVE_IMAGE_SECONDARY` + and :kconfig:option:`CONFIG_MCUMGR_GRP_IMG_ALLOW_CONFIRM_NON_ACTIVE_IMAGE_ANY` + that allow to control whether MCUmgr client will be allowed to confirm + non-active images. + + * Added :kconfig:option:`CONFIG_MCUMGR_GRP_IMG_ALLOW_ERASE_PENDING` that allows + to erase slots pending for next boot, that are not revert slots. + +* File systems + + * Added support for ext2 file system. + * Added support of mounting littlefs on the block device from the shell/fs. + * Added alignment parameter to FS_LITTLEFS_DECLARE_CUSTOM_CONFIG macro, it can speed up read/write + operation for SDMMC devices in case when we align buffers on CONFIG_SDHC_BUFFER_ALIGNMENT, + because we can avoid extra copy of data from card bffer to read/prog buffer. + HALs **** diff --git a/scripts/requirements-doc.txt b/doc/requirements.txt similarity index 81% rename from scripts/requirements-doc.txt rename to doc/requirements.txt index 691466759d5c..2d90048e16f9 100644 --- a/scripts/requirements-doc.txt +++ b/doc/requirements.txt @@ -1,8 +1,8 @@ # DOC: used to generate docs breathe>=4.34 -sphinx~=5.0,!=5.2.0.post0 -sphinx_rtd_theme~=1.0 +sphinx~=6.2 +sphinx_rtd_theme~=1.2 sphinx-tabs sphinxcontrib-svg2pdfconverter pygments>=2.9 diff --git a/doc/services/index.rst b/doc/services/index.rst index 8b9e94092b24..6ba8af68a673 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -22,6 +22,7 @@ OS Services notify.rst pm/index.rst portability/index.rst + poweroff.rst shell/index.rst settings/index.rst smf/index.rst diff --git a/doc/services/poweroff.rst b/doc/services/poweroff.rst new file mode 100644 index 000000000000..a37c4a23b1b8 --- /dev/null +++ b/doc/services/poweroff.rst @@ -0,0 +1,6 @@ +.. _poweroff: + +Power off +######### + +.. doxygengroup:: sys_poweroff diff --git a/drivers/disk/flashdisk.c b/drivers/disk/flashdisk.c index 6336ad4dfd03..3e43716c2b3c 100644 --- a/drivers/disk/flashdisk.c +++ b/drivers/disk/flashdisk.c @@ -420,6 +420,8 @@ static const struct disk_operations flash_disk_ops = { .ioctl = disk_flash_access_ioctl, }; +#ifndef USE_PARTITION_MANAGER +/* The non-Partition manager, DTS based generators below */ #define DT_DRV_COMPAT zephyr_flash_disk #define PARTITION_PHANDLE(n) DT_PHANDLE_BY_IDX(DT_DRV_INST(n), partition, 0) @@ -461,6 +463,82 @@ DT_INST_FOREACH_STATUS_OKAY(VERIFY_CACHE_SIZE_IS_NOT_ZERO_IF_NOT_READ_ONLY) "Devicetree node " DT_NODE_PATH(DT_DRV_INST(n)) \ " has cache size which is not a multiple of its sector size"); DT_INST_FOREACH_STATUS_OKAY(VERIFY_CACHE_SIZE_IS_MULTIPLY_OF_SECTOR_SIZE) +#else /* ifndef USE_PARTITION_MANAGER */ +/* Partition Manager based generators below */ + +/* Gets the PM_..._EXTRA_PARAM_##param value */ +#define PM_FLASH_DISK_ENTRY_EXTRA_PARAM(name, param) PM_##name##_EXTRA_PARAM_disk_##param + +/* Gets the PM_..._NAME value which is originally cased, as in yaml, partition name */ +#define PM_FLASH_DISK_ENTRY_PARTITION_NAME(name) PM_##name##_NAME + +/* Generates flashdiskN_cache variable name, where N is partition ID */ +#define PM_FLASH_DISK_CACHE_VARIABLE(n) UTIL_CAT(flashdisk, UTIL_CAT(FIXED_PARTITION_ID(n), _cache)) + +/* Generate cache buffers */ +#define CACHE_SIZE(n) (COND_CODE_1(PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, read_only), (0), (1)) * \ + PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, cache_size)) +#define DEFINE_FLASHDISKS_CACHE(n) \ + static uint8_t __aligned(4) PM_FLASH_DISK_CACHE_VARIABLE(n)[CACHE_SIZE(n)]; + +PM_FOREACH_AFFILIATED_TO_disk(DEFINE_FLASHDISKS_CACHE) + +/* Generated single Flash Disk device data from Partition Manager partition. + * Partition is required to have type set to disk in partition definitions: + * type: disk + * and following extra params can be provided: + * extra_params: { + * name = "", + * cache_size = , + * sector_size = , + * read_only = + * } + * where: + * is mandatory device name that will be used by Disk Access and FAT FS to mount device; + * is cache r/w cache size, which is mandatory if read_only = 0 or not present, + * and should be multiple of ; + * is mandatory device sector size information, usually should be erase page size, + * for flash devices, for example 4096 bytes; + * read_only is optional, if not present then assumed false; can be 0(false) or 1(true). + */ +#define DEFINE_FLASHDISKS_DEVICE(n) \ +{ \ + .info = { \ + .ops = &flash_disk_ops, \ + .name = STRINGIFY(PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, name)), \ + }, \ + .area_id = FIXED_PARTITION_ID(n), \ + .offset = FIXED_PARTITION_OFFSET(n), \ + .cache = PM_FLASH_DISK_CACHE_VARIABLE(n), \ + .cache_size = sizeof(PM_FLASH_DISK_CACHE_VARIABLE(n)), \ + .size = FIXED_PARTITION_SIZE(n), \ + .sector_size = PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, sector_size), \ +}, + +/* The bellow used PM_FOREACH_TYPE_disk is generated by Partition Manager foreach + * loop macro. The lower case _disk is type name for which the macro has been generated; + * partition entry can have multiple types set and foreach macro will be generated + * for every type found across partition definitions. + */ +static struct flashdisk_data flash_disks[] = { + PM_FOREACH_AFFILIATED_TO_disk(DEFINE_FLASHDISKS_DEVICE) +}; + +#define VERIFY_CACHE_SIZE_IS_NOT_ZERO_IF_NOT_READ_ONLY(n) \ + COND_CODE_1(PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, read_only), \ + (/* cache-size is not used for read-only disks */), \ + (BUILD_ASSERT(PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, cache_size) != 0, \ + "Flash disk partition " STRINGIFY(PM_FLASH_DISK_ENTRY_PARTITION_NAME(n))\ + " must have non-zero cache-size");)) +PM_FOREACH_AFFILIATED_TO_disk(VERIFY_CACHE_SIZE_IS_NOT_ZERO_IF_NOT_READ_ONLY) + +#define VERIFY_CACHE_SIZE_IS_MULTIPLY_OF_SECTOR_SIZE(n) \ + BUILD_ASSERT(PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, cache_size) % \ + PM_FLASH_DISK_ENTRY_EXTRA_PARAM(n, sector_size) == 0, \ + "Devicetree node " STRINGIFY(PM_FLASH_DISK_ENTRY_PARTITION_NAME(n)) \ + " has cache size which is not a multiple of its sector size"); +PM_FOREACH_AFFILIATED_TO_disk(VERIFY_CACHE_SIZE_IS_MULTIPLY_OF_SECTOR_SIZE) +#endif /* USE_PARTITION_MANAGER */ static int disk_flash_init(void) { diff --git a/drivers/entropy/Kconfig.psa_crypto b/drivers/entropy/Kconfig.psa_crypto index 50f315090040..455a2c9b55bc 100644 --- a/drivers/entropy/Kconfig.psa_crypto +++ b/drivers/entropy/Kconfig.psa_crypto @@ -8,6 +8,7 @@ config ENTROPY_PSA_CRYPTO_RNG depends on BUILD_WITH_TFM depends on DT_HAS_ZEPHYR_PSA_CRYPTO_RNG_ENABLED select ENTROPY_HAS_DRIVER + select PSA_WANT_GENERATE_RANDOM default y help Enable the PSA Crypto source Entropy driver. diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index fa433d1044b9..f38492a41d1d 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -37,6 +37,11 @@ LOG_MODULE_REGISTER(flash_nrf); #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER +#include +#include +#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER */ + #ifndef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE #define FLASH_SLOT_WRITE 7500 #if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) @@ -137,6 +142,12 @@ static int flash_nrf_read(const struct device *dev, off_t addr, return 0; } +#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER && PM_APP_ADDRESS + if (addr < PM_APP_ADDRESS) { + return soc_secure_mem_read(data, (void *)addr, len); + } +#endif + nrf_nvmc_buffer_read(data, (uint32_t)addr, len); return 0; diff --git a/drivers/ieee802154/Kconfig.nrf5 b/drivers/ieee802154/Kconfig.nrf5 index 3ab0d19c3991..9acb811e6b60 100644 --- a/drivers/ieee802154/Kconfig.nrf5 +++ b/drivers/ieee802154/Kconfig.nrf5 @@ -88,4 +88,10 @@ config IEEE802154_NRF5_LOG_RX_FAILURES It can be helpful for the network traffic analyze but it generates also a lot of log records in a stress environment. +config IEEE802154_NRF5_MULTIPLE_CCA + bool "Support for multiple CCA attempts before transmission" + help + When this option is enabled the OpenThread capability + IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA is supported by the ieee802154_nrf5. + endif diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index f11c1953c2c7..9639f3071bd1 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -1,7 +1,7 @@ /* ieee802154_nrf5.c - nRF5 802.15.4 driver */ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,6 +34,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #if defined(CONFIG_NET_L2_OPENTHREAD) #include +#include #endif #include @@ -229,7 +230,11 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? IEEE802154_HW_TXTIME : 0UL) | ((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? IEEE802154_HW_RXTIME : 0UL) | IEEE802154_HW_SLEEP_TO_TX | - ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL); + ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA +#endif + ; } /* Radio device API */ @@ -546,8 +551,32 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) return result; } -static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) +static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, + uint8_t *payload, enum ieee802154_tx_mode mode) { + bool cca = false; +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + uint8_t max_extra_cca_attempts = 0; +#endif + + switch (mode) { + case IEEE802154_TX_MODE_TXTIME: + break; + case IEEE802154_TX_MODE_TXTIME_CCA: + cca = true; + break; +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA: + cca = true; + max_extra_cca_attempts = nrf5_data.max_extra_cca_attempts; + break; +#endif + break; + default: + __ASSERT_NO_MSG(false); + return false; + } + nrf_802154_transmit_at_metadata_t metadata = { .frame_props = { .is_secured = net_pkt_ieee802154_frame_secured(pkt), @@ -561,6 +590,9 @@ static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) .power = net_pkt_ieee802154_txpwr(pkt), #endif }, +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + .extra_cca_attempts = max_extra_cca_attempts, +#endif }; uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); @@ -600,9 +632,11 @@ static int nrf5_tx(const struct device *dev, #if defined(CONFIG_NET_PKT_TXTIME) case IEEE802154_TX_MODE_TXTIME: case IEEE802154_TX_MODE_TXTIME_CCA: +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA: +#endif __ASSERT_NO_MSG(pkt); - ret = nrf5_tx_at(pkt, nrf5_radio->tx_psdu, - mode == IEEE802154_TX_MODE_TXTIME_CCA); + ret = nrf5_tx_at(nrf5_radio, pkt, nrf5_radio->tx_psdu, mode); break; #endif /* CONFIG_NET_PKT_TXTIME */ default: @@ -973,6 +1007,14 @@ static int nrf5_configure(const struct device *dev, break; #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS: + nrf5_data.max_extra_cca_attempts = + ((const struct ieee802154_openthread_config *)config) + ->max_extra_cca_attempts; + break; +#endif /* CONFIG_IEEE802154_NRF5_MULTIPLE_CCA */ + default: return -EINVAL; } @@ -980,6 +1022,32 @@ static int nrf5_configure(const struct device *dev, return 0; } +static int nrf5_attr_get(const struct device *dev, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(value); + + switch ((uint32_t)attr) { +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + /* TODO: t_recca and t_ccatx should be provided by the public API of the + * nRF 802.15.4 Radio Driver. + */ + case IEEE802154_OPENTHREAD_ATTR_T_RECCA: + ((struct ieee802154_openthread_attr_value *)value)->t_recca = 0; + break; + case IEEE802154_OPENTHREAD_ATTR_T_CCATX: + ((struct ieee802154_openthread_attr_value *)value)->t_ccatx = 20; + break; +#endif + default: + return -ENOENT; + } + + return 0; +} + /* nRF5 radio driver callbacks */ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, uint64_t time) @@ -1127,15 +1195,13 @@ void nrf_802154_cca_failed(nrf_802154_cca_error_t error) k_sem_give(&nrf5_data.cca_wait); } -void nrf_802154_energy_detected(uint8_t result) +void nrf_802154_energy_detected(const nrf_802154_energy_detected_t *result) { if (nrf5_data.energy_scan_done != NULL) { - int16_t dbm; energy_scan_done_cb_t callback = nrf5_data.energy_scan_done; nrf5_data.energy_scan_done = NULL; - dbm = nrf_802154_dbm_from_energy_level_calculate(result); - callback(net_if_get_device(nrf5_data.iface), dbm); + callback(net_if_get_device(nrf5_data.iface), result->ed_dbm); } } @@ -1179,6 +1245,7 @@ static struct ieee802154_radio_api nrf5_radio_api = { .get_time = nrf5_get_time, .get_sch_acc = nrf5_get_acc, .configure = nrf5_configure, + .attr_get = nrf5_attr_get }; #if defined(CONFIG_NET_L2_IEEE802154) diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index b5a39ce8dfd5..ffb0eca77b89 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -1,7 +1,7 @@ /* ieee802154_nrf5.h - nRF5 802.15.4 driver */ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -89,6 +89,11 @@ struct nrf5_802154_data { /* Indicates if currently processed TX frame has dynamic data updated. */ bool tx_frame_mac_hdr_rdy; + +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + /* The maximum number of extra CCA attempts to be performed before transmission. */ + uint8_t max_extra_cca_attempts; +#endif }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 1b13572dddd4..1a671aaf731d 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -198,13 +198,7 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel, * and till that moment, it ignores any start requests, * so ensure here that it is stopped. */ - /* TODO: Remove nrfy_pwm_events_process() that is temporarly - * added as a workaround for missing functionality in - * nrfx_pwm_stopped_check() - */ - while (!nrfx_pwm_stopped_check(&config->pwm) && - !nrfy_pwm_events_process(config->pwm.p_reg, - NRFY_EVENT_TO_INT_BITMASK(NRF_PWM_EVENT_STOPPED))) { + while (!nrfx_pwm_stopped_check(&config->pwm)) { } } diff --git a/drivers/sensor/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/qdec_nrfx/qdec_nrfx.c index c8c053f29af3..7d8f71cede20 100644 --- a/drivers/sensor/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/qdec_nrfx/qdec_nrfx.c @@ -135,6 +135,13 @@ static void qdec_nrfx_event_handler(nrfx_qdec_event_t event, void *p_context) unsigned int key; switch (event.type) { + case NRF_QDEC_EVENT_SAMPLERDY: + /* The underlying HAL driver may improperly forward an samplerdy event even if it's + * disabled in the configuration. Ignore the event to prevent error logs until the + * issue is fixed in HAL. + */ + break; + case NRF_QDEC_EVENT_REPORTRDY: accumulate(dev_data, event.data.report.acc); diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index 75a8745c7d97..825572f3c6d7 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -131,6 +131,9 @@ static int configure(const struct device *dev, config.mode = get_nrf_spi_mode(spi_cfg->operation); config.bit_order = get_nrf_spi_bit_order(spi_cfg->operation); + nrf_gpio_pin_write(nrf_spi_sck_pin_get(dev_config->spi.p_reg), + spi_cfg->operation & SPI_MODE_CPOL ? 1 : 0); + if (dev_data->initialized) { nrfx_spi_uninit(&dev_config->spi); dev_data->initialized = false; diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 89a0235d9d38..ed5b7aefc294 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -173,6 +173,9 @@ static int configure(const struct device *dev, config.mode = get_nrf_spim_mode(spi_cfg->operation); config.bit_order = get_nrf_spim_bit_order(spi_cfg->operation); + nrfy_gpio_pin_write(nrfy_spim_sck_pin_get(dev_config->spim.p_reg), + spi_cfg->operation & SPI_MODE_CPOL ? 1 : 0); + if (dev_data->initialized) { nrfx_spim_uninit(&dev_config->spim); dev_data->initialized = false; diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 88e214548686..7f2908b7bc09 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -388,7 +388,9 @@ static int esp32_wifi_connect(const struct device *dev, return 0; } -static int esp32_wifi_scan(const struct device *dev, scan_result_cb_t cb) +static int esp32_wifi_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct esp32_wifi_runtime *data = dev->data; int ret = 0; @@ -402,6 +404,11 @@ static int esp32_wifi_scan(const struct device *dev, scan_result_cb_t cb) wifi_scan_config_t scan_config = { 0 }; + if (params) { + /* The enum values are same, so, no conversion needed */ + scan_config->scan_type = params->scan_type; + } + ret = esp_wifi_set_mode(ESP32_WIFI_MODE_STA); ret |= esp_wifi_scan_start(&scan_config, false); @@ -547,7 +554,9 @@ static void esp32_wifi_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct esp32_wifi_runtime *dev_data = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; esp32_wifi_iface = iface; dev_data->state = ESP32_STA_STOPPED; @@ -615,18 +624,22 @@ static int esp32_wifi_dev_init(const struct device *dev) return 0; } +static const struct wifi_mgmt_ops esp32_wifi_mgmt = { + .scan = esp32_wifi_scan, + .connect = esp32_wifi_connect, + .disconnect = esp32_wifi_disconnect, + .ap_enable = esp32_wifi_ap_enable, + .ap_disable = esp32_wifi_ap_disable, + .iface_status = esp32_wifi_status, +#if defined(CONFIG_NET_STATISTICS_WIFI) + .get_stats = esp32_wifi_stats, +#endif +}; + static const struct net_wifi_mgmt_offload esp32_api = { - .wifi_iface.iface_api.init = esp32_wifi_init, + .wifi_iface.iface_api.init = esp32_wifi_init, .wifi_iface.send = esp32_wifi_send, -#if defined(CONFIG_NET_STATISTICS_WIFI) - .get_stats = esp32_wifi_stats, - #endif - .scan = esp32_wifi_scan, - .connect = esp32_wifi_connect, - .disconnect = esp32_wifi_disconnect, - .ap_enable = esp32_wifi_ap_enable, - .ap_disable = esp32_wifi_ap_disable, - .iface_status = esp32_wifi_status, + .wifi_mgmt_api = &esp32_wifi_mgmt, }; NET_DEVICE_DT_INST_DEFINE(0, diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 316a804f5494..6cd41709096d 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -899,10 +899,14 @@ static void esp_mgmt_scan_work(struct k_work *work) dev->scan_cb = NULL; } -static int esp_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int esp_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct esp_data *data = dev->data; + ARG_UNUSED(params); + if (data->scan_cb != NULL) { return -EINPROGRESS; } @@ -1215,14 +1219,24 @@ static void esp_iface_init(struct net_if *iface) esp_offload_init(iface); } +static enum offloaded_net_if_types esp_offload_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +static const struct wifi_mgmt_ops esp_mgmt_ops = { + .scan = esp_mgmt_scan, + .connect = esp_mgmt_connect, + .disconnect = esp_mgmt_disconnect, + .ap_enable = esp_mgmt_ap_enable, + .ap_disable = esp_mgmt_ap_disable, + .iface_status = esp_mgmt_iface_status, +}; + static const struct net_wifi_mgmt_offload esp_api = { .wifi_iface.iface_api.init = esp_iface_init, - .scan = esp_mgmt_scan, - .connect = esp_mgmt_connect, - .disconnect = esp_mgmt_disconnect, - .ap_enable = esp_mgmt_ap_enable, - .ap_disable = esp_mgmt_ap_disable, - .iface_status = esp_mgmt_iface_status, + .wifi_iface.get_type = esp_offload_get_type, + .wifi_mgmt_api = &esp_mgmt_ops, }; static int esp_init(const struct device *dev); diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index ad8976aee3aa..b05c980500d0 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -520,10 +520,14 @@ int eswifi_mgmt_iface_status(const struct device *dev, return 0; } -static int eswifi_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int eswifi_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct eswifi_dev *eswifi = dev->data; + ARG_UNUSED(params); + LOG_DBG(""); eswifi_lock(eswifi); @@ -777,14 +781,24 @@ static int eswifi_init(const struct device *dev) return 0; } +static enum offloaded_net_if_types eswifi_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +static const struct wifi_mgmt_ops eswifi_mgmt_api = { + .scan = eswifi_mgmt_scan, + .connect = eswifi_mgmt_connect, + .disconnect = eswifi_mgmt_disconnect, + .ap_enable = eswifi_mgmt_ap_enable, + .ap_disable = eswifi_mgmt_ap_disable, + .iface_status = eswifi_mgmt_iface_status, +}; + static const struct net_wifi_mgmt_offload eswifi_offload_api = { .wifi_iface.iface_api.init = eswifi_iface_init, - .scan = eswifi_mgmt_scan, - .connect = eswifi_mgmt_connect, - .disconnect = eswifi_mgmt_disconnect, - .ap_enable = eswifi_mgmt_ap_enable, - .ap_disable = eswifi_mgmt_ap_disable, - .iface_status = eswifi_mgmt_iface_status, + .wifi_iface.get_type = eswifi_get_type, + .wifi_mgmt_api = &eswifi_mgmt_api, }; NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, eswifi_init, NULL, diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index b75329e49f43..6e89275ee6fc 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -136,11 +136,15 @@ static void simplelink_scan_work_handler(struct k_work *work) } } -static int simplelink_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int simplelink_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { int err; int status; + ARG_UNUSED(params); + /* Cancel any previous scan processing in progress: */ k_work_cancel_delayable(&simplelink_data.work); @@ -263,11 +267,21 @@ static void simplelink_iface_init(struct net_if *iface) } +static enum offloaded_net_if_types simplelink_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +static const struct wifi_mgmt_ops simplelink_mgmt = { + .scan = simplelink_mgmt_scan, + .connect = simplelink_mgmt_connect, + .disconnect = simplelink_mgmt_disconnect, +}; + static const struct net_wifi_mgmt_offload simplelink_api = { .wifi_iface.iface_api.init = simplelink_iface_init, - .scan = simplelink_mgmt_scan, - .connect = simplelink_mgmt_connect, - .disconnect = simplelink_mgmt_disconnect, + .wifi_iface.get_type = simplelink_get_type, + .wifi_mgmt_api = &simplelink_mgmt, }; static int simplelink_init(const struct device *dev) diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 329e18a8a68c..264882936283 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -976,8 +976,12 @@ static void winc1500_thread(void) } } -static int winc1500_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int winc1500_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { + ARG_UNUSED(params); + if (w1500_data.scan_cb) { return -EALREADY; } @@ -1099,13 +1103,22 @@ static void winc1500_iface_init(struct net_if *iface) w1500_data.iface = iface; } +static enum offloaded_net_if_types winc1500_get_wifi_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + +static const struct wifi_mgmt_ops winc1500_mgmt_ops = { + .scan = winc1500_mgmt_scan, + .connect = winc1500_mgmt_connect, + .disconnect = winc1500_mgmt_disconnect, + .ap_enable = winc1500_mgmt_ap_enable, + .ap_disable = winc1500_mgmt_ap_disable, +}; static const struct net_wifi_mgmt_offload winc1500_api = { .wifi_iface.iface_api.init = winc1500_iface_init, - .scan = winc1500_mgmt_scan, - .connect = winc1500_mgmt_connect, - .disconnect = winc1500_mgmt_disconnect, - .ap_enable = winc1500_mgmt_ap_enable, - .ap_disable = winc1500_mgmt_ap_disable, + .wifi_iface.get_type = winc1500_get_wifi_type, + .wifi_mgmt_api = &winc1500_mgmt_ops, }; static int winc1500_init(const struct device *dev) diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index b7abf05f9655..1186d2422d5b 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -5,7 +5,7 @@ / { chosen { - zephyr,entropy = &rng; + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index 7a32c5398db4..1294203f00ac 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -33,7 +33,7 @@ }; chosen { - zephyr,entropy = &rng_hci; + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index d872680fb20e..a2a490ab0b15 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -28,6 +28,7 @@ }; chosen { + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld index 567e213fe6d1..56c5271462f1 100644 --- a/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld @@ -26,6 +26,35 @@ #endif #define RAMABLE_REGION RAM +#if USE_PARTITION_MANAGER + +#include + +#if CONFIG_NCS_IS_VARIANT_IMAGE && defined(PM_S0_ID) +/* We are linking against S1, create symbol containing the flash ID of S0. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S0_ID; + +#else /* ! CONFIG_NCS_IS_VARIANT_IMAGE */ + +#ifdef PM_S1_ID +/* We are linking against S0, create symbol containing the flash ID of S1. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S1_ID; +#endif /* PM_S1_ID */ + +#endif /* CONFIG_NCS_IS_VARIANT_IMAGE */ + +#define ROM_ADDR PM_ADDRESS +#define ROM_SIZE PM_SIZE + +#define RAM_SIZE PM_SRAM_SIZE +#define RAM_ADDR PM_SRAM_ADDRESS + +#else /* ! USE_PARTITION_MANAGER */ + #if !defined(CONFIG_XIP) && (CONFIG_FLASH_SIZE == 0) #define ROM_ADDR RAM_ADDR #else @@ -52,6 +81,23 @@ #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS #endif +#endif /* USE_PARTITION_MANAGER */ + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay) +#define CCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ccm)) +#define CCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ccm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) +#define ITCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_itcm)) +#define ITCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_itcm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +#define DTCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_dtcm)) +#define DTCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_dtcm)) +#endif + #if defined(CONFIG_CUSTOM_SECTION_ALIGN) _region_min_align = CONFIG_CUSTOM_SECTION_MIN_ALIGN_SIZE; #else diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index a6c6d3b0366c..0403a5a69001 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1081,6 +1081,26 @@ void bt_conn_cb_register(struct bt_conn_cb *cb); */ void bt_set_bondable(bool enable); +/** @brief Set/clear the bonding flag for a given connection. + * + * Set/clear the Bonding flag in the Authentication Requirements of + * SMP Pairing Request/Response data for a given connection. + * + * The bonding flag for a given connection cannot be set/cleared if + * security procedures in the SMP module have already started. + * This function can be called only once per connection. + * + * If the bonding flag is not set/cleared for a given connection, + * the value will depend on global configuration which is set using + * bt_set_bondable. + * The default value of the global configuration is defined using + * CONFIG_BT_BONDABLE Kconfig option. + * + * @param conn Connection object. + * @param enable Value allowing/disallowing to be bondable. + */ +int bt_conn_set_bondable(struct bt_conn *conn, bool enable); + /** @brief Allow/disallow remote LE SC OOB data to be used for pairing. * * Set/clear the OOB data flag for LE SC SMP Pairing Request/Response data. diff --git a/include/zephyr/bluetooth/mesh.h b/include/zephyr/bluetooth/mesh.h index eeea9e4bccaa..a4ef70dc6ded 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -48,5 +48,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */ diff --git a/include/zephyr/bluetooth/mesh/statistic.h b/include/zephyr/bluetooth/mesh/statistic.h new file mode 100644 index 000000000000..c5403d2fd546 --- /dev/null +++ b/include/zephyr/bluetooth/mesh/statistic.h @@ -0,0 +1,69 @@ +/** @file + * @brief BLE mesh statistic APIs. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ + +#include + +/** + * @brief Statistic + * @defgroup bt_mesh_stat Statistic + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** The structure that keeps statistics of mesh frames handling. */ +struct bt_mesh_statistic { + /** All received frames passed basic validation and decryption. */ + /** Received frames over advertiser. */ + uint32_t rx_adv; + /** Received frames over loopback. */ + uint32_t rx_loopback; + /** Received frames over proxy. */ + uint32_t rx_proxy; + /** Received over unknown interface. */ + uint32_t rx_uknown; + /** Counter of frames that were initiated to relay over advertiser bearer. */ + uint32_t tx_adv_relay_planned; + /** Counter of frames that succeeded relaying over advertiser bearer. */ + uint32_t tx_adv_relay_succeeded; + /** Counter of frames that were initiated to send over advertiser bearer locally. */ + uint32_t tx_local_planned; + /** Counter of frames that succeeded to send over advertiser bearer locally. */ + uint32_t tx_local_succeeded; + /** Counter of frames that were initiated to send over friend bearer. */ + uint32_t tx_friend_planned; + /** Counter of frames that succeeded to send over friend bearer. */ + uint32_t tx_friend_succeeded; +}; + +/** @brief Get mesh frame handling statistic. + * + * @param st BLE mesh statistic. + */ +void bt_mesh_stat_get(struct bt_mesh_statistic *st); + +/** @brief Reset mesh frame handling statistic. + */ +void bt_mesh_stat_reset(void); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ */ diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h index 35a129b6ad37..36220c1d128f 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -332,6 +332,15 @@ int img_mgmt_state_confirm(void); */ int img_mgmt_vercmp(const struct image_version *a, const struct image_version *b); +#if IS_ENABLED(CONFIG_MCUMGR_GRP_IMG_MUTEX) +/* + * @brief Will reset the image management state back to default (no ongoing upload), + * requires that CONFIG_MCUMGR_GRP_IMG_MUTEX be enabled to allow for mutex + * locking of the image management state object. + */ +void img_mgmt_reset_upload(void); +#endif + #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL /* * @brief Translate IMG mgmt group error code into MCUmgr error code diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h new file mode 100644 index 000000000000..6ee12fb5a612 --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_IMG_MGMT_CLIENT_ +#define H_IMG_MGMT_CLIENT_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Image list flags. + */ +struct mcumgr_image_list_flags { + /** Bootable image */ + bool bootable: 1; + /** Pending update state */ + bool pending: 1; + /** Confirmed image */ + bool confirmed: 1; + /** Active image */ + bool active: 1; + /** Permanent image state */ + bool permanent: 1; +}; + +/** + * @brief Image list data. + */ +struct mcumgr_image_data { + /** Image slot num */ + uint32_t slot_num; + /** Image number */ + uint32_t img_num; + /** Image SHA256 checksum */ + char hash[IMG_MGMT_HASH_LEN]; + /** Image Version */ + char version[IMG_MGMT_VER_MAX_STR_LEN + 1]; + /** Image Flags */ + struct mcumgr_image_list_flags flags; +}; + +/** + * @brief MCUmgr Image list response. + */ +struct mcumgr_image_state { + /** Status */ + enum mcumgr_err_t status; + /** Length of image_list */ + int image_list_length; + /** Image list pointer */ + struct mcumgr_image_data *image_list; +}; + +/** + * @brief MCUmgr Image upload response. + */ +struct mcumgr_image_upload { + /** Status */ + enum mcumgr_err_t status; + /** Reported image offset */ + size_t image_upload_offset; +}; + +/** + * @brief IMG mgmt client upload structure + * + * Structure is used internally by the client + */ +struct img_gr_upload { + /** Image 256-bit hash */ + char sha256[IMG_MGMT_HASH_LEN]; + /** True when Hash is configured, false when not */ + bool hash_initialized; + /** Image size */ + size_t image_size; + /** Image upload offset state */ + size_t offset; + /** Worst case init upload message size */ + size_t upload_header_size; + /** Image slot num */ + uint32_t image_num; +}; + +/** + * @brief IMG mgmt client object. + */ +struct img_mgmt_client { + /** SMP client object */ + struct smp_client_object *smp_client; + /** Image Upload state data for client internal use */ + struct img_gr_upload upload; + /** Client image list buffer size */ + int image_list_length; + /** Image list buffer */ + struct mcumgr_image_data *image_list; + /** Command status */ + int status; +}; + +/** + * @brief Inilialize image group client. + * + * Function initializes image group client for given SMP client using supplied image data. + * + * @param client IMG mgmt client object + * @param smp_client SMP client object + * @param image_list_size Length of image_list buffer. + * @param image_list Image list buffer pointer. + * + */ +void img_mgmt_client_init(struct img_mgmt_client *client, struct smp_client_object *smp_client, + int image_list_size, struct mcumgr_image_data *image_list); + +/** + * @brief Initialize image upload. + * + * @param client IMG mgmt client object + * @param image_size Size of image in bytes. + * @param image_num Image slot Num. + * @param image_hash Pointer to HASH for image must be SHA256 hash of entire upload + * if present (32 bytes). Use NULL when HASH from image is not available. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size, + uint32_t image_num, const char *image_hash); + +/** + * @brief Upload part of image. + * + * @param client IMG mgmt client object + * @param data Pointer to data. + * @param length Length of data + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length, + struct mcumgr_image_upload *res_buf); + +/** + * @brief Write image state. + * + * @param client IMG mgmt client object + * @param hash Pointer to Hash (Needed for test). + * @param confirm Set false for test and true for confirmation. + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ + +int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm, + struct mcumgr_image_state *res_buf); + +/** + * @brief Read image state. + * + * @param client IMG mgmt client object + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf); + +/** + * @brief Erase selected Image Slot + * + * @param client IMG mgmt client object + * @param slot Slot number + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ + +int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot); + +#ifdef __cplusplus +} +#endif + +#endif /* H_IMG_MGMT_CLIENT_ */ diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h new file mode 100644 index 000000000000..12e8abde246c --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_OS_MGMT_CLIENT_ +#define H_OS_MGMT_CLIENT_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief OS mgmt client object + */ +struct os_mgmt_client { + /** SMP client object */ + struct smp_client_object *smp_client; + /** Command status */ + int status; +}; + +/** + * @brief Initialize OS management client. + * + * @param client OS mgmt client object + * @param smp_client SMP client object + * + */ +void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client); + +/** + * @brief Send SMP message for Echo command. + * + * @param client OS mgmt client object + * @param echo_string Echo string + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string); + +/** + * @brief Send SMP Reset command. + * + * @param client OS mgmt client object + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int os_mgmt_client_reset(struct os_mgmt_client *client); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_MGMT_CLIENT_ */ diff --git a/include/zephyr/mgmt/mcumgr/smp/smp_client.h b/include/zephyr/mgmt/mcumgr/smp/smp_client.h new file mode 100644 index 000000000000..88b2af701b09 --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/smp/smp_client.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_CLIENT_ +#define H_SMP_CLIENT_ + +#include +#include +#include +#include +#include + +/** + * @brief SMP client object + */ +struct smp_client_object { + /** Must be the first member. */ + struct k_work work; + /** FIFO for client TX queue */ + struct k_fifo tx_fifo; + /** SMP transport object */ + struct smp_transport *smpt; + /** SMP SEQ */ + uint8_t smp_seq; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize a SMP client object. + * + * @param smp_client The Client to construct. + * @param smp_type SMP transport type for discovering transport object + * + * @return 0 if successful + * @return mcumgr_err_t code on failure + */ +int smp_client_object_init(struct smp_client_object *smp_client, int smp_type); + +/** + * @brief Response callback for SMP send. + * + * @param nb net_buf for response + * @param user_data same user data that was provided as part of the request + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +typedef int (*smp_client_res_fn)(struct net_buf *nb, void *user_data); + +/** + * @brief SMP client response handler. + * + * @param nb response net_buf + * @param res_hdr Parsed SMP header + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int smp_client_single_response(struct net_buf *nb, const struct smp_hdr *res_hdr); + +/** + * @brief Allocate buffer and initialize with SMP header. + * + * @param smp_client SMP client object + * @param group SMP group id + * @param command_id SMP command id + * @param op SMP operation type + * @param version SMP MCUmgr version + * + * @return A newly-allocated buffer net_buf on success + * @return NULL on failure. + */ +struct net_buf *smp_client_buf_allocation(struct smp_client_object *smp_client, uint16_t group, + uint8_t command_id, uint8_t op, + enum smp_mcumgr_version_t version); +/** + * @brief Free a SMP client buffer. + * + * @param nb The net_buf to free. + */ +void smp_client_buf_free(struct net_buf *nb); + +/** + * @brief SMP client data send request. + * + * @param smp_client SMP client object + * @param nb net_buf packet for send + * @param cb Callback for response handler + * @param user_data user defined data pointer which will be returned back to response callback + * @param timeout_in_sec Timeout in seconds for send process. Client will retry transport + * based CONFIG_SMP_CMD_RETRY_TIME + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, + smp_client_res_fn cb, void *user_data, int timeout_in_sec); + +#ifdef __cplusplus +} +#endif + +#endif /* H_SMP_CLIENT_ */ diff --git a/include/zephyr/mgmt/mcumgr/transport/smp.h b/include/zephyr/mgmt/mcumgr/transport/smp.h index 55c9c7b0826e..d8cec6878f79 100644 --- a/include/zephyr/mgmt/mcumgr/transport/smp.h +++ b/include/zephyr/mgmt/mcumgr/transport/smp.h @@ -134,6 +134,35 @@ struct smp_transport { #endif }; +/** + * @brief SMP transport type for client registration + */ +enum smp_transport_type { + /** SMP serial */ + SMP_SERIAL_TRANSPORT = 0, + /** SMP bluetooth */ + SMP_BLUETOOTH_TRANSPORT, + /** SMP shell*/ + SMP_SHELL_TRANSPORT, + /** SMP UDP IPv4 */ + SMP_UDP_IPV4_TRANSPORT, + /** SMP UDP IPv6 */ + SMP_UDP_IPV6_TRANSPORT, + /** SMP user defined type */ + SMP_USER_DEFINED_TRANSPORT +}; + +/** + * @brief SMP Client transport structure + */ +struct smp_client_transport_entry { + sys_snode_t node; + /** Transport structure pointer */ + struct smp_transport *smpt; + /** Transport type */ + int smpt_type; +}; + /** * @brief Initializes a Zephyr SMP transport object. * @@ -162,6 +191,22 @@ void smp_rx_remove_invalid(struct smp_transport *zst, void *arg); */ void smp_rx_clear(struct smp_transport *zst); +/** + * @brief Register a Zephyr SMP transport object for client. + * + * @param entry The transport to construct. + */ +void smp_client_transport_register(struct smp_client_transport_entry *entry); + +/** + * @brief Discover a registered SMP transport client object. + * + * @param smpt_type Type of transport + * + * @return Pointer to registered object. Unknown type return NULL. + */ +struct smp_transport *smp_client_transport_get(int smpt_type); + /** * @} */ diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 216278fd3447..d06a7b23dcd1 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -269,7 +269,7 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, */ struct coap_pending { struct sockaddr addr; - uint32_t t0; + int64_t t0; uint32_t timeout; uint16_t id; uint8_t *data; diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index 34b885d86321..ba7041a038b3 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -34,7 +35,8 @@ extern "C" { /* Connectivity Events */ #define _NET_MGMT_CONN_LAYER NET_MGMT_LAYER(NET_MGMT_LAYER_L2) #define _NET_MGMT_CONN_CODE NET_MGMT_LAYER_CODE(0x207) -#define _NET_MGMT_CONN_BASE (_NET_MGMT_CONN_LAYER | _NET_MGMT_CONN_CODE) +#define _NET_MGMT_CONN_BASE (_NET_MGMT_CONN_LAYER | _NET_MGMT_CONN_CODE | \ + NET_MGMT_EVENT_BIT) #define _NET_MGMT_CONN_IF_EVENT (NET_MGMT_IFACE_BIT | _NET_MGMT_CONN_BASE) enum net_event_ethernet_cmd { @@ -178,6 +180,18 @@ enum conn_mgr_if_flag { */ CONN_MGR_IF_PERSISTENT, + /* No auto-connect + * When set, conn_mgr will not automatically attempt to connect this iface when it reaches + * admin-up. + */ + CONN_MGR_IF_NO_AUTO_CONNECT, + + /* No auto-down + * When set, conn_mgr will not automatically take the iface admin-down when it stops + * trying to connect, even if NET_CONNECTION_MANAGER_AUTO_IF_DOWN is enabled. + */ + CONN_MGR_IF_NO_AUTO_DOWN, + /** @cond INTERNAL_HIDDEN */ /* Total number of flags - must be at the end of the enum */ CONN_MGR_NUM_IF_FLAGS, @@ -409,6 +423,57 @@ int conn_mgr_if_set_timeout(struct net_if *iface, int timeout); */ void conn_mgr_conn_init(void); +/** + * @brief Convenience function that takes all available ifaces into the admin-up state. + * + * Essentially a wrapper for net_if_up. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up calls returned 0, otherwise the first nonzero value + * returned by a net_if_up call. + */ +int conn_mgr_all_if_up(bool skip_ignored); + + +/** + * @brief Convenience function that takes all available ifaces into the admin-down state. + * + * Essentially a wrapper for net_if_down. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_down calls returned 0, otherwise the first nonzero value + * returned by a net_if_down call. + */ +int conn_mgr_all_if_down(bool skip_ignored); + +/** + * @brief Convenience function that takes all available ifaces into the admin-up state, and + * connects those that support connectivity. + * + * Essentially a wrapper for net_if_up and conn_mgr_if_connect. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero + * value returned by either net_if_up or conn_mgr_if_connect. + */ +int conn_mgr_all_if_connect(bool skip_ignored); + +/** + * @brief Convenience function that disconnects all available ifaces that support connectivity + * without putting them into admin-down state (unless auto-down is enabled for the iface). + * + * Essentially a wrapper for net_if_down. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero + * value returned by either net_if_up or conn_mgr_if_connect. + */ +int conn_mgr_all_if_disconnect(bool skip_ignored); + /** * @} */ diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 0807c2be33ec..4f4374f7b5fb 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -347,6 +347,16 @@ enum ethernet_filter_type { /** @endcond */ +/** Types of Ethernet L2 */ +enum ethernet_if_types { + /** IEEE 802.3 Ethernet (default) */ + L2_ETH_IF_TYPE_ETHERNET, + + /** IEEE 802.11 Wi-Fi*/ + L2_ETH_IF_TYPE_WIFI, +} __packed; + + struct ethernet_filter { /** Type of filter */ enum ethernet_filter_type type; @@ -595,6 +605,9 @@ struct ethernet_context { /** Is this context already initialized */ bool is_init : 1; + + /** Types of Ethernet network interfaces */ + enum ethernet_if_types eth_if_type; }; /** @@ -1002,8 +1015,29 @@ static inline int net_eth_get_ptp_port(struct net_if *iface) */ #if defined(CONFIG_NET_L2_PTP) void net_eth_set_ptp_port(struct net_if *iface, int port); +#else +static inline void net_eth_set_ptp_port(struct net_if *iface, int port) +{ + ARG_UNUSED(iface); + ARG_UNUSED(port); +} #endif /* CONFIG_NET_L2_PTP */ +/** + * @brief Check if the Ethernet L2 network interface can perform Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +static inline bool net_eth_type_is_wifi(struct net_if *iface) +{ + const struct ethernet_context *ctx = (struct ethernet_context *) + net_if_l2_data(iface); + + return ctx->eth_if_type == L2_ETH_IF_TYPE_WIFI; +} + /** * @} */ diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index ec8e7f4ae340..1eba2698eaa4 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -115,8 +115,17 @@ enum ieee802154_hw_caps { IEEE802154_HW_SUB_GHZ = BIT(13), /* Sub-GHz radio supported * TODO: Replace with channel page attribute. */ + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing + * the ieee802154_hw_caps type. + */ }; +/** @brief Number of bits used by ieee802154_hw_caps type. */ +#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (14) + +/** @brief This and higher values are specific to the protocol- or driver-specific extensions. */ +#define IEEE802154_HW_CAPS_BITS_PRIV_START IEEE802154_HW_CAPS_BITS_COMMON_COUNT + enum ieee802154_filter_type { IEEE802154_FILTER_TYPE_IEEE_ADDR, IEEE802154_FILTER_TYPE_SHORT_ADDR, @@ -188,6 +197,12 @@ enum ieee802154_tx_mode { * Requires IEEE802154_HW_TXTIME capability. */ IEEE802154_TX_MODE_TXTIME_CCA, + + /** Number of modes defined in ieee802154_tx_mode. */ + IEEE802154_TX_MODE_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_TX_MODE_PRIV_START = IEEE802154_TX_MODE_COMMON_COUNT, }; /** IEEE802.15.4 Frame Pending Bit table address matching mode. */ @@ -296,6 +311,12 @@ enum ieee802154_config_type { * should disable it for all enabled addresses. */ IEEE802154_CONFIG_ENH_ACK_HEADER_IE, + + /** Number of types defined in ieee802154_config_type. */ + IEEE802154_CONFIG_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_CONFIG_PRIV_START = IEEE802154_CONFIG_COMMON_COUNT, }; /** IEEE802.15.4 driver configuration data. */ @@ -376,6 +397,23 @@ struct ieee802154_config { }; }; +/** IEEE 802.15.4 attributes. */ +enum ieee802154_attr { + /** Number of attributes defined in ieee802154_attr. */ + IEEE802154_ATTR_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_ATTR_PRIV_START = IEEE802154_ATTR_COMMON_COUNT, +}; + +/** IEEE 802.15.4 attribute value data. */ +struct ieee802154_attr_value { + union { + /* TODO: Please remove when first attribute is added. */ + uint8_t dummy; + }; +}; + /** * @brief IEEE 802.15.4 radio interface API. * @@ -455,6 +493,15 @@ struct ieee802154_radio_api { * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. */ uint8_t (*get_sch_acc)(const struct device *dev); + + /** Get the value of an attribute. + * If the requested attribute is supported by implementation, this function returns 0 + * and fills appropriate version of union in `value`. + * If requested attribute is not supported, this function returns -ENOENT. + */ + int (*attr_get)(const struct device *dev, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value); }; /* Make sure that the network interface API is properly setup inside diff --git a/include/zephyr/net/ieee802154_radio_openthread.h b/include/zephyr/net/ieee802154_radio_openthread.h new file mode 100644 index 000000000000..56a9bd8de0dd --- /dev/null +++ b/include/zephyr/net/ieee802154_radio_openthread.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief This file extends interface of ieee802154_radio.h for OpenThread. + */ + +#ifndef ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ +#define ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ + +#include + +/** + * OpenThread specific capabilities of ieee802154 driver. + * This type extends @ref ieee802154_hw_caps. + */ +enum ieee802154_openthread_hw_caps { + /** Capability to transmit with @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA + * mode. + */ + IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA = BIT(IEEE802154_HW_CAPS_BITS_PRIV_START), +}; + +enum ieee802154_openthread_tx_mode { + /** + * The @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA mode allows to send + * a scheduled packet if the channel is reported idle after at most + * 1 + max_extra_cca_attempts CCAs performed back-to-back. + * + * This mode is a non-standard experimental OpenThread feature. It allows transmission + * of a packet within a certain time window. + * The earliest transmission time is specified as in the other TXTIME modes: + * When the first CCA reports an idle channel then the first symbol of the packet's SHR + * SHALL be present at the local antenna at the time represented by the scheduled + * TX timestamp (referred to as T_tx below). + * + * If the first CCA reports a busy channel, then additional CCAs up to + * max_extra_cca_attempts will be done until one of them reports an idle channel and + * the packet is sent out or the max number of attempts is reached in which case + * the transmission fails. + * + * The timing of these additional CCAs depends on the capabilities of the driver + * which reports them in the T_recca and T_ccatx driver attributes + * (see @ref IEEE802154_OPENTHREAD_ATTR_T_RECCA and + * @ref IEEE802154_OPENTHREAD_ATTR_T_CCATX). Based on these attributes the upper layer + * can calculate the latest point in time (T_txmax) that the first symbol of the scheduled + * packet's SHR SHALL be present at the local antenna: + * + * T_maxtxdelay = max_extra_cca_attempts * (aCcaTime + T_recca) - T_recca + T_ccatx + * T_txmax = T_tx + T_maxtxdelay + * + * See IEEE 802.15.4-2020, section 11.3, table 11-1 for the definition of aCcaTime. + * + * Drivers implementing this TX mode SHOULD keep T_recca and T_ccatx as short as possible. + * T_ccatx SHALL be less than or equal aTurnaroundTime as defined in ibid., + * section 11.3, table 11-1. + * + * CCA SHALL be executed as defined by the phyCcaMode PHY PIB attribute (see ibid., + * section 11.3, table 11-2). + * + * Requires IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA capability. + */ + IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA = IEEE802154_TX_MODE_PRIV_START +}; + +/** + * OpenThread specific configuration types of ieee802154 driver. + * This type extends @ref ieee802154_config_type. + */ +enum ieee802154_openthread_config_type { + /** Allows to configure extra CCA for transmission requested with mode + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Requires IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA capability. + */ + IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS = IEEE802154_CONFIG_PRIV_START +}; + +/** OpenThread specific configuration data of ieee802154 driver. */ +struct ieee802154_openthread_config { + union { + struct ieee802154_config common; + + /** ``IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS`` + * + * The maximum number of extra CCAs to be performed when transmission is + * requested with mode @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + */ + uint8_t max_extra_cca_attempts; + }; +}; + +/** + * OpenThread specific attributes of ieee802154 driver. + * This type extends @ref ieee802154_attr + */ +enum ieee802154_openthread_attr { + + /** Attribute: Maximum time between consecutive CCAs performed back-to-back. + * + * This is attribute for T_recca parameter mentioned for + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Time is expressed in microseconds. + */ + IEEE802154_OPENTHREAD_ATTR_T_RECCA = IEEE802154_ATTR_PRIV_START, + + /** Attribute: Maximum time between detection of CCA idle channel and the moment of + * start of SHR at the local antenna. + * + * This is attribute for T_ccatx parameter mentioned for + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Time is expressed in microseconds. + */ + IEEE802154_OPENTHREAD_ATTR_T_CCATX +}; + +/** + * OpenThread specific attribute value data of ieee802154 driver. + * This type extends @ref ieee802154_attr_value + */ +struct ieee802154_openthread_attr_value { + union { + struct ieee802154_attr_value common; + + /** @brief Attribute value for @ref IEEE802154_OPENTHREAD_ATTR_T_RECCA */ + uint16_t t_recca; + + /** @brief Attribute value for @ref IEEE802154_OPENTHREAD_ATTR_T_CCATX */ + uint16_t t_ccatx; + + }; +}; + +#endif /* ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ */ diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 222a90026c3d..6bf0ef0bb371 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -145,7 +145,7 @@ struct lwm2m_ctx { */ void *processed_req; -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) || defined(__DOXYGEN__) /** TLS tag is set by client as a reference used when the * LwM2M engine calls tls_credential_(add|delete) */ @@ -182,7 +182,7 @@ struct lwm2m_ctx { */ bool connection_suspended; -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) +#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) || defined(__DOXYGEN__) /** * Flag to indicate that the client is buffering Notifications and Send messages. * True value buffer Notifications and Send messages. @@ -416,7 +416,7 @@ int lwm2m_device_add_err(uint8_t error_code); #define RESULT_UPDATE_FAILED 8 #define RESULT_UNSUP_PROTO 9 -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback for firmware block transfer. * @@ -489,7 +489,7 @@ void lwm2m_firmware_set_cancel_cb_inst(uint16_t obj_inst_id, lwm2m_engine_user_c */ lwm2m_engine_user_cb_t lwm2m_firmware_get_cancel_cb_inst(uint16_t obj_inst_id); -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback to handle firmware update execute events. * @@ -529,7 +529,7 @@ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id #endif -#if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set callback to handle software activation requests @@ -623,7 +623,7 @@ int lwm2m_swmgmt_install_completed(uint16_t obj_inst_id, int error_code); #endif -#if defined(CONFIG_LWM2M_EVENT_LOG_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_EVENT_LOG_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set callback to read log data @@ -1149,23 +1149,23 @@ int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t bufl * * @param[in] pathstr LwM2M path string "obj/obj-inst/res(/res-inst)" * @param[out] str String buffer to copy data into - * @param[in] strlen Length of buffer + * @param[in] buflen Length of buffer * * @return 0 for success or negative in case of error. */ __deprecated -int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen); +int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen); /** * @brief Get resource (instance) value (string) * * @param[in] path LwM2M path as a struct * @param[out] str String buffer to copy data into - * @param[in] strlen Length of buffer + * @param[in] buflen Length of buffer * * @return 0 for success or negative in case of error. */ -int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t strlen); +int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen); /** * @brief Get resource (instance) value (u8) @@ -1911,21 +1911,6 @@ int lwm2m_engine_delete_res_inst(const char *pathstr); */ int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path); -/** - * @brief Update the period of a given service. - * - * Allow the period modification on an existing service created with - * lwm2m_engine_add_service(). - * Example to frequency at which a periodic_service changes it's values : - * lwm2m_engine_update_service(device_periodic_service,5*MSEC_PER_SEC); - * - * @param[in] service Handler of the periodic_service - * @param[in] period_ms New period for the periodic_service (in milliseconds) - * - * @return 0 for success or negative in case of error. - */ -int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms); - /** * @brief Update the period of the device service. * @@ -2239,5 +2224,38 @@ int lwm2m_engine_enable_cache(char const *resource_path, struct lwm2m_time_serie int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache, size_t cache_len); +/** + * @brief Security modes as defined in LwM2M Security object. + */ +enum lwm2m_security_mode_e { + LWM2M_SECURITY_PSK = 0, /**< Pre-Shared Key mode */ + LWM2M_SECURITY_RAW_PK = 1, /**< Raw Public Key mode */ + LWM2M_SECURITY_CERT = 2, /**< Certificate mode */ + LWM2M_SECURITY_NOSEC = 3, /**< NoSec mode */ + LWM2M_SECURITY_CERT_EST = 4, /**< Certificate mode with EST */ +}; + +/** + * @brief Read security mode from selected security object instance. + * + * This data is valid only if RD client is running. + * + * @param ctx Pointer to client context. + * @return int Positive values are @ref lwm2m_security_mode_e, negative error codes otherwise. + */ +int lwm2m_security_mode(struct lwm2m_ctx *ctx); + +/** + * @brief Set default socket options for DTLS connections. + * + * The engine calls this when @ref lwm2m_ctx::set_socketoptions is not overwritten. + * You can call this from the overwritten callback to set extra options after or + * before defaults. + * + * @param ctx Client context + * @return 0 for success or negative in case of error. + */ +int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx); + #endif /* ZEPHYR_INCLUDE_NET_LWM2M_H_ */ /**@} */ diff --git a/include/zephyr/net/mqtt.h b/include/zephyr/net/mqtt.h index aaba49a60e56..3cd628e5c2b0 100644 --- a/include/zephyr/net/mqtt.h +++ b/include/zephyr/net/mqtt.h @@ -350,6 +350,9 @@ struct mqtt_sec_config { /** Indicates the list of security tags to be used for the session. */ sec_tag_t *sec_tag_list; + /** Indicates the preference for enabling TLS session caching. */ + int session_cache; + /** Peer hostname for ceritificate verification. * May be NULL to skip hostname verification. */ @@ -357,6 +360,9 @@ struct mqtt_sec_config { /** Indicates the preference for copying certificates to the heap. */ int cert_nocopy; + + /** Set socket to native TLS */ + bool set_native_tls; }; /** @brief MQTT transport type. */ diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index cedfe9f1db51..16f104b501f3 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -1208,6 +1208,29 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr); __syscall bool net_if_ipv6_addr_rm_by_index(int index, const struct in6_addr *addr); +/** + * @typedef net_if_ip_addr_cb_t + * @brief Callback used while iterating over network interface IP addresses + * + * @param iface Pointer to the network interface the address belongs to + * @param addr Pointer to current IP address + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_if_ip_addr_cb_t)(struct net_if *iface, + struct net_if_addr *addr, + void *user_data); + +/** + * @brief Go through all IPv6 addresses on a network interface and call callback + * for each used address. + * + * @param iface Pointer to the network interface + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_if_ipv6_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data); + /** * @brief Add a IPv6 multicast address to an interface * @@ -1839,6 +1862,17 @@ __syscall bool net_if_ipv4_addr_add_by_index(int index, __syscall bool net_if_ipv4_addr_rm_by_index(int index, const struct in_addr *addr); +/** + * @brief Go through all IPv4 addresses on a network interface and call callback + * for each used address. + * + * @param iface Pointer to the network interface + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_if_ipv4_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data); + /** * @brief Add a IPv4 multicast address to an interface * @@ -2526,6 +2560,23 @@ int net_if_resume(struct net_if *iface); bool net_if_is_suspended(struct net_if *iface); #endif /* CONFIG_NET_POWER_MANAGEMENT */ +/** + * @brief Check if the network interface supports Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +bool net_if_is_wifi(struct net_if *iface); + +/** + * @brief Get first Wi-Fi network interface. + * + * @return Pointer to network interface, NULL if not found. + */ +struct net_if *net_if_get_first_wifi(void); + + /** @cond INTERNAL_HIDDEN */ struct net_if_api { void (*init)(struct net_if *iface); diff --git a/include/zephyr/net/net_l2.h b/include/zephyr/net/net_l2.h index dc443e0a3f54..7f221f913671 100644 --- a/include/zephyr/net/net_l2.h +++ b/include/zephyr/net/net_l2.h @@ -99,7 +99,7 @@ NET_L2_DECLARE_PUBLIC(DUMMY_L2); #if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_SOCKETS_OFFLOAD) #define OFFLOADED_NETDEV_L2 OFFLOADED_NETDEV NET_L2_DECLARE_PUBLIC(OFFLOADED_NETDEV_L2); -#endif /* CONFIG_NET_L2_ETHERNET */ +#endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_SOCKETS_OFFLOAD */ #ifdef CONFIG_NET_L2_ETHERNET #define ETHERNET_L2 ETHERNET diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 0ffd066981ad..d540a91d9ffa 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -1275,6 +1275,37 @@ static inline bool net_pkt_filter_recv_ok(struct net_pkt *pkt) #endif /* CONFIG_NET_PKT_FILTER */ +#if defined(CONFIG_NET_PKT_FILTER) && \ + (defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK)) + +bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt); + +#else + +static inline bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return true; +} + +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + +#if defined(CONFIG_NET_PKT_FILTER) && defined(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK) + +bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt); + +#else + +static inline bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return true; +} + +#endif /* CONFIG_NET_PKT_FILTER && CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + /* @endcond */ /** diff --git a/include/zephyr/net/net_pkt_filter.h b/include/zephyr/net/net_pkt_filter.h index 735352253000..aa1ad89b0e61 100644 --- a/include/zephyr/net/net_pkt_filter.h +++ b/include/zephyr/net/net_pkt_filter.h @@ -67,6 +67,12 @@ struct npf_rule_list { extern struct npf_rule_list npf_send_rules; /** @brief rule list applied to incoming packets */ extern struct npf_rule_list npf_recv_rules; +/** @brief rule list applied for local incoming packets */ +extern struct npf_rule_list npf_local_in_recv_rules; +/** @brief rule list applied for IPv4 incoming packets */ +extern struct npf_rule_list npf_ipv4_recv_rules; +/** @brief rule list applied for IPv6 incoming packets */ +extern struct npf_rule_list npf_ipv6_recv_rules; /** * @brief Insert a rule at the front of given rule list @@ -111,6 +117,27 @@ bool npf_remove_all_rules(struct npf_rule_list *rules); #define npf_remove_all_send_rules() npf_remove_all_rules(&npf_send_rules) #define npf_remove_all_recv_rules() npf_remove_all_rules(&npf_recv_rules) +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +#define npf_insert_local_in_recv_rule(rule) npf_insert_rule(&npf_local_in_recv_rules, rule) +#define npf_append_local_in_recv_rule(rule) npf_append_rule(&npf_local_in_recv_rules, rule) +#define npf_remove_local_in_recv_rule(rule) npf_remove_rule(&npf_local_in_recv_rules, rule) +#define npf_remove_all_local_in_recv_rules() npf_remove_all_rules(&npf_local_in_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK +#define npf_insert_ipv4_recv_rule(rule) npf_insert_rule(&npf_ipv4_recv_rules, rule) +#define npf_append_ipv4_recv_rule(rule) npf_append_rule(&npf_ipv4_recv_rules, rule) +#define npf_remove_ipv4_recv_rule(rule) npf_remove_rule(&npf_ipv4_recv_rules, rule) +#define npf_remove_all_ipv4_recv_rules() npf_remove_all_rules(&npf_ipv4_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK +#define npf_insert_ipv6_recv_rule(rule) npf_insert_rule(&npf_ipv6_recv_rules, rule) +#define npf_append_ipv6_recv_rule(rule) npf_append_rule(&npf_ipv6_recv_rules, rule) +#define npf_remove_ipv6_recv_rule(rule) npf_remove_rule(&npf_ipv6_recv_rules, rule) +#define npf_remove_all_ipv6_recv_rules() npf_remove_all_rules(&npf_ipv6_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + /** * @brief Statically define one packet filter rule * @@ -296,6 +323,60 @@ extern npf_test_fn_t npf_size_inbounds; .test.fn = npf_size_inbounds, \ } +/** @cond INTERNAL_HIDDEN */ + +struct npf_test_ip { + struct npf_test test; + uint8_t addr_family; + void *ipaddr; + uint32_t ipaddr_num; +}; + +extern npf_test_fn_t npf_ip_src_addr_match; +extern npf_test_fn_t npf_ip_src_addr_unmatch; + +/** @endcond */ + +/** + * @brief Statically define a "ip address allowlist" packet filter condition + * + * This tests if the packet source ip address matches any of the ip + * addresses contained in the provided set. + * + * @param _name Name of the condition + * @param _ip_addr_array Array of struct in_addr or struct in6_addr items to test + *against + * @param _ip_addr_num number of IP addresses in the array + * @param _af Addresses family type (AF_INET / AF_INET6) in the array + */ +#define NPF_IP_SRC_ADDR_ALLOWLIST(_name, _ip_addr_array, _ip_addr_num, _af) \ + struct npf_test_ip _name = { \ + .addr_family = _af, \ + .ipaddr = (_ip_addr_array), \ + .ipaddr_num = _ip_addr_num, \ + .test.fn = npf_ip_src_addr_match, \ + } + +/** + * @brief Statically define a "ip address blocklist" packet filter condition + * + * This tests if the packet source ip address matches any of the ip + * addresses contained in the provided set. + * + * @param _name Name of the condition + * @param _ip_addr_array Array of struct in_addr or struct in6_addr items to test + *against + * @param _ip_addr_num number of IP addresses in the array + * @param _af Addresses family type (AF_INET / AF_INET6) in the array + */ +#define NPF_IP_SRC_ADDR_BLOCKLIST(_name, _ip_addr_array, _ip_addr_num, _af) \ + struct npf_test_ip _name = { \ + .addr_family = _af, \ + .ipaddr = (_ip_addr_array), \ + .ipaddr_num = _ip_addr_num, \ + .test.fn = npf_ip_src_addr_unmatch, \ + } + /** @} */ /** diff --git a/include/zephyr/net/offloaded_netdev.h b/include/zephyr/net/offloaded_netdev.h index 5f778680ba27..ce90cf77bf37 100644 --- a/include/zephyr/net/offloaded_netdev.h +++ b/include/zephyr/net/offloaded_netdev.h @@ -29,6 +29,21 @@ extern "C" { * @{ */ +/** Types of offloaded netdev L2 */ +enum offloaded_net_if_types { + /** Unknown, device hasn't register a type */ + L2_OFFLOADED_NET_IF_TYPE_UNKNOWN, + + /** Ethernet devices */ + L2_OFFLOADED_NET_IF_TYPE_ETHERNET, + + /** Modem */ + L2_OFFLOADED_NET_IF_TYPE_MODEM, + + /** IEEE 802.11 Wi-Fi */ + L2_OFFLOADED_NET_IF_TYPE_WIFI, +}; + /** * @brief Extended net_if_api for offloaded ifaces/network devices, allowing handling of * admin up/down state changes @@ -42,11 +57,29 @@ struct offloaded_if_api { /** Enable or disable the device (in response to admin state change) */ int (*enable)(const struct net_if *iface, bool state); + + /* Types of offloaded net device */ + enum offloaded_net_if_types (*get_type)(void); }; /* Ensure offloaded_if_api is compatible with net_if_api */ BUILD_ASSERT(offsetof(struct offloaded_if_api, iface_api) == 0); +/** + * @brief Check if the offloaded network interface supports Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +static inline bool net_off_is_wifi_offloaded(struct net_if *iface) +{ + const struct offloaded_if_api *api = (const struct offloaded_if_api *) + net_if_get_device(iface)->api; + + return api->get_type && api->get_type() == L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + /** * @} */ diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index 5a28e42ca3b3..18fbdf108c53 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -139,6 +140,7 @@ struct zsock_pollfd { */ #define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8 #define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9 + /** Socket option for preventing certificates from being copied to the mbedTLS * heap if possible. The option is only effective for DER certificates and is * ignored for PEM certificates. diff --git a/include/zephyr/net/socket_ncs.h b/include/zephyr/net/socket_ncs.h new file mode 100644 index 000000000000..dce37910187f --- /dev/null +++ b/include/zephyr/net/socket_ncs.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ +#define ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ + +/** + * @file + * @brief NCS specific additions to the BSD sockets API definitions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* When CONFIG_NET_SOCKETS_OFFLOAD is enabled, offloaded sockets take precedence + * when creating a new socket. Combine this flag with a socket type when + * creating a socket, to enforce native socket creation (e. g. SOCK_STREAM | SOCK_NATIVE). + * If it's desired to create a native TLS socket, but still offload the + * underlying TCP/UDP socket, use e. g. SOCK_STREAM | SOCK_NATIVE_TLS. + */ +#define SOCK_NATIVE 0x80000000 +#define SOCK_NATIVE_TLS 0x40000000 + +/* NCS specific TLS level socket options */ + +/** Socket option to set DTLS handshake timeout, specifically for nRF sockets. + * The option accepts an integer, indicating the total handshake timeout, + * including retransmissions, in seconds. + * Accepted values for the option are: 1, 3, 7, 15, 31, 63, 123. + */ +#define TLS_DTLS_HANDSHAKE_TIMEO 14 + +/** Socket option to set and get DTLS CID setting, specifically for nRF sockets. + * The option accepts an integer, indicating the setting. + * Accepted vaules for the option are: 0, 1 and 2. + */ +#define TLS_DTLS_CID 17 + +/** Socket option to get DTLS CID status, specifically for nRF sockets. + * The option accepts an integer, indicating the setting. + * Accepted vaules for the option are: 0, 1, 2 and 3. + */ +#define TLS_DTLS_CID_STATUS 18 + +/** Socket option to save DTLS connection, specifically for nRF sockets. + */ +#define TLS_DTLS_CONN_SAVE 19 + +/** Socket option to load DTLS connection, specifically for nRF sockets. + */ +#define TLS_DTLS_CONN_LOAD 20 + +/** Socket option to get result of latest TLS/DTLS completed handshakes end status, + * specifically for nRF sockets. + * The option accepts an integer, indicating the setting. + * Accepted vaules for the option are: 0 and 1. + */ +#define TLS_DTLS_HANDSHAKE_STATUS 21 + +/* Valid values for TLS_SESSION_CACHE option */ +#define TLS_SESSION_CACHE_DISABLED 0 /**< Disable TLS session caching. */ +#define TLS_SESSION_CACHE_ENABLED 1 /**< Enable TLS session caching. */ + +/* Valid values for TLS_DTLS_HANDSHAKE_TIMEO option */ +#define TLS_DTLS_HANDSHAKE_TIMEO_NONE 0 /**< No timeout */ +#define TLS_DTLS_HANDSHAKE_TIMEO_1S 1 /**< 1 second */ +#define TLS_DTLS_HANDSHAKE_TIMEO_3S 3 /**< 1s + 2s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_7S 7 /**< 1s + 2s + 4s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_15S 15 /**< 1s + 2s + 4s + 8s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_31S 31 /**< 1s + 2s + 4s + 8s + 16s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_63S 63 /**< 1s + 2s + 4s + 8s + 16s + 32s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_123S 123 /**< 1s + 2s + 4s + 8s + 16s + 32s + 60s */ + +/* Valid values for TLS_DTLS_CID option */ +#define TLS_DTLS_CID_DISABLED 0 +#define TLS_DTLS_CID_SUPPORTED 1 +#define TLS_DTLS_CID_ENABLED 2 + +/* Valid values for TLS_DTLS_CID_STATUS option */ +#define TLS_DTLS_CID_STATUS_DISABLED 0 +#define TLS_DTLS_CID_STATUS_DOWNLINK 1 +#define TLS_DTLS_CID_STATUS_UPLINK 2 +#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3 + +/* Valid values for TLS_DTLS_HANDSHAKE_STATUS option */ +#define TLS_DTLS_HANDSHAKE_STATUS_FULL 0 +#define TLS_DTLS_HANDSHAKE_STATUS_CACHED 1 + +/* NCS specific socket options */ + +#define SO_RAI_NO_DATA 50 +/** sockopt: Release Assistance Indication feature: This will indicate that the + * next call to send/sendto will be the last one for some time. + */ +#define SO_RAI_LAST 51 +/** sockopt: Release Assistance Indication feature: This will indicate that + * after the next call to send/sendto, the application is expecting to receive + * one more data packet before this socket will not be used again for some time. + */ +#define SO_RAI_ONE_RESP 52 +/** sockopt: Release Assistance Indication feature: If a client application + * expects to use the socket more it can indicate that by setting this socket + * option before the next send call which will keep the network up longer. + */ +#define SO_RAI_ONGOING 53 +/** sockopt: Release Assistance Indication feature: If a server application + * expects to use the socket more it can indicate that by setting this socket + * option before the next send call. + */ +#define SO_RAI_WAIT_MORE 54 + +/* NCS specific IPPROTO_ALL level socket options */ + +/** IPv4 and IPv6 protocol level (pseudo-val) for nRF sockets. */ +#define IPPROTO_ALL 512 +/** sockopt: disable all replies to unexpected traffics */ +#define SO_SILENCE_ALL 30 + +/* NCS specific IPPROTO_IP level socket options */ + +/** sockopt: enable IPv4 ICMP replies */ +#define SO_IP_ECHO_REPLY 31 + +/* NCS specific IPPROTO_IPV6 level socket options */ + +/** sockopt: enable IPv6 ICMP replies */ +#define SO_IPV6_ECHO_REPLY 32 + +/* NCS specific TCP level socket options */ + +/** sockopt: Configurable TCP server session timeout in minutes. + * Range is 0 to 135. 0 is no timeout and 135 is 2 h 15 min. Default is 0 (no timeout). + */ +#define SO_TCP_SRV_SESSTIMEO 55 + +/* NCS specific gettaddrinfo() flags */ + +/** Assume `service` contains a Packet Data Network (PDN) ID. + * When specified together with the AI_NUMERICSERV flag, + * `service` shall be formatted as follows: "port:pdn_id" + * where "port" is the port number and "pdn_id" is the PDN ID. + * Example: "8080:1", port 8080 PDN ID 1. + * Example: "42:0", port 42 PDN ID 0. + */ +#define AI_PDNSERV 0x1000 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ */ diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 75139ae36c48..d70bd06846c5 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -6,7 +6,14 @@ /** * @file - * @brief General WiFi Definitions + * @brief IEEE 802.11 protocol and general Wi-Fi definitions. + */ + +/** + * @defgroup wifi_mgmt Wi-Fi Management + * Wi-Fi Management API. + * @ingroup networking + * @{ */ #ifndef ZEPHYR_INCLUDE_NET_WIFI_H_ @@ -19,17 +26,23 @@ #define WIFI_LISTEN_INTERVAL_MIN 0 #define WIFI_LISTEN_INTERVAL_MAX 65535 -/* Not having support for legacy types is deliberate to enforce - * higher security. - */ +/** IEEE 802.11 security types. */ enum wifi_security_type { + /** No security. */ WIFI_SECURITY_TYPE_NONE = 0, + /** WPA2-PSK security. */ WIFI_SECURITY_TYPE_PSK, + /** WPA2-PSK-SHA256 security. */ WIFI_SECURITY_TYPE_PSK_SHA256, + /** WPA3-SAE security. */ WIFI_SECURITY_TYPE_SAE, + /** GB 15629.11-2003 WAPI security. */ WIFI_SECURITY_TYPE_WAPI, + /** EAP security - Enterprise. */ WIFI_SECURITY_TYPE_EAP, + /** WEP security. */ WIFI_SECURITY_TYPE_WEP, + /** WPA-PSK security. */ WIFI_SECURITY_TYPE_WPA_PSK, __WIFI_SECURITY_TYPE_AFTER_LAST, @@ -37,9 +50,7 @@ enum wifi_security_type { WIFI_SECURITY_TYPE_UNKNOWN }; -/** - * wifi_security_txt - Get the security type as a text string - */ +/** Helper function to get user-friendly security type name. */ static inline const char *wifi_security_txt(enum wifi_security_type security) { switch (security) { @@ -65,10 +76,13 @@ static inline const char *wifi_security_txt(enum wifi_security_type security) } } -/* Management frame protection (IEEE 802.11w) options */ +/** IEEE 802.11w - Management frame protection. */ enum wifi_mfp_options { + /** MFP disabled. */ WIFI_MFP_DISABLE = 0, + /** MFP optional. */ WIFI_MFP_OPTIONAL, + /** MFP required. */ WIFI_MFP_REQUIRED, __WIFI_MFP_AFTER_LAST, @@ -76,9 +90,7 @@ enum wifi_mfp_options { WIFI_MFP_UNKNOWN }; -/** - * wifi_mfp_txt - Get the MFP as a text string - */ +/** Helper function to get user-friendly MFP name.*/ static inline const char *wifi_mfp_txt(enum wifi_mfp_options mfp) { switch (mfp) { @@ -94,19 +106,26 @@ static inline const char *wifi_mfp_txt(enum wifi_mfp_options mfp) } } +/** + * @brief IEEE 802.11 operational frequency bands (not exhaustive). + */ enum wifi_frequency_bands { + /** 2.4 GHz band. */ WIFI_FREQ_BAND_2_4_GHZ = 0, + /** 5 GHz band. */ WIFI_FREQ_BAND_5_GHZ, + /** 6 GHz band (Wi-Fi 6E, also extends to 7GHz). */ WIFI_FREQ_BAND_6_GHZ, + /** Number of frequency bands available. */ __WIFI_FREQ_BAND_AFTER_LAST, + /** Highest frequency band available. */ WIFI_FREQ_BAND_MAX = __WIFI_FREQ_BAND_AFTER_LAST - 1, + /** Invalid frequency band */ WIFI_FREQ_BAND_UNKNOWN }; -/** - * wifi_mode_txt - Get the interface mode type as a text string - */ +/** Helper function to get user-friendly frequency band name. */ static inline const char *wifi_band_txt(enum wifi_frequency_bands band) { switch (band) { @@ -129,17 +148,30 @@ static inline const char *wifi_band_txt(enum wifi_frequency_bands band) #define WIFI_CHANNEL_MAX 233 #define WIFI_CHANNEL_ANY 255 -/* Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc */ +/** Wi-Fi interface states. + * + * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc + */ enum wifi_iface_state { + /** Interface is disconnected. */ WIFI_STATE_DISCONNECTED = 0, + /** Interface is disabled (administratively). */ WIFI_STATE_INTERFACE_DISABLED, + /** No enabled networks in the configuration. */ WIFI_STATE_INACTIVE, + /** Interface is scanning for networks. */ WIFI_STATE_SCANNING, + /** Authentication with a network is in progress. */ WIFI_STATE_AUTHENTICATING, + /** Association with a network is in progress. */ WIFI_STATE_ASSOCIATING, + /** Association with a network completed. */ WIFI_STATE_ASSOCIATED, + /** 4-way handshake with a network is in progress. */ WIFI_STATE_4WAY_HANDSHAKE, + /** Group Key exchange with a network is in progress. */ WIFI_STATE_GROUP_HANDSHAKE, + /** All authentication completed, ready to pass data. */ WIFI_STATE_COMPLETED, __WIFI_STATE_AFTER_LAST, @@ -147,9 +179,7 @@ enum wifi_iface_state { WIFI_STATE_UNKNOWN }; -/** - * wifi_state_txt - Get the connection state name as a text string - */ +/** Helper function to get user-friendly interface state name. */ static inline const char *wifi_state_txt(enum wifi_iface_state state) { switch (state) { @@ -179,13 +209,22 @@ static inline const char *wifi_state_txt(enum wifi_iface_state state) } } -/* Based on https://w1.fi/wpa_supplicant/devel/structwpa__ssid.html#a625821e2acfc9014f3b3de6e6593ffb7 */ +/** Wi-Fi interface modes. + * + * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc + */ enum wifi_iface_mode { + /** Infrastructure station mode. */ WIFI_MODE_INFRA = 0, + /** IBSS (ad-hoc) station mode. */ WIFI_MODE_IBSS = 1, + /** AP mode. */ WIFI_MODE_AP = 2, + /** P2P group owner mode. */ WIFI_MODE_P2P_GO = 3, + /** P2P group formation mode. */ WIFI_MODE_P2P_GROUP_FORMATION = 4, + /** 802.11s Mesh mode. */ WIFI_MODE_MESH = 5, __WIFI_MODE_AFTER_LAST, @@ -193,9 +232,7 @@ enum wifi_iface_mode { WIFI_MODE_UNKNOWN }; -/** - * wifi_mode_txt - Get the interface mode type as a text string - */ +/** Helper function to get user-friendly interface mode name. */ static inline const char *wifi_mode_txt(enum wifi_iface_mode mode) { switch (mode) { @@ -217,16 +254,28 @@ static inline const char *wifi_mode_txt(enum wifi_iface_mode mode) } } -/* As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations */ +/** Wi-Fi link operating modes + * + * As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations. + */ enum wifi_link_mode { + /** 802.11 (legacy). */ WIFI_0 = 0, + /** 802.11b. */ WIFI_1, + /** 802.11a. */ WIFI_2, + /** 802.11g. */ WIFI_3, + /** 802.11n. */ WIFI_4, + /** 802.11ac. */ WIFI_5, + /** 802.11ax. */ WIFI_6, + /** 802.11ax 6GHz. */ WIFI_6E, + /** 802.11be. */ WIFI_7, __WIFI_LINK_MODE_AFTER_LAST, @@ -234,9 +283,7 @@ enum wifi_link_mode { WIFI_LINK_MODE_UNKNOWN }; -/** - * wifi_link_mode_txt - Get the link mode type as a text string - */ +/** Helper function to get user-friendly link mode name. */ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode) { switch (link_mode) { @@ -264,98 +311,150 @@ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode) } } +/** Wi-Fi scanning types. */ +enum wifi_scan_type { + /** Active scanning (default). */ + WIFI_SCAN_TYPE_ACTIVE = 0, + /** Passive scanning. */ + WIFI_SCAN_TYPE_PASSIVE, +}; + +/** Wi-Fi power save states. */ enum wifi_ps { + /** Power save disabled. */ WIFI_PS_DISABLED = 0, + /** Power save enabled. */ WIFI_PS_ENABLED, }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_ps2str[] = { [WIFI_PS_DISABLED] = "Power save disabled", [WIFI_PS_ENABLED] = "Power save enabled", }; +/** @endcond */ +/** Wi-Fi power save modes. */ enum wifi_ps_mode { + /** Legacy power save mode. */ WIFI_PS_MODE_LEGACY = 0, /* This has to be configured before connecting to the AP, * as support for ADDTS action frames is not available. */ + /** WMM power save mode. */ WIFI_PS_MODE_WMM, }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_ps_mode2str[] = { [WIFI_PS_MODE_LEGACY] = "Legacy power save", [WIFI_PS_MODE_WMM] = "WMM power save", }; +/** @endcond */ +/** Wi-Fi Target Wake Time (TWT) operations. */ enum wifi_twt_operation { + /** TWT setup operation */ WIFI_TWT_SETUP = 0, + /** TWT teardown operation */ WIFI_TWT_TEARDOWN, }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_operation2str[] = { [WIFI_TWT_SETUP] = "TWT setup", [WIFI_TWT_TEARDOWN] = "TWT teardown", }; +/** @endcond */ +/** Wi-Fi Target Wake Time (TWT) negotiation types. */ enum wifi_twt_negotiation_type { + /** TWT individual negotiation */ WIFI_TWT_INDIVIDUAL = 0, + /** TWT broadcast negotiation */ WIFI_TWT_BROADCAST, + /** TWT wake TBTT negotiation */ WIFI_TWT_WAKE_TBTT }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_negotiation_type2str[] = { [WIFI_TWT_INDIVIDUAL] = "TWT individual negotiation", [WIFI_TWT_BROADCAST] = "TWT broadcast negotiation", [WIFI_TWT_WAKE_TBTT] = "TWT wake TBTT negotiation", }; +/** @endcond */ +/** Wi-Fi Target Wake Time (TWT) setup commands. */ enum wifi_twt_setup_cmd { - /* TWT Requests */ + /** TWT setup request */ WIFI_TWT_SETUP_CMD_REQUEST = 0, + /** TWT setup suggest (parameters can be changed by AP) */ WIFI_TWT_SETUP_CMD_SUGGEST, + /** TWT setup demand (parameters can not be changed by AP) */ WIFI_TWT_SETUP_CMD_DEMAND, - /* TWT Responses */ + /** TWT setup grouping (grouping of TWT flows) */ WIFI_TWT_SETUP_CMD_GROUPING, + /** TWT setup accept (parameters accepted by AP) */ WIFI_TWT_SETUP_CMD_ACCEPT, + /** TWT setup alternate (alternate parameters suggested by AP) */ WIFI_TWT_SETUP_CMD_ALTERNATE, + /** TWT setup dictate (parameters dictated by AP) */ WIFI_TWT_SETUP_CMD_DICTATE, + /** TWT setup reject (parameters rejected by AP) */ WIFI_TWT_SETUP_CMD_REJECT, }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_twt_setup_cmd2str[] = { - /* TWT Requests */ [WIFI_TWT_SETUP_CMD_REQUEST] = "TWT request", [WIFI_TWT_SETUP_CMD_SUGGEST] = "TWT suggest", [WIFI_TWT_SETUP_CMD_DEMAND] = "TWT demand", - /* TWT Responses */ [WIFI_TWT_SETUP_CMD_GROUPING] = "TWT grouping", [WIFI_TWT_SETUP_CMD_ACCEPT] = "TWT accept", [WIFI_TWT_SETUP_CMD_ALTERNATE] = "TWT alternate", [WIFI_TWT_SETUP_CMD_DICTATE] = "TWT dictate", [WIFI_TWT_SETUP_CMD_REJECT] = "TWT reject", }; +/** @endcond */ +/** Wi-Fi Target Wake Time (TWT) negotiation status. */ enum wifi_twt_setup_resp_status { - /* TWT Setup response status */ + /** TWT response received for TWT request */ WIFI_TWT_RESP_RECEIVED = 0, + /** TWT response not received for TWT request */ WIFI_TWT_RESP_NOT_RECEIVED, }; +/** Target Wake Time (TWT) error codes. */ enum wifi_twt_fail_reason { + /** Unspecified error */ WIFI_TWT_FAIL_UNSPECIFIED, + /** Command execution failed */ WIFI_TWT_FAIL_CMD_EXEC_FAIL, + /** Operation not supported */ WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED, + /** Unable to get interface status */ WIFI_TWT_FAIL_UNABLE_TO_GET_IFACE_STATUS, + /** Device not connected to AP */ WIFI_TWT_FAIL_DEVICE_NOT_CONNECTED, + /** Peer not HE (802.11ax/Wi-Fi 6) capable */ WIFI_TWT_FAIL_PEER_NOT_HE_CAPAB, + /** Peer not TWT capable */ WIFI_TWT_FAIL_PEER_NOT_TWT_CAPAB, + /** A TWT flow is already in progress */ WIFI_TWT_FAIL_OPERATION_IN_PROGRESS, + /** Invalid negotiated flow id */ WIFI_TWT_FAIL_INVALID_FLOW_ID, + /** IP address not assigned or configured */ WIFI_TWT_FAIL_IP_NOT_ASSIGNED, + /** Flow already exists */ + WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; +/** @cond INTERNAL_HIDDEN */ static const char * const twt_err_code_tbl[] = { - [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecfied", + [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecified", [WIFI_TWT_FAIL_CMD_EXEC_FAIL] = "Command Execution failed", [WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED] = "Operation not supported", @@ -371,8 +470,12 @@ static const char * const twt_err_code_tbl[] = { "Invalid negotiated flow id", [WIFI_TWT_FAIL_IP_NOT_ASSIGNED] = "IP address not assigned", + [WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS] = + "Flow already exists", }; +/** @endcond */ +/** Helper function to get user-friendly TWT error code name. */ static inline const char *get_twt_err_code_str(int16_t err_no) { if ((err_no) < (int16_t)ARRAY_SIZE(twt_err_code_tbl)) { @@ -382,49 +485,71 @@ static inline const char *get_twt_err_code_str(int16_t err_no) return ""; } +/** Wi-Fi power save parameters. */ enum ps_param_type { + /** Power save state. */ WIFI_PS_PARAM_STATE, + /** Power save listen interval. */ WIFI_PS_PARAM_LISTEN_INTERVAL, + /** Power save wakeup mode. */ WIFI_PS_PARAM_WAKEUP_MODE, + /** Power save mode. */ WIFI_PS_PARAM_MODE, + /** Power save timeout. */ WIFI_PS_PARAM_TIMEOUT, }; +/** Wi-Fi power save modes. */ enum wifi_ps_wakeup_mode { + /** DTIM based wakeup. */ WIFI_PS_WAKEUP_MODE_DTIM = 0, + /** Listen interval based wakeup. */ WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL, }; +/** @cond INTERNAL_HIDDEN */ static const char * const wifi_ps_wakeup_mode2str[] = { [WIFI_PS_WAKEUP_MODE_DTIM] = "PS wakeup mode DTIM", [WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL] = "PS wakeup mode listen interval", }; +/** @endcond */ +/** Wi-Fi power save error codes. */ enum wifi_config_ps_param_fail_reason { + /** Unspecified error */ WIFI_PS_PARAM_FAIL_UNSPECIFIED, + /** Command execution failed */ WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL, + /** Parameter not supported */ WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED, + /** Unable to get interface status */ WIFI_PS_PARAM_FAIL_UNABLE_TO_GET_IFACE_STATUS, + /** Device not connected to AP */ WIFI_PS_PARAM_FAIL_DEVICE_NOT_CONNECTED, + /** Device already connected to AP */ WIFI_PS_PARAM_FAIL_DEVICE_CONNECTED, + /** Listen interval out of range */ WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID, }; +/** @cond INTERNAL_HIDDEN */ static const char * const ps_param_config_err_code_tbl[] = { - [WIFI_PS_PARAM_FAIL_UNSPECIFIED] = "Unspecfied", + [WIFI_PS_PARAM_FAIL_UNSPECIFIED] = "Unspecified", [WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL] = "Command Execution failed", [WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED] = "Operation not supported", [WIFI_PS_PARAM_FAIL_UNABLE_TO_GET_IFACE_STATUS] = "Unable to get iface status", [WIFI_PS_PARAM_FAIL_DEVICE_NOT_CONNECTED] = - "Can not set while device not connected", + "Cannot set parameters while device not connected", [WIFI_PS_PARAM_FAIL_DEVICE_CONNECTED] = - "Can not set while device already connected", + "Cannot set parameters while device connected", [WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID] = - "Can not set due to invalid range", + "Parameter out of range", }; +/** @endcond */ +/** Helper function to get user-friendly power save error code name. */ static inline const char *get_ps_config_err_code_str(int16_t err_no) { if ((err_no) < (int16_t)ARRAY_SIZE(ps_param_config_err_code_tbl)) { @@ -433,4 +558,8 @@ static inline const char *get_ps_config_err_code_str(int16_t err_no) return ""; } + +/** + * @} + */ #endif /* ZEPHYR_INCLUDE_NET_WIFI_H_ */ diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 8740d6b4bd45..456f93116e65 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -21,6 +21,11 @@ extern "C" { #endif +/** + * @addtogroup wifi_mgmt + * @{ + */ + /* Management part definitions */ #define _NET_WIFI_LAYER NET_MGMT_LAYER_L2 @@ -30,18 +35,37 @@ extern "C" { NET_MGMT_LAYER_CODE(_NET_WIFI_CODE)) #define _NET_WIFI_EVENT (_NET_WIFI_BASE | NET_MGMT_EVENT_BIT) +#ifdef CONFIG_WIFI_MGMT_SCAN_SSID_FILT_MAX +#define WIFI_MGMT_SCAN_SSID_FILT_MAX CONFIG_WIFI_MGMT_SCAN_SSID_FILT_MAX +#else +#define WIFI_MGMT_SCAN_SSID_FILT_MAX 0 +#endif /* CONFIG_WIFI_MGMT_SCAN_SSID_FILT_MAX */ + +/** Wi-Fi management commands */ enum net_request_wifi_cmd { + /** Scan for Wi-Fi networks */ NET_REQUEST_WIFI_CMD_SCAN = 1, + /** Connect to a Wi-Fi network */ NET_REQUEST_WIFI_CMD_CONNECT, + /** Disconnect from a Wi-Fi network */ NET_REQUEST_WIFI_CMD_DISCONNECT, + /** Enable AP mode */ NET_REQUEST_WIFI_CMD_AP_ENABLE, + /** Disable AP mode */ NET_REQUEST_WIFI_CMD_AP_DISABLE, + /** Get interface status */ NET_REQUEST_WIFI_CMD_IFACE_STATUS, + /** Set power save status */ NET_REQUEST_WIFI_CMD_PS, + /** Set power save mode */ NET_REQUEST_WIFI_CMD_PS_MODE, + /** Setup or teardown TWT flow */ NET_REQUEST_WIFI_CMD_TWT, + /** Get power save config */ NET_REQUEST_WIFI_CMD_PS_CONFIG, + /** Set or get regulatory domain */ NET_REQUEST_WIFI_CMD_REG_DOMAIN, + /** Set power save timeout */ NET_REQUEST_WIFI_CMD_PS_TIMEOUT, NET_REQUEST_WIFI_CMD_MAX }; @@ -105,15 +129,27 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_TIMEOUT); +/** Wi-Fi management events */ enum net_event_wifi_cmd { + /** Scan results available */ NET_EVENT_WIFI_CMD_SCAN_RESULT = 1, + /** Scan done */ NET_EVENT_WIFI_CMD_SCAN_DONE, + /** Connect result */ NET_EVENT_WIFI_CMD_CONNECT_RESULT, + /** Disconnect result */ NET_EVENT_WIFI_CMD_DISCONNECT_RESULT, + /** Interface status */ NET_EVENT_WIFI_CMD_IFACE_STATUS, + /** TWT events */ NET_EVENT_WIFI_CMD_TWT, + /** TWT sleep status: awake or sleeping, can be used by application + * to determine if it can send data or not. + */ NET_EVENT_WIFI_CMD_TWT_SLEEP_STATE, + /** Raw scan results available */ NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, + /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, }; @@ -143,96 +179,208 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) -/* Each result is provided to the net_mgmt_event_callback + +/** + * @brief Wi-Fi scan parameters structure. + * Used to specify parameters which can control how the Wi-Fi scan + * is performed. + */ +struct wifi_scan_params { + /** Scan type, see enum wifi_scan_type. + * + * The scan_type is only a hint to the underlying Wi-Fi chip for the + * preferred mode of scan. The actual mode of scan can depend on factors + * such as the Wi-Fi chip implementation support, regulatory domain + * restrictions etc. + */ + enum wifi_scan_type scan_type; + /** Bitmap of bands to be scanned. + * Refer to ::wifi_frequency_bands for bit position of each band. + */ + uint8_t bands; + /** Active scan dwell time (in ms) on a channel. + */ + uint16_t dwell_time_active; + /** Passive scan dwell time (in ms) on a channel. + */ + uint16_t dwell_time_passive; + /** Array of SSID strings to scan. + */ + char ssids[WIFI_MGMT_SCAN_SSID_FILT_MAX][WIFI_SSID_MAX_LEN + 1]; + /** Specifies the maximum number of scan results to return. These results would be the + * BSSIDS with the best RSSI values, in all the scanned channels. This should only be + * used to limit the number of returned scan results, and cannot be counted upon to limit + * the scan time, since the underlying Wi-Fi chip might have to scan all the channels to + * find the max_bss_cnt number of APs with the best signal strengths. A value of 0 + * signifies that there is no restriction on the number of scan results to be returned. + */ + uint16_t max_bss_cnt; + /** Channel information array indexed on Wi-Fi frequency bands and channels within that + * band. + * E.g. to scan channel 6 and 11 on the 2.4 GHz band, channel 36 on the 5 GHz band: + * @code{.c} + * chan[WIFI_FREQ_BAND_2_4_GHZ][0] = 6; + * chan[WIFI_FREQ_BAND_2_4_GHZ][1] = 11; + * chan[WIFI_FREQ_BAND_5_GHZ][0] = 36; + * @endcode + * + * This list specifies the channels to be __considered for scan__. The underlying + * Wi-Fi chip can silently omit some channels due to various reasons such as channels + * not conforming to regulatory restrictions etc. The invoker of the API should + * ensure that the channels specified follow regulatory rules. + */ + uint16_t chan[WIFI_FREQ_BAND_MAX + 1][WIFI_CHANNEL_MAX]; +}; + +/** Wi-Fi scan result, each result is provided to the net_mgmt_event_callback * via its info attribute (see net_mgmt.h) */ struct wifi_scan_result { + /** SSID */ uint8_t ssid[WIFI_SSID_MAX_LEN]; + /** SSID length */ uint8_t ssid_length; - + /** Frequency band */ uint8_t band; + /** Channel */ uint8_t channel; + /** Security type */ enum wifi_security_type security; + /** MFP options */ enum wifi_mfp_options mfp; + /** RSSI */ int8_t rssi; - + /** BSSID */ uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** BSSID length */ uint8_t mac_length; }; +/** Wi-Fi connect request parameters */ struct wifi_connect_req_params { + /** SSID */ const uint8_t *ssid; + /** SSID length */ uint8_t ssid_length; /* Max 32 */ - + /** Pre-shared key */ uint8_t *psk; + /** Pre-shared key length */ uint8_t psk_length; /* Min 8 - Max 64 */ - - uint8_t *sae_password; /* Optional with fallback to psk */ + /** SAE password (same as PSK but with no length restrictions), optional */ + uint8_t *sae_password; + /** SAE password length */ uint8_t sae_password_length; /* No length restrictions */ - + /** Frequency band */ uint8_t band; + /** Channel */ uint8_t channel; + /** Security type */ enum wifi_security_type security; + /** MFP options */ enum wifi_mfp_options mfp; - int timeout; /* SYS_FOREVER_MS for no timeout */ + /** Connect timeout in seconds, SYS_FOREVER_MS for no timeout */ + int timeout; }; +/** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; }; +/** Wi-Fi interface status */ struct wifi_iface_status { - int state; /* enum wifi_iface_state */ + /** Interface state, see enum wifi_iface_state */ + int state; + /** SSID length */ unsigned int ssid_len; + /** SSID */ char ssid[WIFI_SSID_MAX_LEN]; + /** BSSID */ char bssid[WIFI_MAC_ADDR_LEN]; + /** Frequency band */ enum wifi_frequency_bands band; + /** Channel */ unsigned int channel; + /** Interface mode, see enum wifi_iface_mode */ enum wifi_iface_mode iface_mode; + /** Link mode, see enum wifi_link_mode */ enum wifi_link_mode link_mode; + /** Security type, see enum wifi_security_type */ enum wifi_security_type security; + /** MFP options, see enum wifi_mfp_options */ enum wifi_mfp_options mfp; + /** RSSI */ int rssi; + /** DTIM period */ unsigned char dtim_period; + /** Beacon interval */ unsigned short beacon_interval; + /** is TWT capable? */ bool twt_capable; }; +/** Wi-Fi power save parameters */ struct wifi_ps_params { + /* Power save state */ enum wifi_ps enabled; + /* Listen interval */ unsigned short listen_interval; + /** Wi-Fi power save wakeup mode */ enum wifi_ps_wakeup_mode wakeup_mode; + /** Wi-Fi power save mode */ enum wifi_ps_mode mode; - int timeout_ms; + /** Wi-Fi power save timeout + * + * This is the time out to wait after sending a TX packet + * before going back to power save (in ms) to receive any replies + * from the AP. Zero means this feature is disabled. + * + * It's a tradeoff between power consumption and latency. + */ + unsigned int timeout_ms; + /** Wi-Fi power save type */ enum ps_param_type type; + /** Wi-Fi power save fail reason */ enum wifi_config_ps_param_fail_reason fail_reason; }; +/** Wi-Fi TWT parameters */ struct wifi_twt_params { + /** TWT operation, see enum wifi_twt_operation */ enum wifi_twt_operation operation; + /** TWT negotiation type, see enum wifi_twt_negotiation_type */ enum wifi_twt_negotiation_type negotiation_type; + /** TWT setup command, see enum wifi_twt_setup_cmd */ enum wifi_twt_setup_cmd setup_cmd; + /** TWT setup response status, see enum wifi_twt_setup_resp_status */ enum wifi_twt_setup_resp_status resp_status; - /* Map requests to responses */ + /** Dialog token, used to map requests to responses */ uint8_t dialog_token; - /* Map setup with teardown */ + /** Flow ID, used to map setup with teardown */ uint8_t flow_id; union { + /** Setup specific parameters */ struct { - /* Interval = Wake up time + Sleeping time */ + /**Interval = Wake up time + Sleeping time */ uint64_t twt_interval; + /** Requestor or responder */ bool responder; + /** Trigger enabled or disabled */ bool trigger; + /** Implicit or explicit */ bool implicit; + /** Announced or unannounced */ bool announce; - /* Wake up time */ + /** Wake up time */ uint32_t twt_wake_interval; } setup; + /** Teardown specific parameters */ struct { - /* Only for Teardown */ + /** Teardown all flows */ bool teardown_all; } teardown; }; + /** TWT fail reason, see enum wifi_twt_fail_reason */ enum wifi_twt_fail_reason fail_reason; }; @@ -241,114 +389,281 @@ struct wifi_twt_params { #define WIFI_MAX_TWT_INTERVAL_US (LONG_MAX - 1) /* 256 (u8) * 1TU */ #define WIFI_MAX_TWT_WAKE_INTERVAL_US 262144 + +/** Wi-Fi TWT flow information */ struct wifi_twt_flow_info { - /* Interval = Wake up time + Sleeping time */ + /** Interval = Wake up time + Sleeping time */ uint64_t twt_interval; - /* Map requests to responses */ + /** Dialog token, used to map requests to responses */ uint8_t dialog_token; - /* Map setup with teardown */ + /** Flow ID, used to map setup with teardown */ uint8_t flow_id; + /** TWT negotiation type, see enum wifi_twt_negotiation_type */ enum wifi_twt_negotiation_type negotiation_type; + /** Requestor or responder */ bool responder; + /** Trigger enabled or disabled */ bool trigger; + /** Implicit or explicit */ bool implicit; + /** Announced or unannounced */ bool announce; - /* Wake up time */ + /** Wake up time */ uint32_t twt_wake_interval; }; +/** Wi-Fi power save configuration */ struct wifi_ps_config { + /** Number of TWT flows */ char num_twt_flows; + /** TWT flow details */ struct wifi_twt_flow_info twt_flows[WIFI_MAX_TWT_FLOWS]; + /** Power save configuration */ struct wifi_ps_params ps_params; }; -/* Generic get/set operation for any command*/ +/** Generic get/set operation for any command*/ enum wifi_mgmt_op { + /** Get operation */ WIFI_MGMT_GET = 0, + /** Set operation */ WIFI_MGMT_SET = 1, }; +/** Regulatory domain information or configuration */ struct wifi_reg_domain { + /* Regulatory domain operation */ enum wifi_mgmt_op oper; - /* Ignore all other regulatory hints */ + /** Ignore all other regulatory hints over this one */ bool force; + /** Country code: ISO/IEC 3166-1 alpha-2 */ uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; }; +/** Wi-Fi TWT sleep states */ enum wifi_twt_sleep_state { + /** TWT sleep state: sleeping */ WIFI_TWT_STATE_SLEEP = 0, + /** TWT sleep state: awake */ WIFI_TWT_STATE_AWAKE = 1, }; -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS +#if defined(CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS) || defined(__DOXYGEN__) +/** Wi-Fi raw scan result */ struct wifi_raw_scan_result { + /** RSSI */ int8_t rssi; + /** Frame length */ int frame_length; + /** Frequency */ unsigned short frequency; + /** Raw scan data */ uint8_t data[CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH]; }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ #include +/** Scan result callback + * + * @param iface Network interface + * @param status Scan result status + * @param entry Scan result entry + */ typedef void (*scan_result_cb_t)(struct net_if *iface, int status, struct wifi_scan_result *entry); #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS +/** Raw scan result callback + * + * @param iface Network interface + * @param status Raw scan result status + * @param entry Raw scan result entry + */ typedef void (*raw_scan_result_cb_t)(struct net_if *iface, int status, struct wifi_raw_scan_result *entry); #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ -struct net_wifi_mgmt_offload { - /** - * Mandatory to get in first position. - * A network device should indeed provide a pointer on such - * net_if_api structure. So we make current structure pointer - * that can be casted to a net_if_api structure pointer. - */ -#ifdef CONFIG_WIFI_USE_NATIVE_NETWORKING - struct ethernet_api wifi_iface; -#else - struct offloaded_if_api wifi_iface; -#endif - /* cb parameter is the cb that should be called for each - * result by the driver. The wifi mgmt part will take care of - * raising the necessary event etc... +/** Wi-Fi management API */ +struct wifi_mgmt_ops { + /** Scan for Wi-Fi networks + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Scan parameters + * @param cb Callback to be called for each result + * cb parameter is the cb that should be called for each + * result by the driver. The wifi mgmt part will take care of + * raising the necessary event etc. + * + * @return 0 if ok, < 0 if error + */ + int (*scan)(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb); + /** Connect to a Wi-Fi network + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Connect parameters + * + * @return 0 if ok, < 0 if error */ - int (*scan)(const struct device *dev, scan_result_cb_t cb); int (*connect)(const struct device *dev, struct wifi_connect_req_params *params); + /** Disconnect from a Wi-Fi network + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return 0 if ok, < 0 if error + */ int (*disconnect)(const struct device *dev); + /** Enable AP mode + * + * @param dev Pointer to the device structure for the driver instance. + * @param params AP mode parameters + * + * @return 0 if ok, < 0 if error + */ int (*ap_enable)(const struct device *dev, struct wifi_connect_req_params *params); + /** Disable AP mode + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return 0 if ok, < 0 if error + */ int (*ap_disable)(const struct device *dev); + /** Get interface status + * + * @param dev Pointer to the device structure for the driver instance. + * @param status Interface status + * + * @return 0 if ok, < 0 if error + */ int (*iface_status)(const struct device *dev, struct wifi_iface_status *status); -#ifdef CONFIG_NET_STATISTICS_WIFI +#if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) + /** Get Wi-Fi statistics + * + * @param dev Pointer to the device structure for the driver instance. + * @param stats Wi-Fi statistics + * + * @return 0 if ok, < 0 if error + */ int (*get_stats)(const struct device *dev, struct net_stats_wifi *stats); #endif /* CONFIG_NET_STATISTICS_WIFI */ + /** Set power save status + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Power save parameters + * + * @return 0 if ok, < 0 if error + */ int (*set_power_save)(const struct device *dev, struct wifi_ps_params *params); + /** Setup or teardown TWT flow + * + * @param dev Pointer to the device structure for the driver instance. + * @param params TWT parameters + * + * @return 0 if ok, < 0 if error + */ int (*set_twt)(const struct device *dev, struct wifi_twt_params *params); + /** Get power save config + * + * @param dev Pointer to the device structure for the driver instance. + * @param config Power save config + * + * @return 0 if ok, < 0 if error + */ int (*get_power_save_config)(const struct device *dev, struct wifi_ps_config *config); + /** Set or get regulatory domain + * + * @param dev Pointer to the device structure for the driver instance. + * @param reg_domain Regulatory domain + * + * @return 0 if ok, < 0 if error + */ int (*reg_domain)(const struct device *dev, struct wifi_reg_domain *reg_domain); }; +/** Wi-Fi management offload API */ +struct net_wifi_mgmt_offload { + /** + * Mandatory to get in first position. + * A network device should indeed provide a pointer on such + * net_if_api structure. So we make current structure pointer + * that can be casted to a net_if_api structure pointer. + */ +#if defined(CONFIG_WIFI_USE_NATIVE_NETWORKING) || defined(__DOXYGEN__) + /** Ethernet API */ + struct ethernet_api wifi_iface; +#else + /** Offloaded network device API */ + struct offloaded_if_api wifi_iface; +#endif + /** Wi-Fi management API */ + const struct wifi_mgmt_ops *const wifi_mgmt_api; +}; + /* Make sure that the network interface API is properly setup inside * Wifi mgmt offload API struct (it is the first one). */ BUILD_ASSERT(offsetof(struct net_wifi_mgmt_offload, wifi_iface) == 0); +/** Wi-Fi management connect result event + * + * @param iface Network interface + * @param status Connect result status + */ void wifi_mgmt_raise_connect_result_event(struct net_if *iface, int status); + +/** Wi-Fi management disconnect result event + * + * @param iface Network interface + * @param status Disconnect result status + */ void wifi_mgmt_raise_disconnect_result_event(struct net_if *iface, int status); + +/** Wi-Fi management interface status event + * + * @param iface Network interface + * @param iface_status Interface status + */ void wifi_mgmt_raise_iface_status_event(struct net_if *iface, struct wifi_iface_status *iface_status); + +/** Wi-Fi management TWT event + * + * @param iface Network interface + * @param twt_params TWT parameters + */ void wifi_mgmt_raise_twt_event(struct net_if *iface, struct wifi_twt_params *twt_params); + +/** Wi-Fi management TWT sleep state event + * + * @param iface Network interface + * @param twt_sleep_state TWT sleep state + */ void wifi_mgmt_raise_twt_sleep_state(struct net_if *iface, int twt_sleep_state); -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS + +#if defined(CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS) || defined(__DOXYGEN__) +/** Wi-Fi management raw scan result event + * + * @param iface Network interface + * @param raw_scan_info Raw scan result + */ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_info); #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ + +/** Wi-Fi management disconnect complete event + * + * @param iface Network interface + * @param status Disconnect complete status + */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); + +/** + * @} + */ #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/wifi_nm.h b/include/zephyr/net/wifi_nm.h new file mode 100644 index 000000000000..dd97fcdd8b61 --- /dev/null +++ b/include/zephyr/net/wifi_nm.h @@ -0,0 +1,100 @@ +/** @file + * @brief Wi-Fi Network manager API + * + * This file contains the Wi-Fi network manager API. These APIs are used by the + * any network management application to register as a Wi-Fi network manager. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ + +#include +#include +#include +#include +#include +/** + * @brief Wi-Fi Network manager API + * @defgroup wifi_nm Wi-Fi Network Manager API + * @ingroup networking + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief WiFi Network manager instance + */ +struct wifi_nm_instance { + /** Name of the Network manager instance */ + const char *name; + /** Wi-Fi Management operations */ + const struct wifi_mgmt_ops *ops; + /** List of Managed interfaces */ + struct net_if *mgd_ifaces[CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES]; +}; + +#define WIFI_NM_NAME(name) wifi_nm_##name + +#define DEFINE_WIFI_NM_INSTANCE(_name, _ops) \ + static STRUCT_SECTION_ITERABLE(wifi_nm_instance, WIFI_NM_NAME(_name)) = { \ + .name = STRINGIFY(_name), \ + .ops = _ops, \ + .mgd_ifaces = { NULL }, \ + } + +/** + * @brief Get a Network manager instance for a given name + * + * @param name Name of the Network manager instance + * + */ +struct wifi_nm_instance *wifi_nm_get_instance(const char *name); + +/** + * @brief Get a Network manager instance for a given interface + * + * @param iface Interface + * + */ +struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface); + +/** + * @brief Register a managed interface + * + * @param nm Pointer to Network manager instance + * @param iface Managed interface + * + * @retval 0 If successful. + * @retval -EINVAL If invalid parameters were passed. + * @retval -ENOTSUP If the interface is not a Wi-Fi interface. + * @retval -ENOMEM If the maximum number of managed interfaces has been reached. + */ +int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface); + +/** + * @brief Unregister managed interface + * + * @param nm Pointer to Network manager instance + * @param iface Interface + * @return int 0 for OK; -EINVAL for invalid parameters; -ENOENT if interface is not registered + * with the Network manager. + */ +int wifi_nm_unregister_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ */ diff --git a/include/zephyr/net/wifi_utils.h b/include/zephyr/net/wifi_utils.h new file mode 100644 index 000000000000..86b39ff46601 --- /dev/null +++ b/include/zephyr/net/wifi_utils.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * + * @brief Utility functions to be used by the Wi-Fi subsystem. + */ + +#ifndef ZEPHYR_INCLUDE_NET_WIFI_UTILS_H_ +#define ZEPHYR_INCLUDE_NET_WIFI_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup wifi_mgmt + * @{ + */ + +/** + * @name Wi-Fi utility functions. + * + * Utility functions for the Wi-Fi subsystem. + * @{ + */ + +#define WIFI_UTILS_MAX_BAND_STR_LEN 3 +#define WIFI_UTILS_MAX_CHAN_STR_LEN 4 + +/** + * @brief Convert a band specification string to a bitmap representing the bands. + * + * @details The function will parse a string which specifies Wi-Fi frequency band + * values as a comma separated string and convert it to a bitmap. The string can + * use the following characters to represent the bands: + * + * - 2: 2.4 GHz + * - 5: 5 GHz + * - 6: 6 GHz + * + * For the bitmap generated refer to ::wifi_frequency_bands + * for bit position of each band. + * + * E.g. a string "2,5,6" will be converted to a bitmap value of 0x7 + * + * @param scan_bands_str String which spe. + * @param band_map Pointer to the bitmap variable to be updated. + * + * @retval 0 on success. + * @retval -errno value in case of failure. + */ +int wifi_utils_parse_scan_bands(char *scan_bands_str, uint8_t *band_map); + + +/** + * @brief Convert a string containing a list of SSIDs to an array of SSID strings. + * + * @details The function will parse a string which specifies Wi-Fi SSIDs + * as a comma separated string and convert it to an array. + * + * @param scan_ssids_str List of SSIDs expressed as a comma separated list. + * @param ssids Pointer to an array where the parsed SSIDs are to be stored. + * + * @retval 0 on success. + * @retval -errno value in case of failure. + */ +int wifi_utils_parse_scan_ssids(char *scan_ssids_str, + char ssids[][WIFI_SSID_MAX_LEN + 1]); + + +/** + * @brief Convert a string containing a specification of scan channels to an array. + * + * @details The function will parse a string which specifies channels to be scanned + * as a string and convert it to an array. + * + * The channel string has to be formatted using the colon (:), comma(,), hyphen (-) and + * underscore (_) delimiters as follows: + * - A colon identifies the value preceding it as a band. A band value + * (2: 2.4 GHz, 5: 5 GHz 6: 6 GHz) has to precede the channels in that band (e.g. 2: etc) + * - Hyphens (-) are used to identify channel ranges (e.g. 2-7, 32-48 etc) + * - Commas are used to separate channel values within a band. Channels can be specified + * as individual values (2,6,48 etc) or channel ranges using hyphens (1-14, 32-48 etc) + * - Underscores (_) are used to specify multiple band-channel sets (e.g. 2:1,2_5:36,40 etc) + * - No spaces should be used anywhere, i.e. before/after commas, + * before/after hyphens etc. + * + * An example channel specification specifying channels in the 2.4 GHz and 5 GHz bands is + * as below: + * 2:1,5,7,9-11_5:36-48,100,163-167 + * + * @param scan_chan_str List of channels expressed in the format described above. + * @param chan Pointer to an array where the parsed channels are to be stored. + * + * @retval 0 on success. + * @retval -errno value in case of failure. + */ +int wifi_utils_parse_scan_chan(char *scan_chan_str, + uint16_t chan[][WIFI_CHANNEL_MAX]); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* ZEPHYR_INCLUDE_NET_WIFI_UTILS_H_ */ diff --git a/include/zephyr/pm/pm.h b/include/zephyr/pm/pm.h index 9d6b69ad21a3..03062eefd12e 100644 --- a/include/zephyr/pm/pm.h +++ b/include/zephyr/pm/pm.h @@ -167,19 +167,6 @@ static inline int pm_notifier_unregister(struct pm_notifier *notifier) return -ENOSYS; } -static inline void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(state); - ARG_UNUSED(substate_id); -} - -static inline void pm_state_exit_post_ops(enum pm_state state, - uint8_t substate_id) -{ - ARG_UNUSED(state); - ARG_UNUSED(substate_id); -} - static inline const struct pm_state_info *pm_state_next_get(uint8_t cpu) { ARG_UNUSED(cpu); diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index 380e58691e9a..cc4a246105d3 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -271,6 +271,10 @@ const char *flash_area_label(const struct flash_area *fa); */ uint8_t flash_area_erased_val(const struct flash_area *fa); +#if USE_PARTITION_MANAGER +#include +#else + #define FLASH_AREA_LABEL_EXISTS(label) __DEPRECATED_MACRO \ DT_HAS_FIXED_PARTITION_LABEL(label) @@ -343,6 +347,8 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); #define FIXED_PARTITION_DEVICE(label) \ DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODELABEL(label))) +#endif /* USE_PARTITION_MANAGER */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/sys/poweroff.h b/include/zephyr/sys/poweroff.h new file mode 100644 index 000000000000..e9a3dc052153 --- /dev/null +++ b/include/zephyr/sys/poweroff.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_POWEROFF_H_ +#define ZEPHYR_INCLUDE_SYS_POWEROFF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup sys_poweroff System power off + * @ingroup os_services + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief System power off hook. + * + * This function needs to be implemented in platform code. It must only + * perform an immediate power off of the system. + */ +FUNC_NORETURN void z_sys_poweroff(void); + +/** @} */ + +/** @endcond */ + +/** + * @brief Perform a system power off. + * + * This function will perform an immediate power off of the system. It is the + * responsability of the caller to ensure that the system is in a safe state to + * be powered off. Any required wake up sources must be enabled before calling + * this function. + * + * @kconfig{CONFIG_POWEROFF} needs to be enabled to use this API. + */ +FUNC_NORETURN void sys_poweroff(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_POWEROFF_H_ */ diff --git a/lib/libc/common/source/stdlib/malloc.c b/lib/libc/common/source/stdlib/malloc.c index 02354cd194dc..df2d425c0b7a 100644 --- a/lib/libc/common/source/stdlib/malloc.c +++ b/lib/libc/common/source/stdlib/malloc.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -229,6 +230,38 @@ void free(void *ptr) (void) sys_mutex_unlock(&z_malloc_heap_mutex); } +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) +struct mallinfo mallinfo(void) +#else +struct mallinfo2 mallinfo2(void) +#endif /* __GLIBC__ < 2 && (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) */ +{ +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) + struct mallinfo info = { 0 }; +#else + struct mallinfo2 info = { 0 }; +#endif /* __GLIBC__ < 2 && (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) */ +#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS + struct sys_memory_stats stats; + int ret = sys_heap_runtime_stats_get(&z_malloc_heap, &stats); + + if (ret != 0) { + LOG_ERR("Failed to get heap stats"); + return info; + } + + info.arena = stats.free_bytes + stats.allocated_bytes; + info.fordblks = stats.free_bytes; + info.uordblks = stats.allocated_bytes; + info.usmblks = stats.max_allocated_bytes; +#else + ARG_UNUSED(info); + LOG_ERR("CONFIG_SYS_HEAP_RUNTIME_STATS is not enabled"); +#endif + + return info; +} + SYS_INIT(malloc_prepare, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #else /* No malloc arena */ void *malloc(size_t size) @@ -251,6 +284,15 @@ void *realloc(void *ptr, size_t size) ARG_UNUSED(ptr); return malloc(size); } + +struct mallinfo2 mallinfo2(void) +{ + struct mallinfo2 info = { 0 }; + + LOG_ERR("CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE is 0"); + + return info; +} #endif /* else no malloc arena */ #endif /* CONFIG_COMMON_LIBC_MALLOC */ diff --git a/lib/libc/minimal/include/malloc.h b/lib/libc/minimal/include/malloc.h new file mode 100644 index 000000000000..7556d2fd19c3 --- /dev/null +++ b/lib/libc/minimal/include/malloc.h @@ -0,0 +1,35 @@ +/* malloc.h */ + +/* + * Copyright (c) 2023 - Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_MALLOC_H_ +#define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_MALLOC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct mallinfo2 { + size_t arena; /* total space allocated from system */ + size_t ordblks; /* number of non-inuse chunks */ + size_t smblks; /* unused -- always zero */ + size_t hblks; /* number of mmapped regions */ + size_t hblkhd; /* total space in mmapped regions */ + size_t usmblks; /* unused -- always zero */ + size_t fsmblks; /* unused -- always zero */ + size_t uordblks; /* total allocated space */ + size_t fordblks; /* total non-inuse space */ + size_t keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +struct mallinfo2 mallinfo2(void); + +#ifdef __cplusplus +} +#endif +#endif /* ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_MALLOC_H_ */ diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt index c32295e1d271..3bbe8128a1f5 100644 --- a/lib/libc/picolibc/CMakeLists.txt +++ b/lib/libc/picolibc/CMakeLists.txt @@ -13,7 +13,7 @@ if(NOT CONFIG_PICOLIBC_USE_MODULE) zephyr_compile_options(--specs=picolibc.specs) zephyr_compile_definitions(_POSIX_C_SOURCE=200809) - zephyr_libc_link_libraries(-T/dev/null --specs=picolibc.specs c -lgcc) + zephyr_libc_link_libraries(--specs=picolibc.specs c -lgcc) if(CONFIG_PICOLIBC_IO_FLOAT) zephyr_compile_definitions(PICOLIBC_DOUBLE_PRINTF_SCANF) zephyr_link_libraries(-DPICOLIBC_DOUBLE_PRINTF_SCANF) diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index ac542223b934..f92b0d6e98e9 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -68,6 +68,8 @@ zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) +zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) + zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/${ARCH}/include diff --git a/lib/os/Kconfig b/lib/os/Kconfig index adb67a510701..5f84c6781b82 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -166,6 +166,17 @@ config REBOOT needed to perform a "safe" reboot (e.g. to stop the system clock before issuing a reset). +config HAS_POWEROFF + bool + help + Option to signal that power off functionality is implemented. + +config POWEROFF + bool "Power off functionality" + depends on HAS_POWEROFF + help + Enable support for system power off. + config UTF8 bool "UTF-8 string operation supported" help diff --git a/lib/os/poweroff.c b/lib/os/poweroff.c new file mode 100644 index 000000000000..f4e90e477caa --- /dev/null +++ b/lib/os/poweroff.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void sys_poweroff(void) +{ + (void)irq_lock(); + + z_sys_poweroff(); +} diff --git a/lib/posix/eventfd.c b/lib/posix/eventfd.c index a8cc059cb20f..d32ac4c06b42 100644 --- a/lib/posix/eventfd.c +++ b/lib/posix/eventfd.c @@ -17,6 +17,8 @@ #define EFD_FLAGS_SET_INTERNAL (EFD_SEMAPHORE | EFD_NONBLOCK) struct eventfd { + struct k_poll_signal read_sig; + struct k_poll_signal write_sig; struct k_spinlock lock; eventfd_t cnt; int flags; @@ -49,12 +51,29 @@ static int eventfd_poll_prepare(struct eventfd *efd, struct k_poll_event **pev, struct k_poll_event *pev_end) { - if ((pfd->events & (ZSOCK_POLLOUT | ZSOCK_POLLIN)) != 0) { + if (pfd->events & ZSOCK_POLLIN) { if (*pev == pev_end) { errno = ENOMEM; return -1; } - **pev = (struct k_poll_event){0}; + + (*pev)->obj = &efd->read_sig; + (*pev)->type = K_POLL_TYPE_SIGNAL; + (*pev)->mode = K_POLL_MODE_NOTIFY_ONLY; + (*pev)->state = K_POLL_STATE_NOT_READY; + (*pev)++; + } + + if (pfd->events & ZSOCK_POLLOUT) { + if (*pev == pev_end) { + errno = ENOMEM; + return -1; + } + + (*pev)->obj = &efd->write_sig; + (*pev)->type = K_POLL_TYPE_SIGNAL; + (*pev)->mode = K_POLL_MODE_NOTIFY_ONLY; + (*pev)->state = K_POLL_STATE_NOT_READY; (*pev)++; } @@ -99,6 +118,12 @@ static int eventfd_read_locked(struct eventfd *efd, eventfd_t *value) efd->cnt = 0; } + if (efd->cnt == 0) { + k_poll_signal_reset(&efd->read_sig); + } + + k_poll_signal_raise(&efd->write_sig, 0); + return 0; } @@ -124,6 +149,12 @@ static int eventfd_write_locked(struct eventfd *efd, eventfd_t *value) /* successful write */ efd->cnt = result; + if (efd->cnt == (UINT64_MAX - 1)) { + k_poll_signal_reset(&efd->write_sig); + } + + k_poll_signal_raise(&efd->read_sig, 0); + return 0; } @@ -398,6 +429,16 @@ int eventfd(unsigned int initval, int flags) efd->flags = EFD_IN_USE_INTERNAL | flags; efd->cnt = initval; + k_poll_signal_init(&efd->write_sig); + k_poll_signal_init(&efd->read_sig); + + if (initval != 0) { + k_poll_signal_raise(&efd->read_sig, 0); + } + if (initval < UINT64_MAX - 1) { + k_poll_signal_raise(&efd->write_sig, 0); + } + z_finalize_fd(fd, efd, &eventfd_fd_vtable); return fd; diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index 1ec8afbfdfb9..c338981b651c 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -7,12 +7,10 @@ zephyr_interface_library_named(zephyr-802154-interface) if (CONFIG_NRF_802154_RADIO_DRIVER) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/radio/platform/nrf_802154_random_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_gpiote_crit_sect.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_clock_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_gpiote_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_irq_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_temperature_zephyr.c + radio/platform/nrf_802154_random_zephyr.c + sl_opensource/platform/nrf_802154_clock_zephyr.c + sl_opensource/platform/nrf_802154_irq_zephyr.c + sl_opensource/platform/nrf_802154_temperature_zephyr.c ) target_compile_definitions(zephyr-802154-interface @@ -37,17 +35,17 @@ endif () if (CONFIG_NRF_802154_SERIALIZATION) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_serialization_crit_sect.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_log.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_backend_ipc.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_response_notifier.c + serialization/platform/nrf_802154_serialization_crit_sect.c + serialization/platform/nrf_802154_spinel_log.c + serialization/platform/nrf_802154_spinel_backend_ipc.c + serialization/platform/nrf_802154_spinel_response_notifier.c ) endif () if (CONFIG_NRF_802154_SER_RADIO) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_init_net.c + serialization/platform/nrf_802154_init_net.c ) endif () @@ -95,6 +93,10 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() +if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) + target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) +endif() + set(NRF52_SERIES ${CONFIG_SOC_SERIES_NRF52X}) set(NRF53_SERIES ${CONFIG_SOC_SERIES_NRF53X}) set(SER_HOST ${CONFIG_NRF_802154_SER_HOST}) diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_crit_sect.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_crit_sect.c deleted file mode 100644 index eac03895f0c1..000000000000 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_crit_sect.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 - 2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "platform/nrf_802154_gpiote.h" - -#include "hal/nrf_gpio.h" -#include "nrf_802154_sl_utils.h" -#include "platform/nrf_802154_irq.h" - -static volatile bool m_gpiote_irq_enabled; -static volatile uint32_t m_gpiote_irq_disabled_cnt; - -void nrf_802154_gpiote_critical_section_enter(void) -{ - nrf_802154_sl_mcu_critical_state_t mcu_cs; - uint32_t cnt; - - nrf_802154_sl_mcu_critical_enter(mcu_cs); - cnt = m_gpiote_irq_disabled_cnt; - - if (cnt == 0U) { - m_gpiote_irq_enabled = nrf_802154_irq_is_enabled(GPIOTE_IRQn); - nrf_802154_irq_disable(GPIOTE_IRQn); - } - - cnt++; - m_gpiote_irq_disabled_cnt = cnt; - - nrf_802154_sl_mcu_critical_exit(mcu_cs); -} - -void nrf_802154_gpiote_critical_section_exit(void) -{ - nrf_802154_sl_mcu_critical_state_t mcu_cs; - uint32_t cnt; - - nrf_802154_sl_mcu_critical_enter(mcu_cs); - - cnt = m_gpiote_irq_disabled_cnt; - cnt--; - - if (cnt == 0U) { - if (m_gpiote_irq_enabled) { - nrf_802154_irq_enable(GPIOTE_IRQn); - } - } - - m_gpiote_irq_disabled_cnt = cnt; - - nrf_802154_sl_mcu_critical_exit(mcu_cs); -} diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_zephyr.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_zephyr.c deleted file mode 100644 index e7cc9ec5b9d2..000000000000 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_zephyr.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2020 - 2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -static const struct device *dev; -static struct gpio_callback grant_cb; -static uint32_t pin_number = COEX_GPIO_PIN_INVALID; - -static void gpiote_irq_handler(const struct device *gpiob, struct gpio_callback *cb, - uint32_t pins) -{ - ARG_UNUSED(gpiob); - ARG_UNUSED(cb); - ARG_UNUSED(pins); - - nrf_802154_wifi_coex_gpiote_irqhandler(); -} - -void nrf_802154_gpiote_init(void) -{ - switch (nrf_802154_wifi_coex_interface_type_id_get()) { - case NRF_802154_WIFI_COEX_IF_NONE: - return; - - case NRF_802154_WIFI_COEX_IF_3WIRE: { - nrf_802154_wifi_coex_3wire_if_config_t cfg; - - nrf_802154_wifi_coex_cfg_3wire_get(&cfg); - - pin_number = cfg.grant_cfg.gpio_pin; - __ASSERT_NO_MSG(pin_number != COEX_GPIO_PIN_INVALID); - - bool use_port_1 = (pin_number > P0_PIN_NUM); - - /* Convert to the Zephyr primitive */ - pin_number = use_port_1 ? pin_number - P0_PIN_NUM : pin_number; - - uint32_t pull_up_down = cfg.grant_cfg.active_high ? - GPIO_PULL_UP : - GPIO_PULL_DOWN; - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpio1), okay) - if (use_port_1) { - dev = DEVICE_DT_GET(DT_NODELABEL(gpio1)); - } else { - dev = DEVICE_DT_GET(DT_NODELABEL(gpio0)); - } -#else - dev = DEVICE_DT_GET(DT_NODELABEL(gpio0)); -#endif - __ASSERT_NO_MSG(device_is_ready(dev)); - - gpio_pin_configure(dev, pin_number, GPIO_INPUT | pull_up_down); - - gpio_init_callback(&grant_cb, gpiote_irq_handler, - BIT(pin_number)); - gpio_add_callback(dev, &grant_cb); - - gpio_pin_interrupt_configure(dev, pin_number, - GPIO_INT_EDGE_BOTH); - break; - } - - default: - __ASSERT_NO_MSG(false); - } -} - -void nrf_802154_gpiote_deinit(void) -{ - switch (nrf_802154_wifi_coex_interface_type_id_get()) { - case NRF_802154_WIFI_COEX_IF_NONE: - break; - - case NRF_802154_WIFI_COEX_IF_3WIRE: - gpio_pin_interrupt_configure(dev, pin_number, GPIO_INT_DISABLE); - gpio_remove_callback(dev, &grant_cb); - pin_number = COEX_GPIO_PIN_INVALID; - break; - - default: - __ASSERT_NO_MSG(false); - } -} diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf51.h b/modules/hal_nordic/nrfx/nrfx_config_nrf51.h index 3e8f51ca1f4c..51d8bb1b8a51 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf51.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf51.h @@ -280,6 +280,57 @@ #define NRFX_PPI_CONFIG_LOG_LEVEL 3 #endif +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + /** * @brief NRFX_QDEC_ENABLED * diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h index 46867f13ad59..33074008de43 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h index 6004836bea5b..ebd63c25ed80 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h index 4eb1a2cd0a97..01169f7b9839 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h index 9b3248ddd095..bfa743224582 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h index 6b1a3d359e76..4e5fe9d58351 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ @@ -626,14 +626,7 @@ * @brief NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE - EGU instance used by the nRF52 Anomaly 109 * workaround for PWM. * - * Integer value. - * Supported values: - * - EGU0 = 0 - * - EGU1 = 1 - * - EGU2 = 2 - * - EGU3 = 3 - * - EGU4 = 4 - * - EGU5 = 5 + * Integer value. Minimum: 0 Maximum: 5 */ #ifndef NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE #define NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE 5 diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h index d842b4c9f728..fc415c59dc3f 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h index f35c716c57fa..ac7a62fc9312 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h index cc787ceee185..873be583a35b 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h @@ -109,8 +109,8 @@ * * Integer value. * Supported values: - * - RC = 1 - * - XTAL = 2 + * - RC = 1 + * - XTAL = 2 */ #ifndef NRFX_CLOCK_CONFIG_LF_SRC #define NRFX_CLOCK_CONFIG_LF_SRC 2 @@ -278,7 +278,7 @@ * Integer value. Minimum: 0 Maximum: 7 */ #ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY 3 +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** diff --git a/modules/mbedtls/Kconfig b/modules/mbedtls/Kconfig index 81edf4ab5742..a33561a9b1c4 100644 --- a/modules/mbedtls/Kconfig +++ b/modules/mbedtls/Kconfig @@ -5,6 +5,7 @@ config ZEPHYR_MBEDTLS_MODULE bool + config MBEDTLS_PROMPTLESS bool help @@ -13,7 +14,6 @@ config MBEDTLS_PROMPTLESS mbed TLS menu prompt and instead handle the selection of MBEDTLS from dependent sub-configurations and thus prevent stuck symbol behavior. - menuconfig MBEDTLS bool "mbed TLS Support" if !MBEDTLS_PROMPTLESS help @@ -27,6 +27,7 @@ choice MBEDTLS_IMPLEMENTATION config MBEDTLS_BUILTIN bool "Use Zephyr in-tree mbedTLS version" + depends on ! DISABLE_MBEDTLS_BUILTIN help Link with mbedTLS sources included with Zephyr distribution. Included mbedTLS version is well integrated with and supported @@ -40,6 +41,11 @@ config MBEDTLS_LIBRARY endchoice +# subsystems cannot deselect MBEDTLS_BUILTIN, but they can select +# DISABLE_MBEDTLS_BUILTIN. +config DISABLE_MBEDTLS_BUILTIN + bool + config CUSTOM_MBEDTLS_CFG_FILE bool "Custom mbed TLS configuration file" help @@ -226,3 +232,6 @@ config APP_LINK_WITH_MBEDTLS issues for 'app'. endif # MBEDTLS + +# Add PSA configurations +rsource "Kconfig.psa" diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa new file mode 100644 index 000000000000..a91bc76a6845 --- /dev/null +++ b/modules/mbedtls/Kconfig.psa @@ -0,0 +1,486 @@ +# +# Copyright (c) 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# +menu "PSA RNG support" + +config PSA_WANT_GENERATE_RANDOM + bool + prompt "PSA RNG support" + help + Provide random number generator (RNG) support. + +config PSA_WANT_ALG_CTR_DRBG + bool + prompt "PSA RNG using CTR-DRBG as PRNG" + help + Provide random number generator (RNG) using CTR-DRBG as the + pseudo-random number generator (PRNG), seeded by a true random + number generator (TRNG). + +config PSA_WANT_ALG_HMAC_DRBG + bool + prompt "PSA RNG using HMAC-DRBG as PRNG" + help + Provide random number generator (RNG) using HMAC-DRBG as the + pseudo-random number generator (PRNG), seeded by a true random + number generator (TRNG). + +endmenu # RNG support + +menu "PSA key type support" + +config PSA_HAS_KEY_SUPPORT + bool + default y + depends on PSA_WANT_KEY_TYPE_DERIVE || \ + PSA_WANT_KEY_TYPE_HMAC || \ + PSA_WANT_KEY_TYPE_AES || \ + PSA_WANT_KEY_TYPE_CHACHA20 || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY || \ + PSA_WANT_KEY_TYPE_DH_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY + +config PSA_WANT_KEY_TYPE_DERIVE + bool "PSA derive key type support" + help + This key type is for high-entropy secrets only. + For low-entropy secrets, password key type should be used instead. + +config PSA_WANT_KEY_TYPE_RAW_DATA + bool "PSA raw data key type support" + help + A "key" of this type cannot be used for any cryptographic operation. + Applications can use this type to store arbitrary data in the keystore. + +config PSA_WANT_KEY_TYPE_HMAC + bool "PSA HMAC key type support" + help + HMAC key. + +config PSA_WANT_KEY_TYPE_AES + bool "PSA AES key type support" + help + Key for cipher, AEAD or MAC algorithm based on the AES block cipher. + +config PSA_WANT_KEY_TYPE_CHACHA20 + bool "PSA ChaCha20 key type support" + default y + depends on PSA_WANT_ALG_CHACHA20_POLY1305 || \ + PSA_WANT_ALG_STREAM_CIPHER + help + Key for the ChaCha20 stream cipher or the ChaCha20-Poly1305 AEAD algorithm. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + bool "PSA ECC key pair support" + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + bool "PSA ECC public key support" + help + Elliptic curve public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + bool "PSA RSA key pair type support" + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + bool "PSA RSA public key support" + help + RSA public key. + +config PSA_WANT_KEY_TYPE_DH_KEY_PAIR + bool "PSA DH key pair type support" + select PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY + help + Finite-field Diffie-Hellman key pair: both the private key and public key. + +config PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY + bool "PSA DH public key support" + help + Finite-field Diffie-Hellman public key. + +endmenu # PSA Key type support + +menu "PSA AEAD support" + +config PSA_HAS_AEAD_SUPPORT + bool + default y + depends on PSA_WANT_ALG_CCM || \ + PSA_WANT_ALG_CCM_STAR_NO_TAG || \ + PSA_WANT_ALG_GCM || \ + PSA_WANT_ALG_CHACHA20_POLY1305 + help + Prompt-less configuration that states that AEAD is supported. + +config PSA_WANT_ALG_CCM + bool + prompt "PSA CCM support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CCM_STAR_NO_TAG + bool + prompt "PSA AES CCM star with no tag support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_GCM + bool + prompt "PSA GCM support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CHACHA20_POLY1305 + bool + prompt "PSA ChaCha20-Poly1305 support" if !PSA_PROMPTLESS + +endmenu # PSA AEAD support + + +menu "PSA MAC support" + +config PSA_HAS_MAC_SUPPORT + bool + default y + depends on PSA_WANT_ALG_CBC_MAC || \ + PSA_WANT_ALG_CMAC || \ + PSA_WANT_ALG_HMAC + help + Prompt-less configuration that states that MAC is supported. + +config PSA_WANT_ALG_CBC_MAC + bool + help + CBC-MAC is not yet supported via the PSA API in Mbed TLS. + +config PSA_WANT_ALG_CMAC + bool + prompt "PSA CMAC support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_HMAC + bool + prompt "PSA HMAC support" if !PSA_PROMPTLESS + +endmenu # PSA MAC support + + +menu "PSA Hash support" + +config PSA_HAS_HASH_SUPPORT + bool + default y + depends on PSA_WANT_ALG_SHA_1 || \ + PSA_WANT_ALG_SHA_224 || \ + PSA_WANT_ALG_SHA_256 || \ + PSA_WANT_ALG_SHA_384 || \ + PSA_WANT_ALG_SHA_512 || \ + PSA_WANT_ALG_RIPEMD160 || \ + PSA_WANT_ALG_MD5 + help + Prompt-less configuration that states that hash is supported. + +config PSA_WANT_ALG_SHA_1 + bool + prompt "PSA SHA-1 support (weak)" if !PSA_PROMPTLESS + help + Warning: The SHA-1 hash is weak and deprecated and is only recommended + for use in legacy protocols. + +config PSA_WANT_ALG_SHA_224 + bool + prompt "PSA SHA-224 support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_SHA_256 + bool + prompt "PSA SHA-256 support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_SHA_384 + bool + prompt "PSA SHA-384 support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_SHA_512 + bool + prompt "PSA SHA-512 support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RIPEMD160 + bool + prompt "PSA RIPEMD-160 support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_MD5 + bool + prompt "PSA MD5 support (weak)" if !PSA_PROMPTLESS + help + Warning: The MD5 hash is weak and deprecated and is only recommended + for use in legacy protocols. + +endmenu # PSA Hash support + +menu "PSA Cipher support" + +config PSA_HAS_CIPHER_SUPPORT + bool + default y + depends on PSA_WANT_ALG_ECB_NO_PADDING || \ + PSA_WANT_ALG_CBC_NO_PADDING || \ + PSA_WANT_ALG_CBC_PKCS7 || \ + PSA_WANT_ALG_CFB || \ + PSA_WANT_ALG_CTR || \ + PSA_WANT_ALG_OFB || \ + PSA_WANT_ALG_CTR || \ + PSA_WANT_ALG_XTS || \ + PSA_WANT_ALG_STREAM_CIPHER + help + Prompt-less configuration that states that cipher is supported. + +config PSA_WANT_ALG_ECB_NO_PADDING + bool + prompt "PSA ECB block cipher mode support (with no padding)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CBC_NO_PADDING + bool + prompt "PSA CBC block cipher mode support (with no padding)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CBC_PKCS7 + bool + prompt "PSA CBC block cipher mode support (with PKCS#7 padding)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CFB + bool + prompt "PSA stream cipher using CFB block cipher mode support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_CTR + bool + prompt "PSA stream cipher using CTR block cipher mode support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_OFB + bool + prompt "PSA stream cipher using OFB block cipher mode support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_XTS + bool + prompt "PSA XTS block cipher mode support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_STREAM_CIPHER + bool + prompt "PSA stream cipher support" if !PSA_PROMPTLESS + +endmenu # PSA Cipher Support + + +menu "PSA Key derivation support" + +config PSA_HAS_KEY_DERIVATION + bool + default y + depends on PSA_WANT_ALG_HKDF || \ + PSA_WANT_ALG_HKDF_EXPAND || \ + PSA_WANT_ALG_HKDF_EXTRACT || \ + PSA_WANT_ALG_PBKDF2_HMAC || \ + PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 || \ + PSA_WANT_ALG_TLS12_PRF || \ + PSA_WANT_ALG_TLS12_PSK_TO_MS || \ + PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS + help + Prompt-less configuration that states that key derivation is supported. + +config PSA_WANT_ALG_HKDF + bool + prompt "PSA HKDF support" if !PSA_PROMPTLESS + depends on PSA_WANT_ALG_HMAC + +config PSA_WANT_ALG_HKDF_EXTRACT + bool + prompt "PSA HKDF extract support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_HKDF_EXPAND + bool + prompt "PSA HKDF expand support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_PBKDF2_HMAC + bool + prompt "PSA PBKDF2 HMAC support" if !PSA_PROMPTLESS + depends on PSA_WANT_ALG_HMAC + +config PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 + bool + prompt "PSA PBKDF2-AES-CMAC-PRF-128 support" if !PSA_PROMPTLESS + depends on PSA_WANT_ALG_CMAC + +config PSA_WANT_ALG_TLS12_PRF + bool + prompt "PSA PRF support (TLS1.2)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_TLS12_PSK_TO_MS + bool + prompt "PSA TLS 1.2 PSK to MS support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS + bool + prompt "PSA TLS 1.2 EC J-PAKE to PMS support" if !PSA_PROMPTLESS + +endmenu # PSA Key derivation support + + +menu "PSA Asymmetric support" + +config PSA_HAS_ASYM_ENCRYPT_SUPPORT + bool + default y + depends on PSA_WANT_ALG_RSA_OAEP || \ + PSA_WANT_ALG_RSA_PKCS1V15_CRYPT + help + Prompt-less configuration that states that asymmetric encryption + is supported. + + +config PSA_HAS_ASYM_SIGN_SUPPORT + bool + default y + depends on PSA_WANT_ALG_DETERMINISTIC_ECDSA || \ + PSA_WANT_ALG_ECDSA || \ + PSA_WANT_ALG_RSA_PKCS1V15_SIGN || \ + PSA_WANT_ALG_RSA_PSS + help + Prompt-less configuration that states that asymmetric signing + is supported. + +config PSA_HAS_ECC_SUPPORT + bool + depends on PSA_WANT_ALG_ECDH || \ + PSA_WANT_ALG_ECDSA || \ + PSA_WANT_ALG_DETERMINISTIC_ECDSA || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + default y + help + Prompt-less configuration that states that ECC is supported. + +config PSA_WANT_ALG_ECDH + bool + prompt "PSA ECDH support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_ECDSA + bool + prompt "PSA ECDSA support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_DETERMINISTIC_ECDSA + bool + prompt "PSA ECDSA support (deterministic mode)" if !PSA_PROMPTLESS + +menu "Elliptic Curve type support" + depends on PSA_HAS_ECC_SUPPORT + +config PSA_WANT_ECC_BRAINPOOL_P_R1_256 + bool + prompt "PSA ECC Brainpool256r1 support" + +config PSA_WANT_ECC_BRAINPOOL_P_R1_384 + bool "PSA ECC Brainpool384r1 support" + +config PSA_WANT_ECC_BRAINPOOL_P_R1_512 + bool "PSA ECC Brainpool512r1 support" + +config PSA_WANT_ECC_MONTGOMERY_255 + bool "PSA ECC Curve25519 (X25519) support" + +config PSA_WANT_ECC_MONTGOMERY_448 + bool "PSA ECC Curve448 (X448) support" + +config PSA_WANT_ECC_TWISTED_EDWARDS_255 + bool "PSA ECC Edwards25519 (Ed25519) support" + +config PSA_WANT_ECC_SECP_K1_192 + bool "PSA ECC secp192k1 support" + +config PSA_WANT_ECC_SECP_K1_224 + bool + help + SECP224K1 is buggy via the PSA API in Mbed TLS + See https://github.com/ARMmbed/mbedtls/issues/3541 + +config PSA_WANT_ECC_SECP_K1_256 + bool + prompt "PSA ECC secp256k1 support" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_192 + bool + prompt "PSA ECC secp192r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_224 + bool + prompt "PSA ECC secp224r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_256 + bool + prompt "PSA ECC secp256r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_384 + bool + prompt "PSA ECC secp384r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_521 + bool + prompt "PSA ECC secp521r1" if !PSA_PROMPTLESS + +endmenu # Elliptic Curve type support + +config PSA_HAS_RSA_SUPPORT + bool + depends on PSA_WANT_ALG_RSA_OAEP || \ + PSA_WANT_ALG_RSA_PKCS1V15_CRYPT || \ + PSA_WANT_ALG_RSA_PKCS1V15_SIGN || \ + PSA_WANT_ALG_RSA_PSS || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + default y + help + Prompt-less configuration that states that RSA is supported. + +config PSA_WANT_ALG_RSA_OAEP + bool + prompt "PSA RSA OAEP support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PKCS1V15_CRYPT + bool + prompt "PSA RSA crypt support (PKCS#1 v1.5 mode)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PKCS1V15_SIGN + bool + prompt "PSA RSA signature support (PKCS#1 v1.5 mode)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PSS + bool + prompt "PSA RSA (PSS mode)" if !PSA_PROMPTLESS + +endmenu # PSA Asymmetric support + +config PSA_WANT_ALG_JPAKE + bool + prompt "PSA EC J-PAKE support" if !PSA_PROMPTLESS + select EXPERIMENTAL + +config PSA_WANT_ALG_SPAKE2P + bool + prompt "PSA SPAKE2+ support" if !PSA_PROMPTLESS + select EXPERIMENTAL + +config PSA_WANT_ALG_SRP_6 + bool + prompt "PSA SRP-6 support" if !PSA_PROMPTLESS + select EXPERIMENTAL + +config PSA_WANT_ALG_PURE_EDDSA + bool + prompt "PSA PURE_EDDSA support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_ED25519PH + bool + prompt "PSA ED25519PH support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_ED448PH + bool + prompt "PSA ED448PH support" if !PSA_PROMPTLESS diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index 6275c6570f75..d8432dc176f1 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -9,6 +9,8 @@ menu "TLS configuration" menu "Supported TLS version" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_TLS_VERSION_1_0 bool "Support for TLS 1.0" select MBEDTLS_CIPHER @@ -33,6 +35,8 @@ config MBEDTLS_DTLS bool "Support for DTLS" depends on MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 +endif + config MBEDTLS_SSL_EXPORT_KEYS bool "Support for exporting SSL key block and master secret" depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 @@ -47,6 +51,8 @@ menu "Ciphersuite configuration" comment "Supported key exchange modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_ALL_ENABLED bool "All available ciphersuite modes" select MBEDTLS_KEY_EXCHANGE_PSK_ENABLED @@ -81,6 +87,8 @@ config MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +endif + config MBEDTLS_PSK_MAX_LEN int "Max size of TLS pre-shared keys" default 32 @@ -88,6 +96,8 @@ config MBEDTLS_PSK_MAX_LEN help Max size of TLS pre-shared keys, in bytes. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_RSA_ENABLED bool "RSA-only based ciphersuite modes" default y if !NET_L2_OPENTHREAD @@ -202,6 +212,7 @@ config MBEDTLS_ECP_NIST_OPTIM bool "NSIT curves optimization" endif +endif # !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) comment "Supported hash" @@ -226,6 +237,8 @@ config MBEDTLS_HASH_SHA512_ENABLED comment "Supported cipher modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CIPHER_ALL_ENABLED bool "All available ciphers" select MBEDTLS_CIPHER_AES_ENABLED @@ -290,8 +303,12 @@ config MBEDTLS_CHACHAPOLY_AEAD_ENABLED bool "ChaCha20-Poly1305 AEAD algorithm" depends on MBEDTLS_CIPHER_CHACHA20_ENABLED || MBEDTLS_MAC_POLY1305_ENABLED +endif + comment "Supported message authentication methods" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MAC_ALL_ENABLED bool "All available MAC methods" select MBEDTLS_MAC_MD4_ENABLED @@ -340,10 +357,14 @@ config MBEDTLS_MAC_CMAC_ENABLED bool "CMAC (Cipher-based Message Authentication Code) mode for block ciphers." depends on MBEDTLS_CIPHER_AES_ENABLED || MBEDTLS_CIPHER_DES_ENABLED +endif + endmenu comment "Random number generators" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CTR_DRBG_ENABLED bool "CTR_DRBG AES-256-based random generator" depends on MBEDTLS_CIPHER_AES_ENABLED @@ -353,14 +374,20 @@ config MBEDTLS_HMAC_DRBG_ENABLED bool "HMAC_DRBG random generator" select MBEDTLS_MD +endif + comment "Other configurations" config MBEDTLS_CIPHER bool "generic cipher layer." +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MD bool "generic message digest layer." +endif + config MBEDTLS_GENPRIME_ENABLED bool "prime-number generation code." @@ -378,11 +405,15 @@ config MBEDTLS_HAVE_ASM of asymmetric cryptography, however this might have an impact on the code size. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_ENTROPY_ENABLED bool "MbedTLS generic entropy pool" depends on MBEDTLS_MAC_SHA256_ENABLED || MBEDTLS_MAC_SHA384_ENABLED || MBEDTLS_MAC_SHA512_ENABLED default y if MBEDTLS_ZEPHYR_ENTROPY +endif + config MBEDTLS_OPENTHREAD_OPTIMIZATIONS_ENABLED bool "MbedTLS optimizations for OpenThread" depends on NET_L2_OPENTHREAD diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 52a5bb2fd16c..626ce2948397 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -478,6 +478,10 @@ #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif +#if defined(CONFIG_NRF_CC3XX_PLATFORM) +#define MBEDTLS_PLATFORM_ZEROIZE_ALT +#endif + #include "mbedtls/check_config.h" #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 508c888e0f3c..267e1a443cda 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -82,6 +82,12 @@ else() set(OT_BORDER_ROUTING_COUNTERS OFF CACHE BOOL "Enable Border routing counters" FORCE) endif() +if(CONFIG_OPENTHREAD_BORDER_ROUTING_DHCP6_PD) + set(OT_BORDER_ROUTING_DHCP6_PD ON CACHE BOOL "DHCPv6-PD support in border routing" FORCE) +else() + set(OT_BORDER_ROUTING_DHCP6_PD OFF CACHE BOOL "DHCPv6-PD support in border routing" FORCE) +endif() + if(CONFIG_OPENTHREAD_CHANNEL_MANAGER) set(OT_CHANNEL_MANAGER ON CACHE BOOL "Enable channel manager support" FORCE) else() @@ -346,6 +352,12 @@ else() set(OT_NETDATA_PUBLISHER OFF CACHE BOOL "Enable Thread Network Data publisher" FORCE) endif() +if(CONFIG_OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT) + set(OT_OPERATIONAL_DATASET_AUTO_INIT ON CACHE BOOL "Enable operational dataset auto init" FORCE) +else() + set(OT_OPERATIONAL_DATASET_AUTO_INIT OFF CACHE BOOL "Enable operational dataset auto init" FORCE) +endif() + if(CONFIG_OPENTHREAD_OTNS) set(OT_OTNS ON CACHE BOOL "Enable OTNS support" FORCE) else() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index dc0624edca17..a6834ce924fa 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -51,6 +51,9 @@ config OPENTHREAD_BORDER_ROUTING config OPENTHREAD_BORDER_ROUTING_COUNTERS bool "Border routing counters support" +config OPENTHREAD_BORDER_ROUTING_DHCP6_PD + bool "DHCPv6-PD support in border routing" + config OPENTHREAD_CHANNEL_MONITOR bool "Channel monitor support" @@ -209,6 +212,10 @@ config OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT config OPENTHREAD_NETDATA_PUBLISHER bool "Thread Network Data publisher" +config OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT + bool "Operational dataset auto init" + default y + config OPENTHREAD_OTNS bool "OTNS support" @@ -247,6 +254,9 @@ config OPENTHREAD_POWER_SUPPLY default "EXTERNAL_UNSTABLE" if OPENTHREAD_POWER_SUPPLY_EXTERNAL_UNSTABLE default "" +config OPENTHREAD_RADIO_STATS + bool "Support for Radio Statistics" + config OPENTHREAD_RAW bool "Raw Link support" diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 7eaccf7948df..8d6b5e54fd08 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -446,4 +446,15 @@ #define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0 #endif + +/** + * @def OPENTHREAD_CONFIG_RADIO_STATS + * + * Enable support for Radio Statistics. + * + */ +#ifdef CONFIG_OPENTHREAD_RADIO_STATS +#define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE CONFIG_OPENTHREAD_RADIO_STATS +#endif + #endif /* OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ */ diff --git a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules index 1b4f7e1b17a4..eb33b9101bd0 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules +++ b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules @@ -17,6 +17,7 @@ config TFM_CRYPTO_RNG_MODULE_ENABLED config TFM_CRYPTO_KEY_MODULE_ENABLED bool "KEY crypto module" default y + depends on PSA_HAS_KEY_SUPPORT && NRF_SECURITY help Enables the KEY crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_key.c' @@ -25,6 +26,7 @@ config TFM_CRYPTO_KEY_MODULE_ENABLED config TFM_CRYPTO_AEAD_MODULE_ENABLED bool "AEAD crypto module" default y + depends on PSA_HAS_AEAD_SUPPORT && NRF_SECURITY help Enables the AEAD crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_aead.c' @@ -33,6 +35,7 @@ config TFM_CRYPTO_AEAD_MODULE_ENABLED config TFM_CRYPTO_MAC_MODULE_ENABLED bool "MAC crypto module" default y + depends on PSA_HAS_MAC_SUPPORT && NRF_SECURITY help Enables the MAC crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_mac.c' @@ -41,6 +44,7 @@ config TFM_CRYPTO_MAC_MODULE_ENABLED config TFM_CRYPTO_HASH_MODULE_ENABLED bool "HASH crypto module" default y + depends on PSA_HAS_HASH_SUPPORT && NRF_SECURITY help Enables the HASH crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_hash.c' @@ -49,6 +53,7 @@ config TFM_CRYPTO_HASH_MODULE_ENABLED config TFM_CRYPTO_CIPHER_MODULE_ENABLED bool "CIPHER crypto module" default y + depends on PSA_HAS_CIPHER_SUPPORT && NRF_SECURITY help Enables the CIPHER crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_cipher.c' @@ -57,6 +62,7 @@ config TFM_CRYPTO_CIPHER_MODULE_ENABLED config TFM_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED bool "ASYM ENCRYPT crypto module" default y + depends on PSA_HAS_ASYM_ENCRYPT_SUPPORT && NRF_SECURITY help Enables the ASYM ENCRYPT crypto module within the crypto partition. Unset this option if the encrypt functionality provided by 'crypto_asymmetric.c' @@ -65,6 +71,7 @@ config TFM_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED config TFM_CRYPTO_ASYM_SIGN_MODULE_ENABLED bool "ASYM SIGN crypto module" default y + depends on PSA_HAS_ASYM_SIGN_SUPPORT && NRF_SECURITY help Enables the ASYM SIGN crypto module within the crypto partition. Unset this option if the sign functionality provided by 'crypto_asymmetric.c' @@ -73,6 +80,7 @@ config TFM_CRYPTO_ASYM_SIGN_MODULE_ENABLED config TFM_CRYPTO_KEY_DERIVATION_MODULE_ENABLED bool "KEY DERIVATION crypto module" default y + depends on PSA_HAS_KEY_DERIVATION && NRF_SECURITY help Enables the KEY_DERIVATION crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_key_derivation.c' diff --git a/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf b/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf new file mode 100644 index 000000000000..e6749ae63990 --- /dev/null +++ b/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf @@ -0,0 +1 @@ +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/samples/boards/nrf/system_off/prj.conf b/samples/boards/nrf/system_off/prj.conf index f32cffde85b6..a57c6919a1ec 100644 --- a/samples/boards/nrf/system_off/prj.conf +++ b/samples/boards/nrf/system_off/prj.conf @@ -1,7 +1,7 @@ -CONFIG_PM=y # Required to disable default behavior of deep sleep on timeout CONFIG_PM_DEVICE=y CONFIG_GPIO=y # Optional select RAM retention (nRF52 only) #CONFIG_APP_RETENTION=y CONFIG_CRC=y +CONFIG_POWEROFF=y diff --git a/samples/boards/nrf/system_off/src/main.c b/samples/boards/nrf/system_off/src/main.c index 31b41e69fcb9..6a2a34916021 100644 --- a/samples/boards/nrf/system_off/src/main.c +++ b/samples/boards/nrf/system_off/src/main.c @@ -7,10 +7,8 @@ #include #include #include -#include -#include #include -#include +#include #include #include "retained.h" #include @@ -18,21 +16,6 @@ #define BUSY_WAIT_S 2U #define SLEEP_S 2U -/* Prevent deep sleep (system off) from being entered on long timeouts - * or `K_FOREVER` due to the default residency policy. - * - * This has to be done before anything tries to sleep, which means - * before the threading system starts up. - */ -static int disable_ds_1(void) -{ - - pm_policy_state_lock_get(PM_STATE_SOFT_OFF, PM_ALL_SUBSTATES); - return 0; -} - -SYS_INIT(disable_ds_1, PRE_KERNEL_1, 99); - int main(void) { int rc; @@ -90,21 +73,7 @@ int main(void) retained_update(); } - /* Above we disabled entry to deep sleep based on duration of - * controlled delay. Here we need to override that, then - * force entry to deep sleep on any delay. - */ - pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0}); + sys_poweroff(); - /* Now we need to go sleep. This will let the idle thread runs and - * the pm subsystem will use the forced state. To confirm that the - * forced state is used, lets set the same timeout used previously. - */ - k_sleep(K_SECONDS(SLEEP_S)); - - printk("ERROR: System off failed\n"); - while (true) { - /* spin to avoid fall-off behavior */ - } return 0; } diff --git a/samples/net/dhcpv4_client/overlay-nrf700x.conf b/samples/net/dhcpv4_client/overlay-nrf700x.conf new file mode 100644 index 000000000000..2d552e9c6231 --- /dev/null +++ b/samples/net/dhcpv4_client/overlay-nrf700x.conf @@ -0,0 +1,14 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/dns_resolve/overlay-nrf700x.conf b/samples/net/dns_resolve/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/dns_resolve/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/dns_resolve/src/main.c b/samples/net/dns_resolve/src/main.c index 62cd71d9e22d..0aa5f2a98863 100644 --- a/samples/net/dns_resolve/src/main.c +++ b/samples/net/dns_resolve/src/main.c @@ -152,57 +152,96 @@ static void do_ipv4_lookup(struct k_work *work) LOG_DBG("DNS id %u", dns_id); } +static void schedule_ipv4_queries(void) +{ + k_work_init_delayable(&ipv4_timer, do_ipv4_lookup); + k_work_reschedule(&ipv4_timer, K_NO_WAIT); + +#if defined(CONFIG_MDNS_RESOLVER) + k_work_init_delayable(&mdns_ipv4_timer, do_mdns_ipv4_lookup); + k_work_reschedule(&mdns_ipv4_timer, K_NO_WAIT); +#endif +} + +static void print_dhcpv4_addr(struct net_if *iface, struct net_if_addr *if_addr, + void *user_data) +{ + bool *found = (bool *)user_data; + char hr_addr[NET_IPV4_ADDR_LEN]; + + if (*found) { + return; + } + + if (if_addr->addr_type != NET_ADDR_DHCP) { + return; + } + + LOG_INF("IPv4 address: %s", + net_addr_ntop(AF_INET, &if_addr->address.in_addr, + hr_addr, NET_IPV4_ADDR_LEN)); + LOG_INF("Lease time: %u seconds", iface->config.dhcpv4.lease_time); + LOG_INF("Subnet: %s", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->netmask, + hr_addr, NET_IPV4_ADDR_LEN)); + LOG_INF("Router: %s", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->gw, + hr_addr, NET_IPV4_ADDR_LEN)); + + *found = true; +} + static void ipv4_addr_add_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { - char hr_addr[NET_IPV4_ADDR_LEN]; - int i; + + bool found = false; if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { return; } - for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - struct net_if_addr *if_addr = - &iface->config.ip.ipv4->unicast[i]; - - if (if_addr->addr_type != NET_ADDR_DHCP || !if_addr->is_used) { - continue; - } - - LOG_INF("IPv4 address: %s", - net_addr_ntop(AF_INET, - &if_addr->address.in_addr, - hr_addr, NET_IPV4_ADDR_LEN)); - LOG_INF("Lease time: %u seconds", - iface->config.dhcpv4.lease_time); - LOG_INF("Subnet: %s", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->netmask, - hr_addr, NET_IPV4_ADDR_LEN)); - LOG_INF("Router: %s", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->gw, - hr_addr, NET_IPV4_ADDR_LEN)); - break; - } + net_if_ipv4_addr_foreach(iface, print_dhcpv4_addr, &found); /* We cannot run DNS lookup directly from this thread as the * management event thread stack is very small by default. * So run it from work queue instead. */ - k_work_init_delayable(&ipv4_timer, do_ipv4_lookup); - k_work_reschedule(&ipv4_timer, K_NO_WAIT); + schedule_ipv4_queries(); +} -#if defined(CONFIG_MDNS_RESOLVER) - k_work_init_delayable(&mdns_ipv4_timer, do_mdns_ipv4_lookup); - k_work_reschedule(&mdns_ipv4_timer, K_NO_WAIT); -#endif +static void check_dhcpv4_addr(struct net_if *iface, struct net_if_addr *if_addr, + void *user_data) +{ + bool *found = (bool *)user_data; + + if (if_addr->addr_type != NET_ADDR_DHCP) { + return; + } + + *found = true; } static void setup_dhcpv4(struct net_if *iface) { + bool found; + + /* If DHCP registers an IP address before we register the + * ipv4_addr_add_handler() callback, we won't be notified. Check + * whether this is the case. + */ + net_if_ipv4_addr_foreach(iface, check_dhcpv4_addr, &found); + + if (found) { + /* Already have DHCP assigned address, schedule queries. */ + schedule_ipv4_queries(); + return; + } + + /* Otherwise, wait for DHCP to assign an address. */ LOG_INF("Getting IPv4 address via DHCP before issuing DNS query"); net_mgmt_init_event_callback(&mgmt4_cb, ipv4_addr_add_handler, diff --git a/samples/net/ipv4_autoconf/overlay-nrf700x.conf b/samples/net/ipv4_autoconf/overlay-nrf700x.conf new file mode 100644 index 000000000000..2d552e9c6231 --- /dev/null +++ b/samples/net/ipv4_autoconf/overlay-nrf700x.conf @@ -0,0 +1,14 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 6299c097cf62..00ad1a679e28 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -52,6 +52,9 @@ samples/net/lwm2m_client directory: - :file:`overlay-queue.conf` This overlay config can be added to enable LWM2M Queue Mode support. +- :file:`overlay-tickless.conf` + This overlay config can be used to stop LwM2M engine for periodically interrupting socket polls. It can have significant effect on power usage on certain devices. + Build the lwm2m-client sample application like this: .. zephyr-app-commands:: diff --git a/samples/net/lwm2m_client/overlay-dtls-cert.conf b/samples/net/lwm2m_client/overlay-dtls-cert.conf new file mode 100644 index 000000000000..1362115f7466 --- /dev/null +++ b/samples/net/lwm2m_client/overlay-dtls-cert.conf @@ -0,0 +1,38 @@ +CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_PEER_PORT=5684 + +# I need room to store certificates +CONFIG_LWM2M_SECURITY_KEY_SIZE=2048 + +# Select Zephyr mbedtls +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_TLS_VERSION_1_2=y + +# Special MbedTLS changes +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=32768 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=1500 +CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y + +# Disable RSA, use only ECC certificates +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=n +# Enable PSK and ECDHE_ECDSA +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=y +# We only need prime256v1 curve +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y +CONFIG_MBEDTLS_CIPHER_GCM_ENABLED=y +# Optional: we could use just binary DER certificates +CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y + +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 +CONFIG_NET_SOCKETS_ENABLE_DTLS=y + +# MbedTLS needs a larger stack +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/samples/net/lwm2m_client/overlay-tickless.conf b/samples/net/lwm2m_client/overlay-tickless.conf new file mode 100644 index 000000000000..132515f6380f --- /dev/null +++ b/samples/net/lwm2m_client/overlay-tickless.conf @@ -0,0 +1,2 @@ +CONFIG_NET_SOCKETPAIR=y +CONFIG_LWM2M_TICKLESS=y diff --git a/samples/net/mdns_responder/overlay-nrf700x.conf b/samples/net/mdns_responder/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/mdns_responder/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/mqtt_publisher/overlay-nrf700x.conf b/samples/net/mqtt_publisher/overlay-nrf700x.conf new file mode 100644 index 000000000000..a812c7896f62 --- /dev/null +++ b/samples/net/mqtt_publisher/overlay-nrf700x.conf @@ -0,0 +1,19 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf b/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf new file mode 100644 index 000000000000..cbc47b965727 --- /dev/null +++ b/samples/net/mqtt_sn_publisher/overlay-nrf700x.conf @@ -0,0 +1,20 @@ +CONFIG_POSIX_MAX_FDS=16 + +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/coap_client/overlay-nrf700x.conf b/samples/net/sockets/coap_client/overlay-nrf700x.conf new file mode 100644 index 000000000000..a0e436e3537d --- /dev/null +++ b/samples/net/sockets/coap_client/overlay-nrf700x.conf @@ -0,0 +1,16 @@ +CONFIG_HEAP_MEM_POOL_SIZE=153000 + +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/coap_server/overlay-nrf700x.conf b/samples/net/sockets/coap_server/overlay-nrf700x.conf new file mode 100644 index 000000000000..4817a4f73ba6 --- /dev/null +++ b/samples/net/sockets/coap_server/overlay-nrf700x.conf @@ -0,0 +1,26 @@ +CONFIG_HEAP_MEM_POOL_SIZE=153000 + +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# The sample can run either IPv4 or IPv6, not both +CONFIG_NET_IPV6=n +CONFIG_NET_CONFIG_NEED_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_CONFIG_NEED_IPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c index 0d126bf28d98..fbd112da5eac 100644 --- a/samples/net/sockets/coap_server/src/coap-server.c +++ b/samples/net/sockets/coap_server/src/coap-server.c @@ -954,8 +954,8 @@ static int large_create_post(struct coap_resource *resource, static void schedule_next_retransmission(void) { struct coap_pending *pending; - int32_t remaining; - uint32_t now = k_uptime_get_32(); + int64_t remaining; + int64_t now = k_uptime_get(); /* Get the first pending retransmission to expire after cycling. */ pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); diff --git a/samples/net/sockets/echo/overlay-nrf700x.conf b/samples/net/sockets/echo/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/sockets/echo/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_async/overlay-nrf700x.conf b/samples/net/sockets/echo_async/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/sockets/echo_async/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_client/CMakeLists.txt b/samples/net/sockets/echo_client/CMakeLists.txt index 3222441653b3..0fe1ad126cc1 100644 --- a/samples/net/sockets/echo_client/CMakeLists.txt +++ b/samples/net/sockets/echo_client/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sockets_echo_client) -if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND - (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) +if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) add_custom_target(development_psk COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" diff --git a/samples/net/sockets/echo_client/overlay-nrf700x.conf b/samples/net/sockets/echo_client/overlay-nrf700x.conf new file mode 100644 index 000000000000..cbc47b965727 --- /dev/null +++ b/samples/net/sockets/echo_client/overlay-nrf700x.conf @@ -0,0 +1,20 @@ +CONFIG_POSIX_MAX_FDS=16 + +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_client/src/common.h b/samples/net/sockets/echo_client/src/common.h index debfa3fbb652..e0b06b7ee141 100644 --- a/samples/net/sockets/echo_client/src/common.h +++ b/samples/net/sockets/echo_client/src/common.h @@ -73,6 +73,7 @@ extern const char lorem_ipsum[]; extern const int ipsum_len; extern struct configs conf; +#if defined(CONFIG_NET_UDP) /* init_udp initializes kernel objects, hence it has to be called from * supervisor thread. */ @@ -80,6 +81,12 @@ void init_udp(void); int start_udp(void); int process_udp(void); void stop_udp(void); +#else +static inline void init_udp(void) { } +static inline int start_udp(void) { return 0; } +static inline int process_udp(void) { return 0; } +static inline void stop_udp(void) { } +#endif /* defined(CONFIG_NET_UDP) */ int start_tcp(void); int process_tcp(void); diff --git a/samples/net/sockets/echo_client/src/echo-client.c b/samples/net/sockets/echo_client/src/echo-client.c index c211de8f3c93..a8388604ba2e 100644 --- a/samples/net/sockets/echo_client/src/echo-client.c +++ b/samples/net/sockets/echo_client/src/echo-client.c @@ -247,7 +247,6 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register public certificate: %d", err); } -#endif #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) err = tls_credential_add(PSK_TAG, @@ -264,7 +263,9 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register PSK ID: %d", err); } -#endif +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */ + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { net_mgmt_init_event_callback(&mgmt_cb, diff --git a/samples/net/sockets/echo_server/CMakeLists.txt b/samples/net/sockets/echo_server/CMakeLists.txt index 5203e1d16408..8e01b63e70c5 100644 --- a/samples/net/sockets/echo_server/CMakeLists.txt +++ b/samples/net/sockets/echo_server/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sockets_echo_server) -if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND - (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) +if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) add_custom_target(development_psk COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" diff --git a/samples/net/sockets/echo_server/overlay-nrf700x.conf b/samples/net/sockets/echo_server/overlay-nrf700x.conf new file mode 100644 index 000000000000..cbc47b965727 --- /dev/null +++ b/samples/net/sockets/echo_server/overlay-nrf700x.conf @@ -0,0 +1,20 @@ +CONFIG_POSIX_MAX_FDS=16 + +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/echo_server/src/echo-server.c b/samples/net/sockets/echo_server/src/echo-server.c index fbf189f898ad..7343b1e82174 100644 --- a/samples/net/sockets/echo_server/src/echo-server.c +++ b/samples/net/sockets/echo_server/src/echo-server.c @@ -135,16 +135,13 @@ static void init_app(void) ARG_UNUSED(ret); #endif -#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || \ - defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) - int err; -#endif - k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); LOG_INF(APP_BANNER); #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + int err; + #if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) err = tls_credential_add(SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, @@ -153,7 +150,7 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register CA certificate: %d", err); } -#endif +#endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */ err = tls_credential_add(SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_SERVER_CERTIFICATE, @@ -170,7 +167,6 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register private key: %d", err); } -#endif #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) err = tls_credential_add(PSK_TAG, @@ -187,7 +183,8 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register PSK ID: %d", err); } -#endif +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */ if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { net_mgmt_init_event_callback(&mgmt_cb, diff --git a/samples/net/sockets/http_get/overlay-nrf700x.conf b/samples/net/sockets/http_get/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/sockets/http_get/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/sockets/sntp_client/overlay-nrf700x.conf b/samples/net/sockets/sntp_client/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/sockets/sntp_client/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/syslog_net/overlay-nrf700x.conf b/samples/net/syslog_net/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/syslog_net/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/net/telnet/overlay-nrf700x.conf b/samples/net/telnet/overlay-nrf700x.conf new file mode 100644 index 000000000000..aa59e5d5ea2d --- /dev/null +++ b/samples/net/telnet/overlay-nrf700x.conf @@ -0,0 +1,18 @@ +# Wi-Fi +CONFIG_WIFI=y +CONFIG_WIFI_NRF700X=y +CONFIG_WPA_SUPP=y +CONFIG_NET_L2_ETHERNET=y + +# DHCPv4 +CONFIG_NET_CONFIG_MY_IPV4_ADDR="" +CONFIG_NET_DHCPV4=y + +# Connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +# Credentials +CONFIG_WIFI_CREDENTIALS=y +CONFIG_WIFI_CREDENTIALS_STATIC=y +CONFIG_WIFI_CREDENTIALS_STATIC_SSID="" +CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="" diff --git a/samples/posix/eventfd/prj.conf b/samples/posix/eventfd/prj.conf index af6bfd12d863..ab7c7475befd 100644 --- a/samples/posix/eventfd/prj.conf +++ b/samples/posix/eventfd/prj.conf @@ -1,5 +1,6 @@ # General config CONFIG_NEWLIB_LIBC=y +CONFIG_NEWLIB_LIBC_NANO=n CONFIG_POSIX_API=y CONFIG_EVENTFD=y diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/child_image/hci_rpmsg.conf b/samples/subsys/mgmt/mcumgr/smp_svr/child_image/hci_rpmsg.conf new file mode 100644 index 000000000000..98260877332f --- /dev/null +++ b/samples/subsys/mgmt/mcumgr/smp_svr/child_image/hci_rpmsg.conf @@ -0,0 +1,10 @@ +# +# Copyright (c) 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT_MAX_CONN=2 +CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_BUF_ACL_TX_SIZE=502 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 diff --git a/samples/subsys/mgmt/updatehub/src/main.c b/samples/subsys/mgmt/updatehub/src/main.c index 9e51c7e7b2dc..022fbd4b2ae8 100644 --- a/samples/subsys/mgmt/updatehub/src/main.c +++ b/samples/subsys/mgmt/updatehub/src/main.c @@ -9,7 +9,10 @@ #include #include #include + +#ifdef CONFIG_NET_L2_WIFI_MGMT #include +#endif /* CONFIG_NET_L2_WIFI_MGMT */ #if defined(CONFIG_UPDATEHUB_DTLS) #include diff --git a/samples/subsys/pm/latency/Kconfig b/samples/subsys/pm/latency/Kconfig index 0e08794c13a8..e3578670ddfb 100644 --- a/samples/subsys/pm/latency/Kconfig +++ b/samples/subsys/pm/latency/Kconfig @@ -8,3 +8,9 @@ endmenu module = APP module-str = Application source "subsys/logging/Kconfig.template.log_config" + + +config APP_PROVIDE_PM_HOOKS + bool "Application provides PM hooks" + default y + select HAS_PM diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 25d7f9df37ee..59e021489d51 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -303,6 +303,13 @@ def get_modules(self, modules_file): modules = [name for name in os.listdir(modules_dir) if os.path.exists(os.path.join(modules_dir, name, 'Kconfig'))] + nrf_modules_dir = ZEPHYR_BASE + '/../nrf/modules' + nrf_modules = [] + if os.path.exists(nrf_modules_dir): + nrf_modules = [name for name in os.listdir(nrf_modules_dir) if + os.path.exists(os.path.join(nrf_modules_dir, name, + 'Kconfig'))] + with open(modules_file, 'r') as fp_module_file: content = fp_module_file.read() @@ -312,6 +319,15 @@ def get_modules(self, modules_file): re.sub('[^a-zA-Z0-9]', '_', module).upper(), modules_dir + '/' + module + '/Kconfig' )) + for module in nrf_modules: + fp_module_file.write("ZEPHYR_{}_KCONFIG = {}\n".format( + re.sub('[^a-zA-Z0-9]', '_', module).upper(), + nrf_modules_dir + '/' + module + '/Kconfig' + )) + fp_module_file.write("NCS_{}_KCONFIG = {}\n".format( + re.sub('[^a-zA-Z0-9]', '_', module).upper(), + modules_dir + '/' + module + '/Kconfig' + )) fp_module_file.write(content) def get_kconfig_dts(self, kconfig_dts_file): diff --git a/scripts/coccinelle/symbols.txt b/scripts/coccinelle/symbols.txt index 3b32b3800cd8..02bd93e0dcc2 100644 --- a/scripts/coccinelle/symbols.txt +++ b/scripts/coccinelle/symbols.txt @@ -207,7 +207,6 @@ strtod64 strtod128 strtof strtok -strtok_r strtol strtold strtoul diff --git a/scripts/gitlint/ncs.py b/scripts/gitlint/ncs.py new file mode 100644 index 000000000000..3ec805550c24 --- /dev/null +++ b/scripts/gitlint/ncs.py @@ -0,0 +1,59 @@ +# Copyright (c) 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +from gitlint.rules import BoolOption, CommitRule, RuleViolation +import re + +class NCSSauceTags(CommitRule): + """This rule enforces the NCS sauce tag specification. + https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/dm_code_base.html#oss-repositories-downstream-project-history + """ + + # A rule MUST have a human friendly name + name = "ncs-sauce-tags" + + # A rule MUST have a *unique* id, we recommend starting with UC (for User-defined Commit-rule). + id = "UC100" + + options_spec = [BoolOption('enable', False, 'Enable the Sauce Tags Rule')] + + def validate(self, commit): + self.log.debug(f'NCSSauceTags: enable:{self.options["enable"].value} ' \ + f'sha:{commit.sha}') + + if not self.options['enable'].value: + self.log.debug(f'Disabled, skipping') + return + + m = re.match(r'^(Revert\s+\")?\[nrf (mergeup|fromtree|fromlist|noup)\]\s+', + commit.message.title) + if not m: + return [RuleViolation(self.id, 'Title does not contain a sauce tag', + line_nr=1)] + + tag = m.group(2) + + if not tag: + return [RuleViolation(self.id, 'Title does not contain a sauce tag', + line_nr=1)] + self.log.debug(f'Matched sauce tag {tag}') + + if tag == 'mergeup': + if not commit.is_merge_commit: + return [RuleViolation(self.id, + 'mergeup used in a non-merge commit')] + if not re.match(r'^\[nrf mergeup\] Merge upstream up to commit \b([a-f0-9]{40})\b', + commit.message.title): + return [RuleViolation(self.id, 'Invalid mergeup commit title')] + elif tag == 'fromlist': + regex = r'^Upstream PR: https://github\.com/.*/pull/\d+' + matches = re.findall(regex, '\n'.join(commit.message.body), re.MULTILINE) + if len(matches) == 0: + return [RuleViolation(self.id, + 'Missing Upstream PR reference in fromlist commit')] + elif tag == 'fromtree': + regex = r'^\(cherry picked from commit \b([a-f0-9]{40})\b\)' + matches = re.findall(regex, '\n'.join(commit.message.body), re.MULTILINE) + if len(matches) == 0: + return [RuleViolation(self.id, + 'Missing cherry-pick reference in fromtree commit')] diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index 5e90b7c84c6f..a0ea7c59a8eb 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -13,7 +13,6 @@ import scl import logging from pathlib import Path -from natsort import natsorted from twisterlib.environment import ZEPHYR_BASE @@ -322,7 +321,7 @@ def readlink(link): def save(self, hwm_file): # use existing map - self.detected = natsorted(self.detected, key=lambda x: x.serial or '') + self.detected.sort(key=lambda x: x.serial or '') if os.path.exists(hwm_file): with open(hwm_file, 'r') as yaml_file: hwm = yaml.load(yaml_file, Loader=SafeLoader) diff --git a/scripts/quarantine.yaml b/scripts/quarantine.yaml new file mode 100644 index 000000000000..b2d68b5d3e63 --- /dev/null +++ b/scripts/quarantine.yaml @@ -0,0 +1,81 @@ +# The configurations resulting as a product of scenarios and platforms +# will be skipped if quarantine is used. More details here: +# https://docs.zephyrproject.org/latest/guides/test/twister.html#quarantine + +- scenarios: + - testing.ztest.busy_sim + - testing.ztest.busy_sim_nrf52840dk_pin + platforms: + - nrf52840dk_nrf52840 + +# Already reported, but will not be fixed (look at the discussion): +# https://github.com/zephyrproject-rtos/zephyr/issues/44947 +- scenarios: + - libraries.cmsis_dsp.matrix.unary_f64 + platforms: + - nrf5340dk_nrf5340_cpunet + - qemu_cortex_m3 + comment: "Flash overflows" + +# Already reported, but will not be fixed (look at the discussion): +# https://github.com/zephyrproject-rtos/zephyr/issues/44947 +- scenarios: + - libraries.cmsis_dsp.matrix.binary_f16 + - libraries.cmsis_dsp.matrix.binary_f16.fpu + platforms: + - nrf5340dk_nrf5340_cpuapp_ns + comment: "Flash overflows" + +# Already reported, but will not be fixed (look at the discussion): +# https://github.com/zephyrproject-rtos/zephyr/issues/44947 +- scenarios: + - libraries.cmsis_dsp.matrix.binary_q15 + - libraries.cmsis_dsp.matrix.binary_q15.fpu + - libraries.cmsis_dsp.matrix.unary_f32 + - libraries.cmsis_dsp.matrix.unary_f32.fpu + - libraries.cmsis_dsp.matrix.unary_f64 + - libraries.cmsis_dsp.matrix.unary_f64.fpu + platforms: + - nrf5340dk_nrf5340_cpuapp_ns + - nrf9160dk_nrf9160_ns + comment: "Flash overflows" + +# libsdl2-dev package should be added into docker image +- scenarios: + - sample.boards.nrf.nrf_led_matrix + - sample.display.lvgl.gui + platforms: + - native_posix + comment: "libsdl2-dev package not available" + +- scenarios: + - sample.net.sockets.echo_server.usbnet + - sample.net.sockets.echo_server.usbnet_composite + platforms: + - nrf5340dk_nrf5340_cpuapp_ns + comment: "Ram/flash overflows, also in the upstream" + +- scenarios: + - sample.net.zperf.netusb_ecm + - sample.net.zperf.netusb_eem + - sample.net.zperf.netusb_rndis + platforms: + - nrf52833dk_nrf52833 + - nrf5340dk_nrf5340_cpuapp_ns + comment: "Ram/flash overflows, also in the upstream" + +- scenarios: + - net.mqtt.tls + platforms: + - nrf5340dk_nrf5340_cpuapp_ns + - nrf9160dk_nrf9160_ns + comment: "Ram/flash overflows, also in the upstream" + +- scenarios: + - kernel.common.picolibc + - libraries.picolibc + - libraries.libc.picolibc.mem_alloc + - libraries.picolibc.sprintf_new + platforms: + - nrf52dk_nrf52832 + comment: "Ram overflows, also in the upstream" diff --git a/scripts/requirements-run-test.txt b/scripts/requirements-run-test.txt index 836921281102..3bb0b21c44e8 100644 --- a/scripts/requirements-run-test.txt +++ b/scripts/requirements-run-test.txt @@ -7,7 +7,6 @@ pyocd>=0.35.0 # used by twister for board/hardware map tabulate -natsort # used by mcuboot cbor>=1.0.0 diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 7bb405afaaa1..e10831d8d605 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,6 +1,5 @@ -r requirements-base.txt -r requirements-build-test.txt --r requirements-doc.txt -r requirements-run-test.txt -r requirements-extras.txt -r requirements-compliance.txt diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 12a6f4f15bb9..84cb937cc7e8 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -86,7 +86,6 @@ endwhile() sysbuild_module_call(PRE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) foreach(image ${IMAGES}) - include(image_config.cmake) ExternalZephyrProject_Cmake(APPLICATION ${image}) endforeach() sysbuild_module_call(POST_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index bdf8f88b8055..e1339107430f 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -34,6 +34,11 @@ function(load_cache) set_property(TARGET ${LOAD_CACHE_IMAGE}_cache APPEND PROPERTY "CACHE:VARIABLES" "${CMAKE_MATCH_1}") set_property(TARGET ${LOAD_CACHE_IMAGE}_cache PROPERTY "${CMAKE_MATCH_1}:TYPE" "${CMAKE_MATCH_2}") set_property(TARGET ${LOAD_CACHE_IMAGE}_cache PROPERTY "${CMAKE_MATCH_1}" "${variable_value}") + if("${CMAKE_MATCH_1}" MATCHES "^BYPRODUCT_.*") + set_property(TARGET ${LOAD_CACHE_IMAGE}_cache APPEND + PROPERTY "EXTRA_BYPRODUCTS" "${variable_value}" + ) + endif() endif() endforeach() endfunction() @@ -263,6 +268,11 @@ function(ExternalZephyrProject_Add) set_target_properties(${ZBUILD_APPLICATION} PROPERTIES MAIN_APP True) endif() + if(DEFINED ZBUILD_APP_TYPE) + set(image_default "${CMAKE_SOURCE_DIR}/image_configurations/${ZBUILD_APP_TYPE}_image_default.cmake") + set_target_properties(${ZBUILD_APPLICATION} PROPERTIES IMAGE_CONF_SCRIPT ${image_default}) + endif() + if(DEFINED ZBUILD_BOARD) # Only set image specific board if provided. # The sysbuild BOARD is exported through sysbuild cache, and will be used @@ -290,6 +300,17 @@ endfunction() # If the application is not due to ExternalZephyrProject_Add() being called, # then an error is raised. # +# The image output files are added as target properties on the image target as: +# ELF_OUT: property specifying the generated elf file. +# BIN_OUT: property specifying the generated bin file. +# HEX_OUT: property specifying the generated hex file. +# S19_OUT: property specifying the generated s19 file. +# UF2_OUT: property specifying the generated uf2 file. +# EXE_OUT: property specifying the generated exe file. +# +# the property is only set if the image is configured to generate the output +# format. Elf files are always created. +# # APPLICATION: : Name of the application. # function(ExternalZephyrProject_Cmake) @@ -326,6 +347,10 @@ function(ExternalZephyrProject_Cmake) get_target_property(${ZCMAKE_APPLICATION}_BOARD ${ZCMAKE_APPLICATION} BOARD) get_target_property(${ZCMAKE_APPLICATION}_MAIN_APP ${ZCMAKE_APPLICATION} MAIN_APP) + get_property(${ZCMAKE_APPLICATION}_CONF_SCRIPT TARGET ${ZCMAKE_APPLICATION} + PROPERTY IMAGE_CONF_SCRIPT + ) + # Update ROOT variables with relative paths to use absolute paths based on # the source application directory. foreach(type MODULE_EXT BOARD SOC ARCH SCA) @@ -377,6 +402,10 @@ function(ExternalZephyrProject_Cmake) ${${ZCMAKE_APPLICATION}_CACHE_FILE} ONLY_IF_DIFFERENT ) + foreach(script ${${ZCMAKE_APPLICATION}_CONF_SCRIPT}) + include(${script}) + endforeach() + set(dotconfigsysbuild ${BINARY_DIR}/zephyr/.config.sysbuild) get_target_property(config_content ${ZCMAKE_APPLICATION} CONFIG) string(CONFIGURE "${config_content}" config_content) @@ -401,6 +430,15 @@ function(ExternalZephyrProject_Cmake) endif() load_cache(IMAGE ${ZCMAKE_APPLICATION} BINARY_DIR ${BINARY_DIR}) import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config TARGET ${ZCMAKE_APPLICATION}) + + # This custom target informs CMake how the BYPRODUCTS are generated if a target + # depends directly on the BYPRODUCT instead of depending on the image target. + get_target_property(${ZCMAKE_APPLICATION}_byproducts ${ZCMAKE_APPLICATION}_cache EXTRA_BYPRODUCTS) + add_custom_target(${ZCMAKE_APPLICATION}_extra_byproducts + COMMAND ${CMAKE_COMMAND} -E true + BYPRODUCTS ${${ZCMAKE_APPLICATION}_byproducts} + DEPENDS ${ZCMAKE_APPLICATION} + ) endfunction() # Usage: diff --git a/share/sysbuild/image_config.cmake b/share/sysbuild/image_config.cmake deleted file mode 100644 index 0d44f379789c..000000000000 --- a/share/sysbuild/image_config.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2023 Nordic Semiconductor -# -# SPDX-License-Identifier: Apache-2.0 - -# This sysbuild CMake file sets the sysbuild controlled settings as properties -# on Zephyr images. - -get_target_property(image_board ${image} BOARD) -if((NOT image_board) OR ("${image_BOARD}" STREQUAL "${BOARD}")) - get_target_property(${image}_APP_TYPE ${image} APP_TYPE) - if(NOT "${${image}_APP_TYPE}" STREQUAL "BOOTLOADER") - set_config_bool(${image} CONFIG_BOOTLOADER_MCUBOOT "${SB_CONFIG_BOOTLOADER_MCUBOOT}") - set_config_string(${image} CONFIG_MCUBOOT_SIGNATURE_KEY_FILE - "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}" - ) - else() - set(keytypes CONFIG_BOOT_SIGNATURE_TYPE_NONE - CONFIG_BOOT_SIGNATURE_TYPE_RSA - CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 - CONFIG_BOOT_SIGNATURE_TYPE_ED25519) - - if(SB_CONFIG_BOOT_SIGNATURE_TYPE_NONE) - set(keytype CONFIG_BOOT_SIGNATURE_TYPE_NONE) - elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA) - set(keytype CONFIG_BOOT_SIGNATURE_TYPE_RSA) - elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) - set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) - elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519) - set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ED25519) - endif() - - foreach(loopkeytype ${keytypes}) - if("${loopkeytype}" STREQUAL "${keytype}") - set_config_bool(${image} ${loopkeytype} y) - else() - set_config_bool(${image} ${loopkeytype} n) - endif() - endforeach() - endif() - - if(SB_CONFIG_BOOTLOADER_MCUBOOT) - if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") - set_config_bool(${image} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) - else() - set_config_bool(${image} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) - endif() - endif() -endif() diff --git a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake new file mode 100644 index 000000000000..5594109668b4 --- /dev/null +++ b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 + +# This sysbuild CMake file sets the sysbuild controlled settings as properties +# on Zephyr MCUboot / bootloader image. + +set(keytypes CONFIG_BOOT_SIGNATURE_TYPE_NONE + CONFIG_BOOT_SIGNATURE_TYPE_RSA + CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 + CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + +if(SB_CONFIG_BOOT_SIGNATURE_TYPE_NONE) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_NONE) +elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_RSA) +elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) +elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ED25519) +endif() + +foreach(loopkeytype ${keytypes}) + if("${loopkeytype}" STREQUAL "${keytype}") + set_config_bool(${ZCMAKE_APPLICATION} ${loopkeytype} y) + else() + set_config_bool(${ZCMAKE_APPLICATION} ${loopkeytype} n) + endif() +endforeach() + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) + else() + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) + endif() +endif() diff --git a/share/sysbuild/image_configurations/MAIN_image_default.cmake b/share/sysbuild/image_configurations/MAIN_image_default.cmake new file mode 100644 index 000000000000..a6bd72d7d1a1 --- /dev/null +++ b/share/sysbuild/image_configurations/MAIN_image_default.cmake @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 + +# This sysbuild CMake file sets the sysbuild controlled settings as properties +# on the main Zephyr image. + +set_config_bool(${ZCMAKE_APPLICATION} CONFIG_BOOTLOADER_MCUBOOT "${SB_CONFIG_BOOTLOADER_MCUBOOT}") +set_config_string(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_SIGNATURE_KEY_FILE + "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}" +) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) + else() + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) + endif() +endif() diff --git a/soc/arm/common/cortex_m/arm_mpu_regions.c b/soc/arm/common/cortex_m/arm_mpu_regions.c index 477dc30566c7..d44c2ee05b3d 100644 --- a/soc/arm/common/cortex_m/arm_mpu_regions.c +++ b/soc/arm/common/cortex_m/arm_mpu_regions.c @@ -9,6 +9,9 @@ #include #include "arm_mpu_mem_cfg.h" +#if USE_PARTITION_MANAGER +#include +#endif static const struct arm_mpu_region mpu_regions[] = { /* Region 0 */ @@ -22,6 +25,14 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* Region 1 */ MPU_REGION_ENTRY("SRAM_0", +#if USE_PARTITION_MANAGER + PM_SRAM_ADDRESS, +#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) + REGION_RAM_ATTR(PM_SRAM_ADDRESS, PM_SRAM_SIZE)), +#else + REGION_RAM_ATTR(REGION_SRAM_SIZE)), +#endif +#else CONFIG_SRAM_BASE_ADDRESS, #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) REGION_RAM_ATTR(CONFIG_SRAM_BASE_ADDRESS, \ @@ -30,6 +41,8 @@ static const struct arm_mpu_region mpu_regions[] = { REGION_RAM_ATTR(REGION_SRAM_SIZE)), #endif +#endif /* USE_PARTITION_MANAGER */ + /* DT-defined regions */ LINKER_DT_REGION_MPU(ARM_MPU_REGION_INIT) }; diff --git a/soc/arm/microchip_mec/mec1501/Kconfig.series b/soc/arm/microchip_mec/mec1501/Kconfig.series index 83683877bf6a..d3b679bb557d 100644 --- a/soc/arm/microchip_mec/mec1501/Kconfig.series +++ b/soc/arm/microchip_mec/mec1501/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_MEC1501X select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select SOC_FAMILY_MEC + select HAS_PM help Enable support for Microchip MEC Cortex-M4 MCU series diff --git a/soc/arm/microchip_mec/mec1501/power.c b/soc/arm/microchip_mec/mec1501/power.c index 53cc7bc9717d..de6e2fd6fbfb 100644 --- a/soc/arm/microchip_mec/mec1501/power.c +++ b/soc/arm/microchip_mec/mec1501/power.c @@ -102,7 +102,7 @@ static void z_power_soc_sleep(void) * For deep sleep pm_system_suspend has executed all the driver * power management call backs. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -126,7 +126,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) * an ISR on wake except for faults. We re-enable interrupts by setting PRIMASK * to 0. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.series index 77f7d4023c10..cb62a2bbfa91 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.series +++ b/soc/arm/microchip_mec/mec172x/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_MEC172X select CPU_HAS_ARM_MPU select SOC_FAMILY_MEC select HAS_SWO + select HAS_PM help Enable support for Microchip MEC Cortex-M4F MCU series diff --git a/soc/arm/microchip_mec/mec172x/power.c b/soc/arm/microchip_mec/mec172x/power.c index ec0034589ef3..0f31cca31288 100644 --- a/soc/arm/microchip_mec/mec172x/power.c +++ b/soc/arm/microchip_mec/mec172x/power.c @@ -144,7 +144,7 @@ static void z_power_soc_sleep(void) * For deep sleep pm_system_suspend has executed all the driver * power management call backs. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -168,7 +168,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) * ISR on wake except for faults. We re-enable interrupts by undoing global disable * and alling irq_unlock with the same value, 0 zephyr core uses. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { __enable_irq(); irq_unlock(0); diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 183ec475fde9..3eedcf350c6c 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -28,9 +28,6 @@ config SYS_CLOCK_TICKS_PER_SEC config ARCH_HAS_CUSTOM_BUSY_WAIT default y if !QEMU_TARGET -config PM - default y if SYS_CLOCK_EXISTS && !HAS_NO_PM && MULTITHREADING - config BUILD_OUTPUT_HEX default y diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index e81d195b2a02..5f3b1de14de7 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -13,10 +13,12 @@ config HAS_HW_NRF_BPROT def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_BPROT)) config HAS_HW_NRF_CC310 - def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_CC310)) + def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_CC310)) || \ + ($(dt_nodelabel_enabled,psa_rng) && SOC_SERIES_NRF91X) config HAS_HW_NRF_CC312 - def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_CC312)) + def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_CC312)) || \ + ($(dt_nodelabel_enabled,psa_rng) && SOC_NRF5340_CPUAPP) config HAS_HW_NRF_CCM def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_CCM)) diff --git a/soc/arm/nordic_nrf/common/CMakeLists.txt b/soc/arm/nordic_nrf/common/CMakeLists.txt index 941ccaea039d..eb074dd05481 100644 --- a/soc/arm/nordic_nrf/common/CMakeLists.txt +++ b/soc/arm/nordic_nrf/common/CMakeLists.txt @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_NRF soc_nrf_common.S) +zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_include_directories(.) if (CONFIG_TFM_PARTITION_PLATFORM) diff --git a/soc/arm/nordic_nrf/common/poweroff.c b/soc/arm/nordic_nrf/common/poweroff.c new file mode 100644 index 000000000000..1c43da3e9eae --- /dev/null +++ b/soc/arm/nordic_nrf/common/poweroff.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) +#include +#else +#include +#endif + +void z_sys_poweroff(void) +{ +#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) + nrf_power_system_off(NRF_POWER); +#else + nrf_regulators_system_off(NRF_REGULATORS); +#endif + + CODE_UNREACHABLE; +} diff --git a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt index 0f11eefca2e1..1a8b943ad5b3 100644 --- a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt @@ -6,10 +6,6 @@ zephyr_library_sources( soc.c ) -zephyr_library_sources_ifdef(CONFIG_PM - power.c - ) - zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/arm/include diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.series index 33f62dc43273..e7028b021909 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_NRF51X select XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_POWEROFF help Enable support for NRF51 MCU series diff --git a/soc/arm/nordic_nrf/nrf51/power.c b/soc/arm/nordic_nrf/nrf51/power.c deleted file mode 100644 index 8291d10700d2..000000000000 --- a/soc/arm/nordic_nrf/nrf51/power.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include - -#include -LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); - -/* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - nrf_power_system_off(NRF_POWER); - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } -} - -/* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - /* Nothing to do. */ - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } - - /* - * System is now in active mode. Reenable interrupts which were disabled - * when OS started idling code. - */ - irq_unlock(0); -} diff --git a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt index c795df3947b3..559ce6a39797 100644 --- a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt @@ -6,10 +6,6 @@ zephyr_library_sources( soc.c ) -zephyr_library_sources_ifdef(CONFIG_PM - power.c - ) - zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/arm/include diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.series index 6ff33c5da4c2..f11bd5cd59f5 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_NRF52X select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_SWO + select HAS_POWEROFF help Enable support for NRF52 MCU series diff --git a/soc/arm/nordic_nrf/nrf52/power.c b/soc/arm/nordic_nrf/nrf52/power.c deleted file mode 100644 index 8291d10700d2..000000000000 --- a/soc/arm/nordic_nrf/nrf52/power.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include - -#include -LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); - -/* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - nrf_power_system_off(NRF_POWER); - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } -} - -/* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - /* Nothing to do. */ - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } - - /* - * System is now in active mode. Reenable interrupts which were disabled - * when OS started idling code. - */ - irq_unlock(0); -} diff --git a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt index bb398c987a9c..af4fe549a635 100644 --- a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt @@ -4,10 +4,6 @@ zephyr_sources( soc.c ) -zephyr_library_sources_ifdef(CONFIG_PM - power.c - ) - zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC sync_rtc.c ) diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 967376088004..122c36988e5d 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -9,10 +9,11 @@ config SOC_NRF5340_CPUAPP select CPU_HAS_NRF_IDAU select CPU_HAS_FPU select ARMV8_M_DSP + select HAS_POWEROFF config SOC_NRF5340_CPUNET bool - select HAS_NO_PM + select ARM_ON_EXIT_CPU_IDLE imply SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED choice diff --git a/soc/arm/nordic_nrf/nrf53/power.c b/soc/arm/nordic_nrf/nrf53/power.c deleted file mode 100644 index ccd658be6ebc..000000000000 --- a/soc/arm/nordic_nrf/nrf53/power.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include - -#include - -#include -LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); - -/* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - nrf_regulators_system_off(NRF_REGULATORS); - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } -} - -/* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - /* Nothing to do. */ - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } - - /* - * System is now in active mode. Reenable interrupts which were disabled - * when OS started idling code. - */ - irq_unlock(0); -} diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h new file mode 100644 index 000000000000..b6cd92ca092a --- /dev/null +++ b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC extensions of cpu_idle.S for the Nordic Semiconductor nRF53 processors family. + */ + + +#if defined(_ASMLANGUAGE) + +#define SOC_ON_EXIT_CPU_IDLE \ + nop; \ + nop; \ + nop; \ + nop; + +#endif /* _ASMLANGUAGE */ diff --git a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt index c9799cf9ae6e..332416ba43b0 100644 --- a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt @@ -3,7 +3,3 @@ zephyr_sources( soc.c ) - -zephyr_library_sources_ifdef(CONFIG_PM - power.c - ) diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.series index 54884ec13d2f..fd8f5b04d7ad 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.series @@ -16,5 +16,6 @@ config SOC_SERIES_NRF91X select XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_POWEROFF help Enable support for NRF91 MCU series diff --git a/soc/arm/nordic_nrf/nrf91/power.c b/soc/arm/nordic_nrf/nrf91/power.c deleted file mode 100644 index 20834906069d..000000000000 --- a/soc/arm/nordic_nrf/nrf91/power.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation. - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include - -#include -LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); - -/* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - nrf_regulators_system_off(NRF_REGULATORS); - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } -} - -/* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(substate_id); - - switch (state) { - case PM_STATE_SOFT_OFF: - /* Nothing to do. */ - break; - default: - LOG_DBG("Unsupported power state %u", state); - break; - } - - /* - * System is now in active mode. Reenable interrupts which were disabled - * when OS started idling code. - */ - irq_unlock(0); -} diff --git a/soc/arm/nuvoton_npcx/common/power.c b/soc/arm/nuvoton_npcx/common/power.c index 379784231d2c..e7fe036f7669 100644 --- a/soc/arm/nuvoton_npcx/common/power.c +++ b/soc/arm/nuvoton_npcx/common/power.c @@ -199,7 +199,7 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode) } /* Invoke when enter "Suspend/Low Power" mode. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -228,7 +228,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle soc specific activity after exiting "Suspend/Low Power" mode. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.series index 3fb6921fc094..8f8898388cf2 100644 --- a/soc/arm/nuvoton_npcx/npcx7/Kconfig.series +++ b/soc/arm/nuvoton_npcx/npcx7/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_NPCX7 select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + select HAS_PM help Enable support for Nuvoton NPCX7 series diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.series b/soc/arm/nuvoton_npcx/npcx9/Kconfig.series index 61f258171fbb..82423b370598 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.series +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_NPCX9 select CPU_HAS_FPU select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX + select HAS_PM help Enable support for Nuvoton NPCX9 series diff --git a/soc/arm/nxp_imx/rt/Kconfig.series b/soc/arm/nxp_imx/rt/Kconfig.series index d1adff602513..0a94b3963b1d 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_IMX_RT select ARM select SOC_FAMILY_IMX select CLOCK_CONTROL + select HAS_PM help Enable support for i.MX RT MCU series diff --git a/soc/arm/nxp_imx/rt/power_rt10xx.c b/soc/arm/nxp_imx/rt/power_rt10xx.c index dea33f3ce8f6..ca10fdecf4dc 100644 --- a/soc/arm/nxp_imx/rt/power_rt10xx.c +++ b/soc/arm/nxp_imx/rt/power_rt10xx.c @@ -183,7 +183,7 @@ static void lpm_raise_voltage(void) /* Sets device into low power mode */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -213,7 +213,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt/power_rt11xx.c b/soc/arm/nxp_imx/rt/power_rt11xx.c index 559e61ce5bcc..871a7d809a3c 100644 --- a/soc/arm/nxp_imx/rt/power_rt11xx.c +++ b/soc/arm/nxp_imx/rt/power_rt11xx.c @@ -283,7 +283,7 @@ void cpu_mode_transition(gpc_cpu_mode_t mode, bool enable_standby) * SOC specific low power mode implementation * Drop to lowest power state possible given system's request */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); @@ -306,7 +306,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } } -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.series b/soc/arm/nxp_imx/rt5xx/Kconfig.series index 057e03115be8..0acc80909516 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.series +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.series @@ -10,5 +10,6 @@ config SOC_SERIES_IMX_RT5XX select CPU_CORTEX_M_HAS_DWT select SOC_FAMILY_IMX select CLOCK_CONTROL + select HAS_PM help Enable support for i.MX RT5XX Series MCU series diff --git a/soc/arm/nxp_imx/rt5xx/power.c b/soc/arm/nxp_imx/rt5xx/power.c index 9c95fc3a424f..b4137827c605 100644 --- a/soc/arm/nxp_imx/rt5xx/power.c +++ b/soc/arm/nxp_imx/rt5xx/power.c @@ -45,7 +45,7 @@ __ramfunc void restore_deepsleep_pin_config(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -82,7 +82,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt6xx/Kconfig.series b/soc/arm/nxp_imx/rt6xx/Kconfig.series index b028afbfa343..bcbf86ff6bfb 100644 --- a/soc/arm/nxp_imx/rt6xx/Kconfig.series +++ b/soc/arm/nxp_imx/rt6xx/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_IMX_RT6XX select CLOCK_CONTROL select CODE_DATA_RELOCATION_SRAM if FLASH_MCUX_FLEXSPI_XIP select PLATFORM_SPECIFIC_INIT + select HAS_PM help Enable support for i.MX RT6XX Series MCU series diff --git a/soc/arm/nxp_imx/rt6xx/power.c b/soc/arm/nxp_imx/rt6xx/power.c index 6709f7b2c9dc..04494737af60 100644 --- a/soc/arm/nxp_imx/rt6xx/power.c +++ b/soc/arm/nxp_imx/rt6xx/power.c @@ -22,7 +22,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); APP_DEEPSLEEP_RAM_APD, APP_DEEPSLEEP_RAM_PPD})) /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -52,7 +52,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_kinetis/ke1xf/Kconfig.series b/soc/arm/nxp_kinetis/ke1xf/Kconfig.series index 259e95e8a6d4..640bc4ec8fdf 100644 --- a/soc/arm/nxp_kinetis/ke1xf/Kconfig.series +++ b/soc/arm/nxp_kinetis/ke1xf/Kconfig.series @@ -32,5 +32,6 @@ config SOC_SERIES_KINETIS_KE1XF select HAS_MCUX_PWT select HAS_MCUX_RCM select PLATFORM_SPECIFIC_INIT + select HAS_PM help Enable support for Kinetis KE1xF MCU series diff --git a/soc/arm/nxp_kinetis/ke1xf/power.c b/soc/arm/nxp_kinetis/ke1xf/power.c index 8d2cdfbe4383..6340df6ff5b9 100644 --- a/soc/arm/nxp_kinetis/ke1xf/power.c +++ b/soc/arm/nxp_kinetis/ke1xf/power.c @@ -25,7 +25,7 @@ __ramfunc static void wait_for_flash_prefetch_and_idle(void) } #endif /* CONFIG_XIP */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_RUNTIME_IDLE: @@ -51,7 +51,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } } -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/silabs_exx32/common/soc_power.c b/soc/arm/silabs_exx32/common/soc_power.c index e1702a100833..cdb279c848fe 100644 --- a/soc/arm/silabs_exx32/common/soc_power.c +++ b/soc/arm/silabs_exx32/common/soc_power.c @@ -20,7 +20,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -63,7 +63,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/silabs_exx32/common/soc_power_pmgr.c b/soc/arm/silabs_exx32/common/soc_power_pmgr.c index aa303874ddec..0286e99e77f5 100644 --- a/soc/arm/silabs_exx32/common/soc_power_pmgr.c +++ b/soc/arm/silabs_exx32/common/soc_power_pmgr.c @@ -21,7 +21,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); sl_power_manager_em_t energy_mode = SL_POWER_MANAGER_EM0; diff --git a/soc/arm/silabs_exx32/efm32hg/Kconfig.series b/soc/arm/silabs_exx32/efm32hg/Kconfig.series index 13c74edb2e6c..4acdfa793ccd 100644 --- a/soc/arm/silabs_exx32/efm32hg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32hg/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_EFM32HG select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 Happy Gecko MCU series diff --git a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series index f454316dad44..2d9675430bef 100644 --- a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_EFM32JG12B select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select HAS_PM help Enable support for EFM32 JadeGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series index 7f99d6d64b8b..ccb7e8178b91 100644 --- a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFM32PG12B select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select HAS_PM help Enable support for EFM32 PearlGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series index 9bbf4def7629..caeae082a3bf 100644 --- a/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFM32PG1B select SOC_GECKO_CMU select SOC_GECKO_EMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 PearlGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32wg/Kconfig.series b/soc/arm/silabs_exx32/efm32wg/Kconfig.series index 5d6e4f21e444..f339c755e050 100644 --- a/soc/arm/silabs_exx32/efm32wg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32wg/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_EFM32WG select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 WonderGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series b/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series index 3fea9b454df3..e7f524a026f7 100644 --- a/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_EFR32BG13P select SOC_GECKO_CMU select SOC_GECKO_EMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFR32BG13P Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg22/Kconfig.series b/soc/arm/silabs_exx32/efr32bg22/Kconfig.series index 776175de925e..266d63917257 100644 --- a/soc/arm/silabs_exx32/efr32bg22/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg22/Kconfig.series @@ -20,5 +20,6 @@ config SOC_SERIES_EFR32BG22 select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32BG22 Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg27/Kconfig.series b/soc/arm/silabs_exx32/efr32bg27/Kconfig.series index 6118e1886294..572e6107f4e2 100644 --- a/soc/arm/silabs_exx32/efr32bg27/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg27/Kconfig.series @@ -20,5 +20,6 @@ config SOC_SERIES_EFR32BG27 select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32BG27 Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series index 1913377b3e70..6f5573775795 100644 --- a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFR32FG13P select SOC_GECKO_CMU select SOC_GECKO_GPIO select SOC_GECKO_HAS_ERRATA_RTCC_E201 + select HAS_PM help Enable support for EFR32 FlexGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series b/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series index b2d1ff287447..f8e509faa6db 100644 --- a/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFR32FG1P select SOC_GECKO_CMU select SOC_GECKO_GPIO select SOC_GECKO_HAS_ERRATA_RTCC_E201 + select HAS_PM help Enable support for EFR32 FlexGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series index 510889568f03..7c636daec862 100644 --- a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFR32MG12P select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select HAS_PM help Enable support for EFR32 Mighty Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series index ab64bea46d1f..c22cb8376ee2 100644 --- a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFR32MG21 select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32MG21 Mighty Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg24/Kconfig.series b/soc/arm/silabs_exx32/efr32mg24/Kconfig.series index 7c6d49d2eaed..064db296cd8e 100644 --- a/soc/arm/silabs_exx32/efr32mg24/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg24/Kconfig.series @@ -22,5 +22,6 @@ config SOC_SERIES_EFR32MG24 select SOC_GECKO_GPIO select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32MG24 Mighty Gecko MCU series diff --git a/soc/arm/st_stm32/stm32g0/Kconfig.series b/soc/arm/st_stm32/stm32g0/Kconfig.series index 43353332745f..acdb926ef61d 100644 --- a/soc/arm/st_stm32/stm32g0/Kconfig.series +++ b/soc/arm/st_stm32/stm32g0/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32G0X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_CORTEX_M_HAS_SYSTICK + select HAS_PM help Enable support for STM32G0 MCU series diff --git a/soc/arm/st_stm32/stm32g0/power.c b/soc/arm/st_stm32/stm32g0/power.c index bc9ca8f2a312..d13ec265679e 100644 --- a/soc/arm/st_stm32/stm32g0/power.c +++ b/soc/arm/st_stm32/stm32g0/power.c @@ -20,7 +20,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -50,7 +50,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate %u", state); diff --git a/soc/arm/st_stm32/stm32g4/Kconfig.series b/soc/arm/st_stm32/stm32g4/Kconfig.series index 93fda8ba9a05..6d81e3f1fc14 100644 --- a/soc/arm/st_stm32/stm32g4/Kconfig.series +++ b/soc/arm/st_stm32/stm32g4/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32G4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL + select HAS_PM help Enable support for STM32G4 MCU series diff --git a/soc/arm/st_stm32/stm32g4/power.c b/soc/arm/st_stm32/stm32g4/power.c index 7d55a3c42094..dadb07114681 100644 --- a/soc/arm/st_stm32/stm32g4/power.c +++ b/soc/arm/st_stm32/stm32g4/power.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -49,7 +49,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate %u", state); diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.series b/soc/arm/st_stm32/stm32l0/Kconfig.series index c465a922848a..950c72d4aa78 100644 --- a/soc/arm/st_stm32/stm32l0/Kconfig.series +++ b/soc/arm/st_stm32/stm32l0/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_STM32L0X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_CORTEX_M_HAS_SYSTICK + select HAS_PM help Enable support for STM32L0 MCU series diff --git a/soc/arm/st_stm32/stm32l0/power.c b/soc/arm/st_stm32/stm32l0/power.c index 585aaf69293f..a2a11f824aad 100644 --- a/soc/arm/st_stm32/stm32l0/power.c +++ b/soc/arm/st_stm32/stm32l0/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -54,7 +54,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/st_stm32/stm32l4/Kconfig.series b/soc/arm/st_stm32/stm32l4/Kconfig.series index 084082188b2f..33758aadefd7 100644 --- a/soc/arm/st_stm32/stm32l4/Kconfig.series +++ b/soc/arm/st_stm32/stm32l4/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_STM32L4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32L4 MCU series diff --git a/soc/arm/st_stm32/stm32l4/power.c b/soc/arm/st_stm32/stm32l4/power.c index b8445a7165cd..8b1a68fc767e 100644 --- a/soc/arm/st_stm32/stm32l4/power.c +++ b/soc/arm/st_stm32/stm32l4/power.c @@ -82,7 +82,7 @@ void set_mode_shutdown(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -106,7 +106,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: diff --git a/soc/arm/st_stm32/stm32l5/Kconfig.series b/soc/arm/st_stm32/stm32l5/Kconfig.series index f9447205a539..ffee96473c32 100644 --- a/soc/arm/st_stm32/stm32l5/Kconfig.series +++ b/soc/arm/st_stm32/stm32l5/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_STM32L5X select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM help Enable support for STM32L5 MCU series diff --git a/soc/arm/st_stm32/stm32l5/power.c b/soc/arm/st_stm32/stm32l5/power.c index e799b88c86ef..1d5316c69635 100644 --- a/soc/arm/st_stm32/stm32l5/power.c +++ b/soc/arm/st_stm32/stm32l5/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -66,7 +66,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate-id %u", state); diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.series b/soc/arm/st_stm32/stm32u5/Kconfig.series index 69082b70e1cf..99835997a6a2 100644 --- a/soc/arm/st_stm32/stm32u5/Kconfig.series +++ b/soc/arm/st_stm32/stm32u5/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_STM32U5X select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM help Enable support for STM32U5 MCU series diff --git a/soc/arm/st_stm32/stm32u5/power.c b/soc/arm/st_stm32/stm32u5/power.c index 32e8e7334e29..4cd5834cf8be 100644 --- a/soc/arm/st_stm32/stm32u5/power.c +++ b/soc/arm/st_stm32/stm32u5/power.c @@ -62,7 +62,7 @@ void set_mode_shutdown(uint8_t substate_id) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -88,7 +88,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: diff --git a/soc/arm/st_stm32/stm32wb/Kconfig.series b/soc/arm/st_stm32/stm32wb/Kconfig.series index 8ba570edfe6e..03c9bf957235 100644 --- a/soc/arm/st_stm32/stm32wb/Kconfig.series +++ b/soc/arm/st_stm32/stm32wb/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32WBX select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32WB MCU series diff --git a/soc/arm/st_stm32/stm32wb/power.c b/soc/arm/st_stm32/stm32wb/power.c index fba9c06aad2d..cf368503c364 100644 --- a/soc/arm/st_stm32/stm32wb/power.c +++ b/soc/arm/st_stm32/stm32wb/power.c @@ -56,7 +56,7 @@ static void lpm_hsem_lock(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state == PM_STATE_SOFT_OFF) { lpm_hsem_lock(); @@ -108,7 +108,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { /* Implementation of STM32 AN5289 algorithm to enter/exit lowpower */ /* Release ENTRY_STOP_MODE semaphore */ diff --git a/soc/arm/st_stm32/stm32wl/Kconfig.series b/soc/arm/st_stm32/stm32wl/Kconfig.series index 3b2645dd6cdd..58dcae421bad 100644 --- a/soc/arm/st_stm32/stm32wl/Kconfig.series +++ b/soc/arm/st_stm32/stm32wl/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_STM32WLX select HAS_STM32CUBE select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL + select HAS_PM help Enable support for STM32WL MCU series diff --git a/soc/arm/st_stm32/stm32wl/power.c b/soc/arm/st_stm32/stm32wl/power.c index e85f55ea39a3..5517ec1ff470 100644 --- a/soc/arm/st_stm32/stm32wl/power.c +++ b/soc/arm/st_stm32/stm32wl/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -74,7 +74,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series index ea9154b262f3..a7c8710bb2b7 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_CC13X2_CC26X2 select SOC_FAMILY_TISIMPLELINK select HAS_CC13X2_CC26X2_SDK select HAS_TI_CCFG + select HAS_PM help Enable support for TI SimpleLink CC13x2 / CC26x2 SoCs diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c index a22ecee538f3..88a519336654 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c @@ -58,7 +58,7 @@ extern PowerCC26X2_ModuleState PowerCC26X2_module; */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -122,7 +122,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series index a937b6c521c1..147dd6821e27 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_CC13X2X7_CC26X2X7 select SOC_FAMILY_TISIMPLELINK select HAS_CC13X2X7_CC26X2X7_SDK select HAS_TI_CCFG if !BOOTLOADER_MCUBOOT + select HAS_PM help Enable support for TI SimpleLink CC13x2x7 / CC26x2x7 SoCs diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c index 07057129e258..f0e1407ef45a 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c @@ -58,7 +58,7 @@ extern PowerCC26X2_ModuleState PowerCC26X2_module; */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -122,7 +122,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/riscv/esp32c3/Kconfig.soc b/soc/riscv/esp32c3/Kconfig.soc index 63321375841f..56d2a64a63ce 100644 --- a/soc/riscv/esp32c3/Kconfig.soc +++ b/soc/riscv/esp32c3/Kconfig.soc @@ -14,6 +14,7 @@ config SOC_ESP32C3 select RISCV_ISA_EXT_M select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR + select HAS_PM if SOC_ESP32C3 diff --git a/soc/riscv/esp32c3/power.c b/soc/riscv/esp32c3/power.c index f7dd0e8ec508..aa63c6925f0a 100644 --- a/soc/riscv/esp32c3/power.c +++ b/soc/riscv/esp32c3/power.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -32,7 +32,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/riscv/riscv-ite/common/power.c b/soc/riscv/riscv-ite/common/power.c index 882101b94346..120c80c68524 100644 --- a/soc/riscv/riscv-ite/common/power.c +++ b/soc/riscv/riscv-ite/common/power.c @@ -16,7 +16,7 @@ static void ite_power_soc_deep_doze(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -31,7 +31,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series b/soc/riscv/riscv-ite/it8xxx2/Kconfig.series index a30d1e554385..ebed0fcd120e 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series +++ b/soc/riscv/riscv-ite/it8xxx2/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_RISCV32_IT8XXX2 # default in most toolchains, causing link-time errors. select CPU_HAS_FPU if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" || RISCV_ISA_EXT_M select SOC_FAMILY_RISCV_ITE + select HAS_PM help Enable support for ITE IT8XXX2 diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/esp32/Kconfig.soc index 56949f965992..97020542b00f 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/esp32/Kconfig.soc @@ -12,6 +12,7 @@ config SOC_ESP32 select XIP if !MCUBOOT select HAS_ESPRESSIF_HAL select CPU_HAS_FPU + select HAS_PM if SOC_ESP32 diff --git a/soc/xtensa/esp32/power.c b/soc/xtensa/esp32/power.c index 440d232d4b3c..ddbf77c42fcc 100644 --- a/soc/xtensa/esp32/power.c +++ b/soc/xtensa/esp32/power.c @@ -16,7 +16,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); static uint32_t intenable; /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -43,7 +43,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/xtensa/esp32s2/Kconfig.soc b/soc/xtensa/esp32s2/Kconfig.soc index f9d77cc1f5d5..1aea6e8beb3a 100644 --- a/soc/xtensa/esp32s2/Kconfig.soc +++ b/soc/xtensa/esp32s2/Kconfig.soc @@ -10,6 +10,7 @@ config SOC_ESP32S2 select PINCTRL select XIP if !MCUBOOT select HAS_ESPRESSIF_HAL + select HAS_PM if SOC_ESP32S2 diff --git a/soc/xtensa/esp32s2/power.c b/soc/xtensa/esp32s2/power.c index 907784d5cd4c..42e7121438ea 100644 --- a/soc/xtensa/esp32s2/power.c +++ b/soc/xtensa/esp32s2/power.c @@ -14,7 +14,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); static uint32_t intenable; /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -35,7 +35,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.series index 8b4f8e61436f..963c33bdf615 100644 --- a/soc/xtensa/intel_adsp/ace/Kconfig.series +++ b/soc/xtensa/intel_adsp/ace/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_INTEL_ACE select SCHED_IPI_SUPPORTED select DW_ICTL_ACE select SOC_HAS_RUNTIME_NUM_CPUS + select HAS_PM help Intel ADSP ACE diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index ea3ea2e6d63f..bd921e3f16b0 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -213,7 +213,7 @@ __imr void pm_state_imr_restore(void) } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); @@ -298,7 +298,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); diff --git a/soc/xtensa/intel_adsp/cavs/Kconfig.series b/soc/xtensa/intel_adsp/cavs/Kconfig.series index 1f398025eb4b..adbc1f39e1d4 100644 --- a/soc/xtensa/intel_adsp/cavs/Kconfig.series +++ b/soc/xtensa/intel_adsp/cavs/Kconfig.series @@ -10,5 +10,6 @@ config SOC_SERIES_INTEL_ADSP_CAVS select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" select ARCH_HAS_COHERENCE + select HAS_PM help Intel ADSP CAVS diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index e05df97c6e72..42598e9b56fd 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(soc); # define SHIM_GPDMA_CLKCTL(x) (SHIM_GPDMA_BASE(x) + 0x4) # define SHIM_CLKCTL_LPGPDMAFDCGB BIT(0) -#ifdef CONFIG_PM_POLICY_CUSTOM +#ifdef CONFIG_PM #define SRAM_ALIAS_BASE 0x9E000000 #define SRAM_ALIAS_MASK 0xFF000000 #define SRAM_ALIAS_OFFSET 0x20000000 @@ -76,7 +76,7 @@ static inline void __sparse_cache *uncache_to_cache(void *address) return (void __sparse_cache *)((uintptr_t)(address) | SRAM_ALIAS_OFFSET); } -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); @@ -112,7 +112,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); @@ -125,7 +125,7 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) __ASSERT(false, "invalid argument - unsupported power state"); } } -#endif /* CONFIG_PM_POLICY_CUSTOM */ +#endif /* CONFIG_PM */ __imr void power_init(void) { diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4cc413ea03cb..1ac1ca29fbac 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -114,7 +114,8 @@ choice BT_LL_CHOICE Select the Bluetooth Link Layer to compile. config BT_LL_SW_SPLIT - bool "Software-based BLE Link Layer" + bool "Software-based BLE Link Layer [EXPERIMENTAL]" + select EXPERIMENTAL select ENTROPY_GENERATOR help Use Zephyr software BLE Link Layer ULL LLL split implementation. diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index ee5d0f0b0e33..8287747878ec 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -299,6 +299,18 @@ config BT_CONN_TX_MAX callback. Normally this can be left to the default value, which is equal to the number of TX buffers in the stack-internal pool. +config BT_CONN_PARAM_ANY + bool "Accept any values for connection parameters" + help + Some controllers support additional connection parameter ranges + beyond what is described in the specification. Enabling this option + allows the application to set any value to all connection parameters. + Tbe Host will perform no limits nor consistency checks on any of the + connection parameters (conn interval min and max, latency and timeout). + However, the Host will still use numerical comparisons between the + min and max connection intervals in order to verify whether the + desired parameters have been established in the connection. + config BT_USER_PHY_UPDATE bool "User control of PHY Update Procedure" depends on BT_PHY_UPDATE @@ -600,6 +612,13 @@ config BT_BONDING_REQUIRED set the bondable flag in their pairing request. Any other kind of requests will be rejected. +config BT_BONDABLE_PER_CONNECTION + bool "Set/clear the bonding flag per-connection [EXPERIMENTAL]" + select EXPERIMENTAL + help + Enable support for the bt_conn_set_bondable API function that is + used to set/clear the bonding flag on a per-connection basis. + config BT_STORE_DEBUG_KEYS bool "Store Debug Mode bonds" help diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index d3cf7146db34..e405a56d1473 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -223,26 +223,26 @@ if BT_GAP_PERIPHERAL_PREF_PARAMS config BT_PERIPHERAL_PREF_MIN_INT int "Peripheral preferred minimum connection interval in 1.25ms units" default 24 - range 6 65535 + range 6 65535 if !BT_CONN_PARAM_ANY help Range 3200 to 65534 is invalid. 65535 represents no specific value. config BT_PERIPHERAL_PREF_MAX_INT int "Peripheral preferred maximum connection interval in 1.25ms units" default 40 - range 6 65535 + range 6 65535 if !BT_CONN_PARAM_ANY help Range 3200 to 65534 is invalid. 65535 represents no specific value. config BT_PERIPHERAL_PREF_LATENCY int "Peripheral preferred peripheral latency in Connection Intervals" default 0 - range 0 499 + range 0 499 if !BT_CONN_PARAM_ANY config BT_PERIPHERAL_PREF_TIMEOUT int "Peripheral preferred supervision timeout in 10ms units" default 42 - range 10 65535 + range 10 65535 if !BT_CONN_PARAM_ANY help It is up to user to provide valid timeout which pass required minimum value: in milliseconds it shall be larger than diff --git a/subsys/bluetooth/host/Kconfig.l2cap b/subsys/bluetooth/host/Kconfig.l2cap index 82c9e55b864b..2393879bed64 100644 --- a/subsys/bluetooth/host/Kconfig.l2cap +++ b/subsys/bluetooth/host/Kconfig.l2cap @@ -66,7 +66,7 @@ config BT_L2CAP_DYNAMIC_CHANNEL allowing the creation of dynamic L2CAP Channels. config BT_L2CAP_ECRED - bool "L2CAP Enhanced Credit Based Flow Control support" + bool "L2CAP Enhanced Credit Based Flow Control support [EXPERIMENTAL]" depends on BT_L2CAP_DYNAMIC_CHANNEL help This option enables support for LE Connection oriented Channels with diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index b6d95b83ebd1..572b9ab00afa 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -416,18 +416,24 @@ static struct bt_conn_tx *conn_tx_alloc(void) int bt_conn_send_iso_cb(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb, bool has_ts) { - int err = bt_conn_send_cb(conn, buf, cb, NULL); - - if (err) { - return err; + if (buf->user_data_size < CONFIG_BT_CONN_TX_USER_DATA_SIZE) { + LOG_ERR("not enough room in user_data %d < %d", + buf->user_data_size, + CONFIG_BT_CONN_TX_USER_DATA_SIZE); + return -EINVAL; } /* Necessary for setting the TS_Flag bit when we pop the buffer from the - * send queue. - * Size check for the user_data is already done in `bt_conn_send_cb`. + * send queue. The flag needs to be set before adding the buffer to the queue. */ tx_data(buf)->iso_has_ts = has_ts; + int err = bt_conn_send_cb(conn, buf, cb, NULL); + + if (err) { + return err; + } + return 0; } diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 8a793d3108f4..6c5cee9cf0a3 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1698,6 +1698,10 @@ static void le_phy_update_complete(struct net_buf *buf) bool bt_le_conn_params_valid(const struct bt_le_conn_param *param) { + if (IS_ENABLED(CONFIG_BT_CONN_PARAM_ANY)) { + return true; + } + /* All limits according to BT Core spec 5.0 [Vol 2, Part E, 7.8.12] */ if (param->interval_min > param->interval_max || diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 2fad1ea235f7..86fbd723cd57 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -209,6 +209,9 @@ struct bt_smp { /* Used Bluetooth authentication callbacks. */ atomic_ptr_t auth_cb; + + /* Bondable flag */ + atomic_t bondable; }; static unsigned int fixed_passkey = BT_PASSKEY_INVALID; @@ -288,6 +291,11 @@ static K_SEM_DEFINE(sc_local_pkey_ready, 0, 1); */ #define BT_SMP_AUTH_CB_UNINITIALIZED ((atomic_ptr_val_t)bt_smp_pool) +/* Value used to mark that per-connection bondable flag is not initialized. + * Value false/true represent if flag is cleared or set and cannot be used for that purpose. + */ +#define BT_SMP_BONDABLE_UNINITIALIZED ((atomic_val_t)-1) + static bool le_sc_supported(void) { /* @@ -310,6 +318,13 @@ static const struct bt_conn_auth_cb *latch_auth_cb(struct bt_smp *smp) return atomic_ptr_get(&smp->auth_cb); } +static bool latch_bondable(struct bt_smp *smp) +{ + atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)bondable); + + return atomic_get(&smp->bondable); +} + static uint8_t get_io_capa(struct bt_smp *smp) { const struct bt_conn_auth_cb *smp_auth_cb = latch_auth_cb(smp); @@ -1632,7 +1647,15 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status) { struct bt_conn *conn = smp->chan.chan.conn; - LOG_DBG("status 0x%x", status); + LOG_DBG("got status 0x%x", status); + + if (conn->state != BT_CONN_CONNECTED) { + /* If disconnection has been triggered in between the security update + * and the call to this function we need to abort the pairing. + */ + LOG_WRN("Not connected!"); + status = BT_SMP_ERR_UNSPECIFIED; + } if (!status) { #if defined(CONFIG_BT_BREDR) @@ -1701,7 +1724,7 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status) smp_reset(smp); - if (conn->sec_level != conn->required_sec_level) { + if (conn->state == BT_CONN_CONNECTED && conn->sec_level != conn->required_sec_level) { bt_smp_start_security(conn); } } @@ -2584,7 +2607,7 @@ static uint8_t get_auth(struct bt_smp *smp, uint8_t auth) auth |= BT_SMP_AUTH_MITM; } - if (bondable) { + if (latch_bondable(smp)) { auth |= BT_SMP_AUTH_BONDING; } else { auth &= ~BT_SMP_AUTH_BONDING; @@ -3969,7 +3992,7 @@ static uint8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf) } if (IS_ENABLED(CONFIG_BT_BONDING_REQUIRED) && - !(bondable && (auth & BT_SMP_AUTH_BONDING))) { + !(latch_bondable(smp) && (auth & BT_SMP_AUTH_BONDING))) { /* Reject security req if not both intend to bond */ LOG_DBG("Bonding required"); return BT_SMP_ERR_UNSPECIFIED; @@ -4533,6 +4556,7 @@ static void bt_smp_connected(struct bt_l2cap_chan *chan) smp_reset(smp); atomic_ptr_set(&smp->auth_cb, BT_SMP_AUTH_CB_UNINITIALIZED); + atomic_set(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED); } static void bt_smp_disconnected(struct bt_l2cap_chan *chan) @@ -5283,6 +5307,24 @@ static inline int smp_self_test(void) } #endif +#if defined(CONFIG_BT_BONDABLE_PER_CONNECTION) +int bt_conn_set_bondable(struct bt_conn *conn, bool enable) +{ + struct bt_smp *smp; + + smp = smp_chan_get(conn); + if (!smp) { + return -EINVAL; + } + + if (atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)enable)) { + return 0; + } else { + return -EALREADY; + } +} +#endif + int bt_smp_auth_cb_overlay(struct bt_conn *conn, const struct bt_conn_auth_cb *cb) { struct bt_smp *smp; diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index df97ee49d0ff..10b142e87f59 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -120,6 +120,8 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV sol_pdu_rpl_srv.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_STATISTIC statistic.c) + if (CONFIG_BT_MESH_USES_TINYCRYPT) zephyr_library_sources(crypto_tc.c) else() diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 3a2a35b28385..02be4ba1c6ad 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -880,7 +880,7 @@ config BT_MESH_LPN_INIT_POLL_TIMEOUT config BT_MESH_LPN_SCAN_LATENCY int "Latency for enabling scanning" range 0 50 - default 15 + default 2 help Latency in milliseconds that it takes to enable scanning. This is in practice how much time in advance before the Receive Window @@ -1667,4 +1667,12 @@ config BT_MESH_DEBUG_USE_ID_ADDR endif # BT_MESH_LOG_LEVEL_DBG +config BT_MESH_STATISTIC + bool "The frame handling statistics [EXPERIMENTAL]" + select EXPERIMENTAL + help + The module gathers statistics of received, relayed, and transmitted + frames. This helps to estimate the quality of the communication and + the sufficiency of configured advertiser instances. + endif # BT_MESH diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index fd5e84a6db1e..2132c14e1519 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -25,6 +25,7 @@ #include "proxy.h" #include "pb_gatt_srv.h" #include "solicitation.h" +#include "statistic.h" #define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL #include @@ -46,6 +47,30 @@ static K_FIFO_DEFINE(bt_mesh_adv_queue); static K_FIFO_DEFINE(bt_mesh_relay_queue); static K_FIFO_DEFINE(bt_mesh_friend_queue); +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv) +{ + if (!adv->started) { + adv->started = 1; + + if (adv->cb && adv->cb->start) { + adv->cb->start(duration, err, adv->cb_data); + } + + if (err) { + adv->cb = NULL; + } else if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { + bt_mesh_stat_succeeded_count(adv); + } + } +} + +static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv const *adv) +{ + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(err, adv->cb_data); + } +} + static void adv_buf_destroy(struct net_buf *buf) { struct bt_mesh_adv adv = *BT_MESH_ADV(buf); @@ -230,6 +255,10 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, BT_MESH_ADV(buf)->cb_data = cb_data; BT_MESH_ADV(buf)->busy = 1U; + if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { + bt_mesh_stat_planned_count(BT_MESH_ADV(buf)); + } + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && BT_MESH_ADV(buf)->tag == BT_MESH_FRIEND_ADV) { net_buf_put(&bt_mesh_friend_queue, net_buf_ref(buf)); diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 9f886c8980bb..eec6ae2fd74f 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -13,8 +13,14 @@ #define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) #define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +#if defined(CONFIG_BT_EXT_ADV) +#define BT_MESH_SCAN_INTERVAL_MS 3000 +#define BT_MESH_SCAN_WINDOW_MS 3000 +#else #define BT_MESH_SCAN_INTERVAL_MS 30 #define BT_MESH_SCAN_WINDOW_MS 30 +#endif enum bt_mesh_adv_type { BT_MESH_ADV_PROV, @@ -83,29 +89,7 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param, int32_t duration const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len); -static inline void bt_mesh_adv_send_start(uint16_t duration, int err, - struct bt_mesh_adv *adv) -{ - if (!adv->started) { - adv->started = 1; - - if (adv->cb && adv->cb->start) { - adv->cb->start(duration, err, adv->cb_data); - } - - if (err) { - adv->cb = NULL; - } - } -} - -static inline void bt_mesh_adv_send_end( - int err, struct bt_mesh_adv const *adv) -{ - if (adv->started && adv->cb && adv->cb->end) { - adv->cb->end(err, adv->cb_data); - } -} +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv); int bt_mesh_scan_active_set(bool active); diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 88c631a5867f..5c1a2bc3c32a 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -13,6 +13,9 @@ #include #include #include +#if defined(CONFIG_BT_LL_SOFTDEVICE) +#include +#endif #include "common/bt_str.h" @@ -137,6 +140,28 @@ static inline struct bt_mesh_ext_adv *gatt_adv_get(void) #endif /* CONFIG_BT_MESH_ADV_EXT_GATT_SEPARATE */ } +static int set_adv_randomness(uint8_t handle, int rand_us) +{ +#if defined(CONFIG_BT_LL_SOFTDEVICE) + struct net_buf *buf; + sdc_hci_cmd_vs_set_adv_randomness_t *cmd_params; + + buf = bt_hci_cmd_create(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, sizeof(*cmd_params)); + if (!buf) { + LOG_ERR("Could not allocate command buffer"); + return -ENOMEM; + } + + cmd_params = net_buf_add(buf, sizeof(*cmd_params)); + cmd_params->adv_handle = handle; + cmd_params->rand_us = rand_us; + + return bt_hci_cmd_send_sync(SDC_HCI_OPCODE_CMD_VS_SET_ADV_RANDOMNESS, buf, NULL); +#else + return 0; +#endif /* defined(CONFIG_BT_LL_SOFTDEVICE) */ +} + static int adv_start(struct bt_mesh_ext_adv *adv, const struct bt_le_adv_param *param, struct bt_le_ext_adv_start_param *start, @@ -473,6 +498,15 @@ int bt_mesh_adv_enable(void) if (err) { return err; } + + if (IS_ENABLED(CONFIG_BT_LL_SOFTDEVICE) && + IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && + adv->tag == BT_MESH_FRIEND_ADV) { + err = set_adv_randomness(adv->instance->handle, 0); + if (err) { + LOG_ERR("Failed to set zero randomness: %d", err); + } + } } return 0; diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 7a65ffe2e6fe..4632d6f7164f 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -35,6 +35,7 @@ #include "settings.h" #include "prov.h" #include "cfg.h" +#include "statistic.h" #ifdef CONFIG_BT_MESH_V1d1 #include "sar_cfg_internal.h" @@ -851,6 +852,10 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, return; } + if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { + bt_mesh_stat_rx(net_if); + } + /* Save the state so the buffer can later be relayed */ net_buf_simple_save(&buf, &state); diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index a5231ce2e7d0..3cf577ea6a82 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -1595,6 +1595,35 @@ static int cmd_appidx(const struct shell *sh, size_t argc, char *argv[]) return 0; } +#if defined(CONFIG_BT_MESH_STATISTIC) +static int cmd_stat_get(const struct shell *sh, size_t argc, char *argv[]) +{ + struct bt_mesh_statistic st; + + bt_mesh_stat_get(&st); + + shell_print(sh, "Received frames over:"); + shell_print(sh, "adv: %d", st.rx_adv); + shell_print(sh, "loopback: %d", st.rx_loopback); + shell_print(sh, "proxy: %d", st.rx_proxy); + shell_print(sh, "unknown: %d", st.rx_uknown); + + shell_print(sh, "Transmitted frames: - "); + shell_print(sh, "relay adv: %d - %d", st.tx_adv_relay_planned, st.tx_adv_relay_succeeded); + shell_print(sh, "local adv: %d - %d", st.tx_local_planned, st.tx_local_succeeded); + shell_print(sh, "friend: %d - %d", st.tx_friend_planned, st.tx_friend_succeeded); + + return 0; +} + +static int cmd_stat_clear(const struct shell *sh, size_t argc, char *argv[]) +{ + bt_mesh_stat_reset(); + + return 0; +} +#endif + #if defined(CONFIG_BT_MESH_SHELL_CDB) SHELL_STATIC_SUBCMD_SET_CREATE( cdb_cmds, @@ -1723,6 +1752,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(target_cmds, SHELL_CMD_ARG(app, NULL, "[AppKeyIdx]", cmd_appidx, 1, 1), SHELL_SUBCMD_SET_END); +#if defined(CONFIG_BT_MESH_STATISTIC) +SHELL_STATIC_SUBCMD_SET_CREATE(stat_cmds, + SHELL_CMD_ARG(get, NULL, NULL, cmd_stat_get, 1, 0), + SHELL_CMD_ARG(clear, NULL, NULL, cmd_stat_clear, 1, 0), + SHELL_SUBCMD_SET_END); +#endif + /* Placeholder for model shell modules that is configured in the application */ SHELL_SUBCMD_SET_CREATE(model_cmds, (mesh, models)); @@ -1760,6 +1796,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, #endif SHELL_CMD(target, &target_cmds, "Target commands", bt_mesh_shell_mdl_cmds_help), +#if defined(CONFIG_BT_MESH_STATISTIC) + SHELL_CMD(stat, &stat_cmds, "Statistic commands", bt_mesh_shell_mdl_cmds_help), +#endif + SHELL_SUBCMD_SET_END ); diff --git a/subsys/bluetooth/mesh/statistic.c b/subsys/bluetooth/mesh/statistic.c new file mode 100644 index 000000000000..5b1ffe7e0f53 --- /dev/null +++ b/subsys/bluetooth/mesh/statistic.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "adv.h" +#include "net.h" +#include "statistic.h" + +static struct bt_mesh_statistic stat; + +void bt_mesh_stat_get(struct bt_mesh_statistic *st) +{ + memcpy(st, &stat, sizeof(struct bt_mesh_statistic)); +} + +void bt_mesh_stat_reset(void) +{ + memset(&stat, 0, sizeof(struct bt_mesh_statistic)); +} + +void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv) +{ + if (adv->tag & BT_MESH_LOCAL_ADV) { + stat.tx_local_planned++; + } else if (adv->tag & BT_MESH_RELAY_ADV) { + stat.tx_adv_relay_planned++; + } else if (adv->tag & BT_MESH_FRIEND_ADV) { + stat.tx_friend_planned++; + } +} + +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv) +{ + if (adv->tag & BT_MESH_LOCAL_ADV) { + stat.tx_local_succeeded++; + } else if (adv->tag & BT_MESH_RELAY_ADV) { + stat.tx_adv_relay_succeeded++; + } else if (adv->tag & BT_MESH_FRIEND_ADV) { + stat.tx_friend_succeeded++; + } +} + +void bt_mesh_stat_rx(enum bt_mesh_net_if net_if) +{ + switch (net_if) { + case BT_MESH_NET_IF_ADV: + stat.rx_adv++; + break; + case BT_MESH_NET_IF_LOCAL: + stat.rx_loopback++; + break; + case BT_MESH_NET_IF_PROXY: + case BT_MESH_NET_IF_PROXY_CFG: + stat.rx_proxy++; + break; + default: + stat.rx_uknown++; + break; + } +} diff --git a/subsys/bluetooth/mesh/statistic.h b/subsys/bluetooth/mesh/statistic.h new file mode 100644 index 000000000000..fdb488f0d81b --- /dev/null +++ b/subsys/bluetooth/mesh/statistic.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ + +void bt_mesh_stat_planned_count(struct bt_mesh_adv *adv); +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv); +void bt_mesh_stat_rx(enum bt_mesh_net_if net_if); + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ */ diff --git a/subsys/fs/littlefs_fs.c b/subsys/fs/littlefs_fs.c index 4e57a4b17803..12fb790c3d65 100644 --- a/subsys/fs/littlefs_fs.c +++ b/subsys/fs/littlefs_fs.c @@ -1054,7 +1054,12 @@ struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = { \ .type = FS_LITTLEFS, \ .mnt_point = DT_INST_PROP(inst, mount_point), \ .fs_data = &fs_data_##inst, \ - .storage_dev = (void *)DT_FIXED_PARTITION_ID(FS_PARTITION(inst)), \ + .storage_dev = (void *) \ + COND_CODE_1(USE_PARTITION_MANAGER, \ + (COND_CODE_1(FIXED_PARTITION_EXISTS(littlefs_storage), \ + (FIXED_PARTITION_ID(littlefs_storage)), \ + (FIXED_PARTITION_ID(storage)))), \ + (DT_FIXED_PARTITION_ID(FS_PARTITION(inst)))), \ .flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)), \ }; diff --git a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c index 684d73944386..3204df31ce88 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c @@ -742,8 +742,8 @@ static int backend_init(const struct device *instance) return 0; } -#define DEFINE_BACKEND_DEVICE(i) \ - static struct backend_config_t backend_config_##i = { \ +#define BACKEND_CONFIG_POPULATE(i) \ + { \ .role = DT_ENUM_IDX_OR(DT_DRV_INST(i), role, ROLE_HOST), \ .shm_size = DT_REG_SIZE(DT_INST_PHANDLE(i, memory_region)), \ .shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(i, memory_region)), \ @@ -758,8 +758,10 @@ static int backend_init(const struct device *instance) .buffer_size = DT_INST_PROP_OR(i, zephyr_buffer_size, \ RPMSG_BUFFER_SIZE), \ .id = i, \ - }; \ - \ + } + +#define BACKEND_DEVICE_DEFINE(i) \ + static struct backend_config_t backend_config_##i = BACKEND_CONFIG_POPULATE(i); \ static struct backend_data_t backend_data_##i; \ \ DEVICE_DT_INST_DEFINE(i, \ @@ -771,20 +773,23 @@ static int backend_init(const struct device *instance) CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY, \ &backend_ops); -DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_DEVICE) +DT_INST_FOREACH_STATUS_OKAY(BACKEND_DEVICE_DEFINE) -#define BACKEND_CONFIG_INIT(n) &backend_config_##n, +#define BACKEND_CONFIG_DEFINE(i) BACKEND_CONFIG_POPULATE(i), #if defined(CONFIG_IPC_SERVICE_BACKEND_RPMSG_SHMEM_RESET) static int shared_memory_prepare(void) { - static const struct backend_config_t *config[] = { - DT_INST_FOREACH_STATUS_OKAY(BACKEND_CONFIG_INIT) + const struct backend_config_t *backend_config; + const struct backend_config_t backend_configs[] = { + DT_INST_FOREACH_STATUS_OKAY(BACKEND_CONFIG_DEFINE) }; - for (int i = 0; i < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); i++) { - if (config[i]->role == ROLE_HOST) { - memset((void *) config[i]->shm_addr, 0, VDEV_STATUS_SIZE); + for (backend_config = backend_configs; + backend_config < backend_configs + ARRAY_SIZE(backend_configs); + backend_config++) { + if (backend_config->role == ROLE_HOST) { + memset((void *) backend_config->shm_addr, 0, VDEV_STATUS_SIZE); } } diff --git a/subsys/ipc/rpmsg_service/rpmsg_backend.h b/subsys/ipc/rpmsg_service/rpmsg_backend.h index a74e46b85207..9996e1d74d9b 100644 --- a/subsys/ipc/rpmsg_service/rpmsg_backend.h +++ b/subsys/ipc/rpmsg_service/rpmsg_backend.h @@ -13,8 +13,35 @@ extern "C" { #endif +#if CONFIG_PARTITION_MANAGER_ENABLED + +#include "pm_config.h" + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) +#define VDEV_START_ADDR PM_RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM_RPMSG_NRF53_SRAM_SIZE +#else +/* The current image is a child image in a different domain than the image + * which defined the required values. To reach the values of the parent domain + * we use the 'PM__' variant of the define. + */ +#define VDEV_START_ADDR PM__RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM__RPMSG_NRF53_SRAM_SIZE +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) */ + +#else #define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) #define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) */ + +#else + +#define VDEV_START_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) +#define VDEV_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) + +#endif /* CONFIG_PARTITION_MANAGER_ENABLED */ #define VDEV_STATUS_ADDR VDEV_START_ADDR #define VDEV_STATUS_SIZE 0x400 diff --git a/subsys/mgmt/mcumgr/CMakeLists.txt b/subsys/mgmt/mcumgr/CMakeLists.txt index c977160f05b0..ad088eca0677 100644 --- a/subsys/mgmt/mcumgr/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/CMakeLists.txt @@ -13,5 +13,14 @@ add_subdirectory(smp) add_subdirectory(util) add_subdirectory(grp) add_subdirectory(transport) +add_subdirectory_ifdef(CONFIG_SMP_CLIENT smp_client) zephyr_library_link_libraries(mgmt_mcumgr) + +if (CONFIG_BOOT_IMAGE_ACCESS_HOOKS) + zephyr_include_directories( + ${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/bootutil/include + ${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/zephyr/include + ) + zephyr_library_sources(bootutil_hooks/nrf53_hooks.c) +endif() diff --git a/subsys/mgmt/mcumgr/Kconfig b/subsys/mgmt/mcumgr/Kconfig index 0aa02b04437d..b21c7dd8c0d0 100644 --- a/subsys/mgmt/mcumgr/Kconfig +++ b/subsys/mgmt/mcumgr/Kconfig @@ -7,6 +7,7 @@ menuconfig MCUMGR depends on NET_BUF depends on ZCBOR depends on CRC + imply BOOT_IMAGE_ACCESS_HOOKS if (SOC_NRF5340_CPUAPP_QKAA && MCUMGR_GRP_IMG) help This option enables the mcumgr management library. @@ -33,6 +34,12 @@ config MCUMGR_SMP_LEGACY_RC_BEHAVIOUR response will be empty with the new behaviour enabled, as opposed to the old behaviour where the rc field will be present in the response. +menu "SMP Client" + +rsource "smp_client/Kconfig" + +endmenu + menu "Command Handlers" rsource "grp/Kconfig" diff --git a/subsys/mgmt/mcumgr/bootutil_hooks/nrf53_hooks.c b/subsys/mgmt/mcumgr/bootutil_hooks/nrf53_hooks.c new file mode 100644 index 000000000000..9971a4e08431 --- /dev/null +++ b/subsys/mgmt/mcumgr/bootutil_hooks/nrf53_hooks.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "bootutil/bootutil_public.h" + +int boot_read_swap_state_primary_slot_hook(int image_index, + struct boot_swap_state *state) +{ + if (image_index == 1) { + /* Pretend that primary slot of image 1 unpopulated */ + state->magic = BOOT_MAGIC_UNSET; + state->swap_type = BOOT_SWAP_TYPE_NONE; + state->image_num = image_index; + state->copy_done = BOOT_FLAG_UNSET; + state->image_ok = BOOT_FLAG_UNSET; + + /* Prevent bootutil from trying to obtain true info */ + return 0; + } + + return BOOT_HOOK_REGULAR; +} diff --git a/subsys/mgmt/mcumgr/grp/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/CMakeLists.txt index 56df0fb51766..b77fcddf25e0 100644 --- a/subsys/mgmt/mcumgr/grp/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/grp/CMakeLists.txt @@ -5,9 +5,11 @@ # SPDX-License-Identifier: Apache-2.0 # -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_FS fs_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG img_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS os_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_STAT stat_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SHELL shell_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_ZBASIC zephyr_basic) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_FS fs_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG img_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG_CLIENT img_mgmt_client) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS os_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS_CLIENT os_mgmt_client) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_STAT stat_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SHELL shell_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_ZBASIC zephyr_basic) diff --git a/subsys/mgmt/mcumgr/grp/Kconfig b/subsys/mgmt/mcumgr/grp/Kconfig index b0a018ca4d3e..6005d57a8504 100644 --- a/subsys/mgmt/mcumgr/grp/Kconfig +++ b/subsys/mgmt/mcumgr/grp/Kconfig @@ -6,8 +6,12 @@ rsource "fs_mgmt/Kconfig" rsource "img_mgmt/Kconfig" +rsource "img_mgmt_client/Kconfig" + rsource "os_mgmt/Kconfig" +rsource "os_mgmt_client/Kconfig" + rsource "shell_mgmt/Kconfig" rsource "stat_mgmt/Kconfig" diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig index 1a028c0743f7..b97b6db84f3c 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig @@ -25,6 +25,7 @@ menuconfig MCUMGR_GRP_IMG if MCUMGR_GRP_IMG if HEAP_MEM_POOL_SIZE > 0 + config MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT bool "Use heap mem pool for flash image DFU context" help @@ -38,6 +39,7 @@ config MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT to allocate this context or it will not be possible to perform DFU; it may also not be possible to allocate such context when heap is under pressure, due to application operation, an issue that should also be addressed within application. + endif config MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER @@ -112,6 +114,15 @@ config MCUMGR_GRP_IMG_STATUS_HOOKS uploads. Note that these are status checking only, to allow inspecting of a file upload or prevent it, CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK must be used. +config MCUMGR_GRP_IMG_MUTEX + bool "Mutex locking" + help + This will enable use of a mutex to lock the image group object access, preventing issues + of concurrent thread (i.e. multiple transport) access. This option also makes the + ``img_mgmt_reset_upload()`` function visible in the image management group header, which + can be used by applications to reset the image management state (useful if there are + multiple ways that firmware updates can be loaded). + module = MCUMGR_GRP_IMG module-str = mcumgr_grp_img source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h b/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h index 57ed3854f0be..df26b4d10111 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h @@ -134,6 +134,18 @@ int img_mgmt_erase_if_needed(uint32_t off, uint32_t len); int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, struct img_mgmt_upload_action *action); +/** + * @brief Takes the image management lock (if enabled) to prevent other + * threads interfering with an ongoing operation. + */ +void img_mgmt_take_lock(void); + +/** + * @brief Releases the held image management lock (if enabled) to allow + * other threads to use image management operations. + */ +void img_mgmt_release_lock(void); + #define ERASED_VAL_32(x) (((x) << 24) | ((x) << 16) | ((x) << 8) | (x)) int img_mgmt_erased_val(int slot, uint8_t *erased_val); diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 953c3776c4c9..6b6581149e15 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -34,6 +34,23 @@ #include #endif +#if USE_PARTITION_MANAGER +#include + +#ifdef PM_MCUBOOT_SECONDARY_PAD_SIZE +BUILD_ASSERT(PM_MCUBOOT_PAD_SIZE == PM_MCUBOOT_SECONDARY_PAD_SIZE); +#endif + +#if CONFIG_BUILD_WITH_TFM + #define PM_ADDRESS_OFFSET (PM_MCUBOOT_PAD_SIZE + PM_TFM_SIZE) +#else + #define PM_ADDRESS_OFFSET (PM_MCUBOOT_PAD_SIZE) +#endif + +#define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ + (FIXED_PARTITION_OFFSET(label) == (PM_ADDRESS - PM_ADDRESS_OFFSET)) + +#else /* ! USE_PARTITION_MANAGER */ #ifndef CONFIG_FLASH_LOAD_OFFSET #error MCUmgr requires application to be built with CONFIG_FLASH_LOAD_OFFSET set \ to be able to figure out application running slot. @@ -41,18 +58,50 @@ #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ (FIXED_PARTITION_OFFSET(label) == CONFIG_FLASH_LOAD_OFFSET) +#endif /* USE_PARTITION_MANAGER */ + +#if FIXED_PARTITION_EXISTS(slot0_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif -#if !(FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot2_partition)) -#error "Unsupported chosen zephyr,code-partition for boot application." +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot0_ns_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot1_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot2_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot2_partition) +#define NUMBER_OF_ACTIVE_IMAGE 1 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot3_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot3_partition) +#define NUMBER_OF_ACTIVE_IMAGE 1 +#endif +#endif + +#ifndef NUMBER_OF_ACTIVE_IMAGE +#error "Unsupported code parition is set as active application partition" #endif LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); struct img_mgmt_state g_img_mgmt_state; +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX +static K_MUTEX_DEFINE(img_mgmt_mutex); +#endif + #ifdef CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR const char *img_mgmt_err_str_app_reject = "app reject"; const char *img_mgmt_err_str_hdr_malformed = "header malformed"; @@ -65,6 +114,20 @@ const char *img_mgmt_err_str_downgrade = "downgrade"; const char *img_mgmt_err_str_image_bad_flash_addr = "img addr mismatch"; #endif +void img_mgmt_take_lock(void) +{ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX + k_mutex_lock(&img_mgmt_mutex, K_FOREVER); +#endif +} + +void img_mgmt_release_lock(void) +{ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX + k_mutex_unlock(&img_mgmt_mutex); +#endif +} + /** * Finds the TLVs in the specified image slot, if any. */ @@ -106,15 +169,9 @@ int img_mgmt_active_slot(int image) int img_mgmt_active_image(void) { -#if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 2 - if (!(FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) || - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) || - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition))) { - return 1; - } -#endif - return 0; + return NUMBER_OF_ACTIVE_IMAGE; } + /* * Reads the version and build hash from the specified image slot. */ @@ -263,10 +320,16 @@ img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver) /* * Resets upload status to defaults (no upload in progress) */ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX void img_mgmt_reset_upload(void) +#else +static void img_mgmt_reset_upload(void) +#endif { + img_mgmt_take_lock(); memset(&g_img_mgmt_state, 0, sizeof(g_img_mgmt_state)); g_img_mgmt_state.area_id = -1; + img_mgmt_release_lock(); } static int @@ -312,6 +375,8 @@ img_mgmt_erase(struct smp_streamer *ctxt) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* * First check if image info is valid. * This check is done incase the flash area has a corrupted image. @@ -345,11 +410,14 @@ img_mgmt_erase(struct smp_streamer *ctxt) if (IS_ENABLED(CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR)) { if (!zcbor_tstr_put_lit(zse, "rc") || !zcbor_int32_put(zse, 0)) { + img_mgmt_release_lock(); return MGMT_ERR_EMSGSIZE; } } end: + img_mgmt_release_lock(); + return MGMT_ERR_EOK; } @@ -426,8 +494,13 @@ img_mgmt_upload(struct smp_streamer *ctxt) bool data_match = false; #endif -#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) || defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) +#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) enum mgmt_cb_return status; +#endif + +#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) || \ +defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) || \ +defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) int32_t ret_rc; uint16_t ret_group; #endif @@ -464,6 +537,8 @@ img_mgmt_upload(struct smp_streamer *ctxt) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* Determine what actions to take as a result of this request. */ rc = img_mgmt_upload_inspect(&req, &action); if (rc != 0) { @@ -482,7 +557,9 @@ img_mgmt_upload(struct smp_streamer *ctxt) /* Request specifies incorrect offset. Respond with a success code and * the correct offset. */ - return img_mgmt_upload_good_rsp(ctxt); + rc = img_mgmt_upload_good_rsp(ctxt); + img_mgmt_release_lock(); + return rc; } #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) @@ -678,6 +755,8 @@ img_mgmt_upload(struct smp_streamer *ctxt) } } + img_mgmt_release_lock(); + if (!ok) { return MGMT_ERR_EMSGSIZE; } diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c index eae5aaa3e8bd..2e673fff9780 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c @@ -245,6 +245,8 @@ img_mgmt_state_read(struct smp_streamer *ctxt) ok = zcbor_tstr_put_lit(zse, "images") && zcbor_list_start_encode(zse, 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER); + img_mgmt_take_lock(); + for (i = 0; ok && i < 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER; i++) { int rc = img_mgmt_read_info(i, &ver, hash, &flags); if (rc != 0) { @@ -291,6 +293,8 @@ img_mgmt_state_read(struct smp_streamer *ctxt) zcbor_int32_put(zse, 0); } + img_mgmt_release_lock(); + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; } @@ -385,6 +389,8 @@ img_mgmt_state_write(struct smp_streamer *ctxt) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* Determine which slot is being operated on. */ if (zhash.len == 0) { if (confirm) { @@ -423,10 +429,13 @@ img_mgmt_state_write(struct smp_streamer *ctxt) /* Send the current image state in the response. */ rc = img_mgmt_state_read(ctxt); if (rc != 0) { + img_mgmt_release_lock(); return rc; } end: + img_mgmt_release_lock(); + if (!ok) { return MGMT_ERR_EMSGSIZE; } diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt new file mode 100644 index 000000000000..693891896d8e --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Image management client group public API is exported by MCUmgr interface API, +# when Image Management client is enabled. + +zephyr_library(mcumgr_grp_img_client) +zephyr_library_sources( + src/img_mgmt_client.c +) + +zephyr_library_include_directories(include) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig new file mode 100644 index 000000000000..dbdb4c4eb603 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig @@ -0,0 +1,39 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to Application Image management group of +# of MCUmgr client subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_IMG_CLIENT_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. + +menuconfig MCUMGR_GRP_IMG_CLIENT + bool "MCUmgr client handlers for image management" + depends on SMP_CLIENT + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_3 + help + Enables MCUmgr client handlers for image management. + +if MCUMGR_GRP_IMG_CLIENT + +config MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE + int "MCUmgr upload data alignment size" + default 4 + help + Change default value when platform needs different data alignment. + +config MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT + int "MCUmgr reset or upload command timeout" + default 15 + help + Change default value when platform needs a different time. + +module = MCUMGR_GRP_IMG_CLIENT +module-str = mcumgr_grp_img_client +source "subsys/logging/Kconfig.template.log_config" + +endif diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c b/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c new file mode 100644 index 000000000000..b0e38640e8c8 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(mcumgr_grp_img_client, CONFIG_MCUMGR_GRP_IMG_CLIENT_LOG_LEVEL); + +#define MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE 128 + +/* Pointer for active Client */ +static struct img_mgmt_client *active_client; +/* Image State read or set response pointer */ +static struct mcumgr_image_state *image_info; +/* Image upload response pointer */ +static struct mcumgr_image_upload *image_upload_buf; + +static K_SEM_DEFINE(mcumgr_img_client_grp_sem, 0, 1); +static K_MUTEX_DEFINE(mcumgr_img_client_grp_mutex); + +static const char smp_images_str[] = "images"; +#define IMAGES_STR_LEN (sizeof(smp_images_str) - 1) + +static int image_state_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + struct zcbor_string value = {0}; + int buf_len, rc; + uint32_t img_num, slot_num; + struct zcbor_string hash, version; + bool bootable, pending, confirmed, active, permanent, ok; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + /* Mandatory */ + ZCBOR_MAP_DECODE_KEY_DECODER("version", zcbor_tstr_decode, &version), + ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash), + ZCBOR_MAP_DECODE_KEY_DECODER("slot", zcbor_uint32_decode, &slot_num), + /* Optional */ + ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num), + ZCBOR_MAP_DECODE_KEY_DECODER("bootable", zcbor_bool_decode, &bootable), + ZCBOR_MAP_DECODE_KEY_DECODER("pending", zcbor_bool_decode, &pending), + ZCBOR_MAP_DECODE_KEY_DECODER("confirmed", zcbor_bool_decode, &confirmed), + ZCBOR_MAP_DECODE_KEY_DECODER("active", zcbor_bool_decode, &active), + ZCBOR_MAP_DECODE_KEY_DECODER("permanent", zcbor_bool_decode, &permanent) + }; + + buf_len = active_client->image_list_length; + + if (!nb) { + image_info->status = MGMT_ERR_ETIMEOUT; + goto out; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + ok = zcbor_map_start_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + + ok = zcbor_tstr_decode(zsd, &value); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + if (value.len != IMAGES_STR_LEN || memcmp(value.value, smp_images_str, IMAGES_STR_LEN)) { + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + + ok = zcbor_list_start_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + + rc = 0; + /* Parse Image map info to configured buffer */ + while (rc == 0) { + decoded = 0; + zcbor_map_decode_bulk_reset(list_res_decode, ARRAY_SIZE(list_res_decode)); + /* Init buffer values */ + active = false; + bootable = false; + confirmed = false; + pending = false; + permanent = false; + img_num = 0; + slot_num = UINT32_MAX; + hash.len = 0; + version.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), + &decoded); + if (rc) { + if (image_info->image_list_length) { + /* No more map */ + break; + } + LOG_ERR("Corrupted Image data %d", rc); + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + /* Check that mandatory parameters have decoded */ + if (hash.len != IMG_MGMT_HASH_LEN || !version.len || + !zcbor_map_decode_bulk_key_found(list_res_decode, ARRAY_SIZE(list_res_decode), + "slot")) { + LOG_ERR("Missing mandatory parametrs"); + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + /* Store parsed values */ + if (buf_len) { + image_info->image_list[image_info->image_list_length].img_num = img_num; + image_info->image_list[image_info->image_list_length].slot_num = slot_num; + memcpy(image_info->image_list[image_info->image_list_length].hash, + hash.value, IMG_MGMT_HASH_LEN); + if (version.len > IMG_MGMT_VER_MAX_STR_LEN) { + LOG_WRN("Version truncated len %d -> %d", version.len, + IMG_MGMT_VER_MAX_STR_LEN); + version.len = IMG_MGMT_VER_MAX_STR_LEN; + } + memcpy(image_info->image_list[image_info->image_list_length].version, + version.value, version.len); + image_info->image_list[image_info->image_list_length].version[version.len] = + '\0'; + /* Set Image flags */ + image_info->image_list[image_info->image_list_length].flags.bootable = + bootable; + image_info->image_list[image_info->image_list_length].flags.pending = + pending; + image_info->image_list[image_info->image_list_length].flags.confirmed = + confirmed; + image_info->image_list[image_info->image_list_length].flags.active = active; + image_info->image_list[image_info->image_list_length].flags.permanent = + permanent; + /* Update valid image count */ + image_info->image_list_length++; + buf_len--; + } else { + LOG_INF("User configured image list buffer size %d can't store all info", + active_client->image_list_length); + } + } + + ok = zcbor_list_end_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + } else { + + image_info->status = MGMT_ERR_EOK; + } + +out: + if (image_info->status != MGMT_ERR_EOK) { + image_info->image_list_length = 0; + } + rc = image_info->status; + k_sem_give(user_data); + return rc; +} + +static int image_upload_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + int rc; + int32_t res_rc = MGMT_ERR_EOK; + + struct zcbor_map_decode_key_val upload_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, + &image_upload_buf->image_upload_offset), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &res_rc)}; + + if (!nb) { + image_upload_buf->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); + if (rc || image_upload_buf->image_upload_offset == SIZE_MAX) { + image_upload_buf->status = MGMT_ERR_EINVAL; + goto end; + } + image_upload_buf->status = res_rc; + + active_client->upload.offset = image_upload_buf->image_upload_offset; +end: + /* Set status for Upload request handler */ + rc = image_upload_buf->status; + k_sem_give(user_data); + return rc; +} + +static int erase_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + int rc, status = MGMT_ERR_EOK; + + struct zcbor_map_decode_key_val upload_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &status) + }; + + if (!nb) { + active_client->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); + if (rc) { + LOG_ERR("Erase fail %d", rc); + active_client->status = MGMT_ERR_EINVAL; + goto end; + } + active_client->status = status; +end: + rc = active_client->status; + k_sem_give(user_data); + return rc; +} + +static size_t upload_message_header_size(struct img_gr_upload *upload_state) +{ + bool ok; + size_t cbor_length; + int map_count; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + uint8_t temp_buf[MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE]; + uint8_t temp_data; + + /* Calculation of message header with data length of 1 */ + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), temp_buf, MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE, + 0); + if (upload_state->hash_initialized) { + map_count = 12; + } else { + map_count = 10; + } + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, upload_state->image_num) && zcbor_tstr_put_lit(zse, "data") && + zcbor_bstr_encode_ptr(zse, &temp_data, 1) && zcbor_tstr_put_lit(zse, "len") && + zcbor_size_put(zse, upload_state->image_size) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, upload_state->offset); + + /* Write hash when it defined and offset is 0 */ + if (ok && upload_state->hash_initialized) { + ok = zcbor_tstr_put_lit(zse, "sha") && + zcbor_bstr_encode_ptr(zse, upload_state->sha256, IMG_MGMT_HASH_LEN); + } + + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + LOG_ERR("Failed to encode Image Upload packet"); + return 0; + } + cbor_length = zse->payload - temp_buf; + /* Return Message header length */ + return cbor_length + (CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE - 1); +} + +void img_mgmt_client_init(struct img_mgmt_client *client, struct smp_client_object *smp_client, + int image_list_size, struct mcumgr_image_data *image_list) +{ + client->smp_client = smp_client; + client->image_list_length = image_list_size; + client->image_list = image_list; +} + +int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size, + uint32_t image_num, const char *image_hash) +{ + int rc; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + client->upload.image_size = image_size; + client->upload.offset = 0; + client->upload.image_num = image_num; + if (image_hash) { + memcpy(client->upload.sha256, image_hash, IMG_MGMT_HASH_LEN); + client->upload.hash_initialized = true; + } else { + client->upload.hash_initialized = false; + } + + /* Calculate worst case header size for adapt payload length */ + client->upload.upload_header_size = upload_message_header_size(&client->upload); + if (client->upload.upload_header_size) { + rc = MGMT_ERR_EOK; + } else { + rc = MGMT_ERR_ENOMEM; + } + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length, + struct mcumgr_image_upload *res_buf) +{ + struct net_buf *nb; + const uint8_t *write_ptr; + int rc; + uint32_t map_count; + bool ok; + size_t write_length, max_data_length, offset_before_send, request_length, wrote_length; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + image_upload_buf = res_buf; + + request_length = length; + wrote_length = 0; + /* Calculate max data length based on + * net_buf size - (SMP header + CBOR message_len + 16-bit CRC + 16-bit length) + */ + max_data_length = CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE - + (active_client->upload.upload_header_size + MGMT_HDR_SIZE + 2U + 2U); + /* Trim length based on CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE */ + if (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE) { + max_data_length -= + (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE); + } + + while (request_length != wrote_length) { + write_ptr = data + wrote_length; + write_length = request_length - wrote_length; + if (write_length > max_data_length) { + write_length = max_data_length; + } + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_UPLOAD, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + if (!nb) { + image_upload_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, + net_buf_tailroom(nb), 0); + if (active_client->upload.offset) { + map_count = 6; + } else if (active_client->upload.hash_initialized) { + map_count = 12; + } else { + map_count = 10; + } + + /* Init map start and write image info, data and offset */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, active_client->upload.image_num) && + zcbor_tstr_put_lit(zse, "data") && + zcbor_bstr_encode_ptr(zse, write_ptr, write_length) && + zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, active_client->upload.offset); + /* Write Len and configured hash when offset is zero */ + if (ok && !active_client->upload.offset) { + ok = zcbor_tstr_put_lit(zse, "len") && + zcbor_size_put(zse, active_client->upload.image_size); + if (ok && active_client->upload.hash_initialized) { + ok = zcbor_tstr_put_lit(zse, "sha") && + zcbor_bstr_encode_ptr(zse, active_client->upload.sha256, + IMG_MGMT_HASH_LEN); + } + } + + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + LOG_ERR("Failed to encode Image Upload packet"); + smp_packet_free(nb); + image_upload_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + offset_before_send = active_client->upload.offset; + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + + image_upload_buf->status = MGMT_ERR_EINVAL; + image_upload_buf->image_upload_offset = SIZE_MAX; + + rc = smp_client_send_cmd(active_client->smp_client, nb, image_upload_res_fn, + &mcumgr_img_client_grp_sem, + CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); + if (rc) { + LOG_ERR("Failed to send SMP Upload init packet, err: %d", rc); + smp_packet_free(nb); + image_upload_buf->status = rc; + goto end; + + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); + if (image_upload_buf->status) { + LOG_ERR("Upload Fail: %d", image_upload_buf->status); + goto end; + } + + if (offset_before_send + write_length < active_client->upload.offset) { + /* Offset further than expected which indicate upload session resume */ + goto end; + } + + wrote_length += write_length; + } +end: + rc = image_upload_buf->status; + active_client = NULL; + image_upload_buf = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + + return rc; +} + +int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm, + struct mcumgr_image_state *res_buf) +{ + struct net_buf *nb; + int rc; + uint32_t map_count; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + image_info = res_buf; + /* Init Response */ + res_buf->image_list_length = 0; + res_buf->image_list = active_client->image_list; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_STATE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + if (hash) { + map_count = 4; + } else { + map_count = 2; + } + + /* Write map start init and confirm params */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "confirm") && + zcbor_bool_put(zse, confirm); + /* Write hash data */ + if (ok && hash) { + ok = zcbor_tstr_put_lit(zse, "hash") && + zcbor_bstr_encode_ptr(zse, hash, IMG_MGMT_HASH_LEN); + } + /* Close map */ + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + smp_packet_free(nb); + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, + &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + res_buf->status = rc; + smp_packet_free(nb); + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = res_buf->status; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf) +{ + struct net_buf *nb; + int rc; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + /* Init Response */ + res_buf->image_list_length = 0; + res_buf->image_list = active_client->image_list; + + image_info = res_buf; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_STATE, MGMT_OP_READ, SMP_MCUMGR_VERSION_1); + if (!nb) { + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + ok = zcbor_map_start_encode(zse, 1) && zcbor_map_end_encode(zse, 1); + if (!ok) { + smp_packet_free(nb); + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, + &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + smp_packet_free(nb); + res_buf->status = rc; + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = res_buf->status; + image_info = NULL; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot) +{ + struct net_buf *nb; + int rc; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_ERASE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "slot") && + zcbor_uint32_put(zse, slot) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_packet_free(nb); + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(client->smp_client, nb, erase_res_fn, &mcumgr_img_client_grp_sem, + CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); + if (rc) { + smp_packet_free(nb); + active_client->status = rc; + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = active_client->status; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt new file mode 100644 index 000000000000..b033b363fa67 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# OS Management client group public API is exposed through zephyr_interface, +# when OS Management is enabled. +zephyr_library(mgmt_mcumgr_grp_os_client) +zephyr_library_sources(src/os_mgmt_client.c) +zephyr_library_include_directories(include) diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig b/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig new file mode 100644 index 000000000000..46c95a3cf871 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig @@ -0,0 +1,35 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to OS management group of +# of MCUmgr client subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_OS_CLIENT_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. + +menuconfig MCUMGR_GRP_OS_CLIENT + bool "MCUmgr client request and response handlers for OS management" + depends on SMP_CLIENT + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_3 + help + Enables MCUmgr client request and response handlers for OS management. + +if MCUMGR_GRP_OS_CLIENT + +config MCUMGR_GRP_OS_CLIENT_ECHO + default y + bool "Support for echo command request" + +config MCUMGR_GRP_OS_CLIENT_RESET + default y + bool "support for reset command request" + +module = MCUMGR_GRP_OS_CLIENT +module-str = mcumgr_grp_os_client +source "subsys/logging/Kconfig.template.log_config" + +endif diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c b/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c new file mode 100644 index 000000000000..2bd804494c41 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(mcumgr_grp_os_client, CONFIG_MCUMGR_GRP_OS_CLIENT_LOG_LEVEL); + +static struct os_mgmt_client *active_client; +static K_SEM_DEFINE(mcummgr_os_client_grp_sem, 0, 1); +static K_MUTEX_DEFINE(mcummgr_os_client_grp_mutex); + +void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client) +{ + client->smp_client = smp_client; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_RESET + +static int reset_res_fn(struct net_buf *nb, void *user_data) +{ + if (!nb) { + active_client->status = MGMT_ERR_ETIMEOUT; + } else { + active_client->status = MGMT_ERR_EOK; + } + k_sem_give(user_data); + return 0; +} + +int os_mgmt_client_reset(struct os_mgmt_client *client) +{ + struct net_buf *nb; + int rc; + + k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER); + active_client = client; + /* allocate buffer */ + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, + OS_MGMT_ID_RESET, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + k_sem_reset(&mcummgr_os_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, reset_res_fn, + &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + active_client->status = rc; + smp_packet_free(nb); + goto end; + } + /* Wait for process end update event */ + k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER); +end: + rc = active_client->status; + active_client = NULL; + k_mutex_unlock(&mcummgr_os_client_grp_mutex); + return rc; +} + +#endif /* CONFIG_MCUMGR_GRP_OS_CLIENT_RESET */ + +#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO + +static int echo_res_fn(struct net_buf *nb, void *user_data) +{ + struct zcbor_string val = {0}; + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + bool ok; + int rc; + struct zcbor_map_decode_key_val echo_response[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("r", zcbor_tstr_decode, &val) + }; + + if (!nb) { + LOG_ERR("Echo command timeout"); + active_client->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + /* Init ZCOR decoder state */ + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, echo_response, ARRAY_SIZE(echo_response), &decoded) == 0; + + if (!ok) { + active_client->status = MGMT_ERR_ECORRUPT; + goto end; + } + active_client->status = MGMT_ERR_EOK; +end: + rc = active_client->status; + k_sem_give(user_data); + return rc; +} + +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string) +{ + struct net_buf *nb; + int rc; + bool ok; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + + k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER); + active_client = client; + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, OS_MGMT_ID_ECHO, + MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + rc = active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + + ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "d") && zcbor_tstr_put_term(zse, echo_string) && + zcbor_map_end_encode(zse, 2); + + if (!ok) { + smp_packet_free(nb); + rc = active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + + LOG_DBG("Echo Command packet len %d", nb->len); + k_sem_reset(&mcummgr_os_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, echo_res_fn, + &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + smp_packet_free(nb); + } else { + k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER); + /* Take response status */ + rc = active_client->status; + } +end: + active_client = NULL; + k_mutex_unlock(&mcummgr_os_client_grp_mutex); + return rc; +} +#endif diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 75e11f2b6c63..2646587cd61c 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -86,12 +87,9 @@ static int smp_translate_error_code(uint16_t group, uint16_t ret) static void cbor_nb_reader_init(struct cbor_nb_reader *cnr, struct net_buf *nb) { - /* Skip the smp_hdr */ - void *new_ptr = net_buf_pull(nb, sizeof(struct smp_hdr)); - cnr->nb = nb; - zcbor_new_decode_state(cnr->zs, ARRAY_SIZE(cnr->zs), new_ptr, - cnr->nb->len, 1); + zcbor_new_decode_state(cnr->zs, ARRAY_SIZE(cnr->zs), nb->data, + nb->len, 1); } static void cbor_nb_writer_init(struct cbor_nb_writer *cnw, struct net_buf *nb) @@ -201,6 +199,7 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp mgmt_handler_fn handler_fn; int rc; #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) + enum mgmt_cb_return status; struct mgmt_evt_op_cmd_arg cmd_recv; int32_t ret_rc; uint16_t ret_group; @@ -229,18 +228,39 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp zcbor_map_start_encode(cbuf->writer->zs, CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); + MGMT_CTXT_SET_RC_RSN(cbuf, NULL); + #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) cmd_recv.group = req_hdr->nh_group; cmd_recv.id = req_hdr->nh_id; cmd_recv.err = MGMT_ERR_EOK; - (void)mgmt_callback_notify(MGMT_EVT_OP_CMD_RECV, &cmd_recv, sizeof(cmd_recv), - &ret_rc, &ret_group); + /* Send request to application to check if handler should run or not. */ + status = mgmt_callback_notify(MGMT_EVT_OP_CMD_RECV, &cmd_recv, sizeof(cmd_recv), + &ret_rc, &ret_group); + + /* Skip running the command if a handler reported an error and return that + * instead. + */ + if (status != MGMT_CB_OK) { + if (status == MGMT_CB_ERROR_RC) { + rc = ret_rc; + } else { + bool ok = smp_add_cmd_ret(cbuf->writer->zs, ret_group, + (uint16_t)ret_rc); + + rc = (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); + } + + goto end; + } #endif - MGMT_CTXT_SET_RC_RSN(cbuf, NULL); rc = handler_fn(cbuf); +#if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) +end: +#endif /* End response payload. */ if (!zcbor_map_end_encode(cbuf->writer->zs, CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES) && @@ -399,37 +419,54 @@ int smp_process_request_packet(struct smp_streamer *streamer, void *vreq) if (rc != 0) { rc = MGMT_ERR_ECORRUPT; break; - } else { - valid_hdr = true; } + + valid_hdr = true; + /* Skip the smp_hdr */ + net_buf_pull(req, sizeof(struct smp_hdr)); /* Does buffer contain whole message? */ - if (req->len < (req_hdr.nh_len + MGMT_HDR_SIZE)) { + if (req->len < req_hdr.nh_len) { rc = MGMT_ERR_ECORRUPT; break; } - rsp = smp_alloc_rsp(req, streamer->smpt); - if (rsp == NULL) { - rc = MGMT_ERR_ENOMEM; - break; - } - - cbor_nb_reader_init(streamer->reader, req); - cbor_nb_writer_init(streamer->writer, rsp); + if (req_hdr.nh_op == MGMT_OP_READ || req_hdr.nh_op == MGMT_OP_WRITE) { + rsp = smp_alloc_rsp(req, streamer->smpt); + if (rsp == NULL) { + rc = MGMT_ERR_ENOMEM; + break; + } + + cbor_nb_reader_init(streamer->reader, req); + cbor_nb_writer_init(streamer->writer, rsp); + + /* Process the request payload and build the response. */ + rc = smp_handle_single_req(streamer, &req_hdr, &handler_found, &rsn); + if (rc != 0) { + break; + } + + /* Send the response. */ + rc = streamer->smpt->functions.output(rsp); + rsp = NULL; + } else if (IS_ENABLED(CONFIG_SMP_CLIENT) && (req_hdr.nh_op == MGMT_OP_READ_RSP || + req_hdr.nh_op == MGMT_OP_WRITE_RSP)) { + rc = smp_client_single_response(req, &req_hdr); + + if (rc == MGMT_ERR_EOK) { + handler_found = true; + } else { + /* Server shuold not send error response for response */ + valid_hdr = false; + } - /* Process the request payload and build the response. */ - rc = smp_handle_single_req(streamer, &req_hdr, &handler_found, &rsn); - if (rc != 0) { - break; + } else { + rc = MGMT_ERR_ENOTSUP; } - /* Send the response. */ - rc = streamer->smpt->functions.output(rsp); - rsp = NULL; if (rc != 0) { break; } - /* Trim processed request to free up space for subsequent responses. */ net_buf_pull(req, req_hdr.nh_len); diff --git a/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt b/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt new file mode 100644 index 000000000000..061d28b30638 --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# Protocol API is only exposed to MCUmgr internals. + +zephyr_library(mgmt_mcumgr_client_protocol) +zephyr_library_sources(src/client.c) diff --git a/subsys/mgmt/mcumgr/smp_client/Kconfig b/subsys/mgmt/mcumgr/smp_client/Kconfig new file mode 100644 index 000000000000..b946efe1b324 --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/Kconfig @@ -0,0 +1,42 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to smp_client subdirectory of MCUmgr +# subsystem and provides Kconfig options to control aspects of +# Simple Management Protocol Client (SMP) processing source code provided +# under the subdirectory. + +config SMP_CLIENT + bool "SMP Client support" + help + This will enable SMP Request generation and response handling. + +if SMP_CLIENT || ZTEST + +config SMP_CMD_DEFAULT_LIFE_TIME + int "SMP command lifetime in seconds" + range 2 30 + default 5 + help + This define lifetime for SMP client send request. This configure is used if a request + with a timeout of 0 is used. + +config SMP_CMD_RETRY_TIME + int "SMP command re-send period in ms" + range 100 1000 + default 500 + help + The time (in ms) which the SMP client will wait for a response before re-sending + a command. + +config SMP_CLIENT_CMD_MAX + int "SMP client max buffer count" + default 4 + help + Define how many active requests that the client can handle + +module = MCUMGR_SMP_CLIENT +module-str = mcumgr_smp_client +source "subsys/logging/Kconfig.template.log_config" + +endif # SMP_CLIENT diff --git a/subsys/mgmt/mcumgr/smp_client/src/client.c b/subsys/mgmt/mcumgr/smp_client/src/client.c new file mode 100644 index 000000000000..cca1738f117e --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/src/client.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** SMP - Simple Management Client Protocol. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mcumgr_smp_client, CONFIG_MCUMGR_SMP_CLIENT_LOG_LEVEL); + +struct smp_client_cmd_req { + sys_snode_t node; + struct net_buf *nb; + struct smp_client_object *smp_client; + void *user_data; + smp_client_res_fn cb; + int64_t timestamp; + int retry_cnt; +}; + +struct smp_client_data_base { + struct k_work_delayable work_delay; + sys_slist_t cmd_free_list; + sys_slist_t cmd_list; +}; + +static struct smp_client_cmd_req smp_cmd_req_bufs[CONFIG_SMP_CLIENT_CMD_MAX]; +static struct smp_client_data_base smp_client_data; + +static void smp_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr); +static void smp_client_cmd_req_free(struct smp_client_cmd_req *cmd_req); + +/** + * Send all SMP client request packets. + */ +static void smp_client_handle_reqs(struct k_work *work) +{ + struct smp_client_object *smp_client; + struct smp_transport *smpt; + struct net_buf *nb; + + smp_client = (void *)work; + smpt = smp_client->smpt; + + while ((nb = net_buf_get(&smp_client->tx_fifo, K_NO_WAIT)) != NULL) { + smpt->functions.output(nb); + } +} + +static void smp_header_init(struct smp_hdr *header, uint16_t group, uint8_t id, uint8_t op, + uint16_t payload_len, uint8_t seq, enum smp_mcumgr_version_t version) +{ + /* Pre config SMP header structure */ + memset(header, 0, sizeof(struct smp_hdr)); + header->nh_version = version; + header->nh_op = op; + header->nh_len = sys_cpu_to_be16(payload_len); + header->nh_group = sys_cpu_to_be16(group); + header->nh_id = id; + header->nh_seq = seq; +} + +static void smp_client_transport_work_fn(struct k_work *work) +{ + struct smp_client_cmd_req *entry, *tmp; + smp_client_res_fn cb; + void *user_data; + int backoff_ms = CONFIG_SMP_CMD_RETRY_TIME; + int64_t time_stamp_cmp; + int64_t time_stamp_ref; + int64_t time_stamp_delta; + + ARG_UNUSED(work); + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* No more packet for Transport */ + return; + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&smp_client_data.cmd_list, entry, tmp, node) { + time_stamp_ref = entry->timestamp; + /* Check Time delta and get current time to reference */ + time_stamp_delta = k_uptime_delta(&time_stamp_ref); + + if (time_stamp_delta < 0) { + time_stamp_cmp = entry->timestamp - time_stamp_ref; + if (time_stamp_cmp < CONFIG_SMP_CMD_RETRY_TIME && + time_stamp_cmp < backoff_ms) { + /* Update new shorter shedule */ + backoff_ms = time_stamp_cmp; + } + continue; + } else if (entry->retry_cnt) { + /* Increment reference for re-transmission */ + entry->nb = net_buf_ref(entry->nb); + entry->retry_cnt--; + entry->timestamp = time_stamp_ref + CONFIG_SMP_CMD_RETRY_TIME; + net_buf_put(&entry->smp_client->tx_fifo, entry->nb); + smp_tx_req(&entry->smp_client->work); + continue; + } + + cb = entry->cb; + user_data = entry->user_data; + smp_client_cmd_req_free(entry); + if (cb) { + cb(NULL, user_data); + } + } + + if (!sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* Re-schedule new timeout to next */ + k_work_reschedule(&smp_client_data.work_delay, K_MSEC(backoff_ms)); + } +} + +static int smp_client_init(void) +{ + k_work_init_delayable(&smp_client_data.work_delay, smp_client_transport_work_fn); + sys_slist_init(&smp_client_data.cmd_list); + sys_slist_init(&smp_client_data.cmd_free_list); + for (int i = 0; i < CONFIG_SMP_CLIENT_CMD_MAX; i++) { + sys_slist_append(&smp_client_data.cmd_free_list, &smp_cmd_req_bufs[i].node); + } + return 0; +} + +static struct smp_client_cmd_req *smp_client_cmd_req_allocate(void) +{ + sys_snode_t *cmd_node; + struct smp_client_cmd_req *req; + + cmd_node = sys_slist_get(&smp_client_data.cmd_free_list); + if (!cmd_node) { + return NULL; + } + + req = SYS_SLIST_CONTAINER(cmd_node, req, node); + + return req; +} + +static void smp_cmd_add_to_list(struct smp_client_cmd_req *cmd_req) +{ + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* Enable timer */ + k_work_reschedule(&smp_client_data.work_delay, K_MSEC(CONFIG_SMP_CMD_RETRY_TIME)); + } + sys_slist_append(&smp_client_data.cmd_list, &cmd_req->node); +} + +static void smp_client_cmd_req_free(struct smp_client_cmd_req *cmd_req) +{ + smp_client_buf_free(cmd_req->nb); + cmd_req->nb = NULL; + sys_slist_find_and_remove(&smp_client_data.cmd_list, &cmd_req->node); + /* Add to free list */ + sys_slist_append(&smp_client_data.cmd_free_list, &cmd_req->node); + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* cancel delay */ + k_work_cancel_delayable(&smp_client_data.work_delay); + } +} + +static struct smp_client_cmd_req *smp_client_response_discover(const struct smp_hdr *res_hdr) +{ + struct smp_hdr smp_header; + enum mcumgr_op_t response; + struct smp_client_cmd_req *cmd_req; + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + return NULL; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&smp_client_data.cmd_list, cmd_req, node) { + smp_read_hdr(cmd_req->nb, &smp_header); + if (smp_header.nh_op == MGMT_OP_READ) { + response = MGMT_OP_READ_RSP; + } else { + response = MGMT_OP_WRITE_RSP; + } + + if (smp_header.nh_seq != res_hdr->nh_seq) { + continue; + } else if (res_hdr->nh_op != response) { + continue; + } + + return cmd_req; + } + return NULL; +} + +int smp_client_object_init(struct smp_client_object *smp_client, int smp_type) +{ + smp_client->smpt = smp_client_transport_get(smp_type); + if (!smp_client->smpt) { + return MGMT_ERR_EINVAL; + } + + /* Init TX FIFO */ + k_work_init(&smp_client->work, smp_client_handle_reqs); + k_fifo_init(&smp_client->tx_fifo); + + return MGMT_ERR_EOK; +} + +int smp_client_single_response(struct net_buf *nb, const struct smp_hdr *res_hdr) +{ + struct smp_client_cmd_req *cmd_req; + smp_client_res_fn cb; + void *user_data; + + /* Discover request for incoming response */ + cmd_req = smp_client_response_discover(res_hdr); + LOG_DBG("Response Header len %d, flags %d OP: %d group %d id %d seq %d", res_hdr->nh_len, + res_hdr->nh_flags, res_hdr->nh_op, res_hdr->nh_group, res_hdr->nh_id, + res_hdr->nh_seq); + + if (cmd_req) { + cb = cmd_req->cb; + user_data = cmd_req->user_data; + smp_client_cmd_req_free(cmd_req); + if (cb) { + cb(nb, user_data); + return MGMT_ERR_EOK; + } + } + + return MGMT_ERR_ENOENT; +} + +struct net_buf *smp_client_buf_allocation(struct smp_client_object *smp_client, uint16_t group, + uint8_t command_id, uint8_t op, + enum smp_mcumgr_version_t version) +{ + struct net_buf *nb; + struct smp_hdr smp_header; + + nb = smp_packet_alloc(); + + if (nb) { + /* Write SMP header with payload length 0 */ + smp_header_init(&smp_header, group, command_id, op, 0, smp_client->smp_seq++, + version); + memcpy(nb->data, &smp_header, sizeof(smp_header)); + nb->len = sizeof(smp_header); + } + return nb; +} + +void smp_client_buf_free(struct net_buf *nb) +{ + smp_packet_free(nb); +} + +static void smp_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + +int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, + smp_client_res_fn cb, void *user_data, int timeout_in_sec) +{ + struct smp_hdr smp_header; + struct smp_client_cmd_req *cmd_req; + + if (timeout_in_sec > 30) { + LOG_ERR("Command timeout can't be over 30 seconds"); + return MGMT_ERR_EINVAL; + } + + if (timeout_in_sec == 0) { + timeout_in_sec = CONFIG_SMP_CMD_DEFAULT_LIFE_TIME; + } + + smp_read_hdr(nb, &smp_header); + if (nb->len < sizeof(smp_header)) { + return MGMT_ERR_EINVAL; + } + /* Update Length */ + smp_header.nh_len = sys_cpu_to_be16(nb->len - sizeof(smp_header)); + smp_header.nh_group = sys_cpu_to_be16(smp_header.nh_group), + memcpy(nb->data, &smp_header, sizeof(smp_header)); + + cmd_req = smp_client_cmd_req_allocate(); + if (!cmd_req) { + return MGMT_ERR_ENOMEM; + } + + LOG_DBG("Command send Header flags %d OP: %d group %d id %d seq %d", smp_header.nh_flags, + smp_header.nh_op, sys_be16_to_cpu(smp_header.nh_group), smp_header.nh_id, + smp_header.nh_seq); + cmd_req->nb = nb; + cmd_req->cb = cb; + cmd_req->smp_client = smp_client; + cmd_req->user_data = user_data; + cmd_req->retry_cnt = timeout_in_sec * (1000 / CONFIG_SMP_CMD_RETRY_TIME); + cmd_req->timestamp = k_uptime_get() + CONFIG_SMP_CMD_RETRY_TIME; + /* Increment reference for re-transmission and read smp header */ + nb = net_buf_ref(nb); + smp_cmd_add_to_list(cmd_req); + net_buf_put(&smp_client->tx_fifo, nb); + smp_tx_req(&smp_client->work); + return MGMT_ERR_EOK; +} + +SYS_INIT(smp_client_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h b/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h index 828a15ffb162..898f2134c26c 100644 --- a/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h +++ b/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h @@ -9,6 +9,7 @@ #define MGMT_MCUMGR_SMP_INTERNAL_H_ #include +#include #include #include @@ -47,6 +48,15 @@ struct zephyr_smp_transport; */ void smp_rx_req(struct smp_transport *smtp, struct net_buf *nb); +#ifdef CONFIG_SMP_CLIENT +/** + * @brief Trig SMP client request packet for transmission. + * + * @param work The transport to use to send the corresponding response(s). + */ +void smp_tx_req(struct k_work *work); +#endif + __deprecated static inline void zephyr_smp_rx_req(struct zephyr_smp_transport *smpt, struct net_buf *nb) { diff --git a/subsys/mgmt/mcumgr/transport/src/smp.c b/subsys/mgmt/mcumgr/transport/src/smp.c index 1052b82cd04f..0f23bd4c44db 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp.c @@ -31,6 +31,10 @@ K_THREAD_STACK_DEFINE(smp_work_queue_stack, CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_ST static struct k_work_q smp_work_queue; +#ifdef CONFIG_SMP_CLIENT +static sys_slist_t smp_transport_clients; +#endif + static const struct k_work_queue_config smp_work_queue_config = { .name = "mcumgr smp" }; @@ -131,6 +135,7 @@ smp_handle_reqs(struct k_work *work) smpt = (void *)work; + /* Read and handle received messages */ while ((nb = net_buf_get(&smpt->fifo, K_NO_WAIT)) != NULL) { smp_process_packet(smpt, nb); } @@ -155,6 +160,33 @@ int smp_transport_init(struct smp_transport *smpt) return 0; } +#ifdef CONFIG_SMP_CLIENT +struct smp_transport *smp_client_transport_get(int smpt_type) +{ + struct smp_client_transport_entry *entry; + + SYS_SLIST_FOR_EACH_CONTAINER(&smp_transport_clients, entry, node) { + if (entry->smpt_type == smpt_type) { + return entry->smpt; + } + } + + return NULL; +} + +void smp_client_transport_register(struct smp_client_transport_entry *entry) +{ + if (smp_client_transport_get(entry->smpt_type)) { + /* Already in list */ + return; + } + + sys_slist_append(&smp_transport_clients, &entry->node); + +} + +#endif /* CONFIG_SMP_CLIENT */ + /** * @brief Enqueues an incoming SMP request packet for processing. * @@ -171,6 +203,13 @@ smp_rx_req(struct smp_transport *smpt, struct net_buf *nb) k_work_submit_to_queue(&smp_work_queue, &smpt->work); } +#ifdef CONFIG_SMP_CLIENT +void smp_tx_req(struct k_work *work) +{ + k_work_submit_to_queue(&smp_work_queue, work); +} +#endif + void smp_rx_remove_invalid(struct smp_transport *zst, void *arg) { struct net_buf *nb; @@ -227,6 +266,10 @@ void smp_rx_clear(struct smp_transport *zst) static int smp_init(void) { +#ifdef CONFIG_SMP_CLIENT + sys_slist_init(&smp_transport_clients); +#endif + k_work_queue_init(&smp_work_queue); k_work_queue_start(&smp_work_queue, smp_work_queue_stack, diff --git a/subsys/mgmt/mcumgr/transport/src/smp_bt.c b/subsys/mgmt/mcumgr/transport/src/smp_bt.c index 6cd2d53d9ffd..87706fd8f47f 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_bt.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_bt.c @@ -109,6 +109,10 @@ BT_CONN_CB_DEFINE(mcumgr_bt_callbacks) = { .disconnected = disconnected, }; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif + /* Helper function that allocates conn_param_data for a conn. */ static struct conn_param_data *conn_param_data_alloc(struct bt_conn *conn) { @@ -665,6 +669,14 @@ static void smp_bt_setup(void) rc = smp_bt_register(); } +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + smp_client_transport.smpt = &smp_bt_transport; + smp_client_transport.smpt_type = SMP_BLUETOOTH_TRANSPORT; + rc = smp_client_transport_register(&smp_client_transport); + } +#endif + if (rc != 0) { LOG_ERR("Bluetooth SMP transport register failed (err %d)", rc); } diff --git a/subsys/mgmt/mcumgr/transport/src/smp_shell.c b/subsys/mgmt/mcumgr/transport/src/smp_shell.c index ac196c100854..c30874070bac 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_shell.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_shell.c @@ -39,6 +39,10 @@ static struct smp_transport smp_shell_transport; static struct mcumgr_serial_rx_ctxt smp_shell_rx_ctxt; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif + /** SMP mcumgr frame fragments. */ enum smp_shell_esc_mcumgr { ESC_MCUMGR_PKT_1, @@ -241,6 +245,13 @@ int smp_shell_init(void) smp_shell_transport.functions.get_mtu = smp_shell_get_mtu; rc = smp_transport_init(&smp_shell_transport); +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + smp_client_transport.smpt = &CONFIG_SMP_CLIENT; + smp_client_transport.smpt_type = SMP_SHELL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); + } +#endif return rc; } diff --git a/subsys/mgmt/mcumgr/transport/src/smp_uart.c b/subsys/mgmt/mcumgr/transport/src/smp_uart.c index 9c3dade2f8e3..643caf6eb48a 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_uart.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_uart.c @@ -31,6 +31,9 @@ K_WORK_DEFINE(smp_uart_work, smp_uart_process_rx_queue); static struct mcumgr_serial_rx_ctxt smp_uart_rx_ctxt; static struct smp_transport smp_uart_transport; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif /** * Processes a single line (fragment) coming from the mcumgr UART driver. @@ -101,6 +104,11 @@ static int smp_uart_init(void) if (rc == 0) { uart_mcumgr_register(smp_uart_rx_frag); +#ifdef CONFIG_SMP_CLIENT + smp_client_transport.smpt = &smp_uart_transport; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); +#endif } return rc; diff --git a/subsys/mgmt/mcumgr/transport/src/smp_udp.c b/subsys/mgmt/mcumgr/transport/src/smp_udp.c index e772cf499de7..6f8f9a137353 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_udp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_udp.c @@ -66,9 +66,15 @@ struct config { struct configs { #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4 struct config ipv4; +#ifdef CONFIG_SMP_CLIENT + struct smp_client_transport_entry ipv4_transport; +#endif #endif #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6 struct config ipv6; +#ifdef CONFIG_SMP_CLIENT + struct smp_client_transport_entry ipv6_transport; +#endif #endif }; @@ -381,7 +387,13 @@ static void smp_udp_start(void) configs.ipv4.smp_transport.functions.ud_copy = smp_udp_ud_copy; rc = smp_transport_init(&configs.ipv4.smp_transport); - +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + configs.ipv4_transport.smpt = &configs.ipv4.smp_transport; + configs.ipv4_transport.smpt_type = SMP_UDP_IPV4_TRANSPORT; + smp_client_transport_register(&configs.ipv4_transport); + } +#endif if (rc) { LOG_ERR("Failed to register IPv4 UDP MCUmgr SMP transport: %d", rc); } @@ -394,6 +406,13 @@ static void smp_udp_start(void) configs.ipv6.smp_transport.functions.ud_copy = smp_udp_ud_copy; rc = smp_transport_init(&configs.ipv6.smp_transport); +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + configs.ipv6_transport.smpt = &configs.ipv6.smp_transport; + configs.ipv6_transport.smpt_type = SMP_UDP_IPV6_TRANSPORT; + smp_client_transport_register(&configs.ipv6_transport); + } +#endif if (rc) { LOG_ERR("Failed to register IPv6 UDP MCUmgr SMP transport: %d", rc); diff --git a/subsys/net/conn_mgr/Kconfig b/subsys/net/conn_mgr/Kconfig index 5c742fb852f5..e74a243b4a0a 100644 --- a/subsys/net/conn_mgr/Kconfig +++ b/subsys/net/conn_mgr/Kconfig @@ -24,6 +24,7 @@ source "subsys/net/Kconfig.template.log_config.net" config NET_CONNECTION_MANAGER_STACK_SIZE int "Size of the stack allocated for the connection manager" + default 8192 if WPA_SUPP default 512 help Sets the stack size which will be used by the connection manager @@ -36,4 +37,8 @@ config NET_CONNECTION_MANAGER_PRIORITY help This sets the starting priority of the connection manager thread. +config NET_CONNECTION_MANAGER_AUTO_IF_DOWN + bool "Automatically take ifaces admin-down if they have stopped trying to connect" + default y + endif # NET_CONNECTION_MANAGER diff --git a/subsys/net/conn_mgr/conn_mgr.c b/subsys/net/conn_mgr/conn_mgr.c index b202c8745664..3374a1acf604 100644 --- a/subsys/net/conn_mgr/conn_mgr.c +++ b/subsys/net/conn_mgr/conn_mgr.c @@ -23,6 +23,10 @@ LOG_MODULE_REGISTER(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL); #define THREAD_PRIORITY K_PRIO_PREEMPT(7) #endif +static K_THREAD_STACK_DEFINE(conn_mgr_thread_stack, + CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE); +static struct k_thread conn_mgr_thread; + /* Internal state array tracking readiness, flags, and other state information for all available * ifaces. Note that indexing starts at 0, whereas Zephyr iface indices start at 1. * conn_mgr_get_if_by_index and conn_mgr_get_index_for_if are used to go back and forth between @@ -212,10 +216,6 @@ static void conn_mgr_handler(void) } } -K_THREAD_DEFINE(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE, - (k_thread_entry_t)conn_mgr_handler, NULL, NULL, NULL, - THREAD_PRIORITY, 0, 0); - void conn_mgr_resend_status(void) { k_mutex_lock(&conn_mgr_lock, K_FOREVER); @@ -326,12 +326,14 @@ static int conn_mgr_init(void) { int i; - for (i = 0; i < ARRAY_SIZE(iface_states); i++) { iface_states[i] = 0; } - k_thread_start(conn_mgr); + k_thread_create(&conn_mgr_thread, conn_mgr_thread_stack, + CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE, + (k_thread_entry_t)conn_mgr_handler, + NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT); return 0; } diff --git a/subsys/net/conn_mgr/conn_mgr_connectivity.c b/subsys/net/conn_mgr/conn_mgr_connectivity.c index 8fae71acec17..e9fb3766484b 100644 --- a/subsys/net/conn_mgr/conn_mgr_connectivity.c +++ b/subsys/net/conn_mgr/conn_mgr_connectivity.c @@ -8,8 +8,10 @@ LOG_MODULE_REGISTER(conn_mgr_conn, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL); #include -#include #include +#include + +#include #include "conn_mgr_private.h" @@ -48,6 +50,8 @@ int conn_mgr_if_connect(struct net_if *iface) return status; } +static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface); + int conn_mgr_if_disconnect(struct net_if *iface) { struct conn_mgr_conn_binding *binding; @@ -77,6 +81,16 @@ int conn_mgr_if_disconnect(struct net_if *iface) out: k_mutex_unlock(binding->mutex); + /* Since the connectivity implementation will not automatically attempt to reconnect after + * a call to conn_mgr_if_disconnect, conn_mgr_conn_if_auto_admin_down should be called. + * + * conn_mgr_conn_handle_iface_down will only call conn_mgr_conn_if_auto_admin_down if + * persistence is disabled. To ensure conn_mgr_conn_if_auto_admin_down is called in all + * cases, we must call it directly from here. If persistence is disabled, this will result + * in conn_mgr_conn_if_auto_admin_down being called twice, but that is not an issue. + */ + conn_mgr_conn_if_auto_admin_down(iface); + return status; } @@ -235,8 +249,140 @@ int conn_mgr_if_set_timeout(struct net_if *iface, int timeout) return 0; } +/* Automated behavior handling */ + +/** + * @brief Perform automated behaviors in response to ifaces going admin-up. + * + * @param iface - The iface which became admin-up. + */ +static void conn_mgr_conn_handle_iface_admin_up(struct net_if *iface) +{ + int err; + + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* Ignore ifaces for which auto-connect is disabled */ + if (conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT)) { + return; + } + + /* Otherwise, automatically instruct the iface to connect */ + err = conn_mgr_if_connect(iface); + if (err < 0) { + NET_ERR("iface auto-connect failed: %d", err); + } +} + +/** + * @brief Take the provided iface admin-down. + * + * Called automatically by conn_mgr when an iface loses connection and does not expect to regain it, + * and AUTO_IF_DOWN is enabled for the iface. + * + * @param iface - The iface to take admin-down + */ +static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface) +{ + /* NOTE: This will be double-fired for ifaces that are both non-persistent + * and are being directly requested to disconnect, since both of these conditions + * separately trigger conn_mgr_conn_if_auto_admin_down. + * + * This is fine, because net_if_down is idempotent, but if you are adding other + * behaviors to this function, bear it in mind. + */ + + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* Take the iface admin-down if AUTO_DOWN is enabled */ + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN) && + !conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN)) { + net_if_down(iface); + } +} + +/** + * @brief Perform automated behaviors in response to any iface that loses oper-up state. + * + * This is how conn_mgr_conn automatically takes such ifaces admin-down if they are not persistent. + * + * @param iface - The iface which lost oper-up state. + */ +static void conn_mgr_conn_handle_iface_down(struct net_if *iface) +{ + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* If the iface is persistent, we expect it to try to reconnect, so nothing else to do */ + if (conn_mgr_if_get_flag(iface, CONN_MGR_IF_PERSISTENT)) { + return; + } + + /* Otherwise, we do not expect the iface to reconnect, and we should call + * conn_mgr_conn_if_auto_admin_down + */ + conn_mgr_conn_if_auto_admin_down(iface); +} + +static struct net_mgmt_event_callback conn_mgr_conn_iface_cb; +static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + if ((mgmt_event & CONN_MGR_CONN_IFACE_EVENTS_MASK) != mgmt_event) { + return; + } + + switch (mgmt_event) { + case NET_EVENT_IF_DOWN: + conn_mgr_conn_handle_iface_down(iface); + break; + case NET_EVENT_IF_ADMIN_UP: + conn_mgr_conn_handle_iface_admin_up(iface); + break; + } +} + +static struct net_mgmt_event_callback conn_mgr_conn_self_cb; +static void conn_mgr_conn_self_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + if ((mgmt_event & CONN_MGR_CONN_SELF_EVENTS_MASK) != mgmt_event) { + return; + } + + switch (NET_MGMT_GET_COMMAND(mgmt_event)) { + case NET_EVENT_CONN_CMD_IF_FATAL_ERROR: + if (cb->info) { + NET_ERR("Fatal connectivity error on iface %d (%p). Reason: %d.", + net_if_get_by_iface(iface), iface, *((int *)cb->info) + ); + } else { + NET_ERR("Unknown fatal connectivity error on iface %d (%p).", + net_if_get_by_iface(iface), iface + ); + } + __fallthrough; + case NET_EVENT_CONN_CMD_IF_TIMEOUT: + /* If a timeout or fatal error occurs, we do not expect the iface to try to + * reconnect, so call conn_mgr_conn_if_auto_admin_down. + */ + conn_mgr_conn_if_auto_admin_down(iface); + break; + } + +} + void conn_mgr_conn_init(void) { + /* Initialize connectivity bindings. */ STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { if (!(binding->impl->api)) { LOG_ERR("Connectivity implementation has NULL API, and will be treated as " @@ -255,4 +401,167 @@ void conn_mgr_conn_init(void) k_mutex_unlock(binding->mutex); } } + + /* Set up event listeners for automated behaviors */ + net_mgmt_init_event_callback(&conn_mgr_conn_iface_cb, conn_mgr_conn_iface_handler, + CONN_MGR_CONN_IFACE_EVENTS_MASK); + net_mgmt_add_event_callback(&conn_mgr_conn_iface_cb); + + net_mgmt_init_event_callback(&conn_mgr_conn_self_cb, conn_mgr_conn_self_handler, + CONN_MGR_CONN_SELF_EVENTS_MASK); + net_mgmt_add_event_callback(&conn_mgr_conn_self_cb); + + /* Trigger any initial automated behaviors for ifaces */ + STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { + if (binding->impl->api) { + /* We need to fire conn_mgr_conn_handle_iface_admin_up for any + * (connectivity-enabled) ifaces that went admin-up before we registerred + * the event callback that typically handles this. + */ + if (net_if_is_admin_up(binding->iface)) { + conn_mgr_conn_handle_iface_admin_up(binding->iface); + } + } + } +} + +enum conn_mgr_conn_all_if_oper { + ALL_IF_UP, + ALL_IF_DOWN, + ALL_IF_CONNECT, + ALL_IF_DISCONNECT +}; + +struct conn_mgr_conn_all_if_ctx { + bool skip_ignored; + enum conn_mgr_conn_all_if_oper operation; + int status; +}; + +/* Per-iface callback for conn_mgr_conn_all_if_up */ +static void conn_mgr_conn_all_if_cb(struct net_if *iface, void *user_data) +{ + int status = 0; + struct conn_mgr_conn_all_if_ctx *context = (struct conn_mgr_conn_all_if_ctx *)user_data; + + /* Skip ignored ifaces if so desired */ + if (context->skip_ignored && conn_mgr_is_iface_ignored(iface)) { + return; + } + + /* Perform the requested operation */ + switch (context->operation) { + case ALL_IF_UP: + /* Do not take iface admin up if it already is. */ + if (net_if_is_admin_up(iface)) { + return; + } + + status = net_if_up(iface); + break; + case ALL_IF_DOWN: + /* Do not take iface admin down if it already is. */ + if (!net_if_is_admin_up(iface)) { + return; + } + + status = net_if_down(iface); + break; + case ALL_IF_CONNECT: + /* Connect operation only supported if iface is bound */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + status = conn_mgr_if_connect(iface); + break; + case ALL_IF_DISCONNECT: + /* Disconnect operation only supported if iface is bound */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + status = conn_mgr_if_disconnect(iface); + break; + } + + if (status == 0) { + return; + } + + if (context->status == 0) { + context->status = status; + } + + NET_ERR("%s failed for iface %d (%p). Error: %d", + context->operation == ALL_IF_UP ? "net_if_up" : + context->operation == ALL_IF_DOWN ? "net_if_down" : + context->operation == ALL_IF_CONNECT ? "conn_mgr_if_connect" : + context->operation == ALL_IF_DISCONNECT ? "conn_mgr_if_disconnect" : + "invalid", + net_if_get_by_iface(iface), iface, status + ); +} + +int conn_mgr_all_if_up(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_UP, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_down(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_DOWN, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_connect(bool skip_ignored) +{ + /* First, take all ifaces up. + * All bound ifaces will do this automatically when connect is called, but non-bound ifaces + * won't, so we must request it explicitly. + */ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_UP, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + /* Now connect all ifaces. + * We are delibarately not resetting context.status between these two calls so that + * the first nonzero status code encountered between the two of them is what is returned. + */ + context.operation = ALL_IF_CONNECT; + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_disconnect(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_DISCONNECT, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; } diff --git a/subsys/net/conn_mgr/conn_mgr_private.h b/subsys/net/conn_mgr/conn_mgr_private.h index 9e147653828b..c2f3097a8d46 100644 --- a/subsys/net/conn_mgr/conn_mgr_private.h +++ b/subsys/net/conn_mgr/conn_mgr_private.h @@ -27,7 +27,7 @@ /* Configuration flags */ #define CONN_MGR_IF_IGNORED BIT(7) -/* Internal state flags*/ +/* Internal state flags */ #define CONN_MGR_IF_READY BIT(14) /* Event flags */ @@ -37,6 +37,12 @@ #define CONN_MGR_IFACE_EVENTS_MASK (NET_EVENT_IF_DOWN | \ NET_EVENT_IF_UP) +#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP |\ + NET_EVENT_IF_DOWN) + +#define CONN_MGR_CONN_SELF_EVENTS_MASK (NET_EVENT_CONN_IF_TIMEOUT | \ + NET_EVENT_CONN_IF_FATAL_ERROR) + #define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \ NET_EVENT_IPV6_ADDR_DEL | \ NET_EVENT_IPV6_DAD_SUCCEED | \ diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 2ce2e35171fe..e5f096e594f5 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -828,6 +828,10 @@ config NET_DEFAULT_IF_PPP bool "PPP interface" depends on NET_L2_PPP +config NET_DEFAULT_IF_WIFI + bool "WiFi interface" + depends on NET_L2_ETHERNET + endchoice config NET_PKT_TIMESTAMP diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index a16e025a9482..a5e073051de8 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -82,6 +82,14 @@ config NET_DHCPV4_OPTION_CALLBACKS can be added. These can be used to support otherwise DHCP options not used by the rest of the system. +config NET_DHCPV4_ACCEPT_UNICAST + bool "Accept unicast DHCPv4 traffic" + depends on NET_DHCPV4 + default y + help + If set, the network stack will accept unicast DHCPv4 responses from + servers, before the assigned address is configured on the interface. + config NET_IPV4_AUTO bool "IPv4 autoconfiguration [EXPERIMENTAL]" depends on NET_ARP diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index b370bc1835fc..225a3fdbaade 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -576,6 +576,11 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, uint8_t pkt_family = net_pkt_family(pkt); uint16_t src_port = 0U, dst_port = 0U; + if (!net_pkt_filter_local_in_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if (IS_ENABLED(CONFIG_NET_IP) && (pkt_family == AF_INET || pkt_family == AF_INET6)) { if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) { src_port = proto_hdr->udp->src_port; diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index be01851bd894..d5aefb3ba90a 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -211,7 +211,8 @@ static struct net_pkt *dhcpv4_create_message(struct net_if *iface, uint8_t type, msg->htype = HARDWARE_ETHERNET_TYPE; msg->hlen = net_if_get_link_addr(iface)->len; msg->xid = htonl(iface->config.dhcpv4.xid); - msg->flags = htons(DHCPV4_MSG_BROADCAST); + msg->flags = IS_ENABLED(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) ? + htons(DHCPV4_MSG_UNICAST) : htons(DHCPV4_MSG_BROADCAST); if (ciaddr) { /* The ciaddr field was zero'd out above, if we are @@ -1397,3 +1398,47 @@ int net_dhcpv4_init(void) #endif return 0; } + +#if defined(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) +bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + struct net_pkt_cursor backup; + struct net_udp_hdr *udp_hdr; + struct net_if *iface; + bool accept = false; + + iface = net_pkt_iface(pkt); + if (iface == NULL) { + return false; + } + + /* Only accept DHCPv4 packets during active query. */ + if (iface->config.dhcpv4.state != NET_DHCPV4_SELECTING && + iface->config.dhcpv4.state != NET_DHCPV4_REQUESTING && + iface->config.dhcpv4.state != NET_DHCPV4_RENEWING && + iface->config.dhcpv4.state != NET_DHCPV4_REBINDING) { + return false; + } + + net_pkt_cursor_backup(pkt, &backup); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt)); + + /* Verify destination UDP port. */ + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access); + if (udp_hdr == NULL) { + goto out; + } + + if (udp_hdr->dst_port != htons(DHCPV4_CLIENT_PORT)) { + goto out; + } + + accept = true; + +out: + net_pkt_cursor_restore(pkt, &backup); + + return accept; +} +#endif /* CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ diff --git a/subsys/net/ip/dhcpv4.h b/subsys/net/ip/dhcpv4.h index 52663f7ee07e..a274e3a6aeae 100644 --- a/subsys/net/ip/dhcpv4.h +++ b/subsys/net/ip/dhcpv4.h @@ -81,9 +81,7 @@ struct dhcp_msg { /* TODO: - * 1) Support for UNICAST flag (some dhcpv4 servers will not reply if - * DISCOVER message contains BROADCAST FLAG). - * 2) Support T2(Rebind) timer. + * 1) Support T2(Rebind) timer. */ /* Maximum number of REQUEST or RENEWAL retransmits before reverting @@ -115,4 +113,33 @@ int net_dhcpv4_init(void); #endif /* CONFIG_NET_DHCPV4 */ +#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) + +/** + * @brief Verify if the incoming packet should be accepted for the DHCPv4 + * module to process. + * + * In case server responds with an unicast IP packet, the IP stack needs to + * pass it through for the DHCPv4 module to process, before the actual + * destination IP address is configured on an interface. + * This function allows to determine whether there is an active DHCPv4 query on + * the interface and the packet is destined for the DHCPv4 module to process. + * + * @param pkt A packet to analyze + * + * @return true if the packet shall be accepted, false otherwise + */ +bool net_dhcpv4_accept_unicast(struct net_pkt *pkt); + +#else + +static inline bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return false; +} + +#endif /* CONFIG_NET_DHCPV4 && CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ + #endif /* __INTERNAL_DHCPV4_H */ diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 0392e75cec1c..922068274f72 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL); #include "icmpv4.h" #include "udp_internal.h" #include "tcp_internal.h" +#include "dhcpv4.h" #include "ipv4.h" BUILD_ASSERT(sizeof(struct in_addr) == NET_IPV4_ADDR_SIZE); @@ -302,6 +303,15 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) goto drop; } + net_pkt_set_ipv4_ttl(pkt, hdr->ttl); + + net_pkt_set_family(pkt, PF_INET); + + if (!net_pkt_filter_ip_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if ((!net_ipv4_is_my_addr((struct in_addr *)hdr->dst) && !net_ipv4_is_addr_mcast((struct in_addr *)hdr->dst) && !(hdr->proto == IPPROTO_UDP && @@ -309,7 +319,8 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) /* RFC 1122 ch. 3.3.6 The 0.0.0.0 is non-standard bcast addr */ (IS_ENABLED(CONFIG_NET_IPV4_ACCEPT_ZERO_BROADCAST) && net_ipv4_addr_cmp((struct in_addr *)hdr->dst, - net_ipv4_unspecified_address()))))) || + net_ipv4_unspecified_address())) || + net_dhcpv4_accept_unicast(pkt)))) || (hdr->proto == IPPROTO_TCP && net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)hdr->dst))) { NET_DBG("DROP: not for me"); @@ -326,10 +337,6 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) } } - net_pkt_set_ipv4_ttl(pkt, hdr->ttl); - - net_pkt_set_family(pkt, PF_INET); - if (IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT)) { /* Check if this is a fragmented packet, and if so, handle reassembly */ if ((ntohs(*((uint16_t *)&hdr->offset[0])) & diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 48165099759c..7ef758314060 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -520,6 +520,11 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_HDR(pkt)->hop_limit); net_pkt_set_family(pkt, PF_INET6); + if (!net_pkt_filter_ip_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if (IS_ENABLED(CONFIG_NET_ROUTE_MCAST) && net_ipv6_is_addr_mcast((struct in6_addr *)hdr->dst)) { /* If the packet is a multicast packet and multicast routing diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 5da2a664678d..e1d3fd5d226a 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -20,6 +20,7 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL); #include #include #include +#include #include #include @@ -618,7 +619,9 @@ struct net_if *net_if_get_default(void) #if defined(CONFIG_NET_DEFAULT_IF_UP) iface = net_if_get_first_up(); #endif - +#if defined(CONFIG_NET_DEFAULT_IF_WIFI) + iface = net_if_get_first_wifi(); +#endif return iface ? iface : _net_if_list_start; } @@ -1956,6 +1959,36 @@ bool z_vrfy_net_if_ipv6_addr_rm_by_index(int index, #include #endif /* CONFIG_USERSPACE */ +void net_if_ipv6_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data) +{ + struct net_if_ipv6 *ipv6; + + if (iface == NULL) { + return; + } + + net_if_lock(iface); + + ipv6 = iface->config.ip.ipv6; + if (ipv6 == NULL) { + goto out; + } + + for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + struct net_if_addr *if_addr = &ipv6->unicast[i]; + + if (!if_addr->is_used) { + continue; + } + + cb(iface, if_addr, user_data); + } + +out: + net_if_unlock(iface); +} + struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface, const struct in6_addr *addr) { @@ -3259,12 +3292,12 @@ static struct in_addr *if_ipv4_get_addr(struct net_if *iface, struct net_if_ipv4 *ipv4; int i; - net_if_lock(iface); - if (!iface) { - goto out; + return NULL; } + net_if_lock(iface); + ipv4 = iface->config.ip.ipv4; if (!ipv4) { goto out; @@ -3758,6 +3791,36 @@ bool z_vrfy_net_if_ipv4_addr_rm_by_index(int index, #include #endif /* CONFIG_USERSPACE */ +void net_if_ipv4_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data) +{ + struct net_if_ipv4 *ipv4; + + if (iface == NULL) { + return; + } + + net_if_lock(iface); + + ipv4 = iface->config.ip.ipv4; + if (ipv4 == NULL) { + goto out; + } + + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + struct net_if_addr *if_addr = &ipv4->unicast[i]; + + if (!if_addr->is_used) { + continue; + } + + cb(iface, if_addr, user_data); + } + +out: + net_if_unlock(iface); +} + static struct net_if_mcast_addr *ipv4_maddr_find(struct net_if *iface, bool is_used, const struct in_addr *addr) @@ -4592,6 +4655,28 @@ void net_if_add_tx_timestamp(struct net_pkt *pkt) } #endif /* CONFIG_NET_PKT_TIMESTAMP_THREAD */ +bool net_if_is_wifi(struct net_if *iface) +{ + if (is_iface_offloaded(iface)) { + return net_off_is_wifi_offloaded(iface); + } +#if defined(CONFIG_NET_L2_ETHERNET) + return net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) && + net_eth_type_is_wifi(iface); +#endif + return false; +} + +struct net_if *net_if_get_first_wifi(void) +{ + STRUCT_SECTION_FOREACH(net_if, iface) { + if (net_if_is_wifi(iface)) { + return iface; + } + } + return NULL; +} + void net_if_init(void) { int if_count = 0; diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h index 351c87c61466..1fce0ab3aae5 100644 --- a/subsys/net/ip/net_private.h +++ b/subsys/net/ip/net_private.h @@ -19,8 +19,10 @@ #include +#ifdef CONFIG_NET_L2_WIFI_MGMT /* For struct wifi_scan_result */ #include +#endif /* CONFIG_NET_L2_WIFI_MGMT */ #define DEFAULT_NET_EVENT_INFO_SIZE 32 /* NOTE: Update this union with all *big* event info structs */ diff --git a/subsys/net/l2/Kconfig b/subsys/net/l2/Kconfig index 468e1729dd78..9c274a5737a8 100644 --- a/subsys/net/l2/Kconfig +++ b/subsys/net/l2/Kconfig @@ -96,13 +96,19 @@ config NET_L2_CUSTOM_IEEE802154_MTU source "subsys/net/l2/canbus/Kconfig" +config NET_L2_WIFI_UTILS + bool + help + This provides utility functions for Wi-Fi subsystem. + config NET_L2_WIFI_MGMT bool "Wi-Fi Management support" select NET_MGMT select NET_MGMT_EVENT select NET_MGMT_EVENT_INFO + select NET_L2_WIFI_UTILS help - Add support for Wi-Fi Management interface. + Enable support for Wi-Fi Management interface. if NET_L2_WIFI_MGMT module = NET_L2_WIFI_MGMT @@ -116,6 +122,9 @@ endif # NET_L2_WIFI_MGMT config NET_L2_WIFI_SHELL bool "Wi-Fi shell module" select NET_L2_WIFI_MGMT + select NET_L2_WIFI_UTILS + select SHELL_GETOPT + select GETOPT_LONG help This can be used for controlling Wi-Fi through the console via exposing a shell module named "wifi". diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index 09450dde7786..b39476bd1696 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -102,6 +102,20 @@ static inline int ieee802154_stop(struct net_if *iface) return radio->stop(net_if_get_device(iface)); } +static inline int ieee802154_radio_attr_get(struct net_if *iface, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + const struct ieee802154_radio_api *radio = + net_if_get_device(iface)->api; + + if (!radio || !radio->attr_get) { + return -ENOENT; + } + + return radio->attr_get(net_if_get_device(iface), attr, value); +} + /** * Sets the radio drivers extended address filter. * diff --git a/subsys/net/l2/wifi/CMakeLists.txt b/subsys/net/l2/wifi/CMakeLists.txt index 3fb8eebd6150..445eb56c0a7d 100644 --- a/subsys/net/l2/wifi/CMakeLists.txt +++ b/subsys/net/l2/wifi/CMakeLists.txt @@ -8,3 +8,11 @@ zephyr_library_compile_definitions_ifdef( zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_MGMT wifi_mgmt.c) zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_SHELL wifi_shell.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM wifi_nm.c) +zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_UTILS wifi_utils.c) + +# Linker section placement for wifi_nm_instance iterable structure +zephyr_linker_sources_ifdef(CONFIG_WIFI_NM DATA_SECTIONS wifi_nm.ld) +if (CONFIG_WIFI_NM) +zephyr_iterable_section(NAME wifi_nm_instance GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +endif() diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 48bcff3943e6..e034a745b5e3 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -38,3 +38,99 @@ config WIFI_MGMT_TWT_CHECK_IP being unreachable (IP Level) or unable to receive down link traffic even when it is awake intervals. Rejecting TWT setup till Wi-Fi interface has a valid IP address might be desirable in most scenarios. + +config WIFI_MGMT_FORCED_PASSIVE_SCAN + bool "Force Passive scan" + help + Force passive scan (typically used to reduce power consumption), + the scan type is always sent as passive. + This doesn't guarantee that passive scan will be used, it depends + on the underlying chip implementation to support and honour scan type. + +config WIFI_MGMT_SCAN_BANDS + string "Frequency bands to scan" + default "" + help + Specifies the frequency bands to scan, as follows: + 2 - 2.4 GHz + 5 - 5 GHz + 6 - 6 GHz + "" - All bands allowed by the regulatory domain. + Multiple bands can be specified as comma separated band values. + Only regulatory domain permitted values are allowed. + +config WIFI_MGMT_SCAN_DWELL_TIME_ACTIVE + int "Active scan dwell time" + default 50 + range 5 1000 + help + Active scan dwell time (in ms) per channel. + +config WIFI_MGMT_SCAN_DWELL_TIME_PASSIVE + int "Passive scan dwell time" + default 130 + range 10 1000 + help + Passive scan dwell time (in ms) per channel. + +config WIFI_MGMT_SCAN_SSID_FILT_MAX + int "Maximum number of SSIDs that can be specified for SSID filtering" + default 1 + help + Maximum number of SSIDs that can be specified for SSID filtering. + This can be set based on the underlying chipsets limitations. + +config WIFI_MGMT_SCAN_SSID_FILT + string "Scan for specific SSIDs" + default "" + help + String of comma separated SSID values to scan for. The number of SSID’s + that can be specified depends on WIFI_MGMT_SCAN_MAX_SSIDS. + Use "" to disable SSID filtering. + +config WIFI_MGMT_SCAN_MAX_BSS_CNT + int "Maximum number of scan results to return." + default 0 + range 0 65535 + help + Maximum number of scan results to return. 0 represents unlimited number of BSSes. + +config WIFI_MGMT_SCAN_CHAN + string "Scan on specific channels" + default "" + help + Formatted string which specifies channels to be scanned. The channel string has to be formatted + using the colon (:), comma(,), hyphen (-) and space ( ) delimiters as follows: + - A colon identifies the value preceding it as a band. A band value + (2: 2.4 GHz, 5: 5 GHz 6: 6 GHz) has to precede the channels in that band (e.g. 2: etc) + - Hyphens are used to identify channel ranges (e.g. 2-7, 32-48 etc) + - Commas are used to separate channel values within a band. Channels can be specified + as individual values (2,6,48 etc) or channel ranges using hyphens (1-14, 32-48 etc) + - Spaces are used to specify multiple band-channel sets (e.g. 2:1,2 5:36,40 etc) + - No spaces should be used anywhere else, i.e. before/after commas, + before/after hyphens. + An example channel specification specifying channels in the 2.4 GHz and 5 GHz bands is + as below: + 2:1,5,7,9-11_5:36-48,100,163-167 + +config WIFI_NM + bool "Wi-Fi Network manager support" + help + This option enables using the Wi-Fi Network managers (e.g. wpa_supplicant) to + manage the Wi-Fi network interfaces. + +if WIFI_NM + +config WIFI_NM_MAX_MANAGED_INTERFACES + int "Maximum number of managed interfaces per Wi-Fi network manager" + default 1 + help + This option defines the maximum number of managed interfaces per Wi-Fi + network manager instance that can be used simultaneously. + +module = WIFI_NM +module-dep = NET_LOG +module-str = Log level for Wi-Fi Network manager module +module-help = Enables using the Wi-Fi Network managers to manage the Wi-Fi network interfaces. +source "subsys/net/Kconfig.template.log_config.net" +endif # WIFI_NM diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 104a79819814..22d54b926ab6 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -8,10 +8,30 @@ LOG_MODULE_REGISTER(net_wifi_mgmt, CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL); #include +#include #include #include #include +#include +#ifdef CONFIG_WIFI_NM +#include +#endif /* CONFIG_WIFI_NM */ + +static const struct wifi_mgmt_ops *const get_wifi_api(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct net_wifi_mgmt_offload *off_api = + (struct net_wifi_mgmt_offload *) dev->api; +#ifdef CONFIG_WIFI_NM + struct wifi_nm_instance *nm = wifi_nm_get_instance_iface(iface); + + if (nm) { + return nm->ops; + } +#endif /* CONFIG_WIFI_NM */ + return off_api ? off_api->wifi_mgmt_api : NULL; +} static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) @@ -19,10 +39,10 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, struct wifi_connect_req_params *params = (struct wifi_connect_req_params *)data; const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - if (off_api == NULL || off_api->connect == NULL) { + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->connect == NULL) { return -ENOTSUP; } @@ -49,7 +69,7 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->connect(dev, params); + return wifi_mgmt_api->connect(dev, params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_CONNECT, wifi_connect); @@ -82,31 +102,83 @@ static int wifi_scan(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + struct wifi_scan_params *params = data; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + bool chan_specified = false; + uint8_t i = 0; - if (off_api == NULL || off_api->scan == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->scan == NULL) { return -ENOTSUP; } - return off_api->scan(dev, scan_result_cb); + if (data && (len == sizeof(*params))) { +#ifdef CONFIG_WIFI_MGMT_FORCED_PASSIVE_SCAN + params->scan_type = WIFI_SCAN_TYPE_PASSIVE; +#endif /* CONFIG_WIFI_MGMT_FORCED_PASSIVE_SCAN */ + + if (!params->bands) { + if (wifi_utils_parse_scan_bands(CONFIG_WIFI_MGMT_SCAN_BANDS, + ¶ms->bands)) { + NET_ERR("Incorrect value(s) in CONFIG_WIFI_MGMT_SCAN_BANDS: %s", + CONFIG_WIFI_MGMT_SCAN_BANDS); + return -EINVAL; + } + } + + if (!params->dwell_time_active) { + params->dwell_time_active = CONFIG_WIFI_MGMT_SCAN_DWELL_TIME_ACTIVE; + } + + if (!params->dwell_time_passive) { + params->dwell_time_passive = CONFIG_WIFI_MGMT_SCAN_DWELL_TIME_PASSIVE; + } + + if (!strlen(params->ssids[0])) { + if (wifi_utils_parse_scan_ssids(CONFIG_WIFI_MGMT_SCAN_SSID_FILT, + params->ssids)) { + NET_ERR("Incorrect value(s) in CONFIG_WIFI_MGMT_SCAN_SSID_FILT: %s", + CONFIG_WIFI_MGMT_SCAN_SSID_FILT); + return -EINVAL; + } + } + + if (!params->max_bss_cnt) { + params->max_bss_cnt = CONFIG_WIFI_MGMT_SCAN_MAX_BSS_CNT; + } + + for (i = 0; i <= WIFI_FREQ_BAND_MAX; i++) { + if (params->chan[i][0]) { + chan_specified = true; + break; + } + } + + if ((!chan_specified) && strlen(CONFIG_WIFI_MGMT_SCAN_CHAN)) { + if (wifi_utils_parse_scan_chan(CONFIG_WIFI_MGMT_SCAN_CHAN, + params->chan)) { + NET_ERR("Incorrect value(s) in CONFIG_WIFI_MGMT_SCAN_CHAN: %s", + CONFIG_WIFI_MGMT_SCAN_CHAN); + return -EINVAL; + } + } + } + + return wifi_mgmt_api->scan(dev, params, scan_result_cb); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN, wifi_scan); - static int wifi_disconnect(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); - if (off_api == NULL || off_api->disconnect == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->disconnect == NULL) { return -ENOTSUP; } - return off_api->disconnect(dev); + return wifi_mgmt_api->disconnect(dev); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_DISCONNECT, wifi_disconnect); @@ -139,14 +211,13 @@ static int wifi_ap_enable(uint32_t mgmt_request, struct net_if *iface, struct wifi_connect_req_params *params = (struct wifi_connect_req_params *)data; const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); - if (off_api == NULL || off_api->ap_enable == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; } - return off_api->ap_enable(dev, params); + return wifi_mgmt_api->ap_enable(dev, params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_ENABLE, wifi_ap_enable); @@ -155,14 +226,13 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); - if (off_api == NULL || off_api->ap_enable == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; } - return off_api->ap_disable(dev); + return wifi_mgmt_api->ap_disable(dev); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE, wifi_ap_disable); @@ -171,11 +241,10 @@ static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_iface_status *status = data; - if (off_api == NULL || off_api->iface_status == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->iface_status == NULL) { return -ENOTSUP; } @@ -183,7 +252,7 @@ static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->iface_status(dev, status); + return wifi_mgmt_api->iface_status(dev, status); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS, wifi_iface_status); @@ -200,11 +269,10 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct net_stats_wifi *stats = data; - if (off_api == NULL || off_api->get_stats == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_stats == NULL) { return -ENOTSUP; } @@ -212,7 +280,7 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->get_stats(dev, stats); + return wifi_mgmt_api->get_stats(dev, stats); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_WIFI, wifi_iface_stats); #endif /* CONFIG_NET_STATISTICS_WIFI */ @@ -221,12 +289,11 @@ static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_ps_params *ps_params = data; struct wifi_iface_status info = { 0 }; - if (off_api == NULL || off_api->set_power_save == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_power_save == NULL) { return -ENOTSUP; } @@ -256,7 +323,7 @@ static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface, return -ENOTSUP; } - return off_api->set_power_save(dev, ps_params); + return wifi_mgmt_api->set_power_save(dev, ps_params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS, wifi_set_power_save); @@ -265,11 +332,10 @@ static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *ifac void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_ps_config *ps_config = data; - if (off_api == NULL || off_api->get_power_save_config == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_power_save_config == NULL) { return -ENOTSUP; } @@ -277,7 +343,7 @@ static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *ifac return -EINVAL; } - return off_api->get_power_save_config(dev, ps_config); + return wifi_mgmt_api->get_power_save_config(dev, ps_config); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG, wifi_get_power_save_config); @@ -286,17 +352,20 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_twt_params *twt_params = data; struct wifi_iface_status info = { 0 }; - if (off_api == NULL || off_api->set_twt == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_twt == NULL) { twt_params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED; return -ENOTSUP; } + if (twt_params->operation == WIFI_TWT_TEARDOWN) { + return wifi_mgmt_api->set_twt(dev, twt_params); + } + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &info, sizeof(struct wifi_iface_status))) { twt_params->fail_reason = @@ -334,7 +403,7 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, goto fail; } - return off_api->set_twt(dev, twt_params); + return wifi_mgmt_api->set_twt(dev, twt_params); fail: return -ENOEXEC; @@ -353,11 +422,10 @@ static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_reg_domain *reg_domain = data; - if (off_api == NULL || off_api->reg_domain == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->reg_domain == NULL) { return -ENOTSUP; } @@ -365,7 +433,7 @@ static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->reg_domain(dev, reg_domain); + return wifi_mgmt_api->reg_domain(dev, reg_domain); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN, wifi_reg_domain); diff --git a/subsys/net/l2/wifi/wifi_nm.c b/subsys/net/l2/wifi/wifi_nm.c new file mode 100644 index 000000000000..4f3e2d239a1a --- /dev/null +++ b/subsys/net/l2/wifi/wifi_nm.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(wifi_nm, CONFIG_WIFI_NM_LOG_LEVEL); + +#include +#include + +struct wifi_nm_instance *wifi_nm_get_instance(const char *name) +{ + STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { + if (!strcmp(nm->name, name)) { + return nm; + } + } + + return NULL; +} + +struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface) +{ + if (!iface || !net_if_is_wifi(iface)) { + return false; + } + + STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (nm->mgd_ifaces[i] == iface) { + return nm; + } + } + } + + return NULL; +} + +int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface) +{ + if (!nm || !iface) { + return -EINVAL; + } + + if (!net_if_is_wifi(iface)) { + return -ENOTSUP; + } + + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (!nm->mgd_ifaces[i]) { + nm->mgd_ifaces[i] = iface; + return 0; + } + } + + return -ENOMEM; +} + +int wifi_nm_unregister_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface) +{ + if (!nm || !iface) { + return -EINVAL; + } + + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (nm->mgd_ifaces[i] == iface) { + nm->mgd_ifaces[i] = NULL; + return 0; + } + } + + return -ENOENT; +} diff --git a/subsys/net/l2/wifi/wifi_nm.ld b/subsys/net/l2/wifi/wifi_nm.ld new file mode 100644 index 000000000000..73bc53f881a5 --- /dev/null +++ b/subsys/net/l2/wifi/wifi_nm.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +ITERABLE_SECTION_RAM(wifi_nm_instance, 4) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 47e47830c8e8..52d611d8fd65 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -14,13 +14,16 @@ LOG_MODULE_REGISTER(net_wifi_shell, LOG_LEVEL_INF); #include #include #include +#include #include #include #include #include -#include #include +#include +#include +#include #include "net_private.h" @@ -241,25 +244,25 @@ static void print_twt_params(uint8_t dialog_token, uint8_t flow_id, bool trigger, uint32_t twt_wake_interval, uint64_t twt_interval) { - shell_fprintf(context.sh, SHELL_NORMAL, "TWT Dialog token: %d\n", - dialog_token); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT flow ID: %d\n", - flow_id); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT negotiation type: %s\n", - wifi_twt_negotiation_type2str[negotiation_type]); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT responder: %s\n", - responder ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT implicit: %s\n", - implicit ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT announce: %s\n", - announce ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT trigger: %s\n", - trigger ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT wake interval: %d us\n", - twt_wake_interval); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT interval: %lld us\n", - twt_interval); - shell_fprintf(context.sh, SHELL_NORMAL, "========================\n"); + print(context.sh, SHELL_NORMAL, "TWT Dialog token: %d\n", + dialog_token); + print(context.sh, SHELL_NORMAL, "TWT flow ID: %d\n", + flow_id); + print(context.sh, SHELL_NORMAL, "TWT negotiation type: %s\n", + wifi_twt_negotiation_type2str[negotiation_type]); + print(context.sh, SHELL_NORMAL, "TWT responder: %s\n", + responder ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT implicit: %s\n", + implicit ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT announce: %s\n", + announce ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT trigger: %s\n", + trigger ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT wake interval: %d us\n", + twt_wake_interval); + print(context.sh, SHELL_NORMAL, "TWT interval: %lld us\n", + twt_interval); + print(context.sh, SHELL_NORMAL, "========================\n"); } static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) @@ -267,9 +270,16 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) const struct wifi_twt_params *resp = (const struct wifi_twt_params *)cb->info; + if (resp->operation == WIFI_TWT_TEARDOWN) { + print(context.sh, SHELL_NORMAL, "TWT teardown received for flow ID %d\n", + resp->flow_id); + return; + } + if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) { print(context.sh, SHELL_NORMAL, "TWT response: %s\n", wifi_twt_setup_cmd2str[resp->setup_cmd]); + print(context.sh, SHELL_NORMAL, "== TWT negotiated parameters ==\n"); print_twt_params(resp->dialog_token, resp->flow_id, resp->negotiation_type, @@ -382,7 +392,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], static int cmd_wifi_connect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_connect_req_params cnx_params = { 0 }; if (__wifi_args_to_params(argc - 1, &argv[1], &cnx_params)) { @@ -410,7 +420,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); int status; context.disconnecting = true; @@ -437,26 +447,160 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, return 0; } + + +static int wifi_scan_args_to_params(const struct shell *sh, + size_t argc, + char *argv[], + struct wifi_scan_params *params, + bool *do_scan) +{ + struct getopt_state *state; + int opt; + static struct option long_options[] = {{"type", required_argument, 0, 't'}, + {"bands", required_argument, 0, 'b'}, + {"dwell_time_active", required_argument, 0, 'a'}, + {"dwell_time_passive", required_argument, 0, 'p'}, + {"ssids", required_argument, 0, 's'}, + {"max_bss", required_argument, 0, 'm'}, + {"chans", required_argument, 0, 'c'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}}; + int opt_index = 0; + int val; + int opt_num = 0; + + *do_scan = true; + + while ((opt = getopt_long(argc, argv, "t:b:a:p:s:m:c:h", long_options, &opt_index)) != -1) { + state = getopt_state_get(); + switch (opt) { + case 't': + if (!strcmp(optarg, "passive")) { + params->scan_type = WIFI_SCAN_TYPE_PASSIVE; + } else if (!strcmp(optarg, "active")) { + params->scan_type = WIFI_SCAN_TYPE_ACTIVE; + } else { + shell_fprintf(sh, SHELL_ERROR, "Invalid scan type %s\n", optarg); + return -ENOEXEC; + } + + opt_num++; + break; + case 'b': + if (wifi_utils_parse_scan_bands(optarg, ¶ms->bands)) { + shell_fprintf(sh, SHELL_ERROR, "Invalid band value(s)\n"); + return -ENOEXEC; + } + + opt_num++; + break; + case 'a': + val = atoi(optarg); + + if ((val < 5) || (val > 1000)) { + shell_fprintf(sh, SHELL_ERROR, "Invalid dwell_time_active val\n"); + return -ENOEXEC; + } + + params->dwell_time_active = val; + opt_num++; + break; + case 'p': + val = atoi(optarg); + + if ((val < 10) || (val > 1000)) { + shell_fprintf(sh, SHELL_ERROR, "Invalid dwell_time_passive val\n"); + return -ENOEXEC; + } + + params->dwell_time_passive = val; + opt_num++; + break; + case 's': + if (wifi_utils_parse_scan_ssids(optarg, params->ssids)) { + shell_fprintf(sh, SHELL_ERROR, "Invalid SSID(s)\n"); + return -ENOEXEC; + } + + opt_num++; + break; + case 'm': + val = atoi(optarg); + + if ((val < 0) || (val > 65535)) { + shell_fprintf(sh, SHELL_ERROR, "Invalid max_bss val\n"); + return -ENOEXEC; + } + + params->max_bss_cnt = val; + opt_num++; + break; + case 'c': + if (wifi_utils_parse_scan_chan(optarg, params->chan)) { + shell_fprintf(sh, + SHELL_ERROR, + "Invalid band or channel value(s)\n"); + return -ENOEXEC; + } + + opt_num++; + break; + case 'h': + shell_help(sh); + *do_scan = false; + opt_num++; + break; + case '?': + default: + shell_fprintf(sh, SHELL_ERROR, "Invalid option or option usage: %s\n", + argv[opt_index + 1]); + return -ENOEXEC; + } + } + + return opt_num; +} + static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); + struct wifi_scan_params params = { 0 }; + bool do_scan = true; + int opt_num; context.sh = sh; - if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) { - shell_fprintf(sh, SHELL_WARNING, "Scan request failed\n"); + if (argc > 1) { + opt_num = wifi_scan_args_to_params(sh, argc, argv, ¶ms, &do_scan); - return -ENOEXEC; + if (opt_num < 0) { + shell_help(sh); + return -ENOEXEC; + } else if (!opt_num) { + shell_fprintf(sh, SHELL_WARNING, "No valid option(s) found\n"); + do_scan = false; + } } - shell_fprintf(sh, SHELL_NORMAL, "Scan requested\n"); + if (do_scan) { + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, ¶ms, sizeof(params))) { + shell_fprintf(sh, SHELL_WARNING, "Scan request failed\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, SHELL_NORMAL, "Scan requested\n"); - return 0; + return 0; + } + + shell_fprintf(sh, SHELL_WARNING, "Scan not initiated\n"); + return -ENOEXEC; } static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_iface_status status = { 0 }; context.sh = sh; @@ -502,7 +646,6 @@ static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) return 0; } - #if defined(CONFIG_NET_STATISTICS_WIFI) && \ defined(CONFIG_NET_STATISTICS_USER_API) static void print_wifi_stats(struct net_if *iface, struct net_stats_wifi *data, @@ -531,7 +674,7 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[]) { #if defined(CONFIG_NET_STATISTICS_WIFI) && \ defined(CONFIG_NET_STATISTICS_USER_API) - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct net_stats_wifi stats = { 0 }; int ret; @@ -554,7 +697,7 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; @@ -586,8 +729,13 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) shell_fprintf(sh, SHELL_NORMAL, "PS wake up mode: %s\n", config.ps_params.wakeup_mode ? "Listen interval" : "DTIM"); - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", - config.ps_params.timeout_ms); + if (config.ps_params.timeout_ms) { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", + config.ps_params.timeout_ms); + } else { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + } + if (config.num_twt_flows == 0) { shell_fprintf(sh, SHELL_NORMAL, "No TWT flows\n"); @@ -634,7 +782,7 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; @@ -664,7 +812,7 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; long timeout_ms = 0; int err = 0; @@ -688,8 +836,11 @@ static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[] return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, - "PS timeout %d ms\n", params.timeout_ms); + if (params.timeout_ms) { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", params.timeout_ms); + } else { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + } return 0; } @@ -697,7 +848,7 @@ static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[] static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; @@ -717,7 +868,7 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, params.flow_id = 0; params.setup.responder = 0; params.setup.implicit = 1; - params.setup.trigger = 1; + params.setup.trigger = 0; params.setup.announce = 0; if (!parse_number(sh, (long *)¶ms.setup.twt_wake_interval, argv[idx++], @@ -746,7 +897,7 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; long neg_type; @@ -801,7 +952,7 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; long neg_type = 0; long setup_cmd = 0; @@ -837,7 +988,7 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n", + shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d success\n", wifi_twt_operation2str[params.operation], params.dialog_token, params.flow_id); @@ -847,7 +998,7 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; context.sh = sh; @@ -864,7 +1015,7 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows\n", + shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows success\n", wifi_twt_operation2str[params.operation]); return 0; @@ -873,7 +1024,7 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); static struct wifi_connect_req_params cnx_params; int ret; @@ -899,7 +1050,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); int ret; ret = net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, NULL, 0); @@ -917,7 +1068,7 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_reg_domain regd = {0}; int ret; @@ -976,7 +1127,7 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; long interval = 0; @@ -1015,7 +1166,7 @@ static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *a static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; @@ -1099,7 +1250,18 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, cmd_wifi_ps_mode, 2, 0), - SHELL_CMD(scan, NULL, "Scan for Wi-Fi APs", cmd_wifi_scan), + SHELL_CMD(scan, NULL, + "Scan for Wi-Fi APs\n" + "OPTIONAL PARAMETERS:\n" + "[-t, --type ] : Preferred mode of scan. The actual mode of scan can depend on factors such as the Wi-Fi chip implementation, regulatory domain restrictions. Default type is active.\n" + "[-b, --bands ] : Bands to be scanned where 2: 2.4 GHz, 5: 5 GHz, 6: 6 GHz.\n" + "[-a, --dwell_time_active ] : Active scan dwell time (in ms) on a channel. Range 5 ms to 1000 ms.\n" + "[-p, --dwell_time_passive ] : Passive scan dwell time (in ms) on a channel. Range 10 ms to 1000 ms.\n" + "[-s, --ssids ] : SSID list to scan for.\n" + "[-m, --max_bss ] : Maximum BSSes to scan for. Range 1 - 65535.\n" + "[-c, --chans ] : Channels to be scanned. The channels must be specified in the form band1:chan1,chan2_band2:chan3,..etc. band1, band2 must be valid band values and chan1, chan2, chan3 must be specified as a list of comma separated values where each value is either a single channel or a channel range specified as chan_start-chan_end. Each band channel set has to be separated by a _. For example, a valid channel specification can be 2:1,6-11,14_5:36,149-165,44\n" + "[-h, --help] : Print out the help for the scan command.", + cmd_wifi_scan), SHELL_CMD(statistics, NULL, "Wi-Fi interface statistics", cmd_wifi_stats), SHELL_CMD(status, NULL, "Status of the Wi-Fi interface", cmd_wifi_status), SHELL_CMD(twt, &wifi_twt_ops, "Manage TWT flows", NULL), diff --git a/subsys/net/l2/wifi/wifi_utils.c b/subsys/net/l2/wifi/wifi_utils.c new file mode 100644 index 000000000000..00585480f349 --- /dev/null +++ b/subsys/net/l2/wifi/wifi_utils.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Utility functions to be used by the Wi-Fi subsytem. + */ +#include +LOG_MODULE_REGISTER(net_wifi_utils, CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Ensure 'strtok_r' is available even with -std=c99. */ +char *strtok_r(char *str, const char *delim, char **saveptr); + +static const uint16_t valid_5g_chans_20mhz[] = {32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 96, 100, + 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 159, 161, + 163, 165, 167, 169, 171, 173, 175, 177}; + +static enum wifi_frequency_bands wifi_utils_map_band_str_to_idx(char *band_str) +{ + enum wifi_frequency_bands band = WIFI_FREQ_BAND_UNKNOWN; + + if (!strcmp(band_str, "2")) { + band = WIFI_FREQ_BAND_2_4_GHZ; + } else if (!strcmp(band_str, "5")) { + band = WIFI_FREQ_BAND_5_GHZ; + } else if (!strcmp(band_str, "6")) { + band = WIFI_FREQ_BAND_6_GHZ; + } + + return band; +} + + +static bool wifi_utils_validate_chan_2g(uint16_t chan) +{ + if ((chan >= 1) && (chan <= 14)) { + return true; + } + + return false; +} + + +static bool wifi_utils_validate_chan_5g(uint16_t chan) +{ + uint16_t i; + + for (i = 0; i < ARRAY_SIZE(valid_5g_chans_20mhz); i++) { + if (chan == valid_5g_chans_20mhz[i]) { + return true; + } + } + + return false; +} + + +static bool wifi_utils_validate_chan_6g(uint16_t chan) +{ + if (((chan >= 1) && (chan <= 233) && (!((chan - 1)%4))) || + (chan == 2)) { + return true; + } + + return false; +} + + +static bool wifi_utils_validate_chan(uint8_t band, + uint16_t chan) +{ + bool result = false; + + switch (band) { + case WIFI_FREQ_BAND_2_4_GHZ: + result = wifi_utils_validate_chan_2g(chan); + break; + case WIFI_FREQ_BAND_5_GHZ: + result = wifi_utils_validate_chan_5g(chan); + break; + case WIFI_FREQ_BAND_6_GHZ: + result = wifi_utils_validate_chan_6g(chan); + break; + default: + NET_ERR("Unknown band: %d", band); + break; + } + + return result; +} + + +static int wifi_utils_get_all_chans_in_range(uint16_t chan_start, + uint16_t chan_end, + uint16_t chan[][WIFI_CHANNEL_MAX], + uint8_t band_idx, + uint8_t *chan_idx) +{ + uint16_t i; + bool start = false; + bool end = false; + uint8_t idx; + + if (!wifi_utils_validate_chan(band_idx, chan_start)) { + NET_ERR("Invalid channel value %d in band %d", chan_start, band_idx); + return -EINVAL; + } + + if (!wifi_utils_validate_chan(band_idx, chan_end)) { + NET_ERR("Invalid channel value %d in band %d", chan_end, band_idx); + return -EINVAL; + } + + if (chan_end < chan_start) { + NET_ERR("Channel range end (%d) cannot be less than start (%d)", + chan_end, + chan_start); + return -EINVAL; + } + + switch (band_idx) { + case WIFI_FREQ_BAND_2_4_GHZ: + idx = *chan_idx; + + for (i = chan_start; i <= chan_end; i++) { + chan[band_idx][idx++] = i; + } + + *chan_idx = idx; + + break; + case WIFI_FREQ_BAND_5_GHZ: + idx = *chan_idx; + + for (i = 0; i < ARRAY_SIZE(valid_5g_chans_20mhz); i++) { + if (valid_5g_chans_20mhz[i] == chan_start) { + start = true; + } + + if (valid_5g_chans_20mhz[i] == chan_end) { + end = true; + } + + if (start) { + chan[band_idx][idx++] = valid_5g_chans_20mhz[i]; + } + + if (end) { + *chan_idx = idx; + break; + } + } + + break; + case WIFI_FREQ_BAND_6_GHZ: + idx = *chan_idx; + + i = chan_start; + + while (i <= chan_end) { + chan[band_idx][idx++] = i; + + if (i == 1) { + i++; + } else if (i == 2) { + i += 3; + } else { + i += 4; + } + } + + *chan_idx = idx; + default: + NET_ERR("Unknown band value: %d", band_idx); + return -EINVAL; + } + + return 0; +} + + +static int wifi_utils_validate_chan_str(char *chan_str) +{ + uint8_t i; + + if ((!chan_str) || (!strlen(chan_str))) { + NET_ERR("Null or empty channel string\n"); + return -EINVAL; + } + + for (i = 0; i < strlen(chan_str); i++) { + if (!isdigit((int)chan_str[i])) { + NET_ERR("Invalid character in channel string %c\n", chan_str[i]); + return -EINVAL; + } + } + + return 0; +} + + +int wifi_utils_parse_scan_bands(char *scan_bands_str, uint8_t *band_map) +{ + char *band_str = NULL; + char *ctx = NULL; + enum wifi_frequency_bands band = WIFI_FREQ_BAND_UNKNOWN; + + if (!scan_bands_str) { + return -EINVAL; + } + + band_str = strtok_r(scan_bands_str, ",", &ctx); + + while (band_str) { + band = wifi_utils_map_band_str_to_idx(band_str); + + if (band == WIFI_FREQ_BAND_UNKNOWN) { + NET_ERR("Invalid band value: %s", band_str); + return -EINVAL; + } + + *band_map |= (1 << band); + + band_str = strtok_r(NULL, ",", &ctx); + } + + return 0; +} + +int wifi_utils_parse_scan_ssids(char *scan_ssids_str, + char ssids[][WIFI_SSID_MAX_LEN + 1]) +{ + char *ssid = NULL; + char *ctx = NULL; + uint8_t i = 0; + + if (!scan_ssids_str) { + return -EINVAL; + } + + ssid = strtok_r(scan_ssids_str, ",", &ctx); + + while (ssid) { + if (strlen(ssid) > WIFI_SSID_MAX_LEN) { + NET_ERR("SSID length (%zu) exceeds maximum value (%d) for SSID %s", + strlen(ssid), + WIFI_SSID_MAX_LEN, + ssid); + return -EINVAL; + } + + if (i >= WIFI_MGMT_SCAN_SSID_FILT_MAX) { + NET_WARN("Exceeded maximum allowed (%d) SSIDs. Ignoring SSIDs %s onwards", + WIFI_MGMT_SCAN_SSID_FILT_MAX, + ssid); + break; + } + + strcpy(&ssids[i++][0], ssid); + + ssid = strtok_r(NULL, ",", &ctx); + } + + return 0; +} + + +int wifi_utils_parse_scan_chan(char *scan_chan_str, + uint16_t chan[][WIFI_CHANNEL_MAX]) +{ + char band_str[WIFI_UTILS_MAX_BAND_STR_LEN] = {0}; + char chan_str[WIFI_UTILS_MAX_CHAN_STR_LEN] = {0}; + enum wifi_frequency_bands band = WIFI_FREQ_BAND_UNKNOWN; + uint16_t band_str_start_idx = 0; + uint16_t chan_str_start_idx = 0; + uint8_t chan_idx = 0; + uint16_t chan_start = 0; + uint16_t chan_val = 0; + uint16_t i = 0; + bool valid_band = false; + bool valid_chan = false; + + while (scan_chan_str[i] != '\0') { + if (scan_chan_str[i] != ':') { + i++; + continue; + } + + if (((i - band_str_start_idx) <= 0) || + ((i - band_str_start_idx) > WIFI_UTILS_MAX_BAND_STR_LEN)) { + NET_ERR("Invalid band value %s", + &scan_chan_str[band_str_start_idx]); + return -EINVAL; + } + + strncpy(band_str, + &scan_chan_str[band_str_start_idx], + (i - band_str_start_idx)); + + band = wifi_utils_map_band_str_to_idx(band_str); + + if (band == WIFI_FREQ_BAND_UNKNOWN) { + NET_ERR("Unsupported band value: %s", band_str); + return -EINVAL; + } + + i++; + chan_idx = 0; + chan_str_start_idx = i; + valid_band = true; + + while (1) { + if ((scan_chan_str[i] != ',') && + (scan_chan_str[i] != '_') && + (scan_chan_str[i] != '-') && + (scan_chan_str[i] != '\0')) { + i++; + continue; + } + + if ((i - chan_str_start_idx) > + WIFI_UTILS_MAX_CHAN_STR_LEN) { + NET_ERR("Invalid chan value %s", + &scan_chan_str[chan_str_start_idx]); + return -EINVAL; + } + + strncpy(chan_str, + &scan_chan_str[chan_str_start_idx], + (i - chan_str_start_idx)); + + if (wifi_utils_validate_chan_str(chan_str)) { + NET_ERR("Channel string validation failed"); + return -EINVAL; + } + + chan_val = atoi(chan_str); + + memset(chan_str, 0, sizeof(chan_str)); + + if (chan_start) { + if (wifi_utils_get_all_chans_in_range(chan_start, + chan_val, + chan, + band, + &chan_idx)) { + NET_ERR("Channel range invalid"); + return -EINVAL; + } + + chan_start = 0; + } else { + if (!wifi_utils_validate_chan(band, + chan_val)) { + NET_ERR("Invalid channel %d", chan_val); + return -EINVAL; + } + + chan[band][chan_idx++] = chan_val; + } + + valid_chan = true; + + if (scan_chan_str[i] == '_') { + band_str_start_idx = ++i; + break; + } else if (scan_chan_str[i] == ',') { + chan_str_start_idx = ++i; + } else if (scan_chan_str[i] == '-') { + chan_start = chan_val; + chan_str_start_idx = ++i; + } else if (scan_chan_str[i] == '\0') { + break; + } + } + } + + if (!valid_band) { + NET_ERR("No valid band found"); + return -EINVAL; + } + + if (!valid_chan) { + NET_ERR("No valid channel found"); + return -EINVAL; + } + + return 0; +} diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index b0a30510fba7..a4dab38eee80 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1287,7 +1287,7 @@ int coap_pending_init(struct coap_pending *pending, pending->data = request->data; pending->len = request->offset; - pending->t0 = k_uptime_get_32(); + pending->t0 = k_uptime_get(); pending->retries = retries; return 0; @@ -1382,7 +1382,7 @@ struct coap_pending *coap_pending_next_to_expire( { struct coap_pending *p, *found = NULL; size_t i; - uint32_t expiry, min_expiry; + int64_t expiry, min_expiry = INT64_MAX; for (i = 0, p = pendings; i < len; i++, p++) { if (!p->timeout) { @@ -1391,7 +1391,7 @@ struct coap_pending *coap_pending_next_to_expire( expiry = p->t0 + p->timeout; - if (!found || (int32_t)(expiry - min_expiry) < 0) { + if (expiry < min_expiry) { min_expiry = expiry; found = p; } diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index 1640a701de94..ec0c4d1f7fb9 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -38,9 +38,9 @@ static int send_request(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { if (addrlen == 0) { - return sendto(sock, buf, len, flags, NULL, 0); + return zsock_sendto(sock, buf, len, flags, NULL, 0); } else { - return sendto(sock, buf, len, flags, dest_addr, addrlen); + return zsock_sendto(sock, buf, len, flags, dest_addr, addrlen); } } @@ -48,9 +48,9 @@ static int receive(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { if (*addrlen == 0) { - return recvfrom(sock, buf, max_len, flags, NULL, NULL); + return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL); } else { - return recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); } } @@ -369,16 +369,16 @@ static int handle_poll(struct coap_client *client) int ret = 0; while (1) { - struct pollfd fds; + struct zsock_pollfd fds; fds.fd = client->fd; - fds.events = POLLIN; + fds.events = ZSOCK_POLLIN; fds.revents = 0; /* rfc7252#section-5.2.2, use separate timeout value for a separate response */ if (client->pending.timeout != 0) { - ret = poll(&fds, 1, client->pending.timeout); + ret = zsock_poll(&fds, 1, client->pending.timeout); } else { - ret = poll(&fds, 1, COAP_SEPARATE_TIMEOUT); + ret = zsock_poll(&fds, 1, COAP_SEPARATE_TIMEOUT); } if (ret < 0) { @@ -403,25 +403,25 @@ static int handle_poll(struct coap_client *client) break; } } else { - if (fds.revents & POLLERR) { + if (fds.revents & ZSOCK_POLLERR) { LOG_ERR("Error in poll"); ret = -EIO; break; } - if (fds.revents & POLLHUP) { + if (fds.revents & ZSOCK_POLLHUP) { LOG_ERR("Error in poll: POLLHUP"); ret = -ECONNRESET; break; } - if (fds.revents & POLLNVAL) { + if (fds.revents & ZSOCK_POLLNVAL) { LOG_ERR("Error in poll: POLLNVAL - fd not open"); ret = -EINVAL; break; } - if (!(fds.revents & POLLIN)) { + if (!(fds.revents & ZSOCK_POLLIN)) { LOG_ERR("Unknown poll error"); ret = -EINVAL; break; @@ -455,7 +455,7 @@ static int recv_response(struct coap_client *client, struct coap_packet *respons int ret; memset(client->recv_buf, 0, sizeof(client->recv_buf)); - len = receive(client->fd, client->recv_buf, sizeof(client->recv_buf), MSG_DONTWAIT, + len = receive(client->fd, client->recv_buf, sizeof(client->recv_buf), ZSOCK_MSG_DONTWAIT, &client->address, &client->socklen); if (len < 0) { diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 30a25a100f0d..b33ce66f0853 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -77,6 +77,20 @@ config LWM2M_DNS_SUPPORT bool "DNS support in the LWM2M client" default y if DNS_RESOLVER +choice + prompt "LwM2M Engine operation mode" + default LWM2M_TICKLESS if NET_SOCKETPAIR + default LWM2M_INTERVAL if !NET_SOCKETPAIR + +config LWM2M_TICKLESS + bool "Tickless operation mode" + depends on NET_SOCKETPAIR + +config LWM2M_INTERVAL + bool "Interval based polling mode" + +endchoice + config LWM2M_ENGINE_STACK_SIZE int "LWM2M engine stack size" default 2560 if NET_LOG @@ -316,7 +330,6 @@ config LWM2M_SECURITY_INSTANCE_COUNT config LWM2M_SECURITY_KEY_SIZE int "Buffer size of the security key resources" default 16 - range 16 256 help This setting establishes the size of the key (pre-shared / public) resources in the security object instances. diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index ad11ba61db8d..91d8c3bd605e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -40,6 +40,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #if defined(CONFIG_LWM2M_DTLS_SUPPORT) #include +#include #endif #if defined(CONFIG_DNS_RESOLVER) #include @@ -72,7 +73,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) #endif -#define ENGINE_UPDATE_INTERVAL_MS 500 +#define ENGINE_SLEEP_MS 500 #ifdef CONFIG_LWM2M_VERSION_1_1 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER * 3 @@ -89,8 +90,8 @@ static bool active_engine_thread; struct service_node { sys_snode_t node; k_work_handler_t service_work; - uint32_t min_call_period; /* ms */ - uint64_t last_timestamp; /* ms */ + uint32_t call_period; /* ms */ + int64_t next_timestamp; /* ms */ }; static struct service_node service_node_data[MAX_PERIODIC_SERVICE]; @@ -106,6 +107,7 @@ static struct zsock_pollfd sock_fds[MAX_POLL_FD]; static struct lwm2m_ctx *sock_ctx[MAX_POLL_FD]; static int sock_nfds; +static int control_sock; /* Resource wrappers */ #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) @@ -125,6 +127,13 @@ static int lwm2m_socket_update(struct lwm2m_ctx *ctx); /* utility functions */ +void lwm2m_engine_wake_up(void) +{ + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + zsock_send(control_sock, &(char){0}, 1, 0); + } +} + int lwm2m_open_socket(struct lwm2m_ctx *client_ctx) { if (client_ctx->sock_fd < 0) { @@ -154,29 +163,27 @@ int lwm2m_open_socket(struct lwm2m_ctx *client_ctx) int lwm2m_close_socket(struct lwm2m_ctx *client_ctx) { - int ret = 0; - if (client_ctx->sock_fd >= 0) { - ret = zsock_close(client_ctx->sock_fd); + int ret = zsock_close(client_ctx->sock_fd); + if (ret) { LOG_ERR("Failed to close socket: %d", errno); ret = -errno; return ret; } + } - client_ctx->sock_fd = -1; - client_ctx->connection_suspended = true; + client_ctx->sock_fd = -1; + client_ctx->connection_suspended = true; #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - /* Enable Queue mode buffer store */ - client_ctx->buffer_client_messages = true; + /* Enable Queue mode buffer store */ + client_ctx->buffer_client_messages = true; #endif - lwm2m_socket_update(client_ctx); - } + lwm2m_socket_update(client_ctx); - return ret; + return 0; } - int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) { int ret = 0; @@ -184,13 +191,11 @@ int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) if (client_ctx->sock_fd >= 0 && !client_ctx->connection_suspended) { int socket_temp_id = client_ctx->sock_fd; + /* Prevent closing */ client_ctx->sock_fd = -1; - client_ctx->connection_suspended = true; -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - /* Enable Queue mode buffer store */ - client_ctx->buffer_client_messages = true; -#endif - lwm2m_socket_update(client_ctx); + /* Just mark as suspended */ + lwm2m_close_socket(client_ctx); + /* store back the socket handle */ client_ctx->sock_fd = socket_temp_id; } @@ -202,16 +207,19 @@ int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx) int ret; if (client_ctx->connection_suspended) { - if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE)) { + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) || + IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) { + LOG_DBG("Resume suspended connection"); lwm2m_socket_update(client_ctx); + client_ctx->connection_suspended = false; } else { + LOG_DBG("Close and resume a new connection"); lwm2m_close_socket(client_ctx); - client_ctx->connection_suspended = false; ret = lwm2m_open_socket(client_ctx); if (ret) { return ret; } - LOG_DBG("Resume suspended connection"); + client_ctx->connection_suspended = false; return lwm2m_socket_start(client_ctx); } } @@ -344,14 +352,15 @@ int bootstrap_delete(struct lwm2m_message *msg) return ret; } #endif -/* returns ms until the next retransmission is due, or INT32_MAX + +/* returns timestamp when next retransmission is due, or INT64_MAX * if no retransmissions are necessary */ -static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t timestamp) +static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t timestamp) { struct lwm2m_message *msg; struct coap_pending *p; - int32_t remaining, next_retransmission = INT32_MAX; + int64_t remaining, next = INT64_MAX; int i; for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) { @@ -359,8 +368,8 @@ static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t t continue; } - remaining = p->t0 + p->timeout - timestamp; - if (remaining < 0) { + remaining = p->t0 + p->timeout; + if (remaining < timestamp) { msg = find_msg(p, NULL); if (!msg) { LOG_ERR("pending has no valid LwM2M message!"); @@ -386,38 +395,28 @@ static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t t lwm2m_send_message_async(msg); break; } - if (remaining < next_retransmission) { - next_retransmission = remaining; + if (remaining < next) { + next = remaining; } } - return next_retransmission; + return next; } -static int32_t engine_next_service_timeout_ms(uint32_t max_timeout, const int64_t timestamp) +static int64_t engine_next_service_timestamp(void) { struct service_node *srv; - uint64_t time_left_ms; - uint32_t timeout = max_timeout; + int64_t next = INT64_MAX; SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - time_left_ms = srv->last_timestamp + srv->min_call_period; - - /* service is due */ - if (time_left_ms < timestamp) { - return 0; - } - - /* service timeout is less than the current timeout */ - time_left_ms -= timestamp; - if (time_left_ms < timeout) { - timeout = time_left_ms; + if (srv->next_timestamp < next) { + next = srv->next_timestamp; } } - return timeout; + return next; } -int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) +static int engine_add_srv(k_work_handler_t service, uint32_t period_ms, int64_t next) { int i; @@ -442,52 +441,97 @@ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) } service_node_data[i].service_work = service; - service_node_data[i].min_call_period = period_ms; - service_node_data[i].last_timestamp = 0U; + service_node_data[i].call_period = period_ms; + service_node_data[i].next_timestamp = next; sys_slist_append(&engine_service_list, &service_node_data[i].node); + lwm2m_engine_wake_up(); + return 0; } +int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) +{ + return engine_add_srv(service, period_ms, k_uptime_get() + period_ms); +} + +int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp) +{ + return engine_add_srv(service, 0, timestamp); +} + +int lwm2m_engine_call_now(k_work_handler_t service) +{ + return engine_add_srv(service, 0, k_uptime_get()); +} + int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms) { int i = 0; for (i = 0; i < MAX_PERIODIC_SERVICE; i++) { if (service_node_data[i].service_work == service) { - service_node_data[i].min_call_period = period_ms; - return 0; + if (period_ms) { + service_node_data[i].call_period = period_ms; + service_node_data[i].next_timestamp = k_uptime_get() + period_ms; + lwm2m_engine_wake_up(); + return 0; + } + sys_slist_find_and_remove(&engine_service_list, &service_node_data[i].node); + service_node_data[i].service_work = NULL; + return 1; } } return -ENOENT; } -static int32_t lwm2m_engine_service(const int64_t timestamp) +static int64_t lwm2m_engine_service(const int64_t timestamp) { - struct service_node *srv; - int64_t service_due_timestamp; - - SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - service_due_timestamp = srv->last_timestamp + srv->min_call_period; - /* service is due */ - if (timestamp >= service_due_timestamp) { - srv->last_timestamp = k_uptime_get(); - srv->service_work(NULL); + struct service_node *srv, *tmp; + bool restart; + + do { + restart = false; + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&engine_service_list, srv, tmp, node) { + /* service is due */ + if (timestamp >= srv->next_timestamp) { + k_work_handler_t work = srv->service_work; + + if (srv->call_period) { + srv->next_timestamp = k_uptime_get() + srv->call_period; + } else { + sys_slist_find_and_remove(&engine_service_list, &srv->node); + srv->service_work = NULL; + } + if (work) { + work(NULL); + } + /* List might have been modified by the callback */ + restart = true; + break; + } } - } + } while (restart); /* calculate how long to sleep till the next service */ - return engine_next_service_timeout_ms(ENGINE_UPDATE_INTERVAL_MS, timestamp); + return engine_next_service_timestamp(); } /* LwM2M Socket Integration */ int lwm2m_socket_add(struct lwm2m_ctx *ctx) { - if (sock_nfds >= MAX_POLL_FD) { - return -ENOMEM; + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* Last poll-handle is reserved for control socket */ + if (sock_nfds >= (MAX_POLL_FD - 1)) { + return -ENOMEM; + } + } else { + if (sock_nfds >= MAX_POLL_FD) { + return -ENOMEM; + } } sock_ctx[sock_nfds] = ctx; @@ -495,6 +539,8 @@ int lwm2m_socket_add(struct lwm2m_ctx *ctx) sock_fds[sock_nfds].events = ZSOCK_POLLIN; sock_nfds++; + lwm2m_engine_wake_up(); + return 0; } @@ -505,6 +551,7 @@ static int lwm2m_socket_update(struct lwm2m_ctx *ctx) continue; } sock_fds[i].fd = ctx->sock_fd; + lwm2m_engine_wake_up(); return 0; } return -1; @@ -531,6 +578,7 @@ void lwm2m_socket_del(struct lwm2m_ctx *ctx) sock_fds[sock_nfds].fd = -1; break; } + lwm2m_engine_wake_up(); } static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) @@ -635,10 +683,12 @@ static int socket_send_message(struct lwm2m_ctx *client_ctx) static void socket_reset_pollfd_events(void) { - for (int i = 0; i < sock_nfds; ++i) { + for (int i = 0; i < MAX_POLL_FD; ++i) { sock_fds[i].events = ZSOCK_POLLIN | - (sys_slist_is_empty(&sock_ctx[i]->pending_sends) ? 0 : ZSOCK_POLLOUT); + (!sock_ctx[i] || sys_slist_is_empty(&sock_ctx[i]->pending_sends) + ? 0 + : ZSOCK_POLLOUT); sock_fds[i].revents = 0; } } @@ -647,8 +697,8 @@ static void socket_reset_pollfd_events(void) static void socket_loop(void) { int i, rc; - int64_t timestamp; - int32_t timeout, next_retransmit; + int64_t now, next; + int64_t timeout, next_retransmit; bool rd_client_paused; while (1) { @@ -675,46 +725,53 @@ static void socket_loop(void) } } - timestamp = k_uptime_get(); - timeout = lwm2m_engine_service(timestamp); - - /* wait for sockets */ - if (sock_nfds < 1) { - k_msleep(timeout); - continue; - } + now = k_uptime_get(); + next = lwm2m_engine_service(now); for (i = 0; i < sock_nfds; ++i) { - if (sock_ctx[i] != NULL && - sys_slist_is_empty(&sock_ctx[i]->pending_sends)) { - next_retransmit = retransmit_request(sock_ctx[i], timestamp); - if (next_retransmit < timeout) { - timeout = next_retransmit; - } + if (sock_ctx[i] == NULL) { + continue; + } + if (!sys_slist_is_empty(&sock_ctx[i]->pending_sends)) { + continue; + } + next_retransmit = retransmit_request(sock_ctx[i], now); + if (next_retransmit < next) { + next = next_retransmit; } - if (sock_ctx[i] != NULL && - sys_slist_is_empty(&sock_ctx[i]->pending_sends) && - lwm2m_rd_client_is_registred(sock_ctx[i])) { - check_notifications(sock_ctx[i], timestamp); + if (lwm2m_rd_client_is_registred(sock_ctx[i])) { + check_notifications(sock_ctx[i], now); } } socket_reset_pollfd_events(); - /* - * FIXME: Currently we timeout and restart poll in case fds - * were modified. - */ - rc = zsock_poll(sock_fds, sock_nfds, timeout); + timeout = next > now ? next - now : 0; + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* prevent roll-over */ + timeout = timeout > INT32_MAX ? INT32_MAX : timeout; + } else { + timeout = timeout > ENGINE_SLEEP_MS ? ENGINE_SLEEP_MS : timeout; + } + + rc = zsock_poll(sock_fds, MAX_POLL_FD, timeout); if (rc < 0) { LOG_ERR("Error in poll:%d", errno); errno = 0; - k_msleep(ENGINE_UPDATE_INTERVAL_MS); + k_msleep(ENGINE_SLEEP_MS); continue; } - for (i = 0; i < sock_nfds; i++) { + for (i = 0; i < MAX_POLL_FD; i++) { + if (sock_fds[i].revents & ZSOCK_POLLIN && sock_fds[i].fd != -1 && + sock_ctx[i] == NULL) { + /* This is the control socket, just read and ignore the data */ + char tmp; + + zsock_recv(sock_fds[i].fd, &tmp, 1, 0); + continue; + } if (sock_ctx[i] != NULL && sock_ctx[i]->sock_fd < 0) { continue; } @@ -753,20 +810,40 @@ static void socket_loop(void) } } -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) && defined(CONFIG_TLS_CREDENTIALS) -static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#if defined(CONFIG_TLS_CREDENTIALS) +static void delete_tls_credentials(sec_tag_t tag) +{ + tls_credential_delete(tag, TLS_CREDENTIAL_PSK_ID); + tls_credential_delete(tag, TLS_CREDENTIAL_PSK); + tls_credential_delete(tag, TLS_CREDENTIAL_SERVER_CERTIFICATE); + tls_credential_delete(tag, TLS_CREDENTIAL_PRIVATE_KEY); + tls_credential_delete(tag, TLS_CREDENTIAL_CA_CERTIFICATE); +} + +static bool is_pem(const void *buf, size_t len) +{ + static const char pem_start[] = "-----BEGIN"; + + if (len < sizeof(pem_start)) { + return false; + } + if (strncmp(pem_start, (const char *) buf, sizeof(pem_start) - 1) == 0) { + return true; + } + return false; +} + +static int load_tls_type(struct lwm2m_ctx *client_ctx, uint16_t res_id, enum tls_credential_type type) { int ret = 0; void *cred = NULL; uint16_t cred_len; - uint8_t cred_flags; + uint16_t max_len; - /* ignore error value */ - tls_credential_delete(client_ctx->tls_tag, type); - - ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, NULL, - &cred_len, &cred_flags); + ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, &max_len, + &cred_len, NULL); if (ret < 0) { LOG_ERR("Unable to get resource data for %d/%d/%d", 0, client_ctx->sec_obj_inst, res_id); @@ -778,6 +855,18 @@ static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, return -EINVAL; } + /* LwM2M registry stores strings without NULL-terminator, so we need to ensure that + * string based PEM credentials are terminated properly. + */ + if (is_pem(cred, cred_len)) { + if (cred_len >= max_len) { + LOG_ERR("No space for string terminator, cannot handle PEM"); + return -EINVAL; + } + ((uint8_t *) cred)[cred_len] = 0; + cred_len += 1; + } + ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len); if (ret < 0) { LOG_ERR("Error setting cred tag %d type %d: Error %d", client_ctx->tls_tag, type, @@ -786,99 +875,212 @@ static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, return ret; } -#endif /* CONFIG_LWM2M_DTLS_SUPPORT && CONFIG_TLS_CREDENTIALS*/ -int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) +static int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx) { - socklen_t addr_len; - int flags; int ret; -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) - uint8_t tmp; + delete_tls_credentials(ctx->tls_tag); - if (client_ctx->load_credentials) { - ret = client_ctx->load_credentials(client_ctx); - if (ret < 0) { - return ret; - } + ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_PSK_ID); + if (ret < 0) { + return ret; } -#if defined(CONFIG_TLS_CREDENTIALS) - else { - ret = load_tls_credential(client_ctx, 3, TLS_CREDENTIAL_PSK_ID); - if (ret < 0) { - return ret; - } - ret = load_tls_credential(client_ctx, 5, TLS_CREDENTIAL_PSK); - if (ret < 0) { - return ret; - } + ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PSK); + return ret; +} + +static int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx) +{ + int ret; + + delete_tls_credentials(ctx->tls_tag); + + ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_SERVER_CERTIFICATE); + if (ret < 0) { + return ret; + } + ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PRIVATE_KEY); + if (ret < 0) { + return ret; } -#endif /* CONFIG_TLS_CREDENTIALS */ -#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ - if (client_ctx->sock_fd < 0) { - ret = lwm2m_open_socket(client_ctx); - if (ret) { - return ret; - } + ret = load_tls_type(ctx, 4, TLS_CREDENTIAL_CA_CERTIFICATE); + if (ret < 0) { + return ret; } + return ret; +} +#else - if (client_ctx->set_socketoptions) { - ret = client_ctx->set_socketoptions(client_ctx); - if (ret) { - return ret; +int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx) +{ + return -EOPNOTSUPP; +} + +int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_TLS_CREDENTIALS*/ + +static int lwm2m_load_tls_credentials(struct lwm2m_ctx *ctx) +{ + switch (lwm2m_security_mode(ctx)) { + case LWM2M_SECURITY_NOSEC: + if (ctx->use_dtls) { + return -EINVAL; } + return 0; + case LWM2M_SECURITY_PSK: + return lwm2m_load_psk_credentials(ctx); + case LWM2M_SECURITY_CERT: + return lwm2m_load_x509_credentials(ctx); + default: + return -EOPNOTSUPP; } +} + +static const int cipher_list_psk[] = { + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, +}; + +static const int cipher_list_cert[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +}; + +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + +int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx) +{ #if defined(CONFIG_LWM2M_DTLS_SUPPORT) - else if (client_ctx->use_dtls) { + if (ctx->use_dtls) { + int ret; + uint8_t tmp; sec_tag_t tls_tag_list[] = { - client_ctx->tls_tag, + ctx->tls_tag, }; - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list, + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list, sizeof(tls_tag_list)); if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret); - goto error; + return ret; } if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) { int session_cache = TLS_SESSION_CACHE_ENABLED; - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE, + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE, &session_cache, sizeof(session_cache)); if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_SESSION_CACHE option: %d", errno); - goto error; + return ret; } } - if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) { + if (ctx->hostname_verify && (ctx->desthostname != NULL)) { /** store character at len position */ - tmp = client_ctx->desthostname[client_ctx->desthostnamelen]; + tmp = ctx->desthostname[ctx->desthostnamelen]; /** change it to '\0' to pass to socket*/ - client_ctx->desthostname[client_ctx->desthostnamelen] = '\0'; + ctx->desthostname[ctx->desthostnamelen] = '\0'; /** mbedtls ignores length */ - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_HOSTNAME, - client_ctx->desthostname, - client_ctx->desthostnamelen); + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_HOSTNAME, + ctx->desthostname, ctx->desthostnamelen); /** restore character */ - client_ctx->desthostname[client_ctx->desthostnamelen] = tmp; + ctx->desthostname[ctx->desthostnamelen] = tmp; if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_HOSTNAME option: %d", ret); - goto error; + return ret; + } + + int verify = TLS_PEER_VERIFY_REQUIRED; + + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify, + sizeof(verify)); + if (ret) { + LOG_ERR("Failed to set TLS_PEER_VERIFY"); + } + + } else { + /* By default, Mbed TLS tries to verify peer hostname, disable it */ + int verify = TLS_PEER_VERIFY_NONE; + + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify, + sizeof(verify)); + if (ret) { + LOG_ERR("Failed to set TLS_PEER_VERIFY"); + } + } + + switch (lwm2m_security_mode(ctx)) { + case LWM2M_SECURITY_PSK: + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST, + cipher_list_psk, sizeof(cipher_list_psk)); + if (ret) { + LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST"); + } + break; + case LWM2M_SECURITY_CERT: + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST, + cipher_list_cert, sizeof(cipher_list_cert)); + if (ret) { + LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST (rc %d, errno %d)", ret, + errno); } + break; + default: + return -EOPNOTSUPP; } } +#else + if (!IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) && ctx->use_dtls) { + return -EOPNOTSUPP; + } #endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + return 0; +} + +int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) +{ + socklen_t addr_len; + int flags; + int ret; + +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + if (client_ctx->load_credentials) { + ret = client_ctx->load_credentials(client_ctx); + } else { + ret = lwm2m_load_tls_credentials(client_ctx); + } + if (ret < 0) { + return ret; + } +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + + if (client_ctx->sock_fd < 0) { + ret = lwm2m_open_socket(client_ctx); + if (ret) { + return ret; + } + } + + if (client_ctx->set_socketoptions) { + ret = client_ctx->set_socketoptions(client_ctx); + } else { + ret = lwm2m_set_default_sockopt(client_ctx); + } + if (ret) { + goto error; + } + if ((client_ctx->remote_addr).sa_family == AF_INET) { addr_len = sizeof(struct sockaddr_in); } else if ((client_ctx->remote_addr).sa_family == AF_INET6) { @@ -965,6 +1167,7 @@ int lwm2m_engine_pause(void) } suspend_engine_thread = true; + lwm2m_engine_wake_up(); while (active_engine_thread) { k_msleep(10); @@ -981,6 +1184,7 @@ int lwm2m_engine_resume(void) } k_thread_resume(engine_thread_id); + lwm2m_engine_wake_up(); while (!active_engine_thread) { k_msleep(10); } @@ -990,12 +1194,43 @@ int lwm2m_engine_resume(void) static int lwm2m_engine_init(void) { - int i; - - for (i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { + for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { sys_slist_append(lwm2m_obs_obj_path_list(), &observe_paths[i].node); } + /* Reset all socket handles to -1 so unused ones are ignored by zsock_poll() */ + for (int i = 0; i < MAX_POLL_FD; ++i) { + sock_fds[i].fd = -1; + } + + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* Create socketpair that is used to wake zsock_poll() in the main loop */ + int s[2]; + int ret = zsock_socketpair(AF_UNIX, SOCK_STREAM, 0, s); + + if (ret) { + LOG_ERR("Error; socketpair() returned %d", ret); + return ret; + } + /* Last poll-handle is reserved for control socket */ + sock_fds[MAX_POLL_FD - 1].fd = s[0]; + control_sock = s[1]; + ret = zsock_fcntl(s[0], F_SETFL, O_NONBLOCK); + if (ret) { + LOG_ERR("zsock_fcntl() %d", ret); + zsock_close(s[0]); + zsock_close(s[1]); + return ret; + } + ret = zsock_fcntl(s[1], F_SETFL, O_NONBLOCK); + if (ret) { + LOG_ERR("zsock_fcntl() %d", ret); + zsock_close(s[0]); + zsock_close(s[1]); + return ret; + } + } + lwm2m_clear_block_contexts(); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) (void)memset(output_block_contexts, 0, sizeof(output_block_contexts)); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 2e589ef15a26..2306fced197c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -94,6 +94,36 @@ int bootstrap_delete(struct lwm2m_message *msg); */ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms); +/** + * @brief Update the period of a given service or remove it. + * + * Allow the period modification on an existing service created with + * lwm2m_engine_add_service(). When period is zero, service is removed. + * + * @param[in] service Handler of the periodic_service + * @param[in] period_ms New period for the periodic_service (in milliseconds) or zero. + * + * @return 0 for success, 1 when service was removed or negative in case of error. + */ +int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms); + +/** + * @brief Call specific service handler only once at given timestamp. + * + * @param[in] service service to be called + * @param[in] timestamp Time when to call + * @return 0 for success or negative in case of error + */ +int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp); + +/** + * @brief Call given handler from engine context. + * + * @param[in] service Service callback to be called. + * @return 0 for success or negative in case of error + */ +int lwm2m_engine_call_now(k_work_handler_t service); + /** * @brief Returns the index in the security objects list corresponding to the object instance * id given by @p obj_inst_id @@ -306,4 +336,13 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx); /* Resources */ struct lwm2m_ctx **lwm2m_sock_ctx(void); int lwm2m_sock_nfds(void); + +/** + * @brief Trigger the LwM2M engine to run. + * + * This function wakes up ongoing poll() from the socket-loop. + * It should be called when new transmissions are scheduled or service schedules are modified. + */ +void lwm2m_engine_wake_up(void); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 6186f8d50a04..deaf77b92154 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -676,6 +676,7 @@ int lwm2m_send_message_async(struct lwm2m_message *msg) if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { engine_update_tx_time(); } + lwm2m_engine_wake_up(); return ret; } @@ -692,6 +693,7 @@ int lwm2m_information_interface_send(struct lwm2m_message *msg) if (msg->ctx->buffer_client_messages) { sys_slist_append(&msg->ctx->queued_messages, &msg->node); + lwm2m_engine_wake_up(); return 0; } #endif diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c index c0e14429c857..aabb9fd3fd1d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c @@ -84,7 +84,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); /* resource state variables */ static int8_t net_bearer; -static int8_t rss; +static int16_t rss; static uint8_t link_quality; static uint32_t cellid; static uint16_t mnc; @@ -99,7 +99,7 @@ static struct lwm2m_engine_obj connmon; static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(CONNMON_NETWORK_BEARER_ID, R, U8), OBJ_FIELD_DATA(CONNMON_AVAIL_NETWORK_BEARER_ID, R, U8), - OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S8), + OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S16), OBJ_FIELD_DATA(CONNMON_LINK_QUALITY, R, U8), OBJ_FIELD_DATA(CONNMON_IP_ADDRESSES, R, STRING), OBJ_FIELD_DATA(CONNMON_ROUTER_IP_ADDRESSES, R_OPT, STRING), diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index c590350e61d1..874925c39d89 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -56,7 +56,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SECURITY_INSTANCE_COUNT #define SECURITY_URI_LEN 255 -#define IDENTITY_LEN 128 +#define IDENTITY_LEN CONFIG_LWM2M_SECURITY_KEY_SIZE #define KEY_LEN CONFIG_LWM2M_SECURITY_KEY_SIZE /* @@ -212,6 +212,21 @@ int lwm2m_security_index_to_inst_id(int index) return inst[index].obj_inst_id; } +int lwm2m_security_mode(struct lwm2m_ctx *ctx) +{ + int ret; + uint8_t mode; + struct lwm2m_obj_path path = + LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, ctx->sec_obj_inst, SECURITY_MODE_ID); + + ret = lwm2m_get_u8(&path, &mode); + if (ret) { + return ret; + } + return (int)mode; +} + + static int lwm2m_security_init(void) { struct lwm2m_engine_obj_inst *obj_inst = NULL; diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 559e33212d9f..91ab9c1709ae 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -373,6 +373,7 @@ int lwm2m_notify_observer_path(const struct lwm2m_obj_path *path) LOG_DBG("NOTIFY EVENT %u/%u/%u", path->obj_id, path->obj_inst_id, path->res_id); ret++; + lwm2m_engine_wake_up(); } } } @@ -913,7 +914,7 @@ static int lwm2m_engine_observer_timestamp_update(sys_slist_t *observer, /* update observe_node accordingly */ SYS_SLIST_FOR_EACH_CONTAINER(observer, obs, node) { - if (!obs->resource_update) { + if (obs->resource_update) { /* Resource Update on going skip this*/ continue; } diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index d89ea3c5f79c..0967cbdb346e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -64,18 +64,20 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_util.h" #define LWM2M_RD_CLIENT_URI "rd" - #define SECONDS_TO_UPDATE_EARLY CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY -#define STATE_MACHINE_UPDATE_INTERVAL_MS 500 - #define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH - #define CLIENT_BINDING_LEN sizeof("UQ") #define CLIENT_QUEUE_LEN sizeof("Q") +#define DELAY_BEFORE_CLOSING (1 * MSEC_PER_SEC) +#define DELAY_FOR_ACK 100U static void sm_handle_registration_update_failure(void); static int sm_send_registration_msg(void); static bool sm_is_suspended(void); +static void lwm2m_rd_client_service(struct k_work *work); +static int64_t calc_next_event(void); +static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms); +static void set_sm_state(uint8_t sm_state); /* The states for the RD client state machine */ /* @@ -117,6 +119,7 @@ struct lwm2m_rd_client_info { int64_t last_update; int64_t last_tx; + int64_t next_event; char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; @@ -167,7 +170,12 @@ void engine_update_tx_time(void) client.last_tx = k_uptime_get(); } -static void set_sm_state(uint8_t sm_state) +static void next_event_at(int64_t timestamp) +{ + (void)lwm2m_engine_call_at(lwm2m_rd_client_service, timestamp); +} + +static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms) { k_mutex_lock(&client.mutex, K_FOREVER); enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; @@ -228,9 +236,15 @@ static void set_sm_state(uint8_t sm_state) lwm2m_close_socket(client.ctx); } } + next_event_at(k_uptime_get() + delay_ms); k_mutex_unlock(&client.mutex); } +static void set_sm_state(uint8_t sm_state) +{ + set_sm_state_delayed(sm_state, 0); +} + static bool sm_is_bootstrap(void) { #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) @@ -369,6 +383,8 @@ void engine_trigger_update(bool update_objects) } client.trigger_update = true; + /* short delay for Ack, then trigger an update */ + next_event_at(k_uptime_get() + DELAY_FOR_ACK); if (update_objects) { client.update_objects = true; @@ -452,7 +468,7 @@ int engine_trigger_bootstrap(void) rd_client_message_free(); client.use_bootstrap = true; client.trigger_update = false; - client.engine_state = ENGINE_INIT; + set_sm_state_delayed(ENGINE_INIT, DELAY_BEFORE_CLOSING); k_mutex_unlock(&client.mutex); return 0; #else @@ -832,7 +848,10 @@ static int sm_do_bootstrap_reg(void) void engine_bootstrap_finish(void) { LOG_INF("Bootstrap data transfer done!"); - set_sm_state(ENGINE_BOOTSTRAP_TRANS_DONE); + /* Delay the state transition, so engine have some time to send ACK + * before we close the socket + */ + set_sm_state_delayed(ENGINE_BOOTSTRAP_TRANS_DONE, DELAY_BEFORE_CLOSING); } static int sm_bootstrap_trans_done(void) @@ -997,8 +1016,8 @@ static void sm_handle_registration_update_failure(void) { k_mutex_lock(&client.mutex, K_FOREVER); LOG_WRN("Registration Update fail -> trigger full registration"); - client.engine_state = ENGINE_SEND_REGISTRATION; lwm2m_engine_context_close(client.ctx); + set_sm_state(ENGINE_SEND_REGISTRATION); k_mutex_unlock(&client.mutex); } @@ -1079,28 +1098,49 @@ static int sm_do_registration(void) return ret; } -static int sm_registration_done(void) +static int64_t next_update(void) { - k_mutex_lock(&client.mutex, K_FOREVER); - int ret = 0; - /* * check for lifetime seconds - SECONDS_TO_UPDATE_EARLY * so that we can update early and avoid lifetime timeout */ + return client.last_update + (client.lifetime - SECONDS_TO_UPDATE_EARLY) * MSEC_PER_SEC; +} + +static int64_t next_rx_off(void) +{ + if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { + return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC; + } else { + return next_update(); + } +} + +/** Return timestamp to next even whether it is RX_OFF or update event */ +static int64_t calc_next_event(void) +{ + return Z_MIN(next_update(), next_rx_off()); +} + +static void sm_registration_done(void) +{ + k_mutex_lock(&client.mutex, K_FOREVER); + + int64_t now = k_uptime_get(); + if (sm_is_registered() && (client.trigger_update || - ((client.lifetime - SECONDS_TO_UPDATE_EARLY) <= - (k_uptime_get() - client.last_update) / 1000))) { + now >= next_update())) { set_sm_state(ENGINE_UPDATE_REGISTRATION); } else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) && - (((k_uptime_get() - client.last_tx) / 1000) >= - CONFIG_LWM2M_QUEUE_MODE_UPTIME)) { + (now >= next_rx_off())) { set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF); + next_event_at(next_update()); + } else { + next_event_at(calc_next_event()); } k_mutex_unlock(&client.mutex); - return ret; } static int update_registration(void) @@ -1214,7 +1254,9 @@ static void sm_do_network_error(void) { int err; - if (--client.retry_delay > 0) { + if (client.retry_delay) { + client.retry_delay = 0; + next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC); return; } @@ -1226,7 +1268,8 @@ static void sm_do_network_error(void) } #endif - if (!client.last_update || (k_uptime_get() - client.last_update) / 1000 > client.lifetime) { + if (!client.last_update || + (k_uptime_get() - client.last_update) / MSEC_PER_SEC > client.lifetime) { /* do full registration as there is no active registration or lifetime exceeded */ lwm2m_engine_context_close(client.ctx); set_sm_state(ENGINE_DO_REGISTRATION); @@ -1252,6 +1295,7 @@ static void lwm2m_rd_client_service(struct k_work *work) k_mutex_lock(&client.mutex, K_FOREVER); if (client.ctx) { + LOG_DBG("State: %d", get_sm_state()); switch (get_sm_state()) { case ENGINE_IDLE: if (client.ctx->sock_fd > -1) { @@ -1374,7 +1418,10 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, client.ep_name[CLIENT_EP_LEN - 1] = '\0'; LOG_INF("Start LWM2M Client: %s", client.ep_name); + next_event_at(0); + k_mutex_unlock(&client.mutex); + return 0; } @@ -1402,12 +1449,14 @@ int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx, k_mutex_unlock(&client.mutex); + return 0; } int lwm2m_rd_client_pause(void) { enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED; + LOG_DBG("lwm2m_rd_client_pause()"); k_mutex_lock(&client.mutex, K_FOREVER); @@ -1415,19 +1464,26 @@ int lwm2m_rd_client_pause(void) k_mutex_unlock(&client.mutex); LOG_ERR("Cannot pause. No context"); return -EPERM; - } else if (client.engine_state == ENGINE_SUSPENDED) { + } else if (sm_is_suspended()) { k_mutex_unlock(&client.mutex); LOG_ERR("LwM2M client already suspended"); return 0; } LOG_INF("Suspend client"); - if (!client.ctx->connection_suspended && client.ctx->event_cb) { + if (client.ctx->event_cb) { client.ctx->event_cb(client.ctx, event); } + /* Suspend or close the socket */ + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) { + lwm2m_close_socket(client.ctx); + } else { + lwm2m_socket_suspend(client.ctx); + } + suspended_client_state = get_sm_state(); - client.engine_state = ENGINE_SUSPENDED; + set_sm_state(ENGINE_SUSPENDED); k_mutex_unlock(&client.mutex); @@ -1436,26 +1492,18 @@ int lwm2m_rd_client_pause(void) int lwm2m_rd_client_resume(void) { - int ret; - k_mutex_lock(&client.mutex, K_FOREVER); - if (!client.ctx) { + if (!lwm2m_rd_client_is_suspended(client.ctx)) { k_mutex_unlock(&client.mutex); - LOG_WRN("Cannot resume. No context"); - return -EPERM; - } - - if (client.engine_state != ENGINE_SUSPENDED) { - k_mutex_unlock(&client.mutex); - LOG_WRN("Cannot resume state is not Suspended"); + LOG_WRN("Cannot resume, state is not suspended"); return -EPERM; } LOG_INF("Resume Client state"); - lwm2m_close_socket(client.ctx); + if (suspended_client_state == ENGINE_UPDATE_SENT) { - /* Set back to Registration done for enable trigger Update */ + /* Set back to Registration done and trigger an update */ suspended_client_state = ENGINE_REGISTRATION_DONE; } /* Clear Possible pending RD Client message */ @@ -1463,20 +1511,27 @@ int lwm2m_rd_client_resume(void) client.engine_state = suspended_client_state; - if (!client.last_update || - (client.lifetime <= (k_uptime_get() - client.last_update) / 1000)) { - client.engine_state = ENGINE_DO_REGISTRATION; - } else { - lwm2m_rd_client_connection_resume(client.ctx); - client.trigger_update = true; + /* Do we need to resume the bootstrap? */ +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (sm_is_bootstrap()) { + client.engine_state = ENGINE_DO_BOOTSTRAP_REG; } - - ret = lwm2m_open_socket(client.ctx); - if (ret) { - LOG_ERR("Socket Open Fail"); - client.engine_state = ENGINE_INIT; +#endif + /* Or do we resume into registration state */ + if (client.engine_state >= ENGINE_DO_REGISTRATION && + client.engine_state <= ENGINE_SUSPENDED) { + if (!client.last_update || + (client.lifetime <= (k_uptime_get() - client.last_update) / MSEC_PER_SEC)) { + /* No lifetime left, register again */ + client.engine_state = ENGINE_DO_REGISTRATION; + } else { + /* Resume similarly like from QUEUE mode */ + client.engine_state = ENGINE_REGISTRATION_DONE_RX_OFF; + lwm2m_rd_client_connection_resume(client.ctx); + } } + next_event_at(0); k_mutex_unlock(&client.mutex); return 0; @@ -1499,22 +1554,22 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx) } if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) { -#ifdef CONFIG_LWM2M_DTLS_SUPPORT /* - * Switch state for triggering a proper registration message - * if CONFIG_LWM2M_TLS_SESSION_CACHING is false we force full - * registration after Fully DTLS handshake + * Switch state to triggering a proper registration message + * If the socket stays open (Connection ID or no-sec), or we have TLS session cache, + * we can trigger the update, otherwise fall back to full registration. */ - if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) { + if ((IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) && + IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) || + (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) || + IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) || + !IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT)) { client.engine_state = ENGINE_REGISTRATION_DONE; client.trigger_update = true; } else { client.engine_state = ENGINE_DO_REGISTRATION; } -#else - client.engine_state = ENGINE_REGISTRATION_DONE; - client.trigger_update = true; -#endif + next_event_at(0); } return 0; @@ -1531,7 +1586,8 @@ int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx) } k_mutex_lock(&client.mutex, K_FOREVER); LOG_WRN("Confirmable Timeout -> Re-connect and register"); - client.engine_state = ENGINE_DO_REGISTRATION; + set_sm_state(ENGINE_DO_REGISTRATION); + next_event_at(0); k_mutex_unlock(&client.mutex); return 0; } @@ -1561,9 +1617,7 @@ int lwm2m_rd_client_init(void) client.engine_state = ENGINE_IDLE; k_mutex_init(&client.mutex); - return lwm2m_engine_add_service(lwm2m_rd_client_service, - STATE_MACHINE_UPDATE_INTERVAL_MS); - + return 0; } static int sys_lwm2m_rd_client_init(void) diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index cd5191c4c464..f34a01fe5ead 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -436,6 +436,22 @@ int path_to_objs(const struct lwm2m_obj_path *path, struct lwm2m_engine_obj_inst return 0; } + +static bool is_string(const struct lwm2m_obj_path *path) +{ + struct lwm2m_engine_obj_field *obj_field; + int ret; + + ret = path_to_objs(path, NULL, &obj_field, NULL, NULL); + if (ret < 0 || !obj_field) { + return false; + } + if (obj_field->data_type == LWM2M_RES_TYPE_STRING) { + return true; + } + return false; +} + /* User data setter functions */ int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len, @@ -610,7 +626,7 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value return ret; } - if (memcmp(data_ptr, value, len) != 0) { + if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) { changed = true; } @@ -628,19 +644,18 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value switch (obj_field->data_type) { case LWM2M_RES_TYPE_OPAQUE: - memcpy((uint8_t *)data_ptr, value, len); + if (len) { + memcpy((uint8_t *)data_ptr, value, len); + } break; case LWM2M_RES_TYPE_STRING: - /* check length (note: we add 1 to string length for NULL pad) */ - if (len > max_data_len - 1) { - LOG_ERR("String length %u is too long for res instance %d data", len, - path->res_id); - k_mutex_unlock(®istry_lock); - return -ENOMEM; + if (len) { + strncpy(data_ptr, value, len - 1); + ((char *)data_ptr)[len - 1] = '\0'; + } else { + ((char *)data_ptr)[0] = '\0'; } - memcpy((uint8_t *)data_ptr, value, len); - ((uint8_t *)data_ptr)[len] = '\0'; break; case LWM2M_RES_TYPE_U32: @@ -753,7 +768,14 @@ int lwm2m_engine_set_opaque(const char *pathstr, const char *data_ptr, uint16_t int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr) { - return lwm2m_engine_set(path, data_ptr, strlen(data_ptr)); + uint16_t len = strlen(data_ptr); + + /* String resources contain terminator as well, opaque resources don't */ + if (is_string(path)) { + len += 1; + } + + return lwm2m_engine_set(path, data_ptr, len); } int lwm2m_engine_set_string(const char *pathstr, const char *data_ptr) @@ -1134,7 +1156,8 @@ static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16 break; case LWM2M_RES_TYPE_STRING: - strncpy((uint8_t *)buf, (uint8_t *)data_ptr, buflen); + strncpy(buf, data_ptr, buflen - 1); + ((char *)buf)[buflen - 1] = '\0'; break; case LWM2M_RES_TYPE_U32: @@ -1229,12 +1252,18 @@ int lwm2m_engine_get_opaque(const char *pathstr, void *buf, uint16_t buflen) return lwm2m_get_opaque(&path, buf, buflen); } -int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t strlen) +int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen) { - return lwm2m_engine_get(path, str, strlen); + /* Ensure termination, in case resource is not a string type */ + if (!is_string(path)) { + memset(str, 0, buflen); + buflen -= 1; /* Last terminator cannot be overwritten */ + } + + return lwm2m_engine_get(path, str, buflen); } -int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen) +int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen) { struct lwm2m_obj_path path; int ret = 0; @@ -1243,7 +1272,7 @@ int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen) if (ret < 0) { return ret; } - return lwm2m_get_opaque(&path, str, strlen); + return lwm2m_get_string(&path, str, buflen); } int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value) diff --git a/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c b/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c index c835656b6cf8..8e9cc87239af 100644 --- a/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c +++ b/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c @@ -22,10 +22,15 @@ int mqtt_client_tls_connect(struct mqtt_client *client) { const struct sockaddr *broker = client->broker; struct mqtt_sec_config *tls_config = &client->transport.tls.config; + int type = SOCK_STREAM; int ret; + if (tls_config->set_native_tls) { + type |= SOCK_NATIVE_TLS; + } + client->transport.tls.sock = zsock_socket(broker->sa_family, - SOCK_STREAM, IPPROTO_TLS_1_2); + type, IPPROTO_TLS_1_2); if (client->transport.tls.sock < 0) { return -errno; } @@ -78,6 +83,16 @@ int mqtt_client_tls_connect(struct mqtt_client *client) } } + if (tls_config->session_cache == TLS_SESSION_CACHE_ENABLED) { + ret = zsock_setsockopt(client->transport.tls.sock, SOL_TLS, + TLS_SESSION_CACHE, + &tls_config->session_cache, + sizeof(tls_config->session_cache)); + if (ret < 0) { + goto error; + } + } + if (tls_config->cert_nocopy != TLS_CERT_NOCOPY_NONE) { ret = zsock_setsockopt(client->transport.tls.sock, SOL_TLS, TLS_CERT_NOCOPY, &tls_config->cert_nocopy, diff --git a/subsys/net/pkt_filter/Kconfig b/subsys/net/pkt_filter/Kconfig index ef3a02ad45e7..8b95a67caa63 100644 --- a/subsys/net/pkt_filter/Kconfig +++ b/subsys/net/pkt_filter/Kconfig @@ -12,6 +12,28 @@ config NET_PKT_FILTER transmission and reception. if NET_PKT_FILTER + +config NET_PKT_FILTER_IPV4_HOOK + bool "Additional network packet filtering hook inside IPv4 stack" + depends on NET_IPV4 + help + This additional hook provides infrastructure to construct custom + rules on the IP packet. + +config NET_PKT_FILTER_IPV6_HOOK + bool "Additional network packet filtering hook inside IPv6 stack" + depends on NET_IPV6 + help + This additional hook provides infrastructure to construct custom + rules on the IP packet. + +config NET_PKT_FILTER_LOCAL_IN_HOOK + bool "Additional network packet filtering hook for connection input" + depends on NET_IP + help + This additional hook provides infrastructure to construct custom + rules for e.g. TCP/UDP packets. + module = NET_PKT_FILTER module-dep = NET_LOG module-str = Log level for packet filtering diff --git a/subsys/net/pkt_filter/base.c b/subsys/net/pkt_filter/base.c index e33091e7af74..bb2eb9f085ba 100644 --- a/subsys/net/pkt_filter/base.c +++ b/subsys/net/pkt_filter/base.c @@ -25,6 +25,50 @@ struct npf_rule_list npf_recv_rules = { .lock = { }, }; +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +struct npf_rule_list npf_local_in_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&local_in_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK +struct npf_rule_list npf_ipv4_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&ipv4_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK +struct npf_rule_list npf_ipv6_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&ipv6_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + +/* + * Helper function + */ +static struct npf_rule_list *get_ip_rules(uint8_t pf) +{ + switch (pf) { + case PF_INET: +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK + return &npf_ipv4_recv_rules; +#endif + break; + case PF_INET6: +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK + return &npf_ipv6_recv_rules; +#endif + break; + default: + return NULL; + } + + return NULL; +} + /* * Rule application */ @@ -98,6 +142,31 @@ bool net_pkt_filter_recv_ok(struct net_pkt *pkt) return result == NET_OK; } +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt) +{ + enum net_verdict result = lock_evaluate(&npf_local_in_recv_rules, pkt); + + return result == NET_OK; +} +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK) +bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt) +{ + struct npf_rule_list *rules = get_ip_rules(net_pkt_family(pkt)); + + if (!rules) { + NET_DBG("no rules"); + return true; + } + + enum net_verdict result = lock_evaluate(rules, pkt); + + return result == NET_OK; +} +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + /* * Rule management */ @@ -199,3 +268,32 @@ bool npf_size_inbounds(struct npf_test *test, struct net_pkt *pkt) return pkt_size >= bounds->min && pkt_size <= bounds->max; } + +bool npf_ip_src_addr_match(struct npf_test *test, struct net_pkt *pkt) +{ + struct npf_test_ip *test_ip = + CONTAINER_OF(test, struct npf_test_ip, test); + uint8_t pkt_family = net_pkt_family(pkt); + + for (uint32_t ip_it = 0; ip_it < test_ip->ipaddr_num; ip_it++) { + if (IS_ENABLED(CONFIG_NET_IPV4) && pkt_family == AF_INET) { + struct in_addr *addr = (struct in_addr *)NET_IPV4_HDR(pkt)->src; + + if (net_ipv4_addr_cmp(addr, &((struct in_addr *)test_ip->ipaddr)[ip_it])) { + return true; + } + } else if (IS_ENABLED(CONFIG_NET_IPV6) && pkt_family == AF_INET6) { + struct in6_addr *addr = (struct in6_addr *)NET_IPV6_HDR(pkt)->src; + + if (net_ipv6_addr_cmp(addr, &((struct in6_addr *)test_ip->ipaddr)[ip_it])) { + return true; + } + } + } + return false; +} + +bool npf_ip_src_addr_unmatch(struct npf_test *test, struct net_pkt *pkt) +{ + return !npf_ip_src_addr_match(test, pkt); +} diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 4395e7718598..3240f936a7d5 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -4,9 +4,15 @@ menu "Power Management" -menuconfig PM +config HAS_PM + bool + help + This option must be selected by SoCs that provide PM hooks, that is, + calls to configure low-power states. + +config PM bool "System Power Management" - depends on SYS_CLOCK_EXISTS && !HAS_NO_PM + depends on SYS_CLOCK_EXISTS && HAS_PM help This option enables the board to implement extra power management policies whenever the kernel becomes idle. The kernel informs the @@ -54,14 +60,6 @@ endchoice endif # PM -config HAS_NO_PM - bool - help - This option blocks selection of PM. It can be selected in SOC - targets where system power management is not supported, for example - on support core of a multi-core device where SoC power management is - the responsibility of a different core. - config PM_DEVICE bool "Device Power Management" help diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index c9eb15e0d351..ae6e8505d891 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -107,35 +107,6 @@ static void pm_resume_devices(void) #endif /* !CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE */ #endif /* CONFIG_PM_DEVICE */ -static inline void pm_exit_pos_ops(struct pm_state_info *info) -{ - extern __weak void - pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id); - - if (pm_state_exit_post_ops != NULL) { - pm_state_exit_post_ops(info->state, info->substate_id); - } else { - /* - * This function is supposed to be overridden to do SoC or - * architecture specific post ops after sleep state exits. - * - * The kernel expects that irqs are unlocked after this. - */ - - irq_unlock(0); - } -} - -static inline void state_set(struct pm_state_info *info) -{ - extern __weak void - pm_state_set(enum pm_state state, uint8_t substate_id); - - if (pm_state_set != NULL) { - pm_state_set(info->state, info->substate_id); - } -} - /* * Function called to notify when the system is entering / exiting a * power state @@ -178,7 +149,7 @@ void pm_system_resume(void) * and it may schedule another thread. */ if (atomic_test_and_clear_bit(z_post_ops_required, id)) { - pm_exit_pos_ops(&z_cpus_pm_state[id]); + pm_state_exit_post_ops(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); pm_state_notify(false); z_cpus_pm_state[id] = (struct pm_state_info){PM_STATE_ACTIVE, 0, 0}; @@ -266,7 +237,7 @@ bool pm_system_suspend(int32_t ticks) /* Enter power state */ pm_state_notify(true); atomic_set_bit(z_post_ops_required, id); - state_set(&z_cpus_pm_state[id]); + pm_state_set(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); pm_stats_stop(); /* Wake up sequence starts here */ diff --git a/subsys/shell/modules/CMakeLists.txt b/subsys/shell/modules/CMakeLists.txt index d002604c6ae0..e5d025956d53 100644 --- a/subsys/shell/modules/CMakeLists.txt +++ b/subsys/shell/modules/CMakeLists.txt @@ -16,3 +16,7 @@ zephyr_sources_ifdef( CONFIG_DEVMEM_SHELL devmem_service.c ) +zephyr_sources_ifdef( + CONFIG_APP_SHELL + app_service.c + ) diff --git a/subsys/shell/modules/Kconfig b/subsys/shell/modules/Kconfig index cb7aedaa79e5..7bb28d80f141 100644 --- a/subsys/shell/modules/Kconfig +++ b/subsys/shell/modules/Kconfig @@ -45,3 +45,9 @@ config DEVMEM_SHELL select GETOPT help This shell command provides read/write access to physical memory. + +config APP_SHELL + bool "application shell (common to all applications)" + default y if !SHELL_MINIMAL + help + This shell module provides access to common helpers. diff --git a/subsys/shell/modules/app_service.c b/subsys/shell/modules/app_service.c new file mode 100644 index 000000000000..8938ff5a944e --- /dev/null +++ b/subsys/shell/modules/app_service.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#if defined(CONFIG_LOG_RUNTIME_FILTERING) +#include +#endif + +#include + +static int cmd_app_heap(const struct shell *sh, size_t argc, char **argv) +{ +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) + /* mallinfo() was deprecated in glibc 2.33 and removed in 2.34. */ + struct mallinfo mi = mallinfo(); +#else + struct mallinfo2 mi = mallinfo2(); +#endif /* __GLIBC__ < 2 && (__GLIBC__ == 2 && __GLIBC_MINOR__ < 33) */ + + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + shell_print(sh, "Heap size: %d bytes", mi.arena); + shell_print(sh, " used: %d bytes", mi.uordblks); + shell_print(sh, " free: %d bytes", mi.fordblks); + shell_print(sh, " max used: %d bytes", mi.usmblks); + shell_print(sh, " free fastbin: %d bytes", mi.fsmblks); + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_app, + SHELL_CMD(heap, NULL, "app heap", cmd_app_heap), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +SHELL_CMD_REGISTER(app, &sub_app, "application commands", NULL); diff --git a/tests/bluetooth/mesh_shell/prj.conf b/tests/bluetooth/mesh_shell/prj.conf index 0672ec6cbb31..6535b77c3ab3 100644 --- a/tests/bluetooth/mesh_shell/prj.conf +++ b/tests/bluetooth/mesh_shell/prj.conf @@ -78,3 +78,4 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_PROVISIONER=y +CONFIG_BT_MESH_STATISTIC=y diff --git a/tests/bluetooth/tester/overlay-mesh.conf b/tests/bluetooth/tester/overlay-mesh.conf index 963b864ba2b9..840af06c1c08 100644 --- a/tests/bluetooth/tester/overlay-mesh.conf +++ b/tests/bluetooth/tester/overlay-mesh.conf @@ -22,3 +22,4 @@ CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_CDB_NODE_COUNT=3 CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY=y CONFIG_BT_MESH_MSG_CACHE_SIZE=10 +CONFIG_BT_MESH_PROXY_CLIENT=y diff --git a/tests/bluetooth/tester/src/btp/btp_mesh.h b/tests/bluetooth/tester/src/btp/btp_mesh.h index 5aa191d7d7b8..d7d2b2cdc7b8 100644 --- a/tests/bluetooth/tester/src/btp/btp_mesh.h +++ b/tests/bluetooth/tester/src/btp/btp_mesh.h @@ -747,6 +747,25 @@ struct btp_mesh_cfg_krp_set_rp { uint8_t phase; } __packed; +#define BTP_MESH_VA_ADD 0x4D +struct btp_mesh_va_add_cmd { + uint8_t label_uuid[16]; +} __packed; +struct btp_mesh_va_add_rp { + uint16_t addr; +} __packed; + +#define BTP_MESH_VA_DEL 0x4E +struct btp_mesh_va_del_cmd { + uint8_t label_uuid[16]; +} __packed; + +#define BTP_MESH_PROXY_CONNECT 0x77 + +struct btp_proxy_connect_cmd { + uint16_t net_idx; +} __packed; + /* events */ #define BTP_MESH_EV_OUT_NUMBER_ACTION 0x80 struct btp_mesh_out_number_action_ev { diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 9af4867a84a3..c922c812631d 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #define LOG_MODULE_NAME bttester_mesh @@ -172,6 +173,8 @@ static uint8_t supported_commands(const void *cmd, uint16_t cmd_len, tester_set_bit(rp->data, BTP_MESH_PROVISION_ADV); tester_set_bit(rp->data, BTP_MESH_CFG_KRP_GET); tester_set_bit(rp->data, BTP_MESH_CFG_KRP_SET); + tester_set_bit(rp->data, BTP_MESH_VA_ADD); + tester_set_bit(rp->data, BTP_MESH_VA_DEL); *rsp_len = sizeof(*rp) + 10; @@ -736,6 +739,10 @@ static uint8_t net_send(const void *cmd, uint16_t cmd_len, .send_ttl = cp->ttl, }; + if (BT_MESH_ADDR_IS_VIRTUAL(ctx.addr)) { + ctx.uuid = bt_mesh_va_uuid_get(ctx.addr, NULL, NULL); + } + LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, ctx.addr, cp->payload_len); @@ -756,6 +763,48 @@ static uint8_t net_send(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +static uint8_t va_add(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_va_add_cmd *cp = cmd; + struct btp_mesh_va_add_rp *rp = rsp; + const struct bt_mesh_va *va; + int err; + + err = bt_mesh_va_add(cp->label_uuid, &va); + if (err) { + LOG_ERR("Failed to add Label UUID (err %d)", err); + return BTP_STATUS_FAILED; + } + + rp->addr = sys_cpu_to_le16(va->addr); + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t va_del(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_va_del_cmd *cp = cmd; + const struct bt_mesh_va *va; + int err; + + va = bt_mesh_va_find(cp->label_uuid); + if (!va) { + LOG_ERR("Failed to find Label UUID"); + return BTP_STATUS_FAILED; + } + + err = bt_mesh_va_del(va->uuid); + if (err) { + LOG_ERR("Failed to delete Label UUID (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + static uint8_t health_generate_faults(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -815,6 +864,10 @@ static uint8_t model_send(const void *cmd, uint16_t cmd_len, .send_ttl = BT_MESH_TTL_DEFAULT, }; + if (BT_MESH_ADDR_IS_VIRTUAL(ctx.addr)) { + ctx.uuid = bt_mesh_va_uuid_get(ctx.addr, NULL, NULL); + } + src = sys_le16_to_cpu(cp->src); /* Lookup source address */ @@ -916,6 +969,23 @@ static uint8_t proxy_identity_enable(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +#if defined(CONFIG_BT_MESH_PROXY_CLIENT) +static uint8_t proxy_connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_proxy_connect_cmd *cp = cmd; + int err; + + err = bt_mesh_proxy_connect(cp->net_idx); + if (err) { + LOG_ERR("Failed to connect to GATT Proxy (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} +#endif + static uint8_t composition_data_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -2827,6 +2897,16 @@ static const struct btp_handler handlers[] = { .expect_len = sizeof(struct btp_mesh_cfg_krp_set_cmd), .func = config_krp_set, }, + { + .opcode = BTP_MESH_VA_ADD, + .expect_len = sizeof(struct btp_mesh_va_add_cmd), + .func = va_add, + }, + { + .opcode = BTP_MESH_VA_DEL, + .expect_len = sizeof(struct btp_mesh_va_del_cmd), + .func = va_del, + }, #if defined(CONFIG_BT_TESTING) { .opcode = BTP_MESH_LPN_SUBSCRIBE, @@ -2849,6 +2929,13 @@ static const struct btp_handler handlers[] = { .expect_len = 0, .func = proxy_identity_enable, }, +#if defined(CONFIG_BT_MESH_PROXY_CLIENT) + { + .opcode = BTP_MESH_PROXY_CONNECT, + .expect_len = sizeof(struct btp_proxy_connect_cmd), + .func = proxy_connect + }, +#endif }; void net_recv_ev(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, const void *payload, diff --git a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c index 7dab3cbc3b0f..f762ee824737 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c @@ -41,6 +41,7 @@ static K_SEM_DEFINE(cmd_sem, 1, 1); static struct k_sem acl_pkts; static struct k_sem tx_credits; static uint16_t peer_mps; +static uint16_t conn_handle; static uint16_t active_opcode = 0xFFFF; static struct net_buf *cmd_rsp; @@ -123,6 +124,9 @@ static void handle_meta_event(struct net_buf *buf) switch (code) { case BT_HCI_EVT_LE_ENH_CONN_COMPLETE: + case BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2: + conn_handle = sys_get_le16(&buf->data[4]); + LOG_DBG("connected: handle: %d", conn_handle); SET_FLAG(is_connected); break; case BT_HCI_EVT_LE_DATA_LEN_CHANGE: @@ -488,7 +492,7 @@ static int send_acl(struct net_buf *buf) uint8_t flags = BT_ACL_START_NO_FLUSH; hdr = net_buf_push(buf, sizeof(*hdr)); - hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(0, flags)); + hdr->handle = sys_cpu_to_le16(bt_acl_handle_pack(conn_handle, flags)); hdr->len = sys_cpu_to_le16(buf->len - sizeof(*hdr)); bt_buf_set_type(buf, BT_BUF_ACL_OUT); diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index d83ca64eeb79..3c314e24a586 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -77,7 +77,7 @@ bst_test_install_t test_installers[] = { static struct k_thread bsim_mesh_thread; static K_KERNEL_STACK_DEFINE(bsim_mesh_thread_stack, 4096); -static void bsim_mesh_entry_point(void *, void *, void *) +static void bsim_mesh_entry_point(void *unused1, void *unused2, void *unused3) { bst_main(); } diff --git a/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh b/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh index 653f96802403..56a364528a50 100755 --- a/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh +++ b/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh @@ -18,13 +18,13 @@ EXECUTE_TIMEOUT=100 cd ${BSIM_OUT_PATH}/bin Execute ./bs_${BOARD}_tests_bsim_net_sockets_echo_test_prj_conf_overlay-ot_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 \ + -v=${verbosity_level} -s=${simulation_id} -start_offset=2e6 -d=0 -RealEncryption=1 \ -testid=echo_client Execute ./bs_${BOARD}_samples_net_sockets_echo_server_prj_conf_overlay-ot_conf\ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=1 \ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ - -D=2 -sim_length=26e6 -argschannel -at=40 -argsmain $@ + -D=2 -sim_length=40e6 -argschannel -at=40 -argsmain $@ wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails diff --git a/tests/drivers/build_all/regulator/testcase.yaml b/tests/drivers/build_all/regulator/testcase.yaml index 9b9c25511c4e..c5dbda1913f3 100644 --- a/tests/drivers/build_all/regulator/testcase.yaml +++ b/tests/drivers/build_all/regulator/testcase.yaml @@ -3,8 +3,6 @@ tests: drivers.regulator.build: - tags: - - drivers - - regulator + tags: drivers regulator build_only: true platform_allow: native_posix diff --git a/tests/lib/c_lib/src/main.c b/tests/lib/c_lib/src/main.c index f5365d493ea8..d824ed657875 100644 --- a/tests/lib/c_lib/src/main.c +++ b/tests/lib/c_lib/src/main.c @@ -1194,6 +1194,61 @@ ZTEST(test_c_lib, test_rand_reproducibility) #endif } +/** + * @brief Test mallinfo2 function + * +*/ +ZTEST(test_c_lib, test_mallinfo2) +{ +#ifdef CONFIG_MINIMAL_LIBC + struct mallinfo2 info; + + info = mallinfo2(); + zassert_equal(info.arena, 0, "mallinfo2 failed"); + zassert_equal(info.ordblks, 0, "mallinfo2 failed"); + zassert_equal(info.smblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblkhd, 0, "mallinfo2 failed"); + zassert_equal(info.usmblks, 0, "mallinfo2 failed"); + zassert_equal(info.fsmblks, 0, "mallinfo2 failed"); + zassert_equal(info.uordblks, 0, "mallinfo2 failed"); + zassert_equal(info.fordblks, 0, "mallinfo2 failed"); + zassert_equal(info.keepcost, 0, "mallinfo2 failed"); + + /* Allocate and verify */ + char *ptr = malloc(10); + zassert_not_null(ptr, "malloc failed"); + info = mallinfo2(); + zassert_equal(info.arena, 4096, "mallinfo2 failed"); + zassert_equal(info.ordblks, 1, "mallinfo2 failed"); + zassert_equal(info.smblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblkhd, 4096, "mallinfo2 failed"); + zassert_equal(info.usmblks, 0, "mallinfo2 failed"); + zassert_equal(info.fsmblks, 0, "mallinfo2 failed"); + zassert_equal(info.uordblks, 0, "mallinfo2 failed"); + zassert_equal(info.fordblks, 4086, "mallinfo2 failed"); + zassert_equal(info.keepcost, 10, "mallinfo2 failed"); + + /* Free and verify */ + free(ptr); + info = mallinfo2(); + zassert_equal(info.arena, 4096, "mallinfo2 failed"); + zassert_equal(info.ordblks, 0, "mallinfo2 failed"); + zassert_equal(info.smblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblks, 0, "mallinfo2 failed"); + zassert_equal(info.hblkhd, 4096, "mallinfo2 failed"); + zassert_equal(info.usmblks, 0, "mallinfo2 failed"); + zassert_equal(info.fsmblks, 0, "mallinfo2 failed"); + zassert_equal(info.uordblks, 0, "mallinfo2 failed"); + zassert_equal(info.fordblks, 4096, "mallinfo2 failed"); + zassert_equal(info.keepcost, 0, "mallinfo2 failed"); +#else + ztest_test_skip(); +#endif /* CONFIG_MINIMAL_LIBC */ +} + + /** * * @brief test abort functions diff --git a/tests/lib/newlib/heap_listener/prj.conf b/tests/lib/newlib/heap_listener/prj.conf index 31bc1ca7e765..8d8ebf99baf2 100644 --- a/tests/lib/newlib/heap_listener/prj.conf +++ b/tests/lib/newlib/heap_listener/prj.conf @@ -1,4 +1,5 @@ CONFIG_ZTEST=y CONFIG_NEWLIB_LIBC=y +CONFIG_NEWLIB_LIBC_NANO=n CONFIG_NEWLIB_LIBC_HEAP_LISTENER=y CONFIG_ZTEST_NEW_API=y diff --git a/tests/net/conn_mgr/src/main.c b/tests/net/conn_mgr/src/main.c index ee7c0c9cbd90..9a225c3fb113 100644 --- a/tests/net/conn_mgr/src/main.c +++ b/tests/net/conn_mgr/src/main.c @@ -44,9 +44,6 @@ static void reset_test_iface(struct net_if *iface) struct in6_addr *ll_ipv6; if (net_if_is_admin_up(iface)) { - if (conn_mgr_if_is_bound(iface)) { - (void)conn_mgr_if_disconnect(iface); - } (void)net_if_down(iface); } @@ -186,10 +183,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -202,10 +195,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -214,10 +203,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect no events */ @@ -227,10 +212,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect connectivity loss */ @@ -266,10 +247,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -278,10 +255,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -292,10 +265,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -308,10 +277,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -320,10 +285,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifba."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -333,10 +294,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect connectivity lost */ @@ -353,10 +310,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -366,10 +319,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -381,10 +330,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) zassert_equal(stats.conn_iface, ifa, "ifa should be blamed."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -396,10 +341,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -408,10 +349,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect connectivity lost */ @@ -424,10 +361,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) zassert_equal(stats.dconn_iface, ifa, "ifa should be blamed."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -481,11 +414,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* Take iface up */ zassert_equal(net_if_up(iface), 0, "net_if_up should succeed."); - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_connect(iface), 0, - "conn_mgr_if_connect should succeed."); - } - /* Verify that no events have been fired yet */ k_sleep(EVENT_WAIT_TIME); stats = get_reset_stats(); @@ -603,10 +531,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* (10 -> 00): Lose oper-up from semi-ready state */ /* Take iface down */ - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_disconnect(iface), 0, - "conn_mgr_if_disconnect should succeed."); - } zassert_equal(net_if_down(iface), 0, "net_if_down should succeed."); /* Verify there are no events fired */ @@ -643,10 +567,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* Take iface up */ zassert_equal(net_if_up(iface), 0, "net_if_up should succeed."); - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_connect(iface), 0, - "conn_mgr_if_connect should succeed."); - } /* Verify events are fired */ k_sleep(EVENT_WAIT_TIME); @@ -660,10 +580,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* (11 -> 01): Lose oper-up from ready state */ /* Take iface down */ - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_disconnect(iface), 0, - "conn_mgr_if_disconnect should succeed."); - } zassert_equal(net_if_down(iface), 0, "net_if_down should succeed."); /* Verify events are fired */ diff --git a/tests/net/conn_mgr_conn/prj.conf b/tests/net/conn_mgr_conn/prj.conf index 5ffa0ba9d9fc..ec6b62f6be3f 100644 --- a/tests/net/conn_mgr_conn/prj.conf +++ b/tests/net/conn_mgr_conn/prj.conf @@ -24,3 +24,7 @@ CONFIG_ZTEST_NEW_API=y CONFIG_NET_IF_MAX_IPV4_COUNT=6 CONFIG_NET_IF_MAX_IPV6_COUNT=6 CONFIG_TEST_USERSPACE=y + +# Increased net event queue size needed since this test performs simultaneous events on a +# large number of ifaces. +CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=16 diff --git a/tests/net/conn_mgr_conn/src/main.c b/tests/net/conn_mgr_conn/src/main.c index dbe1d4cb3374..9d36688ae879 100644 --- a/tests/net/conn_mgr_conn/src/main.c +++ b/tests/net/conn_mgr_conn/src/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "conn_mgr_private.h" #include "test_conn_impl.h" #include "test_ifaces.h" @@ -29,7 +30,12 @@ static inline struct test_conn_data *conn_mgr_if_get_data(struct net_if *iface) return binding->ctx; } -static void reset_test_iface(struct net_if *iface) +/** + * @brief Reset the network state of the provided iface. + * + * @param iface - iface to reset. + */ +static void reset_test_iface_networking(struct net_if *iface) { if (net_if_is_admin_up(iface)) { (void)net_if_down(iface); @@ -37,13 +43,29 @@ static void reset_test_iface(struct net_if *iface) /* Some tests can leave the iface in a bad state where it is admin-down but not dormant */ net_if_dormant_on(iface); +} +/** + * @brief Reset testing state for the provided iface. + * + * @param iface - iface to reset. + */ +static void reset_test_iface_state(struct net_if *iface) +{ struct conn_mgr_conn_binding *iface_binding = conn_mgr_if_get_binding(iface); struct test_conn_data *iface_data = conn_mgr_if_get_data(iface); + /* Some tests mark ifaces as ignored, this must be reset between each test. */ + conn_mgr_watch_iface(iface); + if (iface_binding) { + /* Reset all flags and settings for the binding */ iface_binding->flags = 0; iface_binding->timeout = CONN_MGR_IF_NO_TIMEOUT; + + /* Disable auto-connect and auto-down */ + conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT, true); + conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN, true); } if (iface_data) { @@ -98,12 +120,22 @@ static void conn_mgr_conn_handler(struct net_mgmt_event_callback *cb, static void conn_mgr_conn_before(void *data) { ARG_UNUSED(data); - reset_test_iface(ifa1); - reset_test_iface(ifa2); - reset_test_iface(ifb); - reset_test_iface(ifni); - reset_test_iface(ifnone); - reset_test_iface(ifnull); + reset_test_iface_networking(ifa1); + reset_test_iface_networking(ifa2); + reset_test_iface_networking(ifb); + reset_test_iface_networking(ifni); + reset_test_iface_networking(ifnone); + reset_test_iface_networking(ifnull); + + /* Allow any triggered events to shake out */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + + reset_test_iface_state(ifa1); + reset_test_iface_state(ifa2); + reset_test_iface_state(ifb); + reset_test_iface_state(ifni); + reset_test_iface_state(ifnone); + reset_test_iface_state(ifnull); k_mutex_lock(&event_mutex, K_FOREVER); @@ -171,6 +203,7 @@ ZTEST(conn_mgr_conn, test_connect_disconnect) zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail"); zassert_equal(net_if_up(ifa2), 0, "net_if_up should not fail"); zassert_equal(net_if_up(ifb), 0, "net_if_up should not fail"); + k_sleep(K_MSEC(1)); /* Verify ifaces are still disconnected */ zassert_false(net_if_is_up(ifa1), "Ifaces must be disconnected before test"); @@ -526,7 +559,7 @@ ZTEST(conn_mgr_conn, test_connect_timeout) zassert_false(net_if_is_up(ifa1), "ifa1 should not be up if instructed to time out"); /* Ensure timeout event is fired */ - k_sleep(K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS + 1)); + k_sleep(SIMULATED_EVENT_WAIT_TIME); k_mutex_lock(&event_mutex, K_FOREVER); stats = test_event_stats; @@ -557,7 +590,7 @@ ZTEST(conn_mgr_conn, test_connect_fatal_error) zassert_false(net_if_is_up(ifa1), "ifa1 should not be up if instructed to time out"); /* Ensure fatal_error event is fired */ - k_sleep(K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS + 1)); + k_sleep(SIMULATED_EVENT_WAIT_TIME); k_mutex_lock(&event_mutex, K_FOREVER); stats = test_event_stats; @@ -737,6 +770,9 @@ ZTEST(conn_mgr_conn, test_flags) { struct conn_mgr_conn_binding *ifa1_binding = conn_mgr_if_get_binding(ifa1); + /* Firstly, clear all flags (some are automatically enabled before each test) */ + ifa1_binding->flags = 0; + /* Try setting persistence flag */ zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true), 0, "Setting persistence flag should succeed for ifa1"); @@ -749,6 +785,19 @@ ZTEST(conn_mgr_conn, test_flags) zassert_equal(ifa1_binding->flags, BIT(CONN_MGR_IF_PERSISTENT), "Persistence flag set should affect conn struct"); + /* Try setting no-autoconnect flag */ + zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, true), 0, + "Setting no-autoconnect flag should succeed for ifa1"); + + /* Verify success */ + zassert_true(conn_mgr_if_get_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT), + "No-autoconnect should be set for ifa1"); + + /* Verify that the conn struct agrees, since this is what implementations may use */ + zassert_equal(ifa1_binding->flags, + BIT(CONN_MGR_IF_PERSISTENT) | BIT(CONN_MGR_IF_NO_AUTO_CONNECT), + "Persistence flag set should affect conn struct"); + /* Try unsetting persistence flag */ zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false), 0, "Unsetting persistence flag should succeed for ifa1"); @@ -758,8 +807,20 @@ ZTEST(conn_mgr_conn, test_flags) "Persistence should be unset for ifa1"); /* Verify that the conn struct agrees, since this is what implementations may use */ - zassert_equal(ifa1_binding->flags, 0, + zassert_equal(ifa1_binding->flags, BIT(CONN_MGR_IF_NO_AUTO_CONNECT), "Persistence flag unset should affect conn struct"); + + /* Try unsetting no-autoconnect flag */ + zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false), 0, + "Clearing no-autoconnect flag should succeed for ifa1"); + + /* Verify success */ + zassert_false(conn_mgr_if_get_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT), + "No-autoconnect should be set for ifa1"); + + /* Verify that the conn struct agrees, since this is what implementations may use */ + zassert_equal(ifa1_binding->flags, 0, + "No-autoconnect flag set should affect conn struct"); } /* Verify that flag get/set fail and behave as expected respectively for invalid ifaces and @@ -833,4 +894,689 @@ ZTEST(conn_mgr_conn, test_timeout_invalid) "Getting timeout should yield CONN_MGR_IF_NO_TIMEOUT for ifnone"); } +/* Verify that auto-connect works as expected. */ +ZTEST(conn_mgr_conn, test_auto_connect) +{ + /* Disable auto-connect. + * Not strictly necessary, since this is the default for this suite, but do it anyways + * since this test case specifically focuses on auto-connect. + */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, true); + + /* Take the iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail."); + + /* Verify no connection */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_up(ifa1), "Auto-connect should not trigger if disabled."); + + /* Take the iface down */ + zassert_equal(net_if_down(ifa1), 0, "net_if_down should not fail."); + + /* Enable auto-connect */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Take the iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail."); + + /* Verify connection */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Auto-connect should succeed if enabled."); +} + +/* Verify that if auto-down is enabled, disconnecting an iface also takes it down, + * regardless of whether persistence is enabled, but only if auto-down is disabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_disconnect) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down, disable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on direct disconnect."); + + + + /* Enable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on direct disconnect, even if persistence is enabled."); + + + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify up */ + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger if it is disabled."); +} + +/* Verify that auto-down takes an iface down if connection is lost, but only if persistence is not + * enabled, and only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_conn_loss) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down, disable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on connection loss if persistence is disabled."); + + /* Enable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify up */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection loss if persistence is enabled."); + + /* Disable persistence and disable auto-down*/ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Reconnect iface */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify up */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection loss if it is disabled."); +} + +/* Verify that timeout takes the iface down, even if + * persistence is enabled, but only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_timeout) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down and persistence*/ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Schedule timeout */ + ifa1_data->timeout = true; + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify iface down after timeout */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on connection timeout, even if persistence is enabled."); + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up (timing out again) */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify iface up after timeout */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection timeout if it is disabled."); +} + + +/* Verify that fatal error takes the iface down, even if + * persistence is enabled, but only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_fatal) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down and persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Raise fatal error */ + simulate_fatal_error(ifa1, -EAGAIN); + + /* Verify iface down after fatal error */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on fatal error, even if persistence is enabled."); + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Raise fatal error */ + simulate_fatal_error(ifa1, -EAGAIN); + + /* Verify iface still up after fatal error */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on fatal error if it is disabled."); +} + +/* Verify that all_if_up brings all ifaces up, but only if they are not ignored or + * skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_up) +{ + /* Ignore an iface */ + conn_mgr_ignore_iface(ifa1); + + /* Take all ifaces up (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_up(false), 0, "conn_mgr_all_if_up should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + + /* Manually take all ifaces down */ + zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces up (skip ignored) */ + zassert_equal(conn_mgr_all_if_up(true), 0, "conn_mgr_all_if_up should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all except ignored are up */ + zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-up."); + + zassert_false(net_if_is_admin_up(ifa1), "Ignored iface should not be admin-up."); +} + +/* Verify that all_if_connect brings all ifaces up, and connects all bound ifaces, but only those + * that are not ignored, or all of them if skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_connect) +{ + /* Ignore a bound and an unbound iface */ + conn_mgr_ignore_iface(ifa1); + conn_mgr_ignore_iface(ifnone); + + /* Connect all ifaces (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_connect(false), 0, "conn_mgr_all_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify bound ifaces are connected */ + zassert_true(net_if_is_up(ifa1), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifa2), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All bound ifaces should be connected."); + + /* Manually take all ifaces down */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifa2), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifb), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifni), 0, "net_if_disconnect should succeed."); + + zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Connect all ifaces (skip ignored) */ + zassert_equal(conn_mgr_all_if_connect(true), 0, "conn_mgr_all_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all except ignored are up */ + zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up."); + + zassert_false(net_if_is_admin_up(ifa1), "All ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ignored ifaces should be admin-down."); + + /* Verify bound ifaces are connected, except for ignored */ + zassert_true(net_if_is_up(ifa2), "All non-ignored bound ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All non-ignored bound ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All non-ignored bound ifaces should be connected."); + + zassert_false(net_if_is_up(ifa1), "Ignored iface should not be connected."); +} + +/* Verify that all_if_down takes all ifaces down, but only if they are not ignored, + * or skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_down) +{ + /* Ignore an iface */ + conn_mgr_ignore_iface(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_down(false), 0, "conn_mgr_all_if_down should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are down */ + zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down."); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down (skip ignored) */ + zassert_equal(conn_mgr_all_if_down(true), 0, "conn_mgr_all_if_down should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all except the ignored iface is down */ + zassert_false(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-down."); + + zassert_true(net_if_is_admin_up(ifa1), "Ignored iface should be admin-up."); +} + +/* Verify that all_if_disconnect disconnects all bound ifaces, but only if they are not ignored, + * or skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_disconnect) +{ + /* Ignore a bound iface */ + conn_mgr_ignore_iface(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Disconnect all ifaces (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all bound ifaces are disconnected */ + zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected."); + + /* Verify that all ifaces are still up, even if disconnected */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Manually reconnect bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Disconnect all ifaces (skip ignored) */ + zassert_equal(conn_mgr_all_if_disconnect(true), 0, + "conn_mgr_all_if_disconnect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all bound ifaces are disconnected, except the ignored iface */ + zassert_false(net_if_is_up(ifa2), "All non-ignored bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All non-ignored bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All non-ignored bound ifaces should be disconnected."); + + zassert_true(net_if_is_up(ifa1), "Ignored iface should still be connected"); +} + + +/* Verify that double calls to all_if_up do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_up_double) +{ + /* Take all ifaces up twice in a row */ + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed."); + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); +} + +/* Verify that double calls to all_if_down do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_down_double) +{ + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down twice in a row */ + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed."); + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are down */ + zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down."); +} + +/* Verify that double calls to all_if_connect do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_connect_double) +{ + /* Connect all ifaces twice in a row */ + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed."); + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify all bound ifaces are connected */ +} + +/* Verify that double calls to all_if_disconnect do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_disconnect_double) +{ + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Connect all ifaces twice in a row */ + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed."); + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all bound ifaces are disconnected */ + zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected."); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); +} + + + +/* Testing error passing for all_if_up/all_if_down is not possible without using an L2 other than + * Dummy, since the dummy L2 is not capable of erroring in response to either of these. + * + * However, since all bulk convenience functions share a single implementation, testing + * connect and disconnect is sufficient to gain acceptable coverage of this behavior for all of + * them. + */ + +/* Verify that all_if_connect successfully forwards errors encountered on individual ifaces */ +ZTEST(conn_mgr_conn, test_all_if_connect_err) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* Schedule a connect error on one of the ifaces */ + ifa1_data->api_err = -ECHILD; + + /* Verify that this error is passed to all_if_connect */ + zassert_equal(conn_mgr_all_if_connect(false), -ECHILD, + "conn_mgr_all_if_connect should fail with the requested error."); + k_sleep(K_MSEC(1)); + + /* Verify that all ifaces went admin-up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify that all the non-error ifaces are connected */ + zassert_true(net_if_is_up(ifa2), "All non-failing ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All non-failing ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All non-failing ifaces should be connected."); + + /* Verify that the error iface is not connected */ + zassert_false(net_if_is_up(ifa1), "The failing iface should not be connected."); +} + +/* Verify that all_if_disconnect successfully forwards errors encountered on individual ifaces */ +ZTEST(conn_mgr_conn, test_all_if_disconnect_err) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Schedule a disconnect error on one of the ifaces */ + ifa1_data->api_err = -ECHILD; + + /* Verify that this error is passed to all_if_disconnect */ + zassert_equal(conn_mgr_all_if_disconnect(false), -ECHILD, + "conn_mgr_all_if_disconnect should fail with the requested error."); + + /* Verify that all ifaces are still admin-up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify that all the non-error ifaces are disconnected */ + zassert_false(net_if_is_up(ifa2), "All non-failing ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All non-failing ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All non-failing ifaces should be disconnected."); + + /* Verify that the error iface is not connected */ + zassert_true(net_if_is_up(ifa1), "The failing iface should not be disconnected."); +} + ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL); diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.c b/tests/net/conn_mgr_conn/src/test_conn_impl.c index 8d2395160590..a0f2de45c545 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.c +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.c @@ -57,7 +57,7 @@ static void simulate_event(struct net_if *target, int event) simulated_event = event; simulated_event_iface = target; - k_work_reschedule(&simulate_event_work, K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS)); + k_work_reschedule(&simulate_event_work, SIMULATED_EVENT_DELAY_TIME); k_mutex_unlock(&simulated_event_mutex); } @@ -67,11 +67,16 @@ static void simulate_timeout(struct net_if *target) simulate_event(target, 0); } -static void simulate_fatal_error(struct net_if *target, int reason) +void simulate_fatal_error(struct net_if *target, int reason) { simulate_event(target, reason); } +void simulate_connection_loss(struct net_if *target) +{ + net_if_dormant_on(target); +} + /* Connectivity implementations */ static void inc_call_count(struct test_conn_data *data, bool a) diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.h b/tests/net/conn_mgr_conn/src/test_conn_impl.h index 6408bb802cfc..bab0c9b3aa9a 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.h +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.h @@ -76,7 +76,28 @@ CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_N); #define TEST_L2_CONN_IMPL_NI_CTX_TYPE struct test_conn_data CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_NI); -#define SIMULATED_EVENT_DELAY_SECONDS 5 +#define SIMULATED_EVENT_DELAY_MS 100 +#define SIMULATED_EVENT_DELAY_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS) +#define SIMULATED_EVENT_WAIT_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS + 10) + +/* Helper API for controlling implementations from tests */ + +/** + * @brief Simulate a connection loss on the target iface. + * + * @param target - iface to simulate connection loss on. + */ +void simulate_connection_loss(struct net_if *target); + +/** + * @brief Simulate a fatal error on the target iface + * + * Please do not simulate events on more than one iface at a time. + * + * @param target - iface to simulate fatal error on. + * @param reason - Reason to be given for the fatal error. + */ +void simulate_fatal_error(struct net_if *target, int reason); #ifdef __cplusplus } diff --git a/tests/net/lib/lwm2m/block_transfer/testcase.yaml b/tests/net/lib/lwm2m/block_transfer/testcase.yaml index 55a40d517eb4..66f145fd18fb 100644 --- a/tests/net/lib/lwm2m/block_transfer/testcase.yaml +++ b/tests/net/lib/lwm2m/block_transfer/testcase.yaml @@ -1,5 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.block_transfer: - tags: lwm2m net + platform_key: + - simulation + tags: + - lwm2m + - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_json/prj.conf b/tests/net/lib/lwm2m/content_json/prj.conf index 5f99626db5fb..3f2cd3e60f24 100644 --- a/tests/net/lib/lwm2m/content_json/prj.conf +++ b/tests/net/lib/lwm2m/content_json/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 CONFIG_LWM2M_RW_JSON_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_json/testcase.yaml b/tests/net/lib/lwm2m/content_json/testcase.yaml index 2004897b6e20..a283ce908ef6 100644 --- a/tests/net/lib/lwm2m/content_json/testcase.yaml +++ b/tests/net/lib/lwm2m/content_json/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_json: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_link_format/prj.conf b/tests/net/lib/lwm2m/content_link_format/prj.conf index b70c6003eef6..952b54a4566a 100644 --- a/tests/net/lib/lwm2m/content_link_format/prj.conf +++ b/tests/net/lib/lwm2m/content_link_format/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_RW_JSON_SUPPORT=y CONFIG_JSON_LIBRARY=y diff --git a/tests/net/lib/lwm2m/content_link_format/testcase.yaml b/tests/net/lib/lwm2m/content_link_format/testcase.yaml index c075d55edf3c..5448cf68fd05 100644 --- a/tests/net/lib/lwm2m/content_link_format/testcase.yaml +++ b/tests/net/lib/lwm2m/content_link_format/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_link_format: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_oma_tlv/prj.conf b/tests/net/lib/lwm2m/content_oma_tlv/prj.conf index 9c9cec3be7c5..6041addad837 100644 --- a/tests/net/lib/lwm2m/content_oma_tlv/prj.conf +++ b/tests/net/lib/lwm2m/content_oma_tlv/prj.conf @@ -5,6 +5,4 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y diff --git a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml index 710858883677..2bf877f73537 100644 --- a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml +++ b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_oma_tlv: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_plain_text/prj.conf b/tests/net/lib/lwm2m/content_plain_text/prj.conf index 9c9cec3be7c5..6041addad837 100644 --- a/tests/net/lib/lwm2m/content_plain_text/prj.conf +++ b/tests/net/lib/lwm2m/content_plain_text/prj.conf @@ -5,6 +5,4 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y diff --git a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml index cc902805c829..bd70dd790b30 100644 --- a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml +++ b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_plain_text: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_raw_cbor/prj.conf b/tests/net/lib/lwm2m/content_raw_cbor/prj.conf index 0fae8dcbbeb4..64ab6f89d22a 100644 --- a/tests/net/lib/lwm2m/content_raw_cbor/prj.conf +++ b/tests/net/lib/lwm2m/content_raw_cbor/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_VERSION_1_1=y CONFIG_LWM2M_RW_CBOR_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml index 13a564aa97d4..9fc90f109bc0 100644 --- a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_raw_cbor: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_senml_cbor/prj.conf b/tests/net/lib/lwm2m/content_senml_cbor/prj.conf index d6bdaceb9345..27a8364af588 100644 --- a/tests/net/lib/lwm2m/content_senml_cbor/prj.conf +++ b/tests/net/lib/lwm2m/content_senml_cbor/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_VERSION_1_1=y CONFIG_LWM2M_RW_CBOR_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml index 4d2db6e5838b..55cd89a9f51b 100644 --- a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_senml_cbor: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/engine/prj.conf b/tests/net/lib/lwm2m/engine/prj.conf index 18a5df2ad223..4477075056a5 100644 --- a/tests/net/lib/lwm2m/engine/prj.conf +++ b/tests/net/lib/lwm2m/engine/prj.conf @@ -5,7 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 diff --git a/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c b/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c index 8106d7180b3d..9371702b2e90 100644 --- a/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c +++ b/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c @@ -49,10 +49,10 @@ static void assert_path_list_order(sys_slist_t *lwm2m_path_list) struct lwm2m_obj_path_list *prev = NULL; struct lwm2m_obj_path_list *entry, *tmp; - uint16_t obj_id_max; - uint16_t obj_inst_id_max; - uint16_t res_id_max; - uint16_t res_inst_id_max; + uint16_t obj_id_max = 0; + uint16_t obj_inst_id_max = 0; + uint16_t res_id_max = 0; + uint16_t res_inst_id_max = 0; if (sys_slist_is_empty(lwm2m_path_list)) { return; diff --git a/tests/net/lib/lwm2m/engine/testcase.yaml b/tests/net/lib/lwm2m/engine/testcase.yaml index 28047c0fa5f4..3263441b418d 100644 --- a/tests/net/lib/lwm2m/engine/testcase.yaml +++ b/tests/net/lib/lwm2m/engine/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.engine: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt index 8d4a0e1ddf42..36e161c6b11d 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt +++ b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/lwm2m_engine.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/include/) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/../modules/crypto/mbedtls/include/) add_compile_definitions(CONFIG_LWM2M_ENGINE_MAX_PENDING=2) add_compile_definitions(CONFIG_LWM2M_ENGINE_MAX_REPLIES=2) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c index 86811fec805e..6e432f6dca8b 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c @@ -57,7 +57,6 @@ static int lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path *path, bool *v static void test_service(struct k_work *work) { - LOG_INF("Test service"); k_sleep(K_MSEC(10)); } @@ -339,8 +338,8 @@ ZTEST(lwm2m_engine, test_retransmit_request) k_sleep(K_MSEC(500)); ret = lwm2m_engine_stop(&ctx); zassert_equal(ret, 0); - zassert_equal(lwm2m_reset_message_fake.call_count, 1, "Message was not reseted"); - zassert_equal(lwm2m_send_message_async_fake.call_count, 1, "Message was not sent"); + zassert_not_equal(lwm2m_reset_message_fake.call_count, 0, "Message was not reseted"); + zassert_not_equal(lwm2m_send_message_async_fake.call_count, 0, "Message was not sent"); } ZTEST(lwm2m_engine, test_socket_recv) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c index 2611687f4758..5632e8fc6c62 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c @@ -39,6 +39,7 @@ DEFINE_FAKE_VALUE_FUNC(struct lwm2m_engine_obj_field *, lwm2m_get_engine_obj_fie DEFINE_FAKE_VALUE_FUNC(int, lwm2m_get_bool, const struct lwm2m_obj_path *, bool *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_delete_obj_inst, uint16_t, uint16_t); DEFINE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); +DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); static sys_slist_t obs_obj_path_list = SYS_SLIST_STATIC_INIT(&obs_obj_path_list); sys_slist_t *lwm2m_obs_obj_path_list(void) @@ -77,11 +78,24 @@ int z_impl_zsock_close(int sock) return 0; } +#define PAIR_IN 10 +#define PAIR_OUT 11 + +int z_impl_zsock_socketpair(int family, int type, int proto, int *sv) +{ + sv[0] = PAIR_IN; + sv[1] = PAIR_OUT; + return 0; +} + DEFINE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, socklen_t); ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + if (sock == PAIR_OUT) { + return 1; + } k_sleep(K_MSEC(1)); if (my_events & ZSOCK_POLLOUT) { my_events = 0; @@ -92,6 +106,10 @@ ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + if (sock == PAIR_IN) { + return 1; + } + k_sleep(K_MSEC(1)); if (my_events & ZSOCK_POLLIN) { my_events = 0; @@ -103,7 +121,7 @@ ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, int z_impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int poll_timeout) { - k_sleep(K_MSEC(poll_timeout)); + k_sleep(K_MSEC(1)); fds->revents = my_events; return 0; } diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h index a27c658642c7..c6a61ac180b1 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h @@ -54,6 +54,7 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_get_bool, const struct lwm2m_obj_path *, bool DECLARE_FAKE_VALUE_FUNC(int, lwm2m_delete_obj_inst, uint16_t, uint16_t); DECLARE_FAKE_VOID_FUNC(lwm2m_clear_block_contexts); DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, socklen_t); +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *); #define DO_FOREACH_FAKE(FUNC) \ do { \ @@ -81,6 +82,7 @@ DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, FUNC(lwm2m_delete_obj_inst) \ FUNC(lwm2m_clear_block_contexts) \ FUNC(z_impl_zsock_connect) \ + FUNC(lwm2m_security_mode) \ } while (0) #endif /* STUBS_H */ diff --git a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml index 9f58cafdea44..a7f628405ebf 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.lwm2m_engine: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt b/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt index 2a6e8141a1ce..d69ed3856211 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt @@ -30,3 +30,4 @@ add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_UPTIME=10) add_compile_definitions(CONFIG_LWM2M_LOG_LEVEL=4) add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_ENABLED=1) add_compile_definitions(CONFIG_LWM2M_TLS_SESSION_CACHING=1) +add_compile_definitions(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE=1) diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf b/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf new file mode 100644 index 000000000000..eb56d825c96d --- /dev/null +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/boards/native_posix.conf @@ -0,0 +1 @@ +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c index 4d20c3700f27..60a00b9addb9 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -9,7 +9,9 @@ #include #include #include - +#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) +#include "timer_model.h" +#endif #include LOG_MODULE_REGISTER(lwm2m_rd_client_test); @@ -19,7 +21,7 @@ DEFINE_FFF_GLOBALS; /* Maximum number of iterations within the state machine of RD Client * service that is waited for until a possible event occurs */ -static const uint8_t RD_CLIENT_MAX_LOOKUP_ITERATIONS = 10; +static const uint8_t RD_CLIENT_MAX_LOOKUP_ITERATIONS = 100; FAKE_VOID_FUNC(show_lwm2m_event, enum lwm2m_rd_client_event); FAKE_VOID_FUNC(show_lwm2m_observe, enum lwm2m_observe_event); @@ -127,6 +129,12 @@ static void lwm2m_observe_cb(enum lwm2m_observe_event event, struct lwm2m_obj_pa static void my_suite_before(void *data) { +#if defined(CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME) + /* It is enough that some slow-down is happening on sleeps, it does not have to be + * real time + */ + hwtimer_set_rt_ratio(100.0); +#endif /* Register resets */ DO_FOREACH_FAKE(RESET_FAKE); @@ -135,7 +143,10 @@ static void my_suite_before(void *data) RESET_FAKE(show_lwm2m_event); RESET_FAKE(show_lwm2m_observe); +} +static void my_suite_after(void *data) +{ test_lwm2m_engine_stop_service(); } @@ -157,7 +168,7 @@ void message_reply_timeout_cb_default(struct lwm2m_message *msg) msg->message_timeout_cb(msg); } -ZTEST_SUITE(lwm2m_rd_client, NULL, NULL, my_suite_before, NULL, NULL); +ZTEST_SUITE(lwm2m_rd_client, NULL, NULL, my_suite_before, my_suite_after, NULL); ZTEST(lwm2m_rd_client, test_start_registration_ok) { @@ -167,7 +178,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -186,7 +196,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) coap_header_get_code_fake.custom_fake = coap_header_get_code_fake_deleted; zassert_true(lwm2m_rd_client_stop(&ctx, lwm2m_event_cb, true) == 0, NULL); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT, 2), NULL); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_DISCONNECT, 1), NULL); zassert_true(!lwm2m_rd_client_is_registred(&ctx), NULL); } @@ -198,10 +208,8 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); - wait_for_service(1); lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; @@ -215,7 +223,7 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration) NULL); zassert(lwm2m_rd_client_timeout(&ctx) == 0, ""); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 2), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 1), NULL); } @@ -228,7 +236,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_timeout) test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -250,7 +257,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -272,7 +278,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -288,7 +293,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) NULL); lwm2m_rd_client_update(); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 3), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 2), NULL); } @@ -300,7 +305,6 @@ ZTEST(lwm2m_rd_client, test_rx_off) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -329,7 +333,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -347,7 +350,7 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) RESET_FAKE(coap_header_get_code); lwm2m_rd_client_update(); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE, 3), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE, 2), NULL); } @@ -359,7 +362,6 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -376,12 +378,12 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) test_prepare_pending_message_cb(&message_reply_timeout_cb_default); lwm2m_rd_client_update(); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 2)); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 3), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 1)); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 2), NULL); test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 4), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 3), NULL); } @@ -393,7 +395,6 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -421,7 +422,6 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -448,7 +448,6 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -461,6 +460,8 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration) coap_packet_append_option_fake.custom_fake = coap_packet_append_option_fake_err; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + wait_for_service(100); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, 0), NULL); } @@ -472,7 +473,6 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -489,11 +489,11 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) zassert_true(!lwm2m_rd_client_is_suspended(&ctx), NULL); zassert_true(lwm2m_rd_client_pause() == 0, NULL); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED, 2), NULL); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED, 1), NULL); zassert_true(lwm2m_rd_client_is_suspended(&ctx), NULL); zassert_true(lwm2m_rd_client_resume() == 0, NULL); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 4), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 3), NULL); zassert_true(!lwm2m_rd_client_is_suspended(&ctx), NULL); } @@ -506,7 +506,6 @@ ZTEST(lwm2m_rd_client, test_socket_error) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -522,7 +521,7 @@ ZTEST(lwm2m_rd_client, test_socket_error) NULL); ctx.fault_cb(EIO); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 2), NULL); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 3), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 1), NULL); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE, 2), NULL); } diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c index 7d0bd84c1ac0..877dfdc40d39 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -66,6 +66,7 @@ int lwm2m_get_bool_fake_default(const struct lwm2m_obj_path *path, bool *value) DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); +DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); @@ -79,35 +80,41 @@ char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr) DEFINE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); -DEFINE_FAKE_VALUE_FUNC(int, lwm2m_engine_add_service, k_work_handler_t, uint32_t); -k_work_handler_t lwm2m_engine_add_service_service; -uint32_t lwm2m_engine_add_service_period_ms = 20; -int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms) +k_work_handler_t service; +int64_t next; + +int lwm2m_engine_call_at(k_work_handler_t work, int64_t timestamp) { - lwm2m_engine_add_service_service = service; - lwm2m_engine_add_service_period_ms = period_ms; + service = work; + next = timestamp ? timestamp : 1; return 0; } uint16_t counter = RD_CLIENT_MAX_SERVICE_ITERATIONS; struct lwm2m_message *pending_message; void *(*pending_message_cb)(); +static bool running; static void service_work_fn(struct k_work *work) { - while (lwm2m_engine_add_service_service != NULL) { + while (running) { if (pending_message != NULL && pending_message_cb != NULL) { pending_message_cb(pending_message); pending_message = NULL; } - lwm2m_engine_add_service_service(work); - k_sleep(K_MSEC(lwm2m_engine_add_service_period_ms)); + if (next && next < k_uptime_get()) { + printk("Event!\n"); + next = 0; + service(NULL); + } + k_sleep(K_MSEC(10)); counter--; /* avoid endless loop if rd client is stuck somewhere */ if (counter == 0) { + printk("Counter!\n"); break; } } @@ -118,7 +125,7 @@ void wait_for_service(uint16_t cycles) uint16_t end = counter - cycles; while (counter > end) { - k_sleep(K_MSEC(1)); + k_sleep(K_MSEC(10)); } } @@ -126,6 +133,7 @@ K_WORK_DEFINE(service_work, service_work_fn); void test_lwm2m_engine_start_service(void) { + running = true; counter = RD_CLIENT_MAX_SERVICE_ITERATIONS; k_work_submit(&service_work); } @@ -133,6 +141,7 @@ void test_lwm2m_engine_start_service(void) void test_lwm2m_engine_stop_service(void) { pending_message_cb = NULL; + running = false; k_work_cancel(&service_work); } diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h index b07346de889b..d15b40f3e444 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -51,6 +51,7 @@ int lwm2m_get_bool_fake_default(const struct lwm2m_obj_path *path, bool *value); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_close, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_close_socket, struct lwm2m_ctx *); +DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_suspend, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_inst_id_to_index, uint16_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_connection_resume, struct lwm2m_ctx *); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_push_queued_buffers, struct lwm2m_ctx *); @@ -60,8 +61,6 @@ DECLARE_FAKE_VALUE_FUNC(char *, lwm2m_sprint_ip_addr, const struct sockaddr *); char *lwm2m_sprint_ip_addr_fake_default(const struct sockaddr *addr); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_server_short_id_to_inst, uint16_t); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_index_to_inst_id, int); -DECLARE_FAKE_VALUE_FUNC(int, lwm2m_engine_add_service, k_work_handler_t, uint32_t); -int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms); void wait_for_service(uint16_t cycles); void test_lwm2m_engine_start_service(void); void test_lwm2m_engine_stop_service(void); @@ -106,7 +105,6 @@ DECLARE_FAKE_VALUE_FUNC(int, do_register_op_link_format, struct lwm2m_message *) FUNC(lwm2m_sprint_ip_addr) \ FUNC(lwm2m_server_short_id_to_inst) \ FUNC(lwm2m_security_index_to_inst_id) \ - FUNC(lwm2m_engine_add_service) \ FUNC(lwm2m_init_message) \ FUNC(lwm2m_reset_message) \ FUNC(lwm2m_send_message_async) \ diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml index 7e6415395ca9..b5f21f0d9dc5 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml @@ -1,16 +1,11 @@ common: - depends_on: netif + platform_key: + - simulation tags: - - net - lwm2m - platform_allow: - - native_posix - - qemu_x86 - - qemu_x86_64 + - net integration_platforms: - native_posix - - qemu_x86 - tests: net.lwm2m.lwm2m_rd_client: extra_args: EXTRA_CFLAGS="" diff --git a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf index 3bbd185d38b5..0b7b96721227 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf +++ b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf @@ -2,13 +2,12 @@ CONFIG_NETWORKING=y CONFIG_NET_TEST=y CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y - CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 +CONFIG_LWM2M_SECURITY_KEY_SIZE=32 CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_IPSO_TEMP_SENSOR=y CONFIG_LWM2M_IPSO_TEMP_SENSOR_VERSION_1_1=y diff --git a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c index 7ffd17d196c6..5b79c476e7f0 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -130,12 +130,12 @@ ZTEST(lwm2m_registry, test_connmon) int ret; uint16_t u16_buf = 0; uint32_t u32_buf = 0; - int8_t s8_buf = 0; + int16_t s16_buf = 0; int32_t s32_buf = 0; uint16_t u16_getbuf = 0; uint32_t u32_getbuf = 0; - int8_t s8_getbuf = 0; + int16_t s16_getbuf = 0; int32_t s32_getbuf = 0; ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 9), &u16_buf, sizeof(u16_buf), @@ -144,8 +144,8 @@ ZTEST(lwm2m_registry, test_connmon) ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 8), &u32_buf, sizeof(u32_buf), sizeof(u32_buf), 0); zassert_equal(ret, 0); - ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 2), &s8_buf, sizeof(s8_buf), - sizeof(s8_buf), 0); + ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 2), &s16_buf, sizeof(s16_buf), + sizeof(s16_buf), 0); zassert_equal(ret, 0); ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 11), &s32_buf, sizeof(s32_buf), sizeof(s32_buf), 0); @@ -155,28 +155,28 @@ ZTEST(lwm2m_registry, test_connmon) zassert_equal(ret, 0); ret = lwm2m_set_u32(&LWM2M_OBJ(4, 0, 8), 0xDEADBEEF); zassert_equal(ret, 0); - ret = lwm2m_set_s8(&LWM2M_OBJ(4, 0, 2), -5); + ret = lwm2m_set_s16(&LWM2M_OBJ(4, 0, 2), -5); zassert_equal(ret, 0); ret = lwm2m_set_s32(&LWM2M_OBJ(4, 0, 11), 0xCC00CC00); zassert_equal(ret, 0); zassert_equal(u16_buf, 0x5A5A); zassert_equal(u32_buf, 0xDEADBEEF); - zassert_equal(s8_buf, -5); + zassert_equal(s16_buf, -5); zassert_equal(s32_buf, 0xCC00CC00); ret = lwm2m_get_u16(&LWM2M_OBJ(4, 0, 9), &u16_getbuf); zassert_equal(ret, 0); ret = lwm2m_get_u32(&LWM2M_OBJ(4, 0, 8), &u32_getbuf); zassert_equal(ret, 0); - ret = lwm2m_get_s8(&LWM2M_OBJ(4, 0, 2), &s8_getbuf); + ret = lwm2m_get_s16(&LWM2M_OBJ(4, 0, 2), &s16_getbuf); zassert_equal(ret, 0); ret = lwm2m_get_s32(&LWM2M_OBJ(4, 0, 11), &s32_getbuf); zassert_equal(ret, 0); zassert_equal(u16_buf, u16_getbuf); zassert_equal(u32_buf, u32_getbuf); - zassert_equal(s8_buf, s8_getbuf); + zassert_equal(s16_buf, s16_getbuf); zassert_equal(s32_buf, s32_getbuf); } @@ -294,3 +294,94 @@ ZTEST(lwm2m_registry, test_callbacks) zassert_equal(ret, 0); zassert_equal(callback_checker, 0x7F); } + +ZTEST(lwm2m_registry, test_strings) +{ + int ret; + char buf[256] = {0}; + struct lwm2m_obj_path path = LWM2M_OBJ(0, 0, 0); + static const char uri[] = "coap://127.0.0.1"; + uint16_t len; + uint8_t *p; + + ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL); + zassert_equal(ret, 0); + memset(p, 0xff, len); /* Pre-fill buffer to check */ + + /* Handle strings in string resources */ + ret = lwm2m_set_string(&path, uri); + zassert_equal(ret, 0); + ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL); + zassert_equal(ret, 0); + zassert_equal(len, sizeof(uri)); + zassert_equal(p[len - 1], '\0'); /* string terminator in buffer */ + zassert_equal(p[len], 0xff); + + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(memcmp(uri, buf, sizeof(uri)), 0); + ret = lwm2m_get_string(&path, buf, sizeof(uri)); + zassert_equal(ret, 0); + ret = lwm2m_get_string(&path, buf, strlen(uri)); + zassert_equal(ret, -ENOMEM); + + /* Handle strings in opaque resources (no terminator) */ + path = LWM2M_OBJ(0, 0, 3); + ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL); + zassert_equal(ret, 0); + memset(p, 0xff, len); /* Pre-fill buffer to check */ + + ret = lwm2m_set_string(&path, uri); + zassert_equal(ret, 0); + ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL); + zassert_equal(ret, 0); + zassert_equal(len, strlen(uri)); /* No terminator counted in data length */ + zassert_equal(p[len - 1], '1'); /* Last character in buffer is not terminator */ + zassert_equal(p[len], 0xff); + memset(buf, 0xff, sizeof(buf)); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); /* get_string ensures termination */ + zassert_equal(ret, 0); + zassert_equal(memcmp(uri, buf, sizeof(uri)), 0); + ret = lwm2m_get_string(&path, buf, sizeof(uri)); + zassert_equal(ret, 0); + ret = lwm2m_get_string(&path, buf, strlen(uri)); + zassert_equal(ret, -ENOMEM); + /* Corner case: we request exactly as much is stored in opaque resource, */ + /* but because we request as a string, it must have room for terminator. */ + ret = lwm2m_get_string(&path, buf, len); + zassert_equal(ret, -ENOMEM); +} + +ZTEST(lwm2m_registry, test_null_strings) +{ + int ret; + char buf[256] = {0}; + struct lwm2m_obj_path path = LWM2M_OBJ(0, 0, 0); + + ret = lwm2m_register_post_write_callback(&path, post_write_cb); + zassert_equal(ret, 0); + + callback_checker = 0; + ret = lwm2m_set_string(&path, "string"); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), strlen("string")); + + callback_checker = 0; + ret = lwm2m_set_string(&path, ""); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), 0); + + callback_checker = 0; + ret = lwm2m_set_opaque(&path, NULL, 0); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), 0); +} diff --git a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml index b0fda561cff3..ca0f06f58b57 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.lwm2m_registry: + platform_key: + - simulation tags: - lwm2m - net - filter: TOOLCHAIN_HAS_NEWLIB == 1 + integration_platforms: + - native_posix diff --git a/tests/net/npf/prj.conf b/tests/net/npf/prj.conf index b1e779aa96e2..57d622130907 100644 --- a/tests/net/npf/prj.conf +++ b/tests/net/npf/prj.conf @@ -12,3 +12,7 @@ CONFIG_NET_BUF_TX_COUNT=20 CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_COMPILER_COLOR_DIAGNOSTICS=n +CONFIG_NET_IPV4=y +CONFIG_NET_PKT_FILTER_IPV4_HOOK=y +CONFIG_NET_IPV6=y +CONFIG_NET_PKT_FILTER_IPV6_HOOK=y diff --git a/tests/net/npf/src/main.c b/tests/net/npf/src/main.c index 992ff535ed6e..39aa63daac20 100644 --- a/tests/net/npf/src/main.c +++ b/tests/net/npf/src/main.c @@ -16,6 +16,9 @@ LOG_MODULE_REGISTER(npf_test, NET_LOG_LEVEL); #include #include +#include "ipv4.h" +#include "ipv6.h" + #include #include @@ -72,6 +75,31 @@ static struct net_pkt *build_test_pkt(int type, int size, struct net_if *iface) return pkt; } +static struct net_pkt *build_test_ip_pkt(void *src, void *dst, + sa_family_t family, struct net_if *iface) +{ + struct net_pkt *pkt; + int ret = -1; + int size; + + size = (family == AF_INET) ? sizeof(struct net_ipv4_hdr) : + (family == AF_INET6) ? sizeof(struct net_ipv6_hdr) : 0U; + + pkt = net_pkt_rx_alloc_with_buffer(iface, size, family, 0, K_NO_WAIT); + zassert_not_null(pkt, ""); + + if (family == AF_INET) { + ret = net_ipv4_create(pkt, (struct in_addr *)src, (struct in_addr *)dst); + } else if (family == AF_INET6) { + ret = net_ipv6_create(pkt, (struct in6_addr *)src, (struct in6_addr *)dst); + } + zassert_equal(ret, 0, "Cannot create %s packet (%d)", + (family == AF_INET) ? "IPv4" : "IPv6", ret); + + DBG("pkt %p: iface %p size %d sa_family %d\n", pkt, iface, size, family); + return pkt; +} + /* * Declare some fake interfaces and test their filter conditions. */ @@ -274,6 +302,8 @@ static void test_npf_eth_mac_address(void) zassert_true(npf_remove_recv_rule(&accept_matched_dst_addr), ""); zassert_false(net_pkt_filter_recv_ok(pkt), ""); zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), ""); + + net_pkt_unref(pkt); } static NPF_ETH_SRC_ADDR_MASK_MATCH(matched_src_addr_mask, mac_address_list, @@ -299,6 +329,8 @@ static void test_npf_eth_mac_addr_mask(void) /* cleanup */ zassert_true(npf_remove_all_recv_rules(), ""); + + net_pkt_unref(pkt); } ZTEST(net_pkt_filter_test_suite, test_npf_address_mask) @@ -307,4 +339,148 @@ ZTEST(net_pkt_filter_test_suite, test_npf_address_mask) test_npf_eth_mac_addr_mask(); } +/* + * IP address filtering + */ + +static struct in_addr ipv4_address_list[4] = { + { { { 192, 168, 1, 1 } } }, + { { { 192, 0, 2, 1 } } }, + { { { 172, 16, 0, 1 } } }, + { { { 10, 49, 0, 252 } } } +}; + +static struct in6_addr ipv6_address_list[4] = { + { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, +}; + +static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv4_src_addr, (void *)ipv4_address_list, + ARRAY_SIZE(ipv4_address_list), AF_INET); +static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv4_src_addr, (void *)ipv4_address_list, + ARRAY_SIZE(ipv4_address_list), AF_INET); + +static NPF_RULE(ipv4_allowlist, NET_OK, allowlist_ipv4_src_addr); +static NPF_RULE(ipv4_blocklist, NET_OK, blocklist_ipv4_src_addr); + +ZTEST(net_pkt_filter_test_suite, test_npf_ipv4_address_filtering) +{ + struct in_addr dst = { { { 192, 168, 2, 1 } } }; + struct in_addr bad_addr = { { { 192, 168, 2, 3 } } }; + struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &dst, AF_INET, + &dummy_iface_a); + struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &ipv6_address_list[1], + AF_INET6, &dummy_iface_a); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate allowlist */ + npf_insert_ipv4_recv_rule(&ipv4_allowlist); + + for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) { + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it], + sizeof(struct in_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + } + + /* And one not listed */ + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, + &bad_addr, sizeof(struct in_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* Prepare new test */ + zassert_true(npf_remove_all_ipv4_recv_rules(), ""); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate blocklist */ + npf_insert_ipv4_recv_rule(&ipv4_blocklist); + + for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) { + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it], + sizeof(struct in_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + } + + /* And one not listed */ + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, + &bad_addr, sizeof(struct in_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + + zassert_true(npf_remove_all_ipv4_recv_rules(), ""); + net_pkt_unref(pkt_v6); + net_pkt_unref(pkt_v4); +} + +static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv6_src_addr, (void *)ipv6_address_list, + ARRAY_SIZE(ipv6_address_list), AF_INET6); +static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv6_src_addr, (void *)ipv6_address_list, + ARRAY_SIZE(ipv6_address_list), AF_INET6); + +static NPF_RULE(ipv6_allowlist, NET_OK, allowlist_ipv6_src_addr); +static NPF_RULE(ipv6_blocklist, NET_OK, blocklist_ipv6_src_addr); + +ZTEST(net_pkt_filter_test_suite, test_npf_ipv6_address_filtering) +{ + struct in6_addr dst = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } }; + struct in6_addr bad_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &dst, AF_INET6, + &dummy_iface_a); + struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &ipv4_address_list[1], + AF_INET, &dummy_iface_a); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate allowlist */ + npf_insert_ipv6_recv_rule(&ipv6_allowlist); + + for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) { + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &ipv6_address_list[it], sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + } + + /* And one not listed */ + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &bad_addr, sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* Prepare new test */ + zassert_true(npf_remove_all_ipv6_recv_rules(), ""); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate blocklist */ + npf_insert_ipv6_recv_rule(&ipv6_blocklist); + + for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) { + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &ipv6_address_list[it], sizeof(struct in6_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + } + + /* And one not listed */ + memcpy((struct in6_addr *)NET_IPV4_HDR(pkt_v6)->src, + &bad_addr, sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + zassert_true(npf_remove_all_ipv6_recv_rules(), ""); + net_pkt_unref(pkt_v6); + net_pkt_unref(pkt_v4); +} + ZTEST_SUITE(net_pkt_filter_test_suite, NULL, test_npf_iface, NULL, NULL, NULL); diff --git a/tests/net/wifi/wifi_nm/CMakeLists.txt b/tests/net/wifi/wifi_nm/CMakeLists.txt new file mode 100644 index 000000000000..4a2a6013031f --- /dev/null +++ b/tests/net/wifi/wifi_nm/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(wifi_nm) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/net/wifi/wifi_nm/Kconfig b/tests/net/wifi/wifi_nm/Kconfig new file mode 100644 index 000000000000..57e1217d10a0 --- /dev/null +++ b/tests/net/wifi/wifi_nm/Kconfig @@ -0,0 +1,14 @@ +# Configuration opions for Wi-Fi test + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + + +source "Kconfig.zephyr" + +# The purpose of this Kconfig is to select the hidden symbol +config WIFI_TEST_ENABLE + bool "Enable Wi-Fi test" + default y + select WIFI + select WIFI_USE_NATIVE_NETWORKING diff --git a/tests/net/wifi/wifi_nm/prj.conf b/tests/net/wifi/wifi_nm/prj.conf new file mode 100644 index 000000000000..abeb08fca4fa --- /dev/null +++ b/tests/net/wifi/wifi_nm/prj.conf @@ -0,0 +1,19 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_WIFI_NM=y +CONFIG_NET_LOG=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y + +# Disable internal ethernet drivers as the test is self contained +# and does not need the on board driver to function. +CONFIG_ETH_DRIVER=n diff --git a/tests/net/wifi/wifi_nm/src/main.c b/tests/net/wifi/wifi_nm/src/main.c new file mode 100644 index 000000000000..0ca9e6335531 --- /dev/null +++ b/tests/net/wifi/wifi_nm/src/main.c @@ -0,0 +1,186 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define NET_LOG_LEVEL CONFIG_NET_L2_ETHERNET_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) +#else +#define DBG(fmt, ...) +#endif + +struct wifi_drv_context { + struct net_if *iface; + uint8_t mac_addr[6]; + enum ethernet_if_types eth_if_type; +}; + +static struct wifi_drv_context wifi_context; + +bool wifi_nm_op_called; +bool wifi_offload_op_called; + +static void wifi_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct wifi_drv_context *context = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + + net_if_set_link_addr(iface, context->mac_addr, + sizeof(context->mac_addr), + NET_LINK_ETHERNET); + + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + + ethernet_init(iface); +} + +static int wifi_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + ARG_UNUSED(dev); + ARG_UNUSED(params); + ARG_UNUSED(cb); + + wifi_offload_op_called = true; + + return 0; +} + +static struct wifi_mgmt_ops wifi_mgmt_api = { + .scan = wifi_scan, +}; + +static struct net_wifi_mgmt_offload api_funcs = { + .wifi_iface.iface_api.init = wifi_iface_init, + .wifi_mgmt_api = &wifi_mgmt_api, +}; + +static void generate_mac(uint8_t *mac_addr) +{ + /* 00-00-5E-00-53-xx Documentation RFC 7042 */ + mac_addr[0] = 0x00; + mac_addr[1] = 0x00; + mac_addr[2] = 0x5E; + mac_addr[3] = 0x00; + mac_addr[4] = 0x53; + mac_addr[5] = sys_rand32_get(); +} + +static int wifi_init(const struct device *dev) +{ + struct wifi_drv_context *context = dev->data; + + context->eth_if_type = L2_ETH_IF_TYPE_WIFI; + + generate_mac(context->mac_addr); + + return 0; +} + +ETH_NET_DEVICE_INIT(wlan0, "wifi_test", + wifi_init, NULL, + &wifi_context, NULL, CONFIG_ETH_INIT_PRIORITY, + &api_funcs, NET_ETH_MTU); + +static int wifi_nm_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + ARG_UNUSED(dev); + ARG_UNUSED(params); + ARG_UNUSED(cb); + + wifi_nm_op_called = true; + + return 0; +} + +static struct wifi_mgmt_ops wifi_nm_test_ops = { + .scan = wifi_nm_scan, +}; + +DEFINE_WIFI_NM_INSTANCE(test, &wifi_nm_test_ops); + +static int request_scan(void) +{ + struct net_if *iface = net_if_get_first_wifi(); + + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) { + printk("Scan request failed\n"); + + return -ENOEXEC; + } + + return 0; +} + +ZTEST(net_wifi, test_wifi_offload) +{ + + int ret; +#ifdef CONFIG_WIFI_NM + struct wifi_nm_instance *nm = wifi_nm_get_instance("test"); + + if (wifi_nm_get_instance_iface(net_if_get_first_wifi())) { + ret = wifi_nm_unregister_mgd_iface(nm, net_if_get_first_wifi()); + zassert_equal(ret, 0, "Failed to unregister managed interface"); + } +#endif /* CONFIG_WIFI_NM */ + + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_offload_op_called, "Scan callback not called"); +} + +ZTEST(net_wifi, test_wifi_nm_managed) +{ + + int ret; + struct wifi_nm_instance *nm = wifi_nm_get_instance("test"); + + zassert_equal(nm->ops, &wifi_nm_test_ops, + "Invalid wifi nm ops"); + + /* Offload: in presence of registered NM but with no managed + * interfaces. + */ + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_offload_op_called, "Scan callback not called"); + + ret = wifi_nm_register_mgd_iface(nm, net_if_get_first_wifi()); + zassert_equal(ret, 0, "Failed to register managed interface"); + + zassert_equal(nm->ops, &wifi_nm_test_ops, + "Invalid wifi nm ops"); + + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_nm_op_called, "Scan callback not called"); +} + + +ZTEST_SUITE(net_wifi, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/wifi/wifi_nm/testcase.yaml b/tests/net/wifi/wifi_nm/testcase.yaml new file mode 100644 index 000000000000..227f39feaac1 --- /dev/null +++ b/tests/net/wifi/wifi_nm/testcase.yaml @@ -0,0 +1,6 @@ +common: + depends_on: netif +tests: + net.wifi: + min_ram: 32 + tags: wifi diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt new file mode 100644 index 000000000000..a0f765546295 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(mcumgr_client) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) + +add_compile_definitions(CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER=1) diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf b/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf new file mode 100644 index 000000000000..46835a49dc78 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf @@ -0,0 +1,25 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# ZTEST config +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 + +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +# Enable mcumgr +CONFIG_MCUMGR=y +CONFIG_SMP_CLIENT=y +CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER=1 +CONFIG_MCUMGR_GRP_OS_CLIENT=y +CONFIG_MCUMGR_GRP_IMG_CLIENT=y +CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO=y +CONFIG_MCUMGR_GRP_OS_CLIENT_RESET=y + +# Extend System Workqueue stack size +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c new file mode 100644 index 000000000000..5bd784a3954b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "smp_stub.h" +#include "img_gr_stub.h" + +static struct mcumgr_image_data image_dummy_info[2]; +static size_t test_offset; +static uint8_t *image_hash_ptr; + +#define ZCBOR_ENCODE_FLAG(zse, label, value) \ + (zcbor_tstr_put_lit(zse, label) && zcbor_bool_put(zse, value)) + +void img_upload_stub_init(void) +{ + test_offset = 0; +} + +void img_upload_response(size_t offset, int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + if (status) { + ok = zcbor_map_start_encode(zse, 4) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4); + } else { + /* Drop Status away from response */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4); + } + + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_fail_response(int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_read_response(int count) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + ok = zcbor_map_start_encode(zse, 15) && zcbor_tstr_put_lit(zse, "images") && + zcbor_list_start_encode(zse, 2); + + for (int i = 0; ok && i < count; i++) { + + ok = zcbor_map_start_encode(zse, 15) && + ((zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, image_dummy_info[i].img_num))) && + zcbor_tstr_put_lit(zse, "slot") && + zcbor_uint32_put(zse, image_dummy_info[i].slot_num) && + zcbor_tstr_put_lit(zse, "version") && + zcbor_tstr_put_term(zse, image_dummy_info[i].version) && + + zcbor_tstr_put_term(zse, "hash") && + zcbor_bstr_encode_ptr(zse, image_dummy_info[i].hash, IMG_MGMT_HASH_LEN) && + ZCBOR_ENCODE_FLAG(zse, "bootable", image_dummy_info[i].flags.bootable) && + ZCBOR_ENCODE_FLAG(zse, "pending", image_dummy_info[i].flags.pending) && + ZCBOR_ENCODE_FLAG(zse, "confirmed", image_dummy_info[i].flags.confirmed) && + ZCBOR_ENCODE_FLAG(zse, "active", image_dummy_info[i].flags.active) && + ZCBOR_ENCODE_FLAG(zse, "permanent", image_dummy_info[i].flags.permanent) && + zcbor_map_end_encode(zse, 15); + } + + ok = ok && zcbor_list_end_encode(zse, 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER); + + ok = ok && zcbor_map_end_encode(zse, 15); + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_erase_response(int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_state_write_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + int rc; + struct zcbor_string hash; + bool confirm; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm), + ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash) + }; + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + + decoded = 0; + /* Init buffer values */ + confirm = false; + hash.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc) { + printf("Corrupted data %d\r\n", rc); + img_fail_response(MGMT_ERR_EINVAL); + return; + } + if (hash.len) { + printf("HASH %d", hash.len); + if (memcmp(hash.value, image_dummy_info[1].hash, 32) == 0) { + if (confirm) { + /* Set Permanent bit */ + image_dummy_info[1].flags.permanent = true; + } else { + /* Set pending */ + image_dummy_info[1].flags.pending = true; + } + img_read_response(2); + } else { + img_fail_response(MGMT_ERR_EINVAL); + } + } else { + if (confirm) { + image_dummy_info[0].flags.confirmed = true; + } + img_read_response(2); + } +} + +void img_upload_init_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + int rc; + uint32_t image; + struct zcbor_string sha, data; + size_t decoded, length, offset; + struct zcbor_map_decode_key_val list_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &image), + ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &data), + ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &length), + ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &offset), + ZCBOR_MAP_DECODE_KEY_DECODER("sha", zcbor_bstr_decode, &sha) + }; + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + + decoded = 0; + /* Init buffer values */ + sha.len = 0; + data.len = 0; + length = SIZE_MAX; + offset = SIZE_MAX; + image = UINT32_MAX; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc || data.len == 0 || offset == SIZE_MAX || image != TEST_IMAGE_NUM) { + printf("Corrupted data %d or %d data len\r\n", rc, data.len); + img_upload_response(0, MGMT_ERR_EINVAL); + return; + } + + if (sha.len) { + if (memcmp(sha.value, image_hash_ptr, 32)) { + printf("Hash not same\r\n"); + img_upload_response(0, MGMT_ERR_EINVAL); + return; + } + } + + if (offset != test_offset) { + printf("Offset not exepected %d vs received %d\r\n", test_offset, offset); + } + + if (offset == 0) { + if (length != TEST_IMAGE_SIZE) { + img_upload_response(0, MGMT_ERR_EINVAL); + } + } + + test_offset += data.len; + printf("Upload offset %d\r\n", test_offset); + if (test_offset <= TEST_IMAGE_SIZE) { + img_upload_response(test_offset, MGMT_ERR_EOK); + } else { + img_upload_response(0, MGMT_ERR_EINVAL); + } +} + +void img_gr_stub_data_init(uint8_t *hash_ptr) +{ + image_hash_ptr = hash_ptr; + for (int i = 0; i < 32; i++) { + image_hash_ptr[i] = i; + image_dummy_info[0].hash[i] = i + 32; + image_dummy_info[1].hash[i] = i + 64; + } + /* Set dummy image list data */ + for (int i = 0; i < 2; i++) { + image_dummy_info[i].img_num = i; + image_dummy_info[i].slot_num = i; + /* Write version */ + snprintf(image_dummy_info[i].version, IMG_MGMT_VER_MAX_STR_LEN, "1.1.%u", i); + image_dummy_info[i].version[sizeof(image_dummy_info[i].version) - 1] = '\0'; + image_dummy_info[i].flags.bootable = true; + image_dummy_info[i].flags.pending = false; + if (i) { + image_dummy_info[i].flags.confirmed = false; + image_dummy_info[i].flags.active = false; + } else { + image_dummy_info[i].flags.confirmed = true; + image_dummy_info[i].flags.active = true; + } + image_dummy_info[i].flags.permanent = false; + } +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h new file mode 100644 index 000000000000..95fdbc8203b2 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_IMG_GR_STUB_ +#define H_IMG_GR_STUB_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define TEST_IMAGE_NUM 1 +#define TEST_IMAGE_SIZE 2048 +#define TEST_SLOT_NUMBER 2 + +void img_upload_stub_init(void); +void img_upload_response(size_t offset, int status); +void img_fail_response(int status); +void img_read_response(int count); +void img_erase_response(int status); +void img_upload_init_verify(struct net_buf *nb); +void img_state_write_verify(struct net_buf *nb); +void img_gr_stub_data_init(uint8_t *hash_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* H_IMG_GR_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c new file mode 100644 index 000000000000..a15e82f17a64 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* Include stubbed test helpers */ +#include "smp_stub.h" +#include "img_gr_stub.h" +#include "os_gr_stub.h" + +/* IMG group data */ +static uint8_t image_hash[32]; +static struct mcumgr_image_data image_info[2]; +static uint8_t image_dummy[1024]; + +static const char os_echo_test[] = "TestString"; +static struct smp_client_object smp_client; +static struct img_mgmt_client img_client; +static struct os_mgmt_client os_client; + +ZTEST(mcumgr_client, img_upload) +{ + int rc; + struct mcumgr_image_upload response; + + smp_stub_set_rx_data_verify(NULL); + img_upload_stub_init(); + + img_mgmt_client_init(&img_client, &smp_client, 2, image_info); + + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + /* Start upload and test Timeout */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + zassert_equal(MGMT_ERR_ETIMEOUT, response.status, "Expected to receive %d response %d\n", + MGMT_ERR_ETIMEOUT, response.status); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + /* Start upload and test Timeout */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + zassert_equal(MGMT_ERR_ETIMEOUT, response.status, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, response.status); + + smp_client_send_status_stub(MGMT_ERR_EOK); + + /* Allocate response buf */ + img_upload_response(0, MGMT_ERR_EINVAL); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EINVAL, rc, "Expected to receive %d response %d", MGMT_ERR_EINVAL, + rc); + zassert_equal(MGMT_ERR_EINVAL, response.status, "Expected to receive %d response %d", + MGMT_ERR_EINVAL, response.status); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d\n", MGMT_ERR_EOK, rc); + img_upload_response(1024, MGMT_ERR_EOK); + + smp_stub_set_rx_data_verify(img_upload_init_verify); + img_upload_stub_init(); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(1024, response.image_upload_offset, + "Expected to receive offset %d response %d", 1024, + response.image_upload_offset); + /* Send last frame from image */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(TEST_IMAGE_SIZE, response.image_upload_offset, + "Expected to receive offset %d response %d", TEST_IMAGE_SIZE, + response.image_upload_offset); + + /* Test without hash */ + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, NULL); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + img_upload_stub_init(); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(1024, response.image_upload_offset, + "Expected to receive offset %d response %d", 1024, + response.image_upload_offset); + /* Send last frame from image */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(TEST_IMAGE_SIZE, response.image_upload_offset, + "Expected to receive offset %d response %d", TEST_IMAGE_SIZE, + response.image_upload_offset); +} + +ZTEST(mcumgr_client, img_erase) +{ + int rc; + + smp_client_send_status_stub(MGMT_ERR_EOK); + + /* Test timeout */ + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + + /* Test erase fail */ + img_erase_response(MGMT_ERR_EINVAL); + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_EINVAL, rc, "Expected to receive %d response %d", MGMT_ERR_EINVAL, + rc); + /* Tesk ok */ + img_erase_response(MGMT_ERR_EOK); + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +ZTEST(mcumgr_client, image_state_read) +{ + int rc; + struct mcumgr_image_state res_buf; + + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + /* Testing read successfully 1 image info and print that */ + img_read_response(1); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(1, res_buf.image_list_length, "Expected to receive %d response %d", 1, + res_buf.image_list_length); + img_read_response(2); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); +} + +ZTEST(mcumgr_client, image_state_set) +{ + int rc; + char hash[32]; + struct mcumgr_image_state res_buf; + + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = img_mgmt_client_state_write(&img_client, NULL, false, &res_buf); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + + printf("Timeout OK\r\n"); + /* Read secondary image hash for testing */ + img_read_response(2); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(false, image_info[1].flags.pending, "Expected to receive %d response %d", + false, image_info[1].flags.pending); + /* Copy hash for set pending flag */ + memcpy(hash, image_info[1].hash, 32); + printf("Read OK\r\n"); + + /* Read secondary image hash for testing */ + smp_stub_set_rx_data_verify(img_state_write_verify); + rc = img_mgmt_client_state_write(&img_client, hash, false, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(true, image_info[1].flags.pending, "Expected to receive %d response %d", + true, image_info[1].flags.pending); + /* Test to set confirmed bit */ + image_info[0].flags.confirmed = false; + smp_stub_set_rx_data_verify(img_state_write_verify); + rc = img_mgmt_client_state_write(&img_client, NULL, true, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(true, image_info[0].flags.confirmed, "Expected to receive %d response %d", + true, image_info[0].flags.confirmed); +} + +ZTEST(mcumgr_client, os_reset) +{ + int rc; + + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); + + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = os_mgmt_client_reset(&os_client); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + /* Testing reset successfully handling */ + os_reset_response(); + rc = os_mgmt_client_reset(&os_client); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +ZTEST(mcumgr_client, os_echo) +{ + int rc; + + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = os_mgmt_client_echo(&os_client, os_echo_test); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + /* Test successfully operation */ + smp_stub_set_rx_data_verify(os_echo_verify); + rc = os_mgmt_client_echo(&os_client, os_echo_test); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +static void *setup_custom_os(void) +{ + stub_smp_client_transport_register(); + smp_client_object_init(&smp_client, SMP_SERIAL_TRANSPORT); + os_mgmt_client_init(&os_client, &smp_client); + img_mgmt_client_init(&img_client, &smp_client, 2, image_info); + + img_gr_stub_data_init(image_hash); + os_stub_init(os_echo_test); + return NULL; +} + +static void cleanup_test(void *p) +{ + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); +} + +/* Main test set */ +ZTEST_SUITE(mcumgr_client, NULL, setup_custom_os, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c new file mode 100644 index 000000000000..888f00dba38d --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "smp_stub.h" + +static const char *echo_ptr; + +void os_stub_init(const char *echo_str) +{ + echo_ptr = echo_str; +} + +void os_reset_response(void) +{ + struct net_buf *nb; + + nb = smp_response_buf_allocation(); + if (nb) { + nb->len = 0; + } +} + +static void os_echo_response(int status, struct zcbor_string *echo_data) +{ + struct net_buf *nb; + zcbor_state_t zse[3 + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + if (status) { + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + } else { + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "r") && + zcbor_tstr_encode_ptr(zse, echo_data->value, echo_data->len) && + zcbor_map_end_encode(zse, 2); + } + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void os_echo_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[3 + 2]; + int rc; + int response_status; + struct zcbor_string echo_data; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("d", zcbor_tstr_decode, &echo_data) + }; + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1); + echo_data.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc || !echo_data.len) { + printf("Corrupted data %d or no echo data %d\r\n", rc, echo_data.len); + response_status = MGMT_ERR_EINVAL; + } else if (memcmp(echo_data.value, echo_ptr, echo_data.len)) { + response_status = MGMT_ERR_EINVAL; + } else { + response_status = MGMT_ERR_EOK; + } + + os_echo_response(response_status, &echo_data); +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h new file mode 100644 index 000000000000..ec6f3408979f --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_OS_GR_STUB_ +#define H_OS_GR_STUB_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void os_stub_init(const char *echo_str); +void os_reset_response(void); +void os_echo_verify(struct net_buf *nb); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_GR_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c new file mode 100644 index 000000000000..9b476082dd8e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "smp_stub.h" + +K_THREAD_STACK_DEFINE(smp_stub_work_queue_stack, CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE); + +static mcmgr_client_data_check_fn rx_verify_cb; +static int send_client_failure; +static struct net_buf *response_buf; +static struct smp_hdr res_hdr; +static struct smp_transport smpt_test; +static struct smp_client_transport_entry smp_client_transport; +static struct k_work_q smp_work_queue; +static struct k_work stub_work; + +static const struct k_work_queue_config smp_work_queue_config = { + .name = "mcumgr smp" +}; + +void smp_stub_set_rx_data_verify(mcmgr_client_data_check_fn cb) +{ + rx_verify_cb = cb; +} + +void smp_client_send_status_stub(int status) +{ + send_client_failure = status; +} + +struct net_buf *smp_response_buf_allocation(void) +{ + smp_client_response_buf_clean(); + + response_buf = smp_packet_alloc(); + + return response_buf; +} + +void smp_client_response_buf_clean(void) +{ + if (response_buf) { + smp_client_buf_free(response_buf); + response_buf = NULL; + } +} + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + + +static uint16_t smp_uart_get_mtu(const struct net_buf *nb) +{ + return 256; +} + +static int smp_uart_tx_pkt(struct net_buf *nb) +{ + if (send_client_failure) { + /* Test Send cmd fail */ + return send_client_failure; + } + + memcpy(&res_hdr, nb->data, sizeof(res_hdr)); + res_hdr.nh_len = sys_be16_to_cpu(res_hdr.nh_len); + res_hdr.nh_group = sys_be16_to_cpu(res_hdr.nh_group); + res_hdr.nh_op += 1; /* Request to response */ + + /* Validate Input data if callback is configured */ + if (rx_verify_cb) { + rx_verify_cb(nb); + } + + /* Free tx buf */ + net_buf_unref(nb); + + if (response_buf) { + k_work_submit_to_queue(&smp_work_queue, &stub_work); + } + + return 0; +} + +static void smp_client_handle_reqs(struct k_work *work) +{ + if (response_buf) { + smp_client_single_response(response_buf, &res_hdr); + } +} + +void stub_smp_client_transport_register(void) +{ + + smpt_test.functions.output = smp_uart_tx_pkt; + smpt_test.functions.get_mtu = smp_uart_get_mtu; + + smp_transport_init(&smpt_test); + smp_client_transport.smpt = &smpt_test; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); + + + k_work_queue_init(&smp_work_queue); + + k_work_queue_start(&smp_work_queue, smp_stub_work_queue_stack, + K_THREAD_STACK_SIZEOF(smp_stub_work_queue_stack), + CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_THREAD_PRIO, &smp_work_queue_config); + + k_work_init(&stub_work, smp_client_handle_reqs); +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h new file mode 100644 index 000000000000..c8668a033d2e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_SMP_STUB_ +#define H_SMP_STUB_ + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*mcmgr_client_data_check_fn)(struct net_buf *nb); + +void smp_stub_set_rx_data_verify(mcmgr_client_data_check_fn cb); +void smp_client_send_status_stub(int status); +void smp_client_response_buf_clean(void); +struct net_buf *smp_response_buf_allocation(void); +void stub_smp_client_transport_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_SMP_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt new file mode 100644 index 000000000000..2d5fea068dbc --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(smp_client) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/mgmt/mcumgr/smp_client/prj.conf b/tests/subsys/mgmt/mcumgr/smp_client/prj.conf new file mode 100644 index 000000000000..22740657b784 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/prj.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# ZTEST config +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 + +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_CRC=y +CONFIG_ZCBOR=y +CONFIG_MCUMGR=y +CONFIG_SMP_CLIENT=y + +# Extend System Workqueue stack size +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/main.c b/tests/subsys/mgmt/mcumgr/smp_client/src/main.c new file mode 100644 index 000000000000..be1a3968274a --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/main.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_transport_stub.h" + +static struct net_buf *buf[5]; + +static uint32_t testing_user_data; +static void *response_ptr; +static struct net_buf *res_buf; +static struct smp_client_object smp_client; + +int smp_client_res_cb(struct net_buf *nb, void *user_data) +{ + res_buf = nb; + response_ptr = user_data; + return 0; +} + +ZTEST(smp_client, buf_alloc) +{ + struct smp_client_object smp_client; + + /* Allocate all 4 buffer's and verify that 5th fail */ + for (int i = 0; i < 5; i++) { + buf[i] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, + MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (i == 4) { + zassert_is_null(buf[i], "Buffer was not Null"); + } else { + zassert_not_null(buf[i], "Buffer was Null"); + zassert_equal(sizeof(struct smp_hdr), buf[i]->len, + "Expected to receive %d response %d", + sizeof(struct smp_hdr), buf[i]->len); + } + } + + for (int i = 0; i < 4; i++) { + smp_client_buf_free(buf[i]); + buf[i] = NULL; + } +} + +ZTEST(smp_client, msg_send_timeout) +{ + struct net_buf *nb; + + int rc; + + nb = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(nb, "Buffer was Null"); + rc = smp_client_send_cmd(&smp_client, nb, smp_client_res_cb, &testing_user_data, 2); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + k_sleep(K_SECONDS(3)); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_equal_ptr(response_ptr, &testing_user_data, "User data not returned correctly"); +} + +ZTEST(smp_client, msg_response_handler) +{ + struct smp_hdr dst_hdr; + int rc; + + + response_ptr = NULL; + res_buf = NULL; + + buf[0] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(buf[0], "Buffer was Null"); + rc = smp_client_send_cmd(&smp_client, buf[0], smp_client_res_cb, &testing_user_data, 8); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + buf[1] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(buf[0], "Buffer was Null"); + /* Read Pushed packet Header */ + smp_transport_read_hdr(buf[0], &dst_hdr); + smp_client_single_response(buf[1], &dst_hdr); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_is_null(response_ptr, "NULL pointer was not returned"); + /* Set Correct OP */ + dst_hdr.nh_op = MGMT_OP_WRITE_RSP; + smp_client_single_response(buf[1], &dst_hdr); + zassert_equal_ptr(res_buf, buf[1], "Response Buf not correct"); + zassert_equal_ptr(response_ptr, &testing_user_data, "User data not returned correctly"); + response_ptr = NULL; + res_buf = NULL; + smp_client_single_response(buf[1], &dst_hdr); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_is_null(response_ptr, "NULL pointer was not returned"); +} + +static void *setup_custom_os(void) +{ + /* Registre tarnsport and init client */ + stub_smp_client_transport_register(); + smp_client_object_init(&smp_client, SMP_SERIAL_TRANSPORT); + return NULL; +} + +static void cleanup_test(void *p) +{ + for (int i = 0; i < 5; i++) { + if (buf[i]) { + smp_client_buf_free(buf[i]); + buf[i] = NULL; + } + } +} + +/* Main test set */ +ZTEST_SUITE(smp_client, NULL, setup_custom_os, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c new file mode 100644 index 000000000000..d3248755e5ab --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct smp_transport smpt_test; +static struct smp_client_transport_entry smp_client_transport; + +/* Stubbed functions */ + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + + + + +static uint16_t smp_uart_get_mtu(const struct net_buf *nb) +{ + return 256; +} + +static int smp_uart_tx_pkt(struct net_buf *nb) +{ + smp_packet_free(nb); + return 0; +} + +void stub_smp_client_transport_register(void) +{ + + smpt_test.functions.output = smp_uart_tx_pkt; + smpt_test.functions.get_mtu = smp_uart_get_mtu; + + smp_transport_init(&smpt_test); + smp_client_transport.smpt = &smpt_test; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); +} diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h new file mode 100644 index 000000000000..9046aff622c0 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_OS_GR_STUB_ +#define H_OS_GR_STUB_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr); +void stub_smp_client_transport_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_GR_STUB_ */ diff --git a/tests/subsys/pm/device_wakeup_api/Kconfig b/tests/subsys/pm/device_wakeup_api/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/device_wakeup_api/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/policy_api/Kconfig b/tests/subsys/pm/policy_api/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/policy_api/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/policy_api/src/main.c b/tests/subsys/pm/policy_api/src/main.c index c29c7eb86d0c..8ea72d7e3f03 100644 --- a/tests/subsys/pm/policy_api/src/main.c +++ b/tests/subsys/pm/policy_api/src/main.c @@ -9,6 +9,20 @@ #include #include +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + ARG_UNUSED(state); +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + irq_unlock(0); +} + #ifdef CONFIG_PM_POLICY_DEFAULT /** * @brief Test the behavior of pm_policy_next_state() when diff --git a/tests/subsys/pm/power_mgmt/Kconfig b/tests/subsys/pm/power_mgmt/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/power_mgmt/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/power_mgmt_multicore/Kconfig b/tests/subsys/pm/power_mgmt_multicore/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/power_mgmt_multicore/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/west.yml b/west.yml index 215cc46f50ba..94af73a2d792 100644 --- a/west.yml +++ b/west.yml @@ -170,7 +170,7 @@ manifest: groups: - hal - name: hal_nordic - revision: a1c3e0fbaafda091139b8744becd4853ada2f747 + revision: 9ae7c765985ebdea3d9b98c0d3b154794f0b47cf path: modules/hal/nordic groups: - hal @@ -284,13 +284,13 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 37c571ef7c4a86dad852566fc43eb36f42534e9f + revision: fa1daebb0f6f7ef135f9d2128590adfd88c0af44 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad path: modules/lib/open-amp - name: openthread - revision: d9abe3071c0131a4adb5d7e7451319b735e6d855 + revision: 37fb77098982d17555dd7a3f58832714bb9df56e path: modules/lib/openthread - name: picolibc path: modules/lib/picolibc