From 2392913da6a72acd3af765e3d0929cb18a5594f1 Mon Sep 17 00:00:00 2001 From: Martin Girardot <165289184+Martin-NXP@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:49:08 +0200 Subject: [PATCH] [NXP][rw61x][k32w1] Rework reference apps (#35172) * [NXP][third_party] Add new NXP SDK support Signed-off-by: Martin Girardot * [NXP][examples] Update examples to support new NXP SDK Signed-off-by: Martin Girardot * [NXP][src] Update src to support new NXP SDK Signed-off-by: Martin Girardot * [NXP][docs] Update docs to support new NXP SDK Signed-off-by: Martin Girardot * [NXP][scripts] Update scripts to support new NXP SDK Signed-off-by: Martin Girardot * [NXP][workflows] Update rw61x workflow to support new NXP SDK Signed-off-by: Martin Girardot * [NXP][submodules] Update submodules to support new NXP SDK Signed-off-by: Martin Girardot * Restyled by gn * Restyled by prettier-markdown * [NXP] Spelling fixes Signed-off-by: Martin Girardot * [NXP][examples][common] Add common README file for contact sensor and lighting app Add mcxw71/k32w1 specific OTA guide in nxp docs area. Signed-off-by: marius-alex-tache * Restyled by prettier-markdown * [NXP][rw61x][examples][laundry-washer][thermostat][all-custer-app] Updating path to new nxp_matter_support repo Signed-off-by: Gatien Chapon * [NXP][docs] Update RW61x OTA readme to specify the upgrade type used Signed-off-by: Dina Benamar * [NXP] Doc and spelling fixes Signed-off-by: Martin Girardot * Restyled by gn * Restyled by prettier-markdown * Restyled by prettier-markdown * [NXP][workflows] Update docker image version Signed-off-by: Martin Girardot --------- Signed-off-by: Martin Girardot Signed-off-by: marius-alex-tache Signed-off-by: Gatien Chapon Signed-off-by: Dina Benamar Co-authored-by: Restyled.io Co-authored-by: marius-alex-tache Co-authored-by: Gatien Chapon Co-authored-by: Dina Benamar --- .github/workflows/examples-nxp.yaml | 2 +- docs/guides/nxp/nxp_manufacturing_flow.md | 76 +- docs/guides/nxp/nxp_mcxw71_ota_guide.md | 179 ++++ .../nxp/nxp_rw61x_ota_software_update.md | 71 +- .../all-clusters-app/nxp/rt/rw61x/BUILD.gn | 27 +- .../all-clusters-app/nxp/rt/rw61x/README.md | 98 ++- examples/contact-sensor-app/nxp/README.md | 195 +++++ examples/contact-sensor-app/nxp/k32w1/.gn | 2 +- .../contact-sensor-app/nxp/k32w1/BUILD.gn | 28 +- .../contact-sensor-app/nxp/k32w1/README.md | 452 ++-------- .../contact-sensor-app/nxp/k32w1/args.gni | 1 + .../laundry-washer-app/nxp/rt/rw61x/BUILD.gn | 18 +- examples/lighting-app/nxp/README.md | 137 +++ examples/lighting-app/nxp/k32w1/.gn | 2 +- examples/lighting-app/nxp/k32w1/BUILD.gn | 30 +- examples/lighting-app/nxp/k32w1/README.md | 450 ++-------- examples/lighting-app/nxp/k32w1/args.gni | 5 +- .../source/CommonDeviceCallbacks.cpp | 3 +- .../app/ldscripts/k32w1_app.ld | 0 .../project_include/freeRTOS/FreeRTOSConfig.h | 0 .../openthread/OpenThreadConfig.h | 0 .../app/support/BUILD.gn | 0 .../app/support/FreeRtosHooks.c | 0 .../app/support/FreeRtosHooks.h | 0 .../app/support/Memconfig.cpp | 0 .../board/peripherals.c | 0 .../board/peripherals.h | 0 .../button/ButtonManager.cpp | 0 .../button/ButtonManager.h | 0 .../clusters/Identify.cpp | 0 .../doc/images/debug_k32w1.jpg | Bin .../doc/images/import_demo.jpg | Bin .../doc/images/installed_sdks.jpg | Bin .../doc/images/k32w1-evk.jpg | Bin .../doc/images/mcux-sdk-download.jpg | Bin .../doc/images/new_project.jpg | Bin .../doc/images/ota_topology.JPG | Bin .../source/AppFactoryDataExample.cpp | 0 .../OperationalKeystore.cpp | 0 .../{k32w1 => mcxw71_k32w1}/ota/OtaUtils.cpp | 0 .../{k32w1 => mcxw71_k32w1}/rpc/AppRpc.cpp | 0 .../util/LedDimmer.cpp | 0 .../{k32w1 => mcxw71_k32w1}/util/LedOnOff.cpp | 0 .../util/LightingManagerDimmable.cpp | 0 .../util/LightingManagerDimmable.h | 0 .../source/AppFactoryDataExample.cpp | 11 + examples/thermostat/nxp/rt/rw61x/BUILD.gn | 18 +- scripts/build/builders/nxp.py | 9 +- scripts/setup/nxp/update_nxp_sdk.py | 120 --- .../nxp/factory_data_generator/generate.py | 17 +- .../nxp/common/ConfigurationManagerImpl.cpp | 1 - .../nxp/common/ConnectivityManagerImpl.cpp | 153 +++- .../nxp/common/ConnectivityManagerImpl.h | 15 +- src/platform/nxp/common/DnssdImpl.cpp | 793 +++++++++++------- src/platform/nxp/common/NXPConfig.h | 2 +- src/platform/nxp/common/ram_storage.c | 8 +- .../BLEManagerImpl.cpp | 2 +- .../{k32w1 => mcxw71_k32w1}/BLEManagerImpl.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/BUILD.gn | 8 +- .../BlePlatformConfig.h | 0 .../CHIPCryptoPalK32W1.cpp | 0 .../CHIPDevicePlatformConfig.h | 0 .../CHIPDevicePlatformEvent.h | 0 .../CHIPPlatformConfig.h | 0 .../ConfigurationManagerImpl.cpp | 2 +- .../ConfigurationManagerImpl.h | 2 +- .../ConnectivityManagerImpl.cpp | 0 .../ConnectivityManagerImpl.h | 0 .../DiagnosticDataProviderImpl.cpp | 2 +- .../DiagnosticDataProviderImpl.h | 0 .../FactoryDataDriverImpl.cpp | 2 +- .../FactoryDataDriverImpl.h | 0 .../FactoryDataProviderImpl.cpp | 2 +- .../FactoryDataProviderImpl.h | 0 .../InetPlatformConfig.h | 0 .../{k32w1 => mcxw71_k32w1}/K32W1Config.cpp | 2 +- .../nxp/{k32w1 => mcxw71_k32w1}/K32W1Config.h | 0 .../K32W1PersistentStorageOpKeystore.cpp | 0 .../K32W1PersistentStorageOpKeystore.h | 0 .../KeyValueStoreManagerImpl.cpp | 2 +- .../KeyValueStoreManagerImpl.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/Logging.cpp | 0 .../{k32w1 => mcxw71_k32w1}/LowPowerHooks.cpp | 0 .../OTAFirmwareProcessor.cpp | 2 +- .../OTAFirmwareProcessor.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/OTAHooks.cpp | 4 +- .../PlatformManagerImpl.cpp | 6 +- .../PlatformManagerImpl.h | 0 .../{k32w1 => mcxw71_k32w1}/SMU2Manager.cpp | 0 .../nxp/{k32w1 => mcxw71_k32w1}/SMU2Manager.h | 0 .../SystemPlatformConfig.h | 0 .../SystemTimeSupport.cpp | 0 .../ThreadStackManagerImpl.cpp | 2 +- .../ThreadStackManagerImpl.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/args.gni | 12 +- .../ble_function_mux.c | 0 .../ble_function_mux.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/gatt_db.h | 0 .../{k32w1 => mcxw71_k32w1}/gatt_uuid128.h | 0 .../k32w1-chip-mbedtls-config.h | 0 .../nxp/{k32w1 => mcxw71_k32w1}/ram_storage.c | 0 .../nxp/{k32w1 => mcxw71_k32w1}/ram_storage.h | 0 src/platform/nxp/rt/rw61x/BUILD.gn | 56 +- .../nxp/rt/rw61x/CHIPPlatformConfig.h | 2 +- src/platform/nxp/rt/rw61x/ELSFactoryData.c | 453 ---------- src/platform/nxp/rt/rw61x/ELSFactoryData.h | 247 ------ .../rt/rw61x/FactoryDataProviderEncImpl.cpp | 481 +++++++++++ .../nxp/rt/rw61x/FactoryDataProviderEncImpl.h | 87 ++ .../nxp/rt/rw61x/FactoryDataProviderImpl.cpp | 674 ++------------- .../nxp/rt/rw61x/FactoryDataProviderImpl.h | 4 +- .../nxp/rt/rw61x/PlatformManagerImpl.cpp | 6 +- src/platform/nxp/rt/rw61x/args.gni | 10 +- third_party/nxp/nxp_matter_support | 2 +- third_party/openthread/ot-nxp | 2 +- .../nxp/{k32w1 => mcxw71_k32w1}/BUILD.gn | 6 +- .../platforms/nxp/rt/rw61x/BUILD.gn | 28 +- 116 files changed, 2219 insertions(+), 2812 deletions(-) create mode 100644 docs/guides/nxp/nxp_mcxw71_ota_guide.md create mode 100644 examples/contact-sensor-app/nxp/README.md create mode 100644 examples/lighting-app/nxp/README.md rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/ldscripts/k32w1_app.ld (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/project_include/freeRTOS/FreeRTOSConfig.h (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/project_include/openthread/OpenThreadConfig.h (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/support/BUILD.gn (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/support/FreeRtosHooks.c (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/support/FreeRtosHooks.h (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/app/support/Memconfig.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/board/peripherals.c (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/board/peripherals.h (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/button/ButtonManager.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/button/ButtonManager.h (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/clusters/Identify.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/debug_k32w1.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/import_demo.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/installed_sdks.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/k32w1-evk.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/mcux-sdk-download.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/new_project.jpg (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/doc/images/ota_topology.JPG (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/factory_data/source/AppFactoryDataExample.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/operational_keystore/OperationalKeystore.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/ota/OtaUtils.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/rpc/AppRpc.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/util/LedDimmer.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/util/LedOnOff.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/util/LightingManagerDimmable.cpp (100%) rename examples/platform/nxp/{k32w1 => mcxw71_k32w1}/util/LightingManagerDimmable.h (100%) delete mode 100755 scripts/setup/nxp/update_nxp_sdk.py rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/BLEManagerImpl.cpp (98%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/BLEManagerImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/BUILD.gn (96%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/BlePlatformConfig.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/CHIPCryptoPalK32W1.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/CHIPDevicePlatformConfig.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/CHIPDevicePlatformEvent.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/CHIPPlatformConfig.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ConfigurationManagerImpl.cpp (99%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ConfigurationManagerImpl.h (98%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ConnectivityManagerImpl.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ConnectivityManagerImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/DiagnosticDataProviderImpl.cpp (99%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/DiagnosticDataProviderImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/FactoryDataDriverImpl.cpp (98%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/FactoryDataDriverImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/FactoryDataProviderImpl.cpp (99%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/FactoryDataProviderImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/InetPlatformConfig.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/K32W1Config.cpp (99%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/K32W1Config.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/K32W1PersistentStorageOpKeystore.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/K32W1PersistentStorageOpKeystore.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/KeyValueStoreManagerImpl.cpp (99%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/KeyValueStoreManagerImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/Logging.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/LowPowerHooks.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/OTAFirmwareProcessor.cpp (98%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/OTAFirmwareProcessor.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/OTAHooks.cpp (97%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/PlatformManagerImpl.cpp (96%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/PlatformManagerImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/SMU2Manager.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/SMU2Manager.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/SystemPlatformConfig.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/SystemTimeSupport.cpp (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ThreadStackManagerImpl.cpp (98%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ThreadStackManagerImpl.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/args.gni (89%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ble_function_mux.c (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ble_function_mux.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/gatt_db.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/gatt_uuid128.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/k32w1-chip-mbedtls-config.h (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ram_storage.c (100%) rename src/platform/nxp/{k32w1 => mcxw71_k32w1}/ram_storage.h (100%) delete mode 100644 src/platform/nxp/rt/rw61x/ELSFactoryData.c delete mode 100644 src/platform/nxp/rt/rw61x/ELSFactoryData.h create mode 100644 src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp create mode 100644 src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h rename third_party/openthread/platforms/nxp/{k32w1 => mcxw71_k32w1}/BUILD.gn (93%) diff --git a/.github/workflows/examples-nxp.yaml b/.github/workflows/examples-nxp.yaml index 04094f0b20480d..050751457645d4 100644 --- a/.github/workflows/examples-nxp.yaml +++ b/.github/workflows/examples-nxp.yaml @@ -150,7 +150,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-rw61x:74 + image: ghcr.io/project-chip/chip-build-nxp:74 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/docs/guides/nxp/nxp_manufacturing_flow.md b/docs/guides/nxp/nxp_manufacturing_flow.md index bad70db294a9ae..cb8431cc3b3083 100644 --- a/docs/guides/nxp/nxp_manufacturing_flow.md +++ b/docs/guides/nxp/nxp_manufacturing_flow.md @@ -247,24 +247,58 @@ adding the following gn argument `chip_use_plain_dac_key=true`. Supported platforms: -- RW61X - `src/plaftorm/nxp/rt/rw61x/FactoryDataProviderImpl.h` - -For platforms that have a secure subsystem (`SE50`), the DAC private key can be -converted to an encrypted blob. This blob will overwrite the DAC private key in -factory data and will be imported in the `SE50` before to sign, by the factory -data provider instance. - -The conversion process shall happen at manufacturing time and should be run one -time only: - -- Write factory data binary. -- Build the application with - `chip_with_factory_data=1 chip_convert_dac_private_key=1` set. -- Write the application to the board and let it run. - -After the conversion process: - -- Make sure the application is built with `chip_with_factory_data=1`, but - without `chip_convert_dac_private_key` arg, since conversion already - happened. -- Write the application to the board. +- RW61X + +there are three implementations for factory data protection + +- whole factory data protection with AES encryption ( chip_with_factory_data=1 + chip_enable_secure_whole_factory_data=true ) + `examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp`\ + `src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp` + +- only dac private key protection ( chip_with_factory_data=1 + chip_enable_secure_dac_private_key_storage=true ) + `examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp` + \ + `src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp` + +- whole factory data protection with hard-coded AES key ( + chip_with_factory_data=1 ) + `examples/platform/nxp/common/factory_data/source/AppFactoryDataDefaultImpl.cpp` + \ + `src/platform/nxp/common/factory_data/FactoryDataProviderFwkImpl.cpp` + +for the first one, the whole factory data is encrypted by an AES-256 key, the +AES key can be passed through serial link when in factory production mode, and +will be provisioned into Edge Lock, and the returned AES Key blob (wrapped key) +can be stored in the end of factory data region in TLV format. for the +decryption process, the blob is retrieved and provisioned into Edge Lock and the +whole factory data can be decrypted using the returned key index in Edge Lock. +Compared with only dac private key protection solution, this solution can avoid +tampering with the original factory data. + +the factory data should be encrypted by an AES-256 key using "--aes256_key" +option in "generate.py" script file. + +it will check whether there is AES key blob in factory data region when in each +initialization, if not, the default AES key is converted and the result is +stored into flash, it run only once. + +for the second one, it only protect the dac private key inside the factory data, +the dac private key is retrieved and provisioned into Edge Lock, the returned +key blob replace the previous dac private key, and also update the overall size +and hash, and re-write the factory data. when device is doing matter +commissioning, the blob is retrieved and provisioned into Edge Lock and the +signing can be done using the returned key index in Edge Lock. + +the factory data should be plain text for the first programming. it will check +whether there is dac private key blob (base on the size of blob, should be 48) +in factory data when in each initialization, if not, the dac private key is +converted and the result is stored into flash, it run only once. + +for the third one, it is a little similar to the first one, the whole factory +data is encrypted by an AES key, but there are two differences: + +- the AES key is hard-coded and not provisioned into Edge Lock +- the factory data should be encrypted by AES-128 key using "--aes128_key" + option in "generate.py" script file. diff --git a/docs/guides/nxp/nxp_mcxw71_ota_guide.md b/docs/guides/nxp/nxp_mcxw71_ota_guide.md new file mode 100644 index 00000000000000..b21bf933d7e98e --- /dev/null +++ b/docs/guides/nxp/nxp_mcxw71_ota_guide.md @@ -0,0 +1,179 @@ +# NXP `MCXW71/K32W1` OTA guide + +### Convert `srec` into `sb3` file + +The OTA image files must be encrypted using Over The Air Programming Tool +([OTAP](https://www.nxp.com/design/microcontrollers-developer-resources/connectivity-tool-suite:CONNECTIVITY-TOOL-SUITE?#downloads)). +Bootloader will load the new OTA image only if it detects that the file was +encrypted with the `OTAP` correct keys. + +`.srec` file is input for Over The air Programming (`OTAP`) application +(unencrypted) and it's converted to `.sb3` format (encrypted). + +In `OTAP` application + +- select OTA protocol => `OTAP` Matter +- Browse File +- follow default options (KW45/K32W148, Preserve NVM) +- image information: will update "Application Core (MCU)" - this will generate + the image only for the CM33 core +- keep other settings at default values + +### Generate `ota` file + +In order to build an OTA image, use the NXP wrapper over the standard tool +`src/app/ota_image_tool.py`: + +- `scripts/tools/nxp/ota/ota_image_tool.py` + +The tool can be used to generate an OTA image with the following format: + +``` + | OTA image header | TLV1 | TLV2 | ... | TLVn | +``` + +where each TLV is in the form `|tag|length|value|`. + +Note that "standard" TLV format is used. Matter TLV format is only used for +factory data TLV value. + +Please see more in the +[OTA image tool guide](../../../scripts/tools/nxp/ota/README.md). + +Here is an example that generates an OTA image with application update TLV from +an `.sb3` file: + +``` +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 2 -vs "2.0" -da sha256 --app-input-file ~/binaries/chip-mcxw71-app.sb3 ~/binaries/chip-mcxw71-app.ota + +``` + +A note regarding OTA image header version (`-vn` option). An application binary +has its own software version (given by +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). In +order to have a correct OTA process, the OTA header version should be the same +as the binary embedded software version. A user can set a custom software +version in the gn build args by setting `nxp_software_version` to the wanted +version. + +### OTA factory data + +A user can update the factory data through OTA, at the same time the application +firmware is updated by enabling the following processor in the `gn args`: + +- `chip_enable_ota_factory_data_processor=1` to enable default factory data + update processor (disabled by default). + +The OTA image used must be updated to include the new factory data. + +[OTA image tool guide](../../../scripts/tools/nxp/ota/README.md). + +### Running OTA + +The OTA topology used for OTA testing is illustrated in the figure below. +Topology is similar with the one used for Matter Test Events. + +![OTA_TOPOLOGY](../../../examples/platform/nxp/mcxw71_k32w1/doc/images/ota_topology.JPG) + +The concept for OTA is the next one: + +- there is an OTA Provider Application that holds the OTA image. In our case, + this is a Linux application running on an Ubuntu based-system; +- the OTA Requestor functionality is embedded inside the reference + application. It will be used for requesting OTA blocks from the OTA + Provider; +- the controller (a linux application called chip-tool) will be used for + commissioning both the device and the OTA Provider App. The device will be + commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the + OTA Provider Application will be commissioned using the `onnetwork` option + of `chip-tool`; +- during commissioning, each device is assigned a node id by the chip-tool + (can be specified manually by the user). Using the node id of the device and + of the reference application, chip-tool triggers the OTA transfer by + invoking the `announce-ota-provider` command - basically, the OTA Requestor + is informed of the node id of the OTA Provider Application. + +_Computer #1_ can be any system running an Ubuntu distribution. We recommand +using CSA official instructions from +[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are +proposed. Also, CSA official instructions document point to the OS/Docker images +that should be used on the RPis. For compatibility reasons, we recommand +compiling chip-tool and OTA Provider applications with the same commit id that +was used for compiling the reference application. Also, please note that there +is a single controller (chip-tool) running on Computer #1 which is used for +commissioning both the device and the OTA Provider Application. If needed, +[these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be +used for connecting the RPis to WiFi. + +Build the Linux OTA provider application: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false +``` + +Build Linux `chip-tool`: + +``` +user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app +``` + +Start the OTA Provider Application: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-mcxw71-app.ota +``` + +Provision the OTA provider application and assign node id _1_. Also, grant ACL +entries to allow OTA requestors: + +``` +user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 +``` + +Provision the device and assign node id _2_: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-thread 2 hex: 20202021 3840 +``` + +Start the OTA process: + +``` +user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 +``` + +### Known issues + +- SRP cache on the openthread border router needs to flushed each time a new + commissioning process is attempted. For this, factory reset the device, then + execute `ot-ctl server disable` followed by `ot-ctl server enable`. After + this step, the commissioning process of the device can start; +- Due to some MDNS issues, the commissioning of the OTA Provider Application + may fail. Please make sure that the SRP cache is disabled + (`ot-ctl srp server disable`) on the openthread border router while + commissioning the OTA Provider Application; +- No other Docker image should be running (e.g.: Docker image needed by Test + Harness) except the OTBR one. A docker image can be killed using the + command: + + ``` + user@computer1:~/connectedhomeip$ : sudo docker kill $container_id + ``` + +- In order to avoid MDNS issues, only one interface should be active at one + time. E.g.: if WiFi is used then disable the Ethernet interface and also + disable multicast on that interface: + + ``` + user@computer1:~/connectedhomeip$ sudo ip link set dev eth0 down + user@computer1:~/connectedhomeip$ sudo ifconfig eth0 -multicast + ``` + +- If OTBR Docker image is used, then the "-B" parameter should point to the + interface used for the backbone. + +- If Wi-Fi is used on a RPI4, then a 5Ghz network should be selected. + Otherwise, issues related to BLE-WiFi combo may appear. diff --git a/docs/guides/nxp/nxp_rw61x_ota_software_update.md b/docs/guides/nxp/nxp_rw61x_ota_software_update.md index 1543b2f94402cf..af67b1419d0526 100644 --- a/docs/guides/nxp/nxp_rw61x_ota_software_update.md +++ b/docs/guides/nxp/nxp_rw61x_ota_software_update.md @@ -48,10 +48,9 @@ MCUBoot is an open-source secure bootloader used by RW61x to apply the self-upgrade. For more details, please refer to the [MCUBoot documentation](https://github.com/mcu-tools/mcuboot/blob/main/docs/design.md). -In our use case, the bootloader runs the application residing in the primary -partition. In order to run the OTA update image, the bootloader will swap the -content of the primary and the secondary partitions. This type of upgrade is -called swap-move and is the default upgrade configured by MCUBoot. +For RW61x platform, the bootloader is configured to use the flash remapping +mechanism by default, in order to perform the image upgrade. This is achieved by +using the `MCUBoot DIRECT-XIP` upgrade mode. ## OTA Software Update process for RW61x example application @@ -86,47 +85,42 @@ J-Link > exec EnableEraseAllFlashBanks J-Link > erase 0x8000000, 0x88a0000 ``` -- Using MCUXPresso, import the `mcuboot_opensource` demo example from the SDK - previously downloaded. The example can be found under the `ota_examples` - folder. - ![mcuboot_demo](../../../examples/platform/nxp/rt/rw61x/doc/images/mcuboot_demo.PNG) -- Before building the demo example, it should be specified that the - application to be run by the bootloader is monolithic. As a result, only one - image will be upgraded by the bootloader. This can be done by defining - `MONOLITHIC_APP` as 1 in the settings of the `mcuboot_opensource` project : +- MCUBoot application can be built with SDK installed, using instructions + + below. + +- Retrieve the mcuboot directory with : ``` -Right click on the Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU C Compiler -> Preprocessor -> Add "MONOLITHIC_APP=1" in the Defined Symbols +user@ubuntu: cd ~/Desktop/connectedhomeip/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/armgcc ``` -![rw610_mcuboot_monolithic](../../../examples/platform/nxp/rt/rw61x/doc/images/mcuboot_monolithic_app.PNG) +``: Supported rw612 boards are: `rdrw612bga` or `frdmrw612` -- Build the demo example project. +- Build the mcuboot application : ``` -Right click on the Project -> Build Project +user@ubuntu: chmod +x build_flash_release.sh +user@ubuntu: export ARMGCC_DIR=/opt/gcc-arm-none-eabi-10.3-2021.10 # with ARMGCC_DIR referencing the compiler path +user@ubuntu: ./build_flash_release.sh ``` -- Program the demo example to the target board. +- Program the generated binary to the target board. ``` -Right click on the Project -> Debug -> As->SEGGER JLink probes -> OK -> Select elf file +J-Link > loadbin ~/Desktop/connectedhomeip/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/armgcc/flash_release/mcuboot_opensource.elf ``` -Note : The mcuboot binary is loaded in flash at address 0x8000000. - -- To run the flashed demo, either press the reset button of the device or use - the debugger IDE of MCUXpresso. If it runs successfully, the following logs - will be displayed on the terminal : +- If it runs successfully, the following logs will be displayed on the + terminal : ``` hello sbl. -Bootloader Version 1.9.0 -Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 -Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3 -Boot source: none -Swap type: none -erasing trailer; fa_id=2 +Disabling flash remapping function +Bootloader Version 2.0.0 +Image 0 Primary slot: Image not found +Image 0 Secondary slot: Image not found +No slot to load for image 0 Unable to find bootable image ``` @@ -135,7 +129,7 @@ partitions to be the size of 4.4 MB. If the size is to be changed, the partition addresses should be modified in the flash_partitioning.h accordingly. For more information about the flash partitioning with mcuboot, please refer to the dedicated readme.txt located in -"`SDK_RW612/boards/rdrw612bga/ota_examples/mcuboot_opensource/`". +"`/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/`". ### Generating and flashing the signed application image @@ -162,15 +156,15 @@ arm-none-eabi-objcopy -R .flash_config -R .NVM -O binary chip-rw61x-all-cluster- To sign the image and wrap the raw binary of the application with the header and trailer, "`imgtool`" is provided in the SDK and can be found in -"`/middleware/mcuboot_opensource/scripts/`". +"`/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/middleware/mcuboot_opensource/scripts/`". The following commands can be run (make sure to replace the /path/to/file/binary with the adequate files): ``` -user@ubuntu: cd ~/Desktop/SDK_RW612/middleware/mcuboot_opensource/scripts +user@ubuntu: cd ~/Desktop//third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/middleware/mcuboot_opensource/scripts/ -user@ubuntu: python3 imgtool.py sign --key ~/Desktop/SDK_RW612/boards/rdrw612bga/ota_examples/mcuboot_opensource/keys/sign-rsa2048-priv.pem --align 4 --header-size 0x1000 --pad-header --slot-size 0x440000 --max-sectors 1088 --version "1.0" ~/Desktop/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x/out/debug/chip-rw61x-all-cluster-example.bin ~/Desktop/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x/out/debug/chip-rw61x-all-cluster-example_SIGNED.bin +user@ubuntu: python3 imgtool.py sign --key ~/Desktop//third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/keys/sign-rsa2048-priv.pem --align 4 --header-size 0x1000 --pad-header --pad --confirm --slot-size 0x440000 --max-sectors 1088 --version "1.0" ~/Desktop/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x/out/debug/chip-rw61x-all-cluster-example.bin ~/Desktop/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x/out/debug/chip-rw61x-all-cluster-example_SIGNED.bin ``` Notes : @@ -182,7 +176,7 @@ Notes : adjusted accordingly. - In this example, the image is signed with the private key provided by the SDK as an example - (`SDK_RW612/boards/rdrw612bga/ota_examples/mcuboot_opensource/keys/sign-rsa2048-priv.pem`), + (`/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/keys/sign-rsa2048-priv.pem`), MCUBoot is built with its corresponding public key which would be used to verify the integrity of the image. It is possible to generate a new pair of keys using the following commands. This procedure should be done prior to @@ -201,7 +195,7 @@ user@ubuntu: python3 imgtool.py getpub -k priv_key.pem ``` - The extracted public key can then be copied to the - `SDK_RW612/boards/rdrw612bga/ota_examples/mcuboot_opensource/keys/sign-rsa2048-pub.c`, + `/third_party/nxp/nxp_matter_support/github_sdk/common_sdk/repo/examples//ota_examples/mcuboot_opensource/keys/sign-rsa2048-pub.c`, given as a value to the rsa_pub_key[] array. The resulting output is the signed binary of the application version "1.0". @@ -221,11 +215,12 @@ application and run it. To generate the OTA update image the same procedure can be followed from the [Generating and flashing the signed application image](#generating-and-flashing-the-signed-application-image) sub-section, replacing the "--version "1.0"" argument with "--version "2.0"" -(recent version of the update). +(recent version of the update), without arguments "--pad" "--confirm" when +running `imgtool` script during OTA Update Image generation. Note : When building the update image, the build arguments -`nxp_software_version=2 nxp_sofware_version_string=\"2.0\"` can be added to the -`gn gen` command in order to specify the upgraded version. +nxp_software_version=2 nxp_software_version_string=\"2.0\" can be added to the +gn gen command in order to specify the upgraded version. When the signed binary of the update is generated, the file should be converted into OTA format. To do so, the ota_image_tool is provided in the repo and can be diff --git a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn index e6bf8d64d94524..b0e1c1c47a98ea 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn @@ -65,7 +65,8 @@ rt_sdk("sdk") { defines = [] # To be moved, temporary mbedtls config fix to build app with factory data - if (chip_enable_secure_dac_private_key_storage == 1) { + if (chip_enable_secure_dac_private_key_storage || + chip_enable_secure_whole_factory_data) { defines += [ "MBEDTLS_NIST_KW_C", "MBEDTLS_PSA_CRYPTO_CLIENT", @@ -82,10 +83,18 @@ rt_sdk("sdk") { include_dirs += [ "${example_platform_dir}/board/" ] sources += [ "${example_platform_dir}/board/pin_mux.c" ] sources += [ "${example_platform_dir}/board/hardware_init.c" ] - sources += [ "${example_platform_dir}/board/clock_config.c" ] - sources += [ "${example_platform_dir}/board/board.c" ] sources += [ "${example_platform_dir}/board/peripherals.c" ] + if (board_version == "frdm") { + include_dirs += [ "${example_platform_dir}/board/frdmrw612/" ] + sources += [ "${example_platform_dir}/board/frdmrw612/clock_config.c" ] + sources += [ "${example_platform_dir}/board/frdmrw612/board.c" ] + } else { + include_dirs += [ "${example_platform_dir}/board/rdrw612bga/" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/clock_config.c" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/board.c" ] + } + # Indicate the path to CHIPProjectConfig.h include_dirs += [ "include/config" ] @@ -97,7 +106,7 @@ rt_sdk("sdk") { # For matter with BR feature, increase FreeRTOS heap size if (chip_enable_wifi && chip_enable_openthread) { - defines += [ "configTOTAL_HEAP_SIZE=(size_t)(160 * 1024)" ] + defines += [ "configTOTAL_HEAP_SIZE=(size_t)(170 * 1024)" ] } defines += [ @@ -141,10 +150,12 @@ rt_executable("all_cluster_app") { "../../common/main/main.cpp", ] - if (chip_enable_secure_dac_private_key_storage == 1) { - sources += [ - "${example_platform_dir}/factory_data/source/AppFactoryDataExample.cpp", - ] + if (chip_enable_secure_dac_private_key_storage || + chip_enable_secure_whole_factory_data) { + sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] + if (chip_enable_secure_whole_factory_data) { + defines += [ "ENABLE_SECURE_WHOLE_FACTORY_DATA" ] + } } else { sources += [ "${common_example_dir}/factory_data/source/AppFactoryDataDefaultImpl.cpp", diff --git a/examples/all-clusters-app/nxp/rt/rw61x/README.md b/examples/all-clusters-app/nxp/rt/rw61x/README.md index bdec2c58956274..9356e4b8fe3617 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/README.md +++ b/examples/all-clusters-app/nxp/rt/rw61x/README.md @@ -37,52 +37,70 @@ The example supports: For Matter over Thread configuration : -- [`NXP RD-RW612-BGA`] board -- BLE/15.4 antenna (to plug in Ant1) +- For [`NXP RD-RW612-BGA`] board: BLE/15.4 antenna (to plug in Ant1) +- For [`NXP FRDM-RW612`] board: no external antenna needed (embedded PCB + antenna) For Matter over WiFi configuration : -- [`NXP RD-RW612-BGA`] or [`NXP RD-RW610-BGA`] board -- BLE antenna (to plug in Ant1) -- Wi-Fi antenna (to plug in Ant2) +- For [`NXP RD-RW612-BGA`] or [`NXP RD-RW610-BGA`] board: BLE antenna (to plug + in Ant1) + Wi-Fi antenna (to plug in Ant2) +- For [`NXP FRDM-RW612`] board: no external antenna needed (embedded PCB + antenna) For Matter over Wi-Fi with OpenThread Border Router : -- [`NXP RD-RW612-BGA`] board -- BLE/15.4 antenna (to plug in Ant1) -- Wi-Fi antenna (to plug in Ant2) +- For [`NXP RD-RW612-BGA`] board: BLE/15.4 antenna (to plug in Ant1) + Wi-Fi + antenna (to plug in Ant2) +- For [`NXP FRDM-RW612`] board: no external antenna needed (embedded PCB + antenna) ## Building In order to build the Project CHIP example, we recommend using a Linux -distribution (the demo-application was compiled on Ubuntu 20.04). +distribution (supported Operating Systems are listed in +[BUILDING.md](../../../../../docs/guides/BUILDING.md#prerequisites)). -- Follow instruction in [BUILDING.md](../../../../../docs/guides/BUILDING.md) - to setup the environment to be able to build Matter. +- Make sure that below prerequisites are correctly installed (as described in + [BUILDING.md](../../../../../docs/guides/BUILDING.md#prerequisites))) -- Download - [RD-RW612 SDK for Project CHIP](https://mcuxpresso.nxp.com/en/select). - Creating an nxp.com account is required before being able to download the - SDK. Once the account is created, login and follow the steps for downloading - SDK. The SDK Builder UI selection should be similar with the one from the - image below. +``` +sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ + libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev \ + python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev +``` - ![MCUXpresso SDK Download](../../../../platform/nxp/rt/rw61x/doc/images/mcux-sdk-download.PNG) +- Step 1: checkout NXP specific submodules only - (Note: All SDK components should be selected. If size is an issue Azure RTOS - component can be omitted.) +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive +``` - Please refer to Matter release notes for getting the latest released SDK. +- Step 2: activate local environment -- Start building the application. +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/activate.sh +``` + +If the script says the environment is out of date, you can update it by running +the following command: + +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh +``` + +- Step 3: Init NXP SDK(s) + +``` +user@ubuntu:~/Desktop/git/connectedhomeip$ third_party/nxp/nxp_matter_support/scripts/update_nxp_sdk.py --platform common +``` + +Note: By default update_nxp_sdk.py will try to initialize all NXP SDKs. Arg "-- +help" could be used to view all available options. ``` -user@ubuntu:~/Desktop/git/connectedhomeip$ export NXP_SDK_ROOT=/home/user/Desktop/SDK_RW612/ -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive -user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/bootstrap.sh -user@ubuntu:~/Desktop/git/connectedhomeip$ source ./scripts/activate.sh user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/all-clusters-app/nxp/rt/rw61x/ ``` @@ -91,7 +109,7 @@ user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/all-clusters-app/nxp/rt/r - Build Matter-over-Wifi configuration with BLE commissioning (ble-wifi) : ``` -user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ gn gen --args="chip_enable_wifi=true is_sdk_package=true" out/debug +user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ gn gen --args="chip_enable_wifi=true" out/debug user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ ninja -C out/debug ``` @@ -100,7 +118,7 @@ user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x - Build Matter-over-Thread configuration with BLE commissioning. ``` -user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ gn gen --args="chip_enable_openthread=true chip_inet_config_enable_ipv4=false chip_config_network_layer_ble=true is_sdk_package=true" out/debug +user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ gn gen --args="chip_enable_openthread=true chip_inet_config_enable_ipv4=false chip_config_network_layer_ble=true" out/debug user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x$ ninja -C out/debug ``` @@ -113,7 +131,7 @@ Thread network on the Border Router. (ble-wifi) : ``` -user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw610$ gn gen --args="chip_enable_wifi=true chip_enable_openthread=true chip_enable_matter_cli=true is_sdk_package=true openthread_root=\"//third_party/connectedhomeip/third_party/openthread/ot-nxp/openthread-br\"" out/debug +user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw610$ gn gen --args="chip_enable_wifi=true chip_enable_openthread=true chip_enable_matter_cli=true" out/debug user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw610$ ninja -C out/debug ``` @@ -128,12 +146,9 @@ Optional GN options that can be added when building an application: [matter CLI](README.md#testing-the-all-clusters-application-with-matter-cli-enabled), the argument `chip_enable_matter_cli=true` must be added to the _gn gen_ command. -- To switch the SDK type used, the argument `is_=true` must be added - to the _gn gen_ command (with being either sdk_package or - sdk_internal). -- By default, the RW612 A1 board revision will be chosen. To switch to an A2 - revision, the argument `board_version=\"A2\"` must be added to the _gn gen_ - command. +- By default, the `NXP RD-RW612-BGA` board revision will be chosen. To switch + to `NXP FRDM-RW612` board revision, the argument `board_version=\"frdm\"` + must be added to the _gn gen_ command. - To build the application in debug mode, the argument `is_debug=true optimize_debug=false` must be added to the _gn gen_ command. - To build with the option to have Matter certificates/keys pre-loaded in a @@ -215,9 +230,6 @@ Right click on the Project -> C/C++ Build-> Tool Chain Editor -> NXP MCU Tools - Right click on the Project -> Debug -> As->SEGGER JLink probes -> OK -> Select elf file ``` -(Note : if SDK package is used, a simpler way could be duplicating the debug -configuration from the SDK Hello World example after importing it.) - - Debug using the newly created configuration file. @@ -261,6 +273,10 @@ using the matter shell, follow instructions from In this configuration, the device can be commissioned over Wi-Fi with the 'ble-wifi' pairing method. +### NVM + +By default the file system used by the application is NVS. + ### Testing the all-clusters application without Matter CLI: 1. Prepare the board with the flashed `All-cluster application` (as shown @@ -319,8 +335,10 @@ Here are described steps to use the all-cluster-app with the Matter CLI enabled 3. The All-cluster example uses UART2 (`FlexComm0`) to print logs while running the server. To view raw UART output, a pin should be plugged to an USB to - UART adapter (connector `HD2 pin 03`), then start a terminal emulator like - PuTTY and connect to the used COM port with the following UART settings: + UART adapter (connector `HD2 pin 03` for [`NXP RD-RW612-BGA`] board and + `J5 pin 4` (`mikroBUS`: TX) for [`NXP FRDM-RW612`] board), then start a + terminal emulator like PuTTY and connect to the used COM port with the + following UART settings: - Baud rate: 115200 - 8 data bits diff --git a/examples/contact-sensor-app/nxp/README.md b/examples/contact-sensor-app/nxp/README.md new file mode 100644 index 00000000000000..473afb793f9700 --- /dev/null +++ b/examples/contact-sensor-app/nxp/README.md @@ -0,0 +1,195 @@ +# Matter NXP Contact Sensor Example Application + +This reference application implements a Contact Sensor device type. It uses +board buttons or `matter-cli` for user input and LEDs for state feedback. You +can use this example as a reference for creating your own application. + +The example is based on: + +- [Matter](https://github.com/project-chip/connectedhomeip) +- [NXP github SDK](https://github.com/nxp-mcuxpresso/mcux-sdk) + +- [Matter NXP Contact Sensor Example Application](#matter-nxp-contact-sensor-example-application) + - [Supported devices](#supported-devices) + - [Introduction](#introduction) + - [Device UI](#device-ui) + - [Prerequisites for building](#prerequisites-for-building) + - [Building](#building) + - [Data model](#data-model) + - [Manufacturing data](#manufacturing-data) + - [Long Idle Time ICD Support](#long-idle-time-icd-support) + - [Low power](#low-power) + - [Flashing and debugging](#flashing-and-debugging) + +## Supported devices + +- [k32w1](k32w1/README.md) + +## Introduction + +The application showcases a contact sensor that communicates with clients over a +low-power, 802.15.4 Thread network. + +It can be commissioned into an existing Matter network using a controller such +as `chip-tool`. + +This example implements a `User-Intent Commissioning Flow`, meaning the user has +to press a button in order for the device to be ready for commissioning. The +initial commissioning is done through `ble-thread` pairing method. + +The Thread network dataset will be transferred on the device using a secure +session over Bluetooth LE. In order to start the commissioning process, the user +must enable BLE advertising on the device manually. To pair successfully, the +commissioner must know the commissioning information corresponding to the +device: setup passcode and discriminator. This data is usually encoded within a +QR code or printed to the UART console. + +## Device UI + +The example application provides a simple UI that depicts the state of the +device and offers basic user control. This UI is implemented via the +general-purpose LEDs and buttons built in the evaluation boards. Please see each +supported device readme file for details. + +## Prerequisites for building + +In order to build the example, it is recommended to use a Linux distribution. +Please visit the supported Operating Systems list in +[BUILDING.md](../../../docs/guides/BUILDING.md#prerequisites). + +- Make sure that below prerequisites are correctly installed (as described in + [BUILDING.md](../../../docs/guides/BUILDING.md#prerequisites)) + +``` +sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev +``` + +- Step 1: checkout NXP specific submodules only + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive + ``` + +- Step 2: activate local environment + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/activate.sh + ``` + + If the script says the environment is out of date, you can update it by + running the following command: + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh + ``` + +- Step 3: Init NXP SDK(s) + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ third_party/nxp/nxp_matter_support/scripts/update_nxp_sdk.py --platform common + ``` + +Note: By default, `update_nxp_sdk.py` will try to initialize all NXP SDKs. +Please run the script with arg `--help` to view all available options. + +## Building + +There are two options for building this reference app: + +- Using `build_examples.py` framework. +- Manually generating `ninja` files using `gn`. + +For manual generation and building, please see the specific readme file for your +device. + +A list of all available contact sensor targets can be viewed in the following +table: + +| target name | description | +| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| nxp-device-freertos-contact-sensor-low-power | Default low-power contact sensor | +| nxp-device-freertos-contact-sensor-low-power-factory | Default low-power contact sensor with factory data | +| nxp-device-freertos-contact-sensor-low-power-lit | Low-power contact sensor as LIT ICD | +| nxp-device-freertos-contact-sensor-low-power-sw-v2 | Low-power contact sensor with software version 2 (can be used to test OTA) | +| nxp-device-freertos-contact-sensor-low-power-factory-sw-v2 | Low-power contact sensor with factory data and software version 2 (can be used to test OTA) | + +where `device` can be one of the [Supported devices](#supported-devices). + +### Data model + +There are two available data models that can be used by the application: + +| path | description | +| -------------------------------- | ------------------------------ | +| `zap-lit/contact-sensor-app.zap` | Data model for LIT ICD support | +| `zap-sit/contact-sensor-app.zap` | Data model for SIT ICD support | + +The selection is done automatically by the build system based on the ICD +configuration. + +The data model can be changed by simply replacing the gn `deps` statement +corresponding to data model target. + +### Manufacturing data + +Use `chip_with_factory_data=1` in the gn build command to enable factory data. + +For a full guide on manufacturing flow, please see +[Guide for writing manufacturing data on NXP devices](../../../docs/guides/nxp/nxp_manufacturing_flow.md). + +### Long Idle Time ICD Support + +By default, the application is compiled as a SIT ICD (Short Idle Time +Intermittently Connected Device). + +This is a list of ICD configuration gn args. + +| gn arg | default value | description | +| ------------------------------------------------------------------------------ | ------------- | ---------------------------------------------------------------------------------------------------------- | +| nxp_ot_idle_interval_ms | 2000 (ms) | OT Idle Interval duration | +| nxp_ot_active_interval_ms | 500 (ms) | OT Active Interval duration | +| nxp_idle_mode_duration_s | 600 (s) | Idle Mode Interval duration | +| nxp_active_mode_duration_ms | 10000 (ms) | Active Mode Interval duration | +| nxp_active_mode_threshold_ms | 1000 (ms) | Active Mode Threshold value | +| nxp_icd_supported_clients_per_fabric | 2 | Registration slots per fabric | +| chip_enable_icd_lit | false | Enable LIT ICD support | +| chip_persist_subscriptions | true | Try once to re-establish subscriptions from the server side after reboot. May be disabled for LIT use case | +| chip_subscription_timeout_resumption | true | Same as above, but try to re-establish timeout out subscriptions | +| using `Fibonacci Backoff` for retries pacing. May be disabled for LIT use case | + +If LIT ICD support is needed then `chip_enable_icd_lit=true` must be specified +as gn argument and the above parameters must be modified to comply with LIT +requirements (e.g.: LIT devices must configure +`chip_ot_idle_interval_ms > 15000`). Example LIT configuration: + +``` +nxp_ot_idle_interval_ms = 15000 # 15s Idle Intervals +nxp_ot_active_interval_ms = 500 # 500ms Active Intervals +nxp_idle_mode_duration_s = 3600 # 60min Idle Mode Interval +nxp_active_mode_duration_ms = 0 # 0 Active Mode Interval +nxp_active_mode_threshold_ms = 30000 # 30s Active Mode Threshold +``` + +### Low power + +The example also offers the possibility to run in low power mode. This means +that the board will go in deep sleep most of the time and the power consumption +will be very low. + +In order to build with low power support, the following gn args must be used: + +``` +chip_with_low_power = 1 +chip_openthread_ftd = false +chip_with_ot_cli = 0 +chip_logging = false +``` + +In order to maintain a low power consumption, the UI LEDs are disabled. Console +logs can be used instead, but it might affect low power timings. Also, please +note that once the board is flashed with MCUXpresso the debugger disconnects +because the board enters low power. + +## Flashing and debugging + +Please see the device specific readme file. diff --git a/examples/contact-sensor-app/nxp/k32w1/.gn b/examples/contact-sensor-app/nxp/k32w1/.gn index 885f306753076d..6a134466e0067b 100644 --- a/examples/contact-sensor-app/nxp/k32w1/.gn +++ b/examples/contact-sensor-app/nxp/k32w1/.gn @@ -28,5 +28,5 @@ default_args = { import("//args.gni") # Import default platform configs - import("${chip_root}/src/platform/nxp/k32w1/args.gni") + import("${chip_root}/src/platform/nxp/mcxw71_k32w1/args.gni") } diff --git a/examples/contact-sensor-app/nxp/k32w1/BUILD.gn b/examples/contact-sensor-app/nxp/k32w1/BUILD.gn index 119dc5cf722eac..0e24893bd06737 100644 --- a/examples/contact-sensor-app/nxp/k32w1/BUILD.gn +++ b/examples/contact-sensor-app/nxp/k32w1/BUILD.gn @@ -40,7 +40,7 @@ assert(target_os == "freertos") example_platform_dir = "${chip_root}/examples/platform/nxp/${nxp_platform}" common_example_dir = "${chip_root}/examples/platform/nxp/common" -k32w1_sdk("sdk") { +mcxw71_k32w1_sdk("sdk") { defines = [] include_dirs = [] sources = [] @@ -55,20 +55,20 @@ k32w1_sdk("sdk") { include_dirs += [ "${example_platform_dir}/app/project_include/openthread" ] include_dirs += [ - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480", ] sources += [ - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/clock_config.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/pin_mux.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/app_services_init.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_comp.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_dcdc.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_extflash.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_lp.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/hardware_init.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/clock_config.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/pin_mux.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/app_services_init.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_comp.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_dcdc.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_extflash.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_lp.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/hardware_init.c", ] if (is_debug) { @@ -90,7 +90,7 @@ k32w1_sdk("sdk") { } } -k32w1_executable("contact_sensor_app") { +mcxw71_k32w1_executable("contact_sensor_app") { output_name = "chip-k32w1-contact-example" defines = [] @@ -235,7 +235,7 @@ k32w1_executable("contact_sensor_app") { cflags = [ "-Wconversion" ] - ldscript = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" + ldscript = "${nxp_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" inputs = [ ldscript ] diff --git a/examples/contact-sensor-app/nxp/k32w1/README.md b/examples/contact-sensor-app/nxp/k32w1/README.md index 7a70f746f6e445..217f06e11906b6 100644 --- a/examples/contact-sensor-app/nxp/k32w1/README.md +++ b/examples/contact-sensor-app/nxp/k32w1/README.md @@ -1,162 +1,57 @@ # Matter K32W1 Contact Sensor Example Application -Matter K32W1 Contact Sensor Example uses buttons to test changing the lock and -device states and LEDs to show the state of these changes. You can use this -example as a reference for creating your own application. - -The example is based on -[Matter](https://github.com/project-chip/connectedhomeip) and the NXP K32W1 SDK, -and a simulated contact sensor over a low-power, 802.15.4 Thread network. - -The example behaves as a Matter accessory, that is a device that can be paired -into an existing Matter network and can be controlled by this network. - -
+For generic information related to contact sensor application, please see the +[common README](../README.md). - [Matter K32W1 Contact Sensor Example Application](#matter-k32w1-contact-sensor-example-application) - [Introduction](#introduction) - - [Bluetooth LE Advertising](#bluetooth-le-advertising) - - [Bluetooth LE Rendezvous](#bluetooth-le-rendezvous) - - [Thread Provisioning](#thread-provisioning) - [Device UI](#device-ui) - [Building](#building) - - [Long Idle Time ICD Support](#long-idle-time-icd-support) - - [Manufacturing data](#manufacturing-data) - [Flashing](#flashing) - [Flashing the `NBU` image](#flashing-the-nbu-image) - [Flashing the host image](#flashing-the-host-image) - [Debugging](#debugging) - [OTA](#ota) - - [Convert `srec` into `sb3` file](#convert-srec-into-sb3-file) - - [Convert `sb3` into `ota` file](#convert-sb3-into-ota-file) - - [OTA factory data](#ota-factory-data) - - [Running OTA](#running-ota) - - [Low power](#low-power) - - [Known issues](#known-issues) ## Introduction -![K32W1 EVK](../../../platform/nxp/k32w1/doc/images/k32w1-evk.jpg) - -The K32W1 contact sensor example application provides a working demonstration of -a connected contact sensor device, built using the Matter codebase and the NXP -K32W1 SDK. The example supports remote access (e.g.: using CHIP Tool from a -mobile phone) and control of a simulated contact sensor over a low-power, -802.15.4 Thread network. It is capable of being paired into an existing Matter -network along with other Matter-enabled devices. - -The Matter device that runs the contact sensor application is controlled by the -Matter controller device over the Thread protocol. By default, the Matter device -has Thread disabled, and it should be paired over Bluetooth LE with the Matter -controller and obtain configuration from it. The actions required before -establishing full communication are described below. - -### Bluetooth LE Advertising - -In this example, to commission the device onto a Matter network, it must be -discoverable over Bluetooth LE. For security reasons, you must start Bluetooth -LE advertising manually after powering up the device by pressing Button SW2. - -### Bluetooth LE Rendezvous +This is a contact sensor application implemented for a k32w1 device. -In this example, the commissioning procedure (called rendezvous) is done over -Bluetooth LE between a Matter device and the Matter controller, where the -controller has the commissioner role. - -To start the rendezvous, the controller must get the commissioning information -from the Matter device. The data payload is encoded within a QR code, or printed -to the UART console. - -### Thread Provisioning +The following board was used when testing this Matter reference app for a +`k32w1` device: +![K32W1 EVK](../../../platform/nxp/mcxw71_k32w1/doc/images/k32w1-evk.jpg) ## Device UI -The example application provides a simple UI that depicts the state of the -device and offers basic user control. This UI is implemented via the -general-purpose LEDs and buttons built in the K32W1 EVK board. - -**LED 2** shows the overall state of the device and its connectivity. Four -states are depicted: - -- _Short Flash On (50ms on/950ms off)_ — The device is in an - unprovisioned (unpaired) state and is waiting for a commissioning - application to connect. +The state feedback is provided through LED effects: -* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an - unprovisioned state and a commissioning application is connected via BLE. +| widget | effect | description | +| ------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------- | +| LED2 | short flash on (50ms on/950ms off) | The device is in an unprovisioned (unpaired) state and is waiting for a commissioner to connect. | +| LED2 | rapid even flashing (100ms period) | The device is in an unprovisioned state and a commissioner is connected via BLE. | +| LED2 | short flash off (950ms on/50ms off) | The device is fully provisioned, but does not yet have full network (Thread) or service connectivity. | +| LED2 | solid on | The device is fully provisioned and has full network and service connectivity. | +| RGB LED | on | The `StateValue` attribute of the `BooleanState` cluster is `true` (simulating detection). | +| RGB LED | off | The `StateValue` attribute of the `BooleanState` cluster is `false` (simulating no detection). | -- _Short Flash Off (950ms on/50ms off)_ — The device is full - provisioned, but does not yet have full network (Thread) or service - connectivity. +NOTE: `LED2` will be disabled when OTA is used. On K32W1 EVK board, `PTB0` is +wired to both `LED2` and CS (Chip Select) of the External Flash Memory. Since +the OTA image is stored in external memory, `LED2` operations will affect OTA +operation by corrupting packages and OTA will not work. -* _Solid On_ — The device is fully provisioned and has full network and - service connectivity. +The user actions are summarized below: -NOTE: LED2 will be disabled when CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR is -enabled. On K32W1 EVK board, `PTB0` is wired to `LED2` also is wired to CS (Chip -Select) External Flash Memory. OTA image is stored in external memory because of -it's size. If LED2 is enabled then it will affect External Memory CS and OTA -will not work. - -**RGB LED** shows the state of the simulated contact sensor. when the LED is -lit, the sensor is contacted, when not lit, the sensor is non-contacted. - -**Button SW2**. SHORT press function is overloaded depending on the device type -and commissioning state. If the device is not commissioned, a SHORT press of the -button will enable Bluetooth LE advertising for a predefined period of time. If -the device is commissioned and is acting as a LIT ICD then a SHORT press of the -button will enable Active Mode. A LONG Press of Button SW2 initiates a factory -reset. After an initial period of 3 seconds, LED 2 and RGB LED will flash in -unison to signal the pending reset. After 6 seconds will cause the device to -reset its persistent configuration and initiate a reboot. The reset action can -be cancelled by press SW2 button at any point before the 6 second limit. - -**Button SW3** can be used to change the state of the simulated contact sensor. -The button behaves as a toggle, swapping the state every time it is short -pressed. When long pressed, it does a clean soft reset that takes into account -Matter shutdown procedure. +| button | action | state | output | +| ------ | ----------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| SW2 | short press | not commissioned | Enable BLE advertising | +| SW2 | short press | commissioned + device is LIT | Enable Active Mode | +| SW2 | long press | NA | Initiate a factory reset (can be cancelled by pressing the button again within the factory reset timeout limit - 6 seconds by default) | +| SW3 | short press | NA | Toggle attribute `StateValue` value | +| SW3 | long press | NA | Clean soft reset of the device (takes into account proper Matter shutdown procedure) | ## Building -In order to build the Project CHIP example, we recommend using a Linux -distribution. Supported Operating Systems and prerequisites are listed in -[BUILDING](../../../../docs/guides/BUILDING.md). - -- Make sure that below prerequisites are correctly installed - -``` -sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ - libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev \ - python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev -``` - -- Step 1: checkout NXP specific submodules only - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive -``` - -- Step 2: activate local environment - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/activate.sh -``` - -If the script says the environment is out of date, you can update it by running -the following command: - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh -``` - -- Step 3: Init NXP SDK(s) - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/setup/nxp/update_nxp_sdk.py --platform common_sdk -``` - -Note: By default setup/nxp/update_nxp_sdk.py will try to initialize all NXP -SDKs. Arg "-- help" could be used to view all available options. +Manually building requires running the following commands: ``` user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/contact-sensor-app/nxp/k32w1 @@ -164,55 +59,11 @@ user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w1$ user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w1$ ninja -C out/debug ``` -In case that Openthread CLI is needed, chip_with_ot_cli build argument must be -set to 1. - -After a successful build, the `elf` and `srec` files are found in `out/debug/` - -`see the files prefixed with chip-k32w1-contact-example`. - -## Long Idle Time ICD Support - -By default, contact-sensor is compiled as SIT ICD (Short Idle Time -Intermittently Connected Device) - see rules from k32w1_sdk.gni: - -``` -chip_ot_idle_interval_ms = 2000 # 2s Idle Intervals -chip_ot_active_interval_ms = 500 # 500ms Active Intervals - -nxp_idle_mode_duration_s = 600 # 10min Idle Mode Interval -nxp_active_mode_duration_ms = 10000 # 10s Active Mode Interval -nxp_active_mode_threshold_ms = 1000 # 1s Active Mode Threshold -nxp_icd_supported_clients_per_fabric = 2 # 2 registration slots per fabric -``` - -If LIT ICD support is needed then `chip_enable_icd_lit=true` must be specified -as gn argument and the above parameters can be modified to comply with LIT -requirements (e.g.: LIT devices must configure -`chip_ot_idle_interval_ms > 15000`). Example LIT configuration: - -``` -chip_ot_idle_interval_ms = 15000 # 15s Idle Intervals -chip_ot_active_interval_ms = 500 # 500ms Active Intervals - -nxp_idle_mode_duration_s = 3600 # 60min Idle Mode Interval -nxp_active_mode_duration_ms = 0 # 0 Active Mode Interval -nxp_active_mode_threshold_ms = 30000 # 30s Active Mode Threshold -``` - -ICD parameters that may be disabled once LIT functionality is enabled: - -``` -chip_persist_subscriptions: try once to re-establish subscriptions from the server side after reboot -chip_subscription_timeout_resumption: same as above + try to re-establish timeout out subscriptions -using Fibonacci backoff for retries pacing. -``` - -## Manufacturing data - -Use `chip_with_factory_data=1` in the gn build command to enable factory data. +Please note that running `gn gen out/debug` without `--args` option will use the +default gn args values found in `args.gni`. -For a full guide on manufacturing flow, please see -[Guide for writing manufacturing data on NXP devices](../../../../docs/guides/nxp/nxp_manufacturing_flow.md). +After a successful build, the `elf` and `srec` files are found in `out/debug/`. +See the files prefixed with `chip-k32w1-contact-example`. ## Flashing @@ -222,7 +73,7 @@ Two images must be written to the board: one for the host (CM33) and one for the The image needed on the host side is the one generated in `out/debug/` while the one needed on the `NBU` side can be found in the downloaded NXP-SDK package at path - -`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter_$version.sb3`. +`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter.sb3`. ### Flashing the `NBU` image @@ -244,29 +95,26 @@ build process. If debugging is needed then jump directly to the [Debugging](#debugging) section. Otherwise, if only flashing is needed then -[JLink 7.84b](https://www.segger.com/downloads/jlink/) can be used: +[JLink 7.84b or greater](https://www.segger.com/downloads/jlink/) can be used: - Plug K32W1 to the USB port (no need to keep the SW4 button pressed while - doing this) - -- Create a new file, `commands_script`, with the following content (change - application name accordingly): - -```bash -reset -halt -loadfile chip-k32w1-contact-example.srec -reset -go -quit -``` + doing this, e.g. ISP mode is not needed for host flashing) -- copy the application and `commands_script` in the same folder that JLink - executable is placed. Execute: +- Connect JLink to the device: -```bash -$ jlink -device K32W1480 -if SWD -speed 4000 -autoconnect 1 -CommanderScript commands_script -``` + ```bash + JLinkExe -device K32W1480 -if SWD -speed 4000 -autoconnect 1 + ``` + +- Run the following commands: + ```bash + reset + halt + loadfile chip-k32w1-contact-example.srec + reset + go + quit + ``` ## Debugging @@ -275,7 +123,7 @@ One option for debugging would be to use MCUXpresso IDE. - Drag-and-drop the zip file containing the NXP SDK in the "Installed SDKs" tab: -![Installed SDKs](../../../platform/nxp/k32w1/doc/images/installed_sdks.jpg) +![Installed SDKs](../../../platform/nxp/mcxw71_k32w1/doc/images/installed_sdks.jpg) - Import any demo application from the installed SDK: @@ -283,7 +131,7 @@ One option for debugging would be to use MCUXpresso IDE. Import SDK example(s).. -> choose a demo app (demo_apps -> hello_world) -> Finish ``` -![Import demo](../../../platform/nxp/k32w1/doc/images/import_demo.jpg) +![Import demo](../../../platform/nxp/mcxw71_k32w1/doc/images/import_demo.jpg) - Flash the previously imported demo application on the board: @@ -302,7 +150,7 @@ resulted after ot-nxp compilation. File -> Import -> C/C++ -> Existing Code as Makefile Project ``` -![New Project](../../../platform/nxp/k32w1/doc/images/new_project.jpg) +![New Project](../../../platform/nxp/mcxw71_k32w1/doc/images/new_project.jpg) - Replace the path of the existing demo application with the path of the K32W1 application: @@ -311,199 +159,9 @@ File -> Import -> C/C++ -> Existing Code as Makefile Project Run -> Debug Configurations... -> C/C++ Application ``` -![Debug K32W1](../../../platform/nxp/k32w1/doc/images/debug_k32w1.jpg) +![Debug K32W1](../../../platform/nxp/mcxw71_k32w1/doc/images/debug_k32w1.jpg) ## OTA -### Convert `srec` into `sb3` file - -The OTA image files must be encrypted using Over The Air Programming Tool -([OTAP](https://www.nxp.com/design/microcontrollers-developer-resources/connectivity-tool-suite:CONNECTIVITY-TOOL-SUITE?#downloads)). -Bootloader will load the new OTA image only if it detects that the file was -encrypted with the `OTAP` correct keys. - -`.srec` file is input for Over The air Programming (`OTAP`) application -(unencrypted) and it's converted to `.sb3` format (encrypted). - -In `OTAP` application - -- select OTA protocol => `OTAP` Matter -- Browse File -- follow default options (KW45/K32W148, Preserve NVM) -- image information: will update "Application Core (MCU)" - this will generate - the image only for the CM33 core -- keep other settings at default values - -### Convert `sb3` into `ota` file - -In order to build an OTA image, use NXP wrapper over the standard tool -`src/app/ota_image_tool.py`: - -- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py`. - -The tool can be used to generate an OTA image with the following format: - -``` - | OTA image header | TLV1 | TLV2 | ... | TLVn | -``` - -where each TLV is in the form `|tag|length|value|`. - -Note that "standard" TLV format is used. Matter TLV format is only used for -factory data TLV value. - -Please see more in the -[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). - -Here is an example that generates an OTA image with application update TLV from -a `sb3` file: - -``` -./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 43033 -vs "1.0" -da sha256 --app-input-file ~/binaries/chip-k32w1-43033.sb3 ~/binaries/chip-k32w1-43033.ota - -``` - -A note regarding OTA image header version (`-vn` option). An application binary -has its own software version (given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For -having a correct OTA process, the OTA header version should be the same as the -binary embedded software version. A user can set a custom software version in -the gn build args by setting `chip_software_version` to the wanted version. - -### OTA factory data - -A user can update the factory data through OTA, at the same time the application -firmware is updated by enabling the following processor in the `gn args`: - -- `chip_enable_ota_factory_data_processor=1` to enable default factory data - update processor (disabled by default). - -The OTA image used must be updated to include the new factory data. - -[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). - -### Running OTA - -The OTA topology used for OTA testing is illustrated in the figure below. -Topology is similar with the one used for Matter Test Events. - -![OTA_TOPOLOGY](../../../platform/nxp/k32w1/doc/images/ota_topology.JPG) - -The concept for OTA is the next one: - -- there is an OTA Provider Application that holds the OTA image. In our case, - this is a Linux application running on an Ubuntu based-system; -- the OTA Requestor functionality is embedded inside the Contact Sensor - Application. It will be used for requesting OTA blocks from the OTA - Provider; -- the controller (a linux application called chip-tool) will be used for - commissioning both the device and the OTA Provider App. The device will be - commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the - OTA Provider Application will be commissioned using the _onnetwork_ option - of chip-tool; -- during commissioning, each device is assigned a node id by the chip-tool - (can be specified manually by the user). Using the node id of the device and - of the contact sensor application, chip-tool triggers the OTA transfer by - invoking the _announce-ota-provider_ command - basically, the OTA Requestor - is informed of the node id of the OTA Provider Application. - -_Computer #1_ can be any system running an Ubuntu distribution. We recommand -using CSA official instructions from -[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are -proposed. Also, CSA official instructions document point to the OS/Docker images -that should be used on the RPis. For compatibility reasons, we recommand -compiling chip-tool and OTA Provider applications with the same commit id that -was used for compiling the Contact Sensor Application. Also, please note that -there is a single controller (chip-tool) running on Computer #1 which is used -for commissioning both the device and the OTA Provider Application. If needed, -[these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be -used for connecting the RPis to WiFi. - -Build the Linux OTA provider application: - -``` -user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false -``` - -Build Linux chip-tool: - -``` -user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app -``` - -Start the OTA Provider Application: - -``` -user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* -user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w1-43033.ota -``` - -Provision the OTA provider application and assign node id _1_. Also, grant ACL -entries to allow OTA requestors: - -``` -user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 -``` - -Provision the device and assign node id _2_: - -``` -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-thread 2 hex: 20202021 3840 -``` - -Start the OTA process: - -``` -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 -``` - -## Low power - -The example also offers the possibility to run in low power mode. This means -that the board will go in deep sleep most of the time and the power consumption -will be very low. - -In order to build with low power support, the `chip_with_low_power=1` must be -provided to the build system. In this case, please note that the GN build -arguments `chip_openthread_ftd` and `chip_with_ot_cli` must be set to `false/0` -and `chip_logging` must be set to `false` to disable logging. - -In order to maintain a low power consumption, the LEDs showing the state of the -contact sensor and the internal state are disabled. Console logs can be used -instead. Also, please note that once the board is flashed with MCUXpresso the -debugger disconnects because the board enters low power. - -### Known issues - -- SRP cache on the openthread border router needs to flushed each time a new - commissioning process is attempted. For this, factory reset the device, then - execute _ot-ctl server disable_ followed by _ot-ctl server enable_. After - this step, the commissioning process of the device can start; -- Due to some MDNS issues, the commissioning of the OTA Provider Application - may fail. Please make sure that the SRP cache is disabled (_ot-ctl srp - server disable_) on the openthread border router while commissioning the OTA - Provider Application; -- No other Docker image should be running (e.g.: Docker image needed by Test - Harness) except the OTBR one. A docker image can be killed using the - command: - -``` -user@computer1:~/connectedhomeip$ : sudo docker kill $container_id -``` - -- In order to avoid MDNS issues, only one interface should be active at one - time. E.g.: if WiFi is used then disable the Ethernet interface and also - disable multicast on that interface: - -``` -user@computer1:~/connectedhomeip$ sudo ip link set dev eth0 down -user@computer1:~/connectedhomeip$ sudo ifconfig eth0 -multicast -``` - -- If OTBR Docker image is used, then the "-B" parameter should point to the - interface used for the backbone. - -- If Wi-Fi is used on a RPI4, then a 5Ghz network should be selected. - Otherwise, issues related to BLE-WiFi combo may appear. +Please see +[k32w1 OTA guide](../../../../docs/guides/nxp/nxp_mcxw71_ota_guide.md). diff --git a/examples/contact-sensor-app/nxp/k32w1/args.gni b/examples/contact-sensor-app/nxp/k32w1/args.gni index cb952c94bd74d1..b1c31aa7eb642a 100644 --- a/examples/contact-sensor-app/nxp/k32w1/args.gni +++ b/examples/contact-sensor-app/nxp/k32w1/args.gni @@ -23,6 +23,7 @@ nxp_device = "K32W1480" chip_enable_ota_requestor = true chip_stack_lock_tracking = "fatal" chip_enable_ble = true +chip_generate_link_map_file = true chip_system_config_provide_statistics = false chip_system_config_use_open_thread_inet_endpoints = true diff --git a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn index 081b5891b9c5f6..f487ff415f1330 100644 --- a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn @@ -83,10 +83,18 @@ rt_sdk("sdk") { include_dirs += [ "${example_platform_dir}/board/" ] sources += [ "${example_platform_dir}/board/pin_mux.c" ] sources += [ "${example_platform_dir}/board/hardware_init.c" ] - sources += [ "${example_platform_dir}/board/clock_config.c" ] - sources += [ "${example_platform_dir}/board/board.c" ] sources += [ "${example_platform_dir}/board/peripherals.c" ] + if (board_version == "frdm") { + include_dirs += [ "${example_platform_dir}/board/frdmrw612/" ] + sources += [ "${example_platform_dir}/board/frdmrw612/clock_config.c" ] + sources += [ "${example_platform_dir}/board/frdmrw612/board.c" ] + } else { + include_dirs += [ "${example_platform_dir}/board/rdrw612bga/" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/clock_config.c" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/board.c" ] + } + # Indicate the path to CHIPProjectConfig.h include_dirs += [ "include/config" ] @@ -98,7 +106,7 @@ rt_sdk("sdk") { # For matter with BR feature, increase FreeRTOS heap size if (chip_enable_wifi && chip_enable_openthread) { - defines += [ "configTOTAL_HEAP_SIZE=(size_t)(160 * 1024)" ] + defines += [ "configTOTAL_HEAP_SIZE=(size_t)(170 * 1024)" ] } defines += [ @@ -143,9 +151,7 @@ rt_executable("laundry-washer") { ] if (chip_enable_secure_dac_private_key_storage == 1) { - sources += [ - "${example_platform_dir}/factory_data/source/AppFactoryDataExample.cpp", - ] + sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] } else { sources += [ "${common_example_dir}/factory_data/source/AppFactoryDataDefaultImpl.cpp", diff --git a/examples/lighting-app/nxp/README.md b/examples/lighting-app/nxp/README.md new file mode 100644 index 00000000000000..74d0f9dc294813 --- /dev/null +++ b/examples/lighting-app/nxp/README.md @@ -0,0 +1,137 @@ +# Matter NXP Lighting Example Application + +This reference application implements an On/Off Light device type. It uses board +buttons or `matter-cli` for user input and LEDs for state feedback. You can use +this example as a reference for creating your own application. + +The example is based on: + +- [Matter](https://github.com/project-chip/connectedhomeip) +- [NXP github SDK](https://github.com/nxp-mcuxpresso/mcux-sdk) + +- [Matter NXP Lighting Example Application](#matter-nxp-lighting-example-application) + - [Supported devices](#supported-devices) + - [Introduction](#introduction) + - [Device UI](#device-ui) + - [Prerequisites for building](#prerequisites-for-building) + - [Building](#building) + - [Data model](#data-model) + - [Manufacturing data](#manufacturing-data) + - [Flashing and debugging](#flashing-and-debugging) + +## Supported devices + +- [k32w1](k32w1/README.md) + +## Introduction + +The application showcases a light bulb device that communicates with clients +over a low-power, 802.15.4 Thread network. + +It can be commissioned into an existing Matter network using a controller such +as `chip-tool`. + +This example implements a `User-Intent Commissioning Flow`, meaning the user has +to press a button in order for the device to be ready for commissioning. The +initial commissioning is done through `ble-thread` pairing method. + +The Thread network dataset will be transferred on the device using a secure +session over Bluetooth LE. In order to start the commissioning process, the user +must enable BLE advertising on the device manually. To pair successfully, the +commissioner must know the commissioning information corresponding to the +device: setup passcode and discriminator. This data is usually encoded within a +QR code or printed to the UART console. + +## Device UI + +The example application provides a simple UI that depicts the state of the +device and offers basic user control. This UI is implemented via the +general-purpose LEDs and buttons built in the evaluation boards. Please see each +supported device readme file for details. + +## Prerequisites for building + +In order to build the example, it is recommended to use a Linux distribution. +Please visit the supported Operating Systems list in +[BUILDING.md](../../../docs/guides/BUILDING.md#prerequisites). + +- Make sure that below prerequisites are correctly installed (as described in + [BUILDING.md](../../../docs/guides/BUILDING.md#prerequisites)) + +``` +sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev +``` + +- Step 1: checkout NXP specific submodules only + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive + ``` + +- Step 2: activate local environment + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/activate.sh + ``` + + If the script says the environment is out of date, you can update it by + running the following command: + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh + ``` + +- Step 3: Init NXP SDK(s) + + ``` + user@ubuntu:~/Desktop/git/connectedhomeip$ third_party/nxp/nxp_matter_support/scripts/update_nxp_sdk.py --platform common + ``` + +Note: By default, `update_nxp_sdk.py` will try to initialize all NXP SDKs. +Please run the script with arg `--help` to view all available options. + +## Building + +There are two options for building this reference app: + +- Using `build_examples.py` framework. +- Manually generating `ninja` files using `gn`. + +For manual generation and building, please see the specific readme file for your +device. + +A list of all available contact sensor targets can be viewed in the following +table: + +| target name | description | +| --------------------------------------------------- | ------------------------------------------------------------------------------- | +| nxp-device-freertos-lighting | Default lighting app | +| nxp-device-freertos-lighting-factory | Default lighting app with factory data | +| nxp-device-freertos-lighting-rotating-id | Lighting app with rotating device id support | +| nxp-device-freertos-lighting-factory-dac-conversion | Lighting app that leverages a secure enclave to secure the DAC private key | +| nxp-device-freertos-lighting-sw-v2 | Lighting app with software version 2 (can be used to test OTA) | +| nxp-device-freertos-lighting-factory-sw-v2 | Lighting app with factory data and software version 2 (can be used to test OTA) | + +where `device` can be one of the [Supported devices](#supported-devices). + +### Data model + +The application uses an NXP specific data model file: + +| path | description | +| ----------------------------- | --------------------------------------- | +| `zap-lit/lighting-on-off.zap` | Data model for On/Off Light device type | + +The data model can be changed by simply replacing the gn `deps` statement +corresponding to data model target. + +### Manufacturing data + +Use `chip_with_factory_data=1` in the gn build command to enable factory data. + +For a full guide on manufacturing flow, please see +[Guide for writing manufacturing data on NXP devices](../../../docs/guides/nxp/nxp_manufacturing_flow.md). + +## Flashing and debugging + +Please see the device specific readme file. diff --git a/examples/lighting-app/nxp/k32w1/.gn b/examples/lighting-app/nxp/k32w1/.gn index afa5bfea46aca8..5d6e10a31e334d 100644 --- a/examples/lighting-app/nxp/k32w1/.gn +++ b/examples/lighting-app/nxp/k32w1/.gn @@ -27,5 +27,5 @@ default_args = { import("//args.gni") # Import default platform configs - import("${chip_root}/src/platform/nxp/k32w1/args.gni") + import("${chip_root}/src/platform/nxp/mcxw71_k32w1/args.gni") } diff --git a/examples/lighting-app/nxp/k32w1/BUILD.gn b/examples/lighting-app/nxp/k32w1/BUILD.gn index b6e6db814ad221..9544ca8486a2ff 100644 --- a/examples/lighting-app/nxp/k32w1/BUILD.gn +++ b/examples/lighting-app/nxp/k32w1/BUILD.gn @@ -45,7 +45,7 @@ assert(target_os == "freertos") example_platform_dir = "${chip_root}/examples/platform/nxp/${nxp_platform}" common_example_dir = "${chip_root}/examples/platform/nxp/common" -k32w1_sdk("sdk") { +mcxw71_k32w1_sdk("sdk") { defines = [] include_dirs = [] sources = [] @@ -60,20 +60,20 @@ k32w1_sdk("sdk") { include_dirs += [ "${example_platform_dir}/app/project_include/openthread" ] include_dirs += [ - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480", ] sources += [ - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/clock_config.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/pin_mux.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/app_services_init.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_comp.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_dcdc.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_extflash.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_lp.c", - "${k32w1_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/hardware_init.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/clock_config.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/K32W1480/pin_mux.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/app_services_init.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_comp.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_dcdc.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_extflash.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/board_lp.c", + "${nxp_sdk_root}/middleware/wireless/framework/boards/kw45_k32w1/hardware_init.c", ] if (is_debug) { @@ -104,7 +104,7 @@ k32w1_sdk("sdk") { } } -k32w1_executable("light_app") { +mcxw71_k32w1_executable("light_app") { output_name = "chip-k32w1-light-example" defines = [] @@ -237,9 +237,9 @@ k32w1_executable("light_app") { if (use_smu2_static) { ldscript = "${example_platform_dir}/app/ldscripts/k32w1_app.ld" - base_ldscript_dir = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc" + base_ldscript_dir = "${nxp_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc" } else { - ldscript = "${k32w1_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" + ldscript = "${nxp_sdk_root}/middleware/wireless/framework/Common/devices/kw45_k32w1/gcc/connectivity.ld" } inputs = [ ldscript ] diff --git a/examples/lighting-app/nxp/k32w1/README.md b/examples/lighting-app/nxp/k32w1/README.md index 349deef640727d..ab54aab153e272 100644 --- a/examples/lighting-app/nxp/k32w1/README.md +++ b/examples/lighting-app/nxp/k32w1/README.md @@ -1,167 +1,63 @@ # Matter K32W1 Lighting Example Application -Matter K32W1 Lighting Example demonstrates how to remotely control a light bulb. -The light bulb is simulated using one of the LEDs from the expansion board. It -uses buttons to test turn on/turn off of the light bulb. You can use this -example as a reference for creating your own application. - -The example is based on -[Matter](https://github.com/project-chip/connectedhomeip) and the NXP K32W1 SDK, -and supports remote access and control of a light bulb over a low-power, -802.15.4 Thread network. - -The example behaves as a Matter accessory, that is a device that can be paired -into an existing Matter network and can be controlled by this network. - -
+For generic information related to on/off light application, please see the +[common README](../README.md). - [Matter K32W1 Lighting Example Application](#matter-k32w1-lighting-example-application) - [Introduction](#introduction) - - [Bluetooth LE Advertising](#bluetooth-le-advertising) - - [Bluetooth LE Rendezvous](#bluetooth-le-rendezvous) - - [Thread Provisioning](#thread-provisioning) - [Device UI](#device-ui) - [Building](#building) - [`SMU2` Memory](#smu2-memory) - [LED PWM](#led-pwm) - - [Manufacturing data](#manufacturing-data) - [Flashing](#flashing) - [Flashing the `NBU` image](#flashing-the-nbu-image) - [Flashing the host image](#flashing-the-host-image) - [Debugging](#debugging) - - [OTA](#ota) - - [Convert `srec` into `sb3` file](#convert-srec-into-sb3-file) - - [Convert `sb3` into `ota` file](#convert-sb3-into-ota-file) - - [OTA factory data](#ota-factory-data) - - [Running OTA](#running-ota) - - [Known issues](#known-issues) - [Running RPC console](#running-rpc-console) - - + - [OTA](#ota) ## Introduction -![K32W1 EVK](../../../platform/nxp/k32w1/doc/images/k32w1-evk.jpg) - -The K32W1 lighting example application provides a working demonstration of a -light bulb device, built using the Matter codebase and the NXP K32W1 SDK. The -example supports remote access (e.g.: using CHIP Tool from a mobile phone) and -control of a light bulb over a low-power, 802.15.4 Thread network. It is capable -of being paired into an existing Matter network along with other Matter-enabled -devices. - -The Matter device that runs the lighting application is controlled by the Matter -controller device over the Thread protocol. By default, the Matter device has -Thread disabled, and it should be paired over Bluetooth LE with the Matter -controller and obtain configuration from it. The actions required before -establishing full communication are described below. +This is an on/off lighting application implemented for a k32w1 device. -### Bluetooth LE Advertising +The following board was used when testing this Matter reference app for a +`k32w1` device: +![K32W1 EVK](../../../platform/nxp/mcxw71_k32w1/doc/images/k32w1-evk.jpg) -In this example, to commission the device onto a Matter network, it must be -discoverable over Bluetooth LE. For security reasons, you must start Bluetooth -LE advertising manually after powering up the device by pressing Button SW2. +## Device UI -### Bluetooth LE Rendezvous +The state feedback is provided through LED effects: -In this example, the commissioning procedure (called rendezvous) is done over -Bluetooth LE between a Matter device and the Matter controller, where the -controller has the commissioner role. +| widget | effect | description | +| ------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------- | +| LED2 | short flash on (50ms on/950ms off) | The device is in an unprovisioned (unpaired) state and is waiting for a commissioner to connect. | +| LED2 | rapid even flashing (100ms period) | The device is in an unprovisioned state and a commissioner is connected via BLE. | +| LED2 | short flash off (950ms on/50ms off) | The device is fully provisioned, but does not yet have full network (Thread) or service connectivity. | +| LED2 | solid on | The device is fully provisioned and has full network and service connectivity. | +| RGB LED | on | The `OnOff` attribute of the `On/Off` cluster is `true` (simulating device turned on). | +| RGB LED | off | The `OnOff` attribute of the `On/Off` cluster is `false` (simulating device turned off). | -To start the rendezvous, the controller must get the commissioning information -from the Matter device. The data payload is encoded within a QR code, or printed -to the UART console. +NOTE: `LED2` will be disabled when OTA is used. On K32W1 EVK board, `PTB0` is +wired to both `LED2` and CS (Chip Select) of the External Flash Memory. Since +the OTA image is stored in external memory, `LED2` operations will affect OTA +operation by corrupting packages and OTA will not work. -### Thread Provisioning +The user actions are summarized below: -## Device UI +| button | action | output | +| ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| SW2 | short press | Enable BLE advertising | +| SW2 | long press | Initiate a factory reset (can be cancelled by pressing the button again within the factory reset timeout limit - 6 seconds by default) | +| SW3 | short press | Toggle attribute `OnOff` value | +| SW3 | long press | Clean soft reset of the device (takes into account proper Matter shutdown procedure) | The example application provides a simple UI that depicts the state of the device and offers basic user control. This UI is implemented via the general-purpose LEDs and buttons built in the K32W1 EVK board. -**LED 2** shows the overall state of the device and its connectivity. Four -states are depicted: - -- _Short Flash On (50ms on/950ms off)_ — The device is in an - unprovisioned (unpaired) state and is waiting for a commissioning - application to connect. - -* _Rapid Even Flashing (100ms on/100ms off)_ — The device is in an - unprovisioned state and a commissioning application is connected via BLE. - -- _Short Flash Off (950ms on/50ms off)_ — The device is full - provisioned, but does not yet have full network (Thread) or service - connectivity. - -* _Solid On_ — The device is fully provisioned and has full network and - service connectivity. - -NOTE: LED2 will be disabled when CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR is -enabled. On K32W1 EVK board, `PTB0` is wired to LED2 also is wired to CS (Chip -Select) External Flash Memory. OTA image is stored in external memory because of -it's size. If LED2 is enabled then it will affect External Memory CS and OTA -will not work. - -**RGB LED** shows the state of the simulated light bulb. When the LED is lit the -light bulb is on; when not lit, the light bulb is off. - -**Button SW2** can be used to start BLE advertising. A SHORT press of the button -will enable Bluetooth LE advertising for a predefined period of time. A LONG -Press Button SW2 initiates a factory reset. After an initial period of 3 -seconds, LED 2 and RGB LED will flash in unison to signal the pending reset. -After 6 seconds will cause the device to reset its persistent configuration and -initiate a reboot. The reset action can be cancelled by press SW2 button at any -point before the 6 second limit. - -**Button SW3** can be used to change the state of the simulated light bulb. This -can be used to mimic a user manually operating a switch. The button behaves as a -toggle, swapping the state every time it is short pressed. When long pressed, it -does a clean soft reset that takes into account Matter shutdown procedure. - ## Building -In order to build the Project CHIP example, we recommend using a Linux -distribution. Supported Operating Systems and prerequisites are listed in -[BUILDING](../../../../docs/guides/BUILDING.md). - -- Make sure that below prerequisites are correctly installed - -``` -sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ - libglib2.0-dev libavahi-client-dev ninja-build python3-venv python3-dev \ - python3-pip unzip libgirepository1.0-dev libcairo2-dev libreadline-dev -``` - -- Step 1: checkout NXP specific submodules only - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/checkout_submodules.py --shallow --platform nxp --recursive -``` - -- Step 2: activate local environment - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/activate.sh -``` - -If the script says the environment is out of date, you can update it by running -the following command: - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh -``` - -- Step 3: Init NXP SDK(s) - -``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/setup/nxp/update_nxp_sdk.py --platform common_sdk -``` - -Note: By default setup/nxp/update_nxp_sdk.py will try to initialize all NXP -SDKs. Arg "-- help" could be used to view all available options. - -- Start building the application. +Manually building requires running the following commands: ``` user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lighting-app/nxp/k32w1 @@ -169,37 +65,40 @@ user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w1$ gn ge user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w1$ ninja -C out/debug ``` -In case that Openthread CLI is needed, `chip_with_ot_cli` build argument must be -set to 1. +Please note that running `gn gen out/debug` without `--args` option will use the +default gn args values found in `args.gni`. -After a successful build, the `elf` and `srec` files are found in `out/debug/` - -see the files prefixed with `chip-k32w1-light-example`. +After a successful build, the `elf` and `srec` files are found in `out/debug/`. +See the files prefixed with `chip-k32w1-light-example`. ### `SMU2` Memory -Some Matter instances and global variables can be placed in the `NBU` `SMU2` -memory. When compiling with OpenThread FTD support (`chip_openthread_ftd=true`) -and with `use_smu2_static=true`, the following components are placed in `SMU2` -memory: +Additional memory is provided to the application by moving some Matter instances +and global variables in the shared memory area from `NBU` domain. -- `gImageProcessor` from OTAImageProcessorImpl.cpp. -- `gApplicationProcessor` from OTAHooks.cpp. -- `Server::sServer` from Server.cpp. -- `ThreadStackManagerImpl::sInstance` from ThreadStackManagerImpl.cpp. - -These instances and global variables are placed in `SMU2` memory through name -matching in the application linker script. They should not be changed or, if -changed, the names must be updated in `k32w1_app.ld`. See +Note: These instances and global variables are placed in `SMU2` memory through +name matching in the application linker script. They should not be changed or, +if changed, the names must be updated in `k32w1_app.ld`. See [k32w1_app.ld](../../../platform/nxp/k32w1/app/ldscripts/k32w1_app.ld) for names and `SMU2` memory range size. -The OpenThread buffers can be allocated from a 13KB `SMU2` range after a -successful commissioning process until a factory reset is initiated. This way, -the OpenThread buffers will be dynamically allocated instead of statically, -freeing some `SRAM`. To enable this feature compile with OpenThread FTD support -(`chip_openthread_ftd=true`) and with `use_smu2_dynamic=true`. +When compiling the application as an OT Full Thread Device +(`chip_openthread_ftd=true`), using `use_smu2_static=true` gn arg will cause the +following symbols to be moved to `SMU2` area: + +| symbol name | file | +| ----------------------------------- | ---------------------------- | +| `gImageProcessor` | `OTAImageProcessorImpl.cpp` | +| `gApplicationProcessor` | `OTAHooks.cpp` | +| `Server::sServer` | `Server.cpp` | +| `ThreadStackManagerImpl::sInstance` | `ThreadStackManagerImpl.cpp` | -`use_smu2_static` and `use_smu2_dynamic` are set to `true` by default. +Additionally, using `use_smu2_dynamic=true` will cause the OpenThread buffers to +be dynamically allocated from a 13KB `SMU2` range after a successful +commissioning process. + +`use_smu2_static` and `use_smu2_dynamic` are set to `true` in the default +example. ### LED PWM @@ -208,17 +107,10 @@ pins. In order to enable the dimming feature, the pins need to be configured in PWM mode and synced with channels of the `TPM` (Timer PWM Module). To enable this feature, compile the application with: `chip_config_dimmable_led=true` -If the feature is enabled, the LED brightness can be controlled using **Level -control** cluster +If the feature is enabled, the LED brightness can be controlled using +`LevelControl` cluster [commands](../../../../docs/guides/chip_tool_guide.md#step-7-control-application-data-model-clusters). -## Manufacturing data - -Use `chip_with_factory_data=1` in the gn build command to enable factory data. - -For a full guide on manufacturing flow, please see -[Guide for writing manufacturing data on NXP devices](../../../../docs/guides/nxp/nxp_manufacturing_flow.md). - ## Flashing Two images must be written to the board: one for the host (CM33) and one for the @@ -227,7 +119,7 @@ Two images must be written to the board: one for the host (CM33) and one for the The image needed on the host side is the one generated in `out/debug/` while the one needed on the `NBU` side can be found in the downloaded NXP-SDK package at path - -`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter_$version.sb3`. +`middleware\wireless\ieee-802.15.4\bin\k32w1\k32w1_nbu_ble_15_4_dyn_matter.sb3`. ### Flashing the `NBU` image @@ -249,29 +141,26 @@ build process. If debugging is needed then jump directly to the [Debugging](#debugging) section. Otherwise, if only flashing is needed then -[JLink 7.84b](https://www.segger.com/downloads/jlink/) can be used: +[JLink 7.84b or greater](https://www.segger.com/downloads/jlink/) can be used: - Plug K32W1 to the USB port (no need to keep the SW4 button pressed while - doing this) - -- Create a new file, `commands_script`, with the following content (change - application name accordingly): - -```bash -reset -halt -loadfile chip-k32w1-light-example.srec -reset -go -quit -``` + doing this, e.g. ISP mode is not needed for host flashing) -- copy the application and `commands_script` in the same folder that JLink - executable is placed. Execute: +- Connect JLink to the device: -```bash -$ jlink -device K32W1480 -if SWD -speed 4000 -autoconnect 1 -CommanderScript commands_script -``` + ```bash + JLinkExe -device K32W1480 -if SWD -speed 4000 -autoconnect 1 + ``` + +- Run the following commands: + ```bash + reset + halt + loadfile chip-k32w1-light-example.srec + reset + go + quit + ``` ## Debugging @@ -280,7 +169,7 @@ One option for debugging would be to use MCUXpresso IDE. - Drag-and-drop the zip file containing the NXP SDK in the "Installed SDKs" tab: -![Installed SDKs](../../../platform/nxp/k32w1/doc/images/installed_sdks.jpg) +![Installed SDKs](../../../platform/nxp/mcxw71_k32w1/doc/images/installed_sdks.jpg) - Import any demo application from the installed SDK: @@ -288,7 +177,7 @@ One option for debugging would be to use MCUXpresso IDE. Import SDK example(s).. -> choose a demo app (demo_apps -> hello_world) -> Finish ``` -![Import demo](../../../platform/nxp/k32w1/doc/images/import_demo.jpg) +![Import demo](../../../platform/nxp/mcxw71_k32w1/doc/images/import_demo.jpg) - Flash the previously imported demo application on the board: @@ -307,7 +196,7 @@ resulted after ot-nxp compilation. File -> Import -> C/C++ -> Existing Code as Makefile Project ``` -![New Project](../../../platform/nxp/k32w1/doc/images/new_project.jpg) +![New Project](../../../platform/nxp/mcxw71_k32w1/doc/images/new_project.jpg) - Replace the path of the existing demo application with the path of the K32W1 application: @@ -316,185 +205,7 @@ File -> Import -> C/C++ -> Existing Code as Makefile Project Run -> Debug Configurations... -> C/C++ Application ``` -![Debug K32W1](../../../platform/nxp/k32w1/doc/images/debug_k32w1.jpg) - -## OTA - -### Convert `srec` into `sb3` file - -The OTA image files must be encrypted using Over The Air Programming Tool -([OTAP](https://www.nxp.com/design/microcontrollers-developer-resources/connectivity-tool-suite:CONNECTIVITY-TOOL-SUITE?#downloads)). -Bootloader will load the new OTA image only if it detects that the file was -encrypted with the `OTAP` correct keys. - -`.srec` file is input for Over The air Programming (`OTAP`) application -(unencrypted) and it's converted to `.sb3` format (encrypted). - -In `OTAP` application - -- select OTA protocol => `OTAP` Matter -- Browse File -- follow default options (KW45/K32W148, Preserve NVM) -- image information: will update "Application Core (MCU)" - this will generate - the image only for the CM33 core -- keep other settings at default values - -### Convert `sb3` into `ota` file - -In order to build an OTA image, use NXP wrapper over the standard tool -`src/app/ota_image_tool.py`: - -- `scripts/tools/nxp/factory_data_generator/ota_image_tool.py` - -The tool can be used to generate an OTA image with the following format: - -``` - | OTA image header | TLV1 | TLV2 | ... | TLVn | -``` - -where each TLV is in the form `|tag|length|value|`. - -Note that "standard" TLV format is used. Matter TLV format is only used for -factory data TLV value. - -Please see more in the -[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). - -Here is an example that generates an OTA image with application update TLV from -a sb3 file: - -``` -./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 43033 -vs "1.0" -da sha256 --app-input-file ~/binaries/chip-k32w1-43033.sb3 ~/binaries/chip-k32w1-43033.ota - -``` - -A note regarding OTA image header version (`-vn` option). An application binary -has its own software version (given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION`, which can be overwritten). For -having a correct OTA process, the OTA header version should be the same as the -binary embedded software version. A user can set a custom software version in -the gn build args by setting `chip_software_version` to the wanted version. - -### OTA factory data - -A user can update the factory data through OTA, at the same time the application -firmware is updated by enabling the following processor in the `gn args`: - -- `chip_enable_ota_factory_data_processor=1` to enable default factory data - update processor (disabled by default). - -The OTA image used must be updated to include the new factory data. - -[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). - -### Running OTA - -The OTA topology used for OTA testing is illustrated in the figure below. -Topology is similar with the one used for Matter Test Events. - -![OTA_TOPOLOGY](../../../platform/nxp/k32w1/doc/images/ota_topology.JPG) - -The concept for OTA is the next one: - -- there is an OTA Provider Application that holds the OTA image. In our case, - this is a Linux application running on an Ubuntu based-system; -- the OTA Requestor functionality is embedded inside the Lighting Application. - It will be used for requesting OTA blocks from the OTA Provider; -- the controller (a linux application called chip-tool) will be used for - commissioning both the device and the OTA Provider App. The device will be - commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the - OTA Provider Application will be commissioned using the _onnetwork_ option - of chip-tool; -- during commissioning, each device is assigned a node id by the chip-tool - (can be specified manually by the user). Using the node id of the device and - of the lighting application, chip-tool triggers the OTA transfer by invoking - the _announce-ota-provider_ command - basically, the OTA Requestor is - informed of the node id of the OTA Provider Application. - -_Computer #1_ can be any system running an Ubuntu distribution. We recommand -using CSA official instructions from -[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are -proposed. Also, CSA official instructions document point to the OS/Docker images -that should be used on the RPis. For compatibility reasons, we recommand -compiling chip-tool and OTA Provider applications with the same commit id that -was used for compiling the Lighting Application. Also, please note that there is -a single controller (chip-tool) running on Computer #1 which is used for -commissioning both the device and the OTA Provider Application. If needed, -[these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be -used for connecting the RPis to WiFi. - -Build the Linux OTA provider application: - -``` -user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/ota-provider-app chip_config_network_layer_ble=false -``` - -Build Linux chip-tool: - -``` -user@computer1:~/connectedhomeip$ : ./scripts/examples/gn_build_example.sh examples/chip-tool out/chip-tool-app -``` - -Start the OTA Provider Application: - -``` -user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* -user@computer1:~/connectedhomeip$ : ./out/ota-provider-app/chip-ota-provider-app -f chip-k32w1-43033.ota -``` - -Provision the OTA provider application and assign node id _1_. Also, grant ACL -entries to allow OTA requestors: - -``` -user@computer1:~/connectedhomeip$ : rm -rf /tmp/chip_* -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing onnetwork 1 20202021 -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": null, "targets": null}]' 1 0 -``` - -Provision the device and assign node id _2_: - -``` -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool pairing ble-thread 2 hex: 20202021 3840 -``` - -Start the OTA process: - -``` -user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-ota-provider 1 0 0 0 2 0 -``` - -### Known issues - -- SRP cache on the openthread border router needs to flushed each time a new - commissioning process is attempted. For this, factory reset the device, then - execute _ot-ctl server disable_ followed by _ot-ctl server enable_. After - this step, the commissioning process of the device can start; -- Due to some MDNS issues, the commissioning of the OTA Provider Application - may fail. Please make sure that the SRP cache is disabled (_ot-ctl srp - server disable_) on the openthread border router while commissioning the OTA - Provider Application; -- No other Docker image should be running (e.g.: Docker image needed by Test - Harness) except the OTBR one. A docker image can be killed using the - command: - -``` -user@computer1:~/connectedhomeip$ : sudo docker kill $container_id -``` - -- In order to avoid MDNS issues, only one interface should be active at one - time. E.g.: if WiFi is used then disable the Ethernet interface and also - disable multicast on that interface: - -``` -user@computer1:~/connectedhomeip$ sudo ip link set dev eth0 down -user@computer1:~/connectedhomeip$ sudo ifconfig eth0 -multicast -``` - -- If OTBR Docker image is used, then the "-B" parameter should point to the - interface used for the backbone. - -- If Wi-Fi is used on a RPI4, then a 5Ghz network should be selected. - Otherwise, issues related to BLE-WiFi combo may appear. +![Debug K32W1](../../../platform/nxp/mcxw71_k32w1/doc/images/debug_k32w1.jpg) ## Running RPC console @@ -506,7 +217,7 @@ client. An example of an RPC client is the `chip-console`, which can be accessed by running: `chip-console --device /dev/tty. -b 115200 -o pw_log.out` -The console should already have been installed in the virtual environment. From +The console should have already been installed in the virtual environment. From the `chip-console`, a user can send specific commands to the device. For button commands, please run `rpcs.chip.rpc.Button.Event(index)` based on the @@ -520,3 +231,8 @@ table below: | 3 | Soft reset the device | To reboot the device, please run `rpcs.chip.rpc.Device.Reboot()`. + +## OTA + +Please see +[k32w1 OTA guide](../../../../docs/guides/nxp/nxp_mcxw71_ota_guide.md). diff --git a/examples/lighting-app/nxp/k32w1/args.gni b/examples/lighting-app/nxp/k32w1/args.gni index 7d5e752aae6934..5c854bc1c3c187 100644 --- a/examples/lighting-app/nxp/k32w1/args.gni +++ b/examples/lighting-app/nxp/k32w1/args.gni @@ -23,6 +23,7 @@ chip_config_dimmable_led = false chip_enable_ota_requestor = true chip_stack_lock_tracking = "fatal" chip_enable_ble = true +chip_generate_link_map_file = true is_debug = false @@ -34,5 +35,5 @@ chip_system_config_provide_statistics = false chip_system_config_use_open_thread_inet_endpoints = true chip_with_lwip = false -use_smu2_static = false -use_smu2_dynamic = false +use_smu2_static = true +use_smu2_dynamic = true diff --git a/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp b/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp index bc7a8dca431c42..2e40fdefb2e119 100644 --- a/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp +++ b/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp @@ -120,9 +120,8 @@ void chip::NXP::App::CommonDeviceCallbacks::OnInternetConnectivityChange(const C char ip_addr[Inet::IPAddress::kMaxStringLength]; event->InternetConnectivityChange.ipAddress.ToString(ip_addr); ChipLogProgress(DeviceLayer, "IPv6 Server ready at: [%s]:%d", ip_addr, CHIP_PORT); -#if !CHIP_ENABLE_OPENTHREAD // No need to do this for OT mDNS server + chip::app::DnssdServer::Instance().StartServer(); -#endif } else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) { diff --git a/examples/platform/nxp/k32w1/app/ldscripts/k32w1_app.ld b/examples/platform/nxp/mcxw71_k32w1/app/ldscripts/k32w1_app.ld similarity index 100% rename from examples/platform/nxp/k32w1/app/ldscripts/k32w1_app.ld rename to examples/platform/nxp/mcxw71_k32w1/app/ldscripts/k32w1_app.ld diff --git a/examples/platform/nxp/k32w1/app/project_include/freeRTOS/FreeRTOSConfig.h b/examples/platform/nxp/mcxw71_k32w1/app/project_include/freeRTOS/FreeRTOSConfig.h similarity index 100% rename from examples/platform/nxp/k32w1/app/project_include/freeRTOS/FreeRTOSConfig.h rename to examples/platform/nxp/mcxw71_k32w1/app/project_include/freeRTOS/FreeRTOSConfig.h diff --git a/examples/platform/nxp/k32w1/app/project_include/openthread/OpenThreadConfig.h b/examples/platform/nxp/mcxw71_k32w1/app/project_include/openthread/OpenThreadConfig.h similarity index 100% rename from examples/platform/nxp/k32w1/app/project_include/openthread/OpenThreadConfig.h rename to examples/platform/nxp/mcxw71_k32w1/app/project_include/openthread/OpenThreadConfig.h diff --git a/examples/platform/nxp/k32w1/app/support/BUILD.gn b/examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn similarity index 100% rename from examples/platform/nxp/k32w1/app/support/BUILD.gn rename to examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn diff --git a/examples/platform/nxp/k32w1/app/support/FreeRtosHooks.c b/examples/platform/nxp/mcxw71_k32w1/app/support/FreeRtosHooks.c similarity index 100% rename from examples/platform/nxp/k32w1/app/support/FreeRtosHooks.c rename to examples/platform/nxp/mcxw71_k32w1/app/support/FreeRtosHooks.c diff --git a/examples/platform/nxp/k32w1/app/support/FreeRtosHooks.h b/examples/platform/nxp/mcxw71_k32w1/app/support/FreeRtosHooks.h similarity index 100% rename from examples/platform/nxp/k32w1/app/support/FreeRtosHooks.h rename to examples/platform/nxp/mcxw71_k32w1/app/support/FreeRtosHooks.h diff --git a/examples/platform/nxp/k32w1/app/support/Memconfig.cpp b/examples/platform/nxp/mcxw71_k32w1/app/support/Memconfig.cpp similarity index 100% rename from examples/platform/nxp/k32w1/app/support/Memconfig.cpp rename to examples/platform/nxp/mcxw71_k32w1/app/support/Memconfig.cpp diff --git a/examples/platform/nxp/k32w1/board/peripherals.c b/examples/platform/nxp/mcxw71_k32w1/board/peripherals.c similarity index 100% rename from examples/platform/nxp/k32w1/board/peripherals.c rename to examples/platform/nxp/mcxw71_k32w1/board/peripherals.c diff --git a/examples/platform/nxp/k32w1/board/peripherals.h b/examples/platform/nxp/mcxw71_k32w1/board/peripherals.h similarity index 100% rename from examples/platform/nxp/k32w1/board/peripherals.h rename to examples/platform/nxp/mcxw71_k32w1/board/peripherals.h diff --git a/examples/platform/nxp/k32w1/button/ButtonManager.cpp b/examples/platform/nxp/mcxw71_k32w1/button/ButtonManager.cpp similarity index 100% rename from examples/platform/nxp/k32w1/button/ButtonManager.cpp rename to examples/platform/nxp/mcxw71_k32w1/button/ButtonManager.cpp diff --git a/examples/platform/nxp/k32w1/button/ButtonManager.h b/examples/platform/nxp/mcxw71_k32w1/button/ButtonManager.h similarity index 100% rename from examples/platform/nxp/k32w1/button/ButtonManager.h rename to examples/platform/nxp/mcxw71_k32w1/button/ButtonManager.h diff --git a/examples/platform/nxp/k32w1/clusters/Identify.cpp b/examples/platform/nxp/mcxw71_k32w1/clusters/Identify.cpp similarity index 100% rename from examples/platform/nxp/k32w1/clusters/Identify.cpp rename to examples/platform/nxp/mcxw71_k32w1/clusters/Identify.cpp diff --git a/examples/platform/nxp/k32w1/doc/images/debug_k32w1.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/debug_k32w1.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/debug_k32w1.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/debug_k32w1.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/import_demo.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/import_demo.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/import_demo.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/import_demo.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/installed_sdks.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/installed_sdks.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/installed_sdks.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/installed_sdks.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/k32w1-evk.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/k32w1-evk.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/k32w1-evk.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/k32w1-evk.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/mcux-sdk-download.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/mcux-sdk-download.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/mcux-sdk-download.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/mcux-sdk-download.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/new_project.jpg b/examples/platform/nxp/mcxw71_k32w1/doc/images/new_project.jpg similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/new_project.jpg rename to examples/platform/nxp/mcxw71_k32w1/doc/images/new_project.jpg diff --git a/examples/platform/nxp/k32w1/doc/images/ota_topology.JPG b/examples/platform/nxp/mcxw71_k32w1/doc/images/ota_topology.JPG similarity index 100% rename from examples/platform/nxp/k32w1/doc/images/ota_topology.JPG rename to examples/platform/nxp/mcxw71_k32w1/doc/images/ota_topology.JPG diff --git a/examples/platform/nxp/k32w1/factory_data/source/AppFactoryDataExample.cpp b/examples/platform/nxp/mcxw71_k32w1/factory_data/source/AppFactoryDataExample.cpp similarity index 100% rename from examples/platform/nxp/k32w1/factory_data/source/AppFactoryDataExample.cpp rename to examples/platform/nxp/mcxw71_k32w1/factory_data/source/AppFactoryDataExample.cpp diff --git a/examples/platform/nxp/k32w1/operational_keystore/OperationalKeystore.cpp b/examples/platform/nxp/mcxw71_k32w1/operational_keystore/OperationalKeystore.cpp similarity index 100% rename from examples/platform/nxp/k32w1/operational_keystore/OperationalKeystore.cpp rename to examples/platform/nxp/mcxw71_k32w1/operational_keystore/OperationalKeystore.cpp diff --git a/examples/platform/nxp/k32w1/ota/OtaUtils.cpp b/examples/platform/nxp/mcxw71_k32w1/ota/OtaUtils.cpp similarity index 100% rename from examples/platform/nxp/k32w1/ota/OtaUtils.cpp rename to examples/platform/nxp/mcxw71_k32w1/ota/OtaUtils.cpp diff --git a/examples/platform/nxp/k32w1/rpc/AppRpc.cpp b/examples/platform/nxp/mcxw71_k32w1/rpc/AppRpc.cpp similarity index 100% rename from examples/platform/nxp/k32w1/rpc/AppRpc.cpp rename to examples/platform/nxp/mcxw71_k32w1/rpc/AppRpc.cpp diff --git a/examples/platform/nxp/k32w1/util/LedDimmer.cpp b/examples/platform/nxp/mcxw71_k32w1/util/LedDimmer.cpp similarity index 100% rename from examples/platform/nxp/k32w1/util/LedDimmer.cpp rename to examples/platform/nxp/mcxw71_k32w1/util/LedDimmer.cpp diff --git a/examples/platform/nxp/k32w1/util/LedOnOff.cpp b/examples/platform/nxp/mcxw71_k32w1/util/LedOnOff.cpp similarity index 100% rename from examples/platform/nxp/k32w1/util/LedOnOff.cpp rename to examples/platform/nxp/mcxw71_k32w1/util/LedOnOff.cpp diff --git a/examples/platform/nxp/k32w1/util/LightingManagerDimmable.cpp b/examples/platform/nxp/mcxw71_k32w1/util/LightingManagerDimmable.cpp similarity index 100% rename from examples/platform/nxp/k32w1/util/LightingManagerDimmable.cpp rename to examples/platform/nxp/mcxw71_k32w1/util/LightingManagerDimmable.cpp diff --git a/examples/platform/nxp/k32w1/util/LightingManagerDimmable.h b/examples/platform/nxp/mcxw71_k32w1/util/LightingManagerDimmable.h similarity index 100% rename from examples/platform/nxp/k32w1/util/LightingManagerDimmable.h rename to examples/platform/nxp/mcxw71_k32w1/util/LightingManagerDimmable.h diff --git a/examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp b/examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp index 50992a049f01a5..489c867f0ea254 100644 --- a/examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp +++ b/examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp @@ -25,6 +25,11 @@ #if CONFIG_CHIP_PLAT_LOAD_REAL_FACTORY_DATA #include "FactoryDataProvider.h" +#ifdef ENABLE_SECURE_WHOLE_FACTORY_DATA +static uint8_t aes256TestKey[] + __attribute__((aligned)) = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; +#endif #else #include #endif @@ -47,6 +52,12 @@ CHIP_ERROR NXP::App::AppFactoryData_PreMatterStackInit(void) CHIP_ERROR NXP::App::AppFactoryData_PostMatterStackInit(void) { #if CONFIG_CHIP_PLAT_LOAD_REAL_FACTORY_DATA +#ifdef ENABLE_SECURE_WHOLE_FACTORY_DATA + /* Please Note, because currently we only support AES-256 key provisioning and de-wrap, so the trasfterred AES key should be 256 + * bit size*/ + FactoryDataPrvdImpl().SetEncryptionMode(FactoryDataProvider::encrypt_ecb); + FactoryDataPrvdImpl().SetAes256Key(&aes256TestKey[0]); +#endif FactoryDataPrvdImpl().Init(); SetDeviceInstanceInfoProvider(&FactoryDataPrvd()); SetDeviceAttestationCredentialsProvider(&FactoryDataPrvd()); diff --git a/examples/thermostat/nxp/rt/rw61x/BUILD.gn b/examples/thermostat/nxp/rt/rw61x/BUILD.gn index 409fa9efbbce0a..711ebf0d655f20 100644 --- a/examples/thermostat/nxp/rt/rw61x/BUILD.gn +++ b/examples/thermostat/nxp/rt/rw61x/BUILD.gn @@ -83,10 +83,18 @@ rt_sdk("sdk") { include_dirs += [ "${example_platform_dir}/board/" ] sources += [ "${example_platform_dir}/board/pin_mux.c" ] sources += [ "${example_platform_dir}/board/hardware_init.c" ] - sources += [ "${example_platform_dir}/board/clock_config.c" ] - sources += [ "${example_platform_dir}/board/board.c" ] sources += [ "${example_platform_dir}/board/peripherals.c" ] + if (board_version == "frdm") { + include_dirs += [ "${example_platform_dir}/board/frdmrw612/" ] + sources += [ "${example_platform_dir}/board/frdmrw612/clock_config.c" ] + sources += [ "${example_platform_dir}/board/frdmrw612/board.c" ] + } else { + include_dirs += [ "${example_platform_dir}/board/rdrw612bga/" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/clock_config.c" ] + sources += [ "${example_platform_dir}/board/rdrw612bga/board.c" ] + } + # Indicate the path to CHIPProjectConfig.h include_dirs += [ "include/config" ] @@ -98,7 +106,7 @@ rt_sdk("sdk") { # For matter with BR feature, increase FreeRTOS heap size if (chip_enable_wifi && chip_enable_openthread) { - defines += [ "configTOTAL_HEAP_SIZE=(size_t)(160 * 1024)" ] + defines += [ "configTOTAL_HEAP_SIZE=(size_t)(170 * 1024)" ] } } @@ -139,9 +147,7 @@ rt_executable("thermostat") { ] if (chip_enable_secure_dac_private_key_storage == 1) { - sources += [ - "${example_platform_dir}/factory_data/source/AppFactoryDataExample.cpp", - ] + sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] } else { sources += [ "${common_example_dir}/factory_data/source/AppFactoryDataDefaultImpl.cpp", diff --git a/scripts/build/builders/nxp.py b/scripts/build/builders/nxp.py index 00678e8b0cc246..3592400fc0c631 100644 --- a/scripts/build/builders/nxp.py +++ b/scripts/build/builders/nxp.py @@ -126,8 +126,7 @@ def __init__(self, enable_wifi: bool = False, disable_ipv4: bool = False, enable_shell: bool = False, - enable_ota: bool = False, - is_sdk_package: bool = True): + enable_ota: bool = False): super(NxpBuilder, self).__init__( root=app.BuildRoot(root, board, os_env), runner=runner) @@ -149,7 +148,6 @@ def __init__(self, self.enable_wifi = enable_wifi self.enable_ota = enable_ota self.enable_shell = enable_shell - self.is_sdk_package = is_sdk_package def GnBuildArgs(self): args = [] @@ -198,11 +196,6 @@ def GnBuildArgs(self): # thread is enabled by default on kw32 if self.board == NxpBoard.RW61X: args.append('chip_enable_openthread=true chip_inet_config_enable_ipv4=false') - if self.enable_wifi: - args.append('openthread_root=\\"//third_party/connectedhomeip/third_party/openthread/ot-nxp/openthread-br\\"') - - if self.is_sdk_package: - args.append('is_sdk_package=true') return args diff --git a/scripts/setup/nxp/update_nxp_sdk.py b/scripts/setup/nxp/update_nxp_sdk.py deleted file mode 100755 index da948306f887d7..00000000000000 --- a/scripts/setup/nxp/update_nxp_sdk.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2024 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import argparse -import logging -import os -import shutil -import subprocess -import sys -from dataclasses import dataclass - -CHIP_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..')) - - -@dataclass(init=False) -class NxpSdk: - sdk_name: str - sdk_target_location: str - sdk_manifest_path: str - - def __init__(self, name, sdk_target_location): - self.sdk_name = name - self.sdk_target_location = sdk_target_location - self.sdk_manifest_path = os.path.abspath(os.path.join(sdk_target_location, 'manifest')) - - -def NxpSdk_k32w0(): - rel_path_k32w0 = 'third_party/nxp/nxp_matter_support/github_sdk/k32w0' - sdk = NxpSdk('k32w0', os.path.abspath(os.path.join(CHIP_ROOT, rel_path_k32w0))) - return sdk - - -ALL_PLATFORM_SDK = [ - NxpSdk_k32w0(), -] - -ALL_PLATFORM_NAME = [p.sdk_name for p in ALL_PLATFORM_SDK] - - -def clean_sdk_local_changes(sdk_location): - logging.warning("SDK will be cleaned all local modification(s) will be lost") - # Cleaning all local modifications - git_clean_command = "git reset --hard && git clean -xdf" - command = ['west', 'forall', '-c', git_clean_command, '-a'] - subprocess.run(command, cwd=sdk_location, check=True) - - -def init_nxp_sdk_version(nxp_sdk, force): - print("Init SDK in: " + nxp_sdk.sdk_target_location) - west_path = os.path.join(nxp_sdk.sdk_target_location, '.west') - if os.path.exists(west_path): - if not force: - logging.error("SDK is already initialized, use --force to force init") - sys.exit(1) - shutil.rmtree(west_path) - - command = ['west', 'init', '-l', nxp_sdk.sdk_manifest_path, '--mf', 'west.yml'] - subprocess.run(command, check=True) - update_nxp_sdk_version(nxp_sdk, force) - - -def update_nxp_sdk_version(nxp_sdk, force): - print("Update SDK in " + nxp_sdk.sdk_target_location) - if not os.path.exists(os.path.join(nxp_sdk.sdk_target_location, '.west')): - logging.error("--update-only error SDK is not initialized") - sys.exit(1) - command = ['west', 'update', '--fetch', 'smart'] - try: - subprocess.run(command, cwd=nxp_sdk.sdk_target_location, check=True) - except (RuntimeError, subprocess.CalledProcessError) as exception: - if force: - if nxp_sdk.sdk_name == 'k32w0': - logging.error('Force update not yet supported for %s platform', nxp_sdk.sdk_name) - else: - # In case of force update option and in case of update failure: - # 1. try to clean all local modications if any - # 2. Retry the west update command. It should be successfull now as all local modifications have been cleaned - clean_sdk_local_changes(nxp_sdk.sdk_target_location) - subprocess.run(command, cwd=nxp_sdk.sdk_target_location, check=True) - else: - logging.exception( - 'Error SDK cannot be updated, local changes should be cleaned manually or use --force to force update %s', exception) - - -def main(): - - parser = argparse.ArgumentParser(description='Checkout or update relevant NXP SDK') - parser.add_argument( - "--update-only", help="Update NXP SDK to the correct version. Would fail if the SDK does not exist", action="store_true") - parser.add_argument('--platform', nargs='+', choices=ALL_PLATFORM_NAME, default=ALL_PLATFORM_NAME, - help='Allows to select which SDK for a particular NXP platform to initialize') - parser.add_argument('--force', action='store_true', - help='Force SDK initialization, hard clean will be done in case of failure - WARNING -- All local SDK modification(s) will be lost') - - args = parser.parse_args() - - for current_plat in args.platform: - nxp_sdk = [p for p in ALL_PLATFORM_SDK if p.sdk_name == current_plat][0] - if args.update_only: - update_nxp_sdk_version(nxp_sdk, args.force) - else: - init_nxp_sdk_version(nxp_sdk, args.force) - - -if __name__ == '__main__': - main() diff --git a/scripts/tools/nxp/factory_data_generator/generate.py b/scripts/tools/nxp/factory_data_generator/generate.py index b3ee98562b6c3a..945f8bde641749 100755 --- a/scripts/tools/nxp/factory_data_generator/generate.py +++ b/scripts/tools/nxp/factory_data_generator/generate.py @@ -106,7 +106,7 @@ def generate(self): return data - def to_bin(self, klv, out, aes128_key): + def to_bin(self, klv, out, aes_key): fullContent = bytearray() with open(out, "wb") as file: for entry in klv: @@ -115,7 +115,7 @@ def to_bin(self, klv, out, aes128_key): fullContent += entry[2] size = len(fullContent) - if (aes128_key is None): + if (aes_key is None): # Calculate 4 bytes of hashing hashing = hashlib.sha256(fullContent).hexdigest() hashing = hashing[0:8] @@ -146,7 +146,7 @@ def to_bin(self, klv, out, aes128_key): logging.info("Size of final generated binary is: {} bytes".format(size)) file.write(fullContent) else: - # In case a aes128_key is given the data will be encrypted + # In case a aes_key is given the data will be encrypted # Always add a padding to be 16 bytes aligned padding_len = size % 16 padding_len = 16 - padding_len @@ -156,7 +156,7 @@ def to_bin(self, klv, out, aes128_key): size = len(fullContent) logging.info("(After padding) Size of generated binary is: {} bytes".format(size)) from Crypto.Cipher import AES - cipher = AES.new(bytes.fromhex(aes128_key), AES.MODE_ECB) + cipher = AES.new(bytes.fromhex(aes_key), AES.MODE_ECB) fullContentCipher = cipher.encrypt(fullContent) # Add 4 bytes of hashing to generated binary to check for integrity @@ -229,6 +229,8 @@ def main(): help="[base64 str] Already generated spake2p verifier") optional.add_argument("--aes128_key", help="[hex] AES 128 bits key used to encrypt the whole dataset") + optional.add_argument("--aes256_key", + help="[hex] AES 256 bits key used to encrypt the whole dataset") optional.add_argument("--date", type=ManufacturingDate, help="[str] Manufacturing Date (YYYY-MM-DD)") optional.add_argument("--part_number", type=PartNumber, @@ -252,7 +254,12 @@ def main(): klv = KlvGenerator(args) data = klv.generate() - klv.to_bin(data, args.out, args.aes128_key) + aes_key = None + if args.aes256_key: + aes_key = args.aes256_key + elif args.aes128_key: + aes_key = args.aes128_key + klv.to_bin(data, args.out, aes_key) if __name__ == "__main__": diff --git a/src/platform/nxp/common/ConfigurationManagerImpl.cpp b/src/platform/nxp/common/ConfigurationManagerImpl.cpp index ad8f00eaf3a4cb..09fb98abac6a3f 100644 --- a/src/platform/nxp/common/ConfigurationManagerImpl.cpp +++ b/src/platform/nxp/common/ConfigurationManagerImpl.cpp @@ -106,7 +106,6 @@ CHIP_ERROR ConfigurationManagerImpl::Init() { CHIP_ERROR err; uint32_t rebootCount = 0; - bool failSafeArmed; #if CONFIG_BOOT_REASON_SDK_SUPPORT uint8_t rebootCause = POWER_GetResetCause(); diff --git a/src/platform/nxp/common/ConnectivityManagerImpl.cpp b/src/platform/nxp/common/ConnectivityManagerImpl.cpp index cbdb866ae71973..9c3eb7fb7a88e8 100644 --- a/src/platform/nxp/common/ConnectivityManagerImpl.cpp +++ b/src/platform/nxp/common/ConnectivityManagerImpl.cpp @@ -48,21 +48,23 @@ extern "C" { #include "wlan.h" #include "wm_net.h" -#include } #include #if CHIP_DEVICE_CONFIG_ENABLE_THREAD -#include +#include +#include "border_agent.h" #include "br_rtos_manager.h" +#include "infra_if.h" #endif /* CHIP_DEVICE_CONFIG_ENABLE_THREAD */ #endif /* CHIP_DEVICE_CONFIG_ENABLE_WPA */ #if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include "ConnectivityManagerImpl.h" #include #endif /* CHIP_DEVICE_CONFIG_ENABLE_THREAD */ @@ -319,7 +321,6 @@ int ConnectivityManagerImpl::_WlanEventCallback(enum wlan_event_reason wlanEvent void ConnectivityManagerImpl::OnStationConnected() { - CHIP_ERROR err; ChipDeviceEvent event; event.Type = DeviceEventType::kWiFiConnectivityChange; @@ -332,7 +333,6 @@ void ConnectivityManagerImpl::OnStationConnected() void ConnectivityManagerImpl::OnStationDisconnected() { - CHIP_ERROR err; ChipDeviceEvent event; event.Type = DeviceEventType::kWiFiConnectivityChange; @@ -353,9 +353,6 @@ void ConnectivityManagerImpl::UpdateInternetConnectivityState() const ip6_addr_t * addr6; CHIP_ERROR err; ChipDeviceEvent event; -#if CHIP_ENABLE_OPENTHREAD - otIp6Address newIpAddress; -#endif // If the WiFi station is currently in the connected state... if (_IsWiFiStationConnected()) @@ -392,11 +389,6 @@ void ConnectivityManagerImpl::UpdateInternetConnectivityState() { haveIPv6Conn = true; addr6 = netif_ip6_addr(netif, i); -#if CHIP_ENABLE_OPENTHREAD - // We are using ot mDNS sever and need to add IP address to server list - memcpy(&newIpAddress.mFields.m32, addr6->addr, sizeof(Inet::IPAddress)); - otMdnsServerAddAddress(ThreadStackMgrImpl().OTInstance(), &newIpAddress); -#endif break; } } @@ -428,20 +420,29 @@ void ConnectivityManagerImpl::UpdateInternetConnectivityState() event.Type = DeviceEventType::kInternetConnectivityChange; event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); - if (haveIPv6Conn) - { - event.InternetConnectivityChange.ipAddress = IPAddress(*addr6); #if CHIP_ENABLE_OPENTHREAD - // Start the Border Router services including MDNS Server - StartBrServices(); + // In case of boot, start the Border Router services including MDNS Server, otherwise inform of link state change + // The posted event will signal the application to restart the Matter mDNS server instance + bool bLinkState = event.InternetConnectivityChange.IPv6 == kConnectivity_Established ? true : false; + BrHandleStateChange(bLinkState); #endif + if (haveIPv6Conn) + { + event.InternetConnectivityChange.ipAddress = IPAddress(*addr6); } err = PlatformMgr().PostEvent(&event); VerifyOrDie(err == CHIP_NO_ERROR); ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST"); } + +#if CHIP_ENABLE_OPENTHREAD + if (haveIPv6Conn && UpdateIp6AddrList()) + { + UpdateMdnsHost(); + } +#endif } void ConnectivityManagerImpl::_NetifExtCallback(struct netif * netif, netif_nsc_reason_t reason, @@ -463,7 +464,6 @@ void ConnectivityManagerImpl::_NetifExtCallback(struct netif * netif, netif_nsc_ void ConnectivityManagerImpl::StartWiFiManagement() { struct netif * netif = nullptr; - EventBits_t bits; int32_t result; LOCK_TCPIP_CORE(); @@ -484,35 +484,107 @@ void ConnectivityManagerImpl::StartWiFiManagement() } } #if CHIP_ENABLE_OPENTHREAD -void ConnectivityManagerImpl::StartBrServices() +void ConnectivityManagerImpl::BrHandleStateChange(bool bLinkState) { if (mBorderRouterInit == false) { - struct netif * extNetIfPtr = static_cast(net_get_mlan_handle()); - struct netif * thrNetIfPtr = ThreadStackMgrImpl().ThreadNetIf(); - otInstance * thrInstancePtr; - - // Initalize internal interface variables, these can be used by other modules like the DNSSD Impl to - // get the underlying IP interface - Inet::InterfaceId tmpExtIf(extNetIfPtr); - Inet::InterfaceId tmpThrIf(thrNetIfPtr); - mExternalNetIf = tmpExtIf; - mThreadNetIf = tmpThrIf; - - // Need to wait for the wifi to be connected because the mlan netif can be !=null but not initialized - // properly. If the thread netif is !=null it means that it was fully initialized - - // Lock OT task - if ((thrNetIfPtr) && (mWiFiStationState == kWiFiStationState_Connected)) + if (bLinkState) { - mBorderRouterInit = true; - // Check if OT instance is init - thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + struct netif * extNetIfPtr = static_cast(net_get_mlan_handle()); + struct netif * thrNetIfPtr = ThreadStackMgrImpl().ThreadNetIf(); + otInstance * thrInstancePtr; + + // Need to wait for the wifi to be connected because the mlan netif can be !=null but not initialized + // properly. If the thread netif is !=null it means that it was fully initialized - BrInitServices(thrInstancePtr, extNetIfPtr, thrNetIfPtr); - otMdnsServerStart(thrInstancePtr); + // Lock OT task ? + if ((thrNetIfPtr) && (mWiFiStationState == kWiFiStationState_Connected)) + { + // Initalize internal interface variables, these can be used by other modules like the DNSSD Impl to + // get the underlying IP interface + Inet::InterfaceId tmpExtIf(extNetIfPtr); + Inet::InterfaceId tmpThrIf(thrNetIfPtr); + mExternalNetIf = tmpExtIf; + mThreadNetIf = tmpThrIf; + + mBorderRouterInit = true; + // Check if OT instance is init + thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + + BrInitPlatform(thrInstancePtr, extNetIfPtr, thrNetIfPtr); + BrInitServices(); + + UpdateIp6AddrList(); + UpdateMdnsHost(); + BorderAgentInit(thrInstancePtr, mHostname); + } } } + else + { + InfraIfLinkState(bLinkState); + } +} + +void ConnectivityManagerImpl::UpdateMdnsHost() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + otMdnsHost mdnsHost; + + if (strlen(mHostname) == 0) + { + uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; + MutableByteSpan mac(macBuffer); + err = DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac); + SuccessOrExit(err); + + chip::Dnssd::MakeHostName(mHostname, sizeof(mHostname), mac); + } + + mdnsHost.mAddresses = mIp6AddrList; + mdnsHost.mAddressesLength = mIp6AddrNum; + mdnsHost.mHostName = mHostname; + mdnsHost.mInfraIfIndex = netif_get_index(mExternalNetIf.GetPlatformInterface()); + + // Allways use ID 0 for host + otMdnsRegisterHost(ThreadStackMgrImpl().OTInstance(), &mdnsHost, 0, nullptr); + +exit: + return; +} + +bool ConnectivityManagerImpl::UpdateIp6AddrList() +{ + const ip6_addr_t * addr6 = nullptr; + bool bAddrChange = false; + uint32_t newIp6AddrNum = 0; + struct netif * extNetIfPtr = mExternalNetIf.GetPlatformInterface(); + uint32_t lwipIterator, addrListIterator; + + for (lwipIterator = 0; lwipIterator < LWIP_IPV6_NUM_ADDRESSES; lwipIterator++) + { + if (ip6_addr_ispreferred(netif_ip6_addr_state(extNetIfPtr, lwipIterator)) && (mIp6AddrNum <= kMaxIp6Addr)) + { + addr6 = netif_ip6_addr(extNetIfPtr, lwipIterator); + for (addrListIterator = 0; addrListIterator < kMaxIp6Addr; addrListIterator++) + { + if (0 == memcmp(&mIp6AddrList[addrListIterator].mFields.m32, addr6->addr, sizeof(Inet::IPAddress))) + { + break; + } + } + if (addrListIterator == kMaxIp6Addr) + { + bAddrChange |= true; + } + memcpy(&mIp6AddrList[newIp6AddrNum++].mFields.m32, addr6->addr, sizeof(Inet::IPAddress)); + } + } + + bAddrChange |= (newIp6AddrNum != mIp6AddrNum) ? true : false; + mIp6AddrNum = newIp6AddrNum; + + return bAddrChange; } Inet::InterfaceId ConnectivityManagerImpl::GetThreadInterface() @@ -532,7 +604,6 @@ CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, uint #if CHIP_DEVICE_CONFIG_ENABLE_WPA CHIP_ERROR ret = CHIP_NO_ERROR; struct wlan_network * pNetworkData = (struct wlan_network *) malloc(sizeof(struct wlan_network)); - int result; VerifyOrExit(pNetworkData != NULL, ret = CHIP_ERROR_NO_MEMORY); VerifyOrExit(ssidLen <= IEEEtypes_SSID_SIZE, ret = CHIP_ERROR_INVALID_ARGUMENT); diff --git a/src/platform/nxp/common/ConnectivityManagerImpl.h b/src/platform/nxp/common/ConnectivityManagerImpl.h index 82ce24f814d544..9327e4d2d1ec9b 100644 --- a/src/platform/nxp/common/ConnectivityManagerImpl.h +++ b/src/platform/nxp/common/ConnectivityManagerImpl.h @@ -20,6 +20,7 @@ #pragma once +#include #include #include #include @@ -93,6 +94,7 @@ class ConnectivityManagerImpl final : public ConnectivityManager, #if CHIP_ENABLE_OPENTHREAD Inet::InterfaceId GetExternalInterface(); Inet::InterfaceId GetThreadInterface(); + const char * GetHostName() { return sInstance.mHostname; } #endif #endif @@ -144,8 +146,14 @@ class ConnectivityManagerImpl final : public ConnectivityManager, static netif_ext_callback_t sNetifCallback; #if CHIP_ENABLE_OPENTHREAD + static constexpr uint8_t kMaxIp6Addr = 3; + Inet::InterfaceId mThreadNetIf; Inet::InterfaceId mExternalNetIf; + + char mHostname[chip::Dnssd::kHostNameMaxLength + 1] = ""; + otIp6Address mIp6AddrList[kMaxIp6Addr]; + uint32_t mIp6AddrNum = 0; #endif static int _WlanEventCallback(enum wlan_event_reason event, void * data); @@ -155,9 +163,12 @@ class ConnectivityManagerImpl final : public ConnectivityManager, void OnStationDisconnected(void); void UpdateInternetConnectivityState(void); #if CHIP_ENABLE_OPENTHREAD - void StartBrServices(void); + void BrHandleStateChange(bool bLinkState); + void UpdateMdnsHost(void); + bool UpdateIp6AddrList(void); #endif /* CHIP_DEVICE_CONFIG_ENABLE_THREAD */ -#endif /* CHIP_DEVICE_CONFIG_ENABLE_WPA */ +#endif + /* CHIP_DEVICE_CONFIG_ENABLE_WPA */ }; inline bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity(void) diff --git a/src/platform/nxp/common/DnssdImpl.cpp b/src/platform/nxp/common/DnssdImpl.cpp index 743e4ab30cafa1..d0069cebcf1c4a 100644 --- a/src/platform/nxp/common/DnssdImpl.cpp +++ b/src/platform/nxp/common/DnssdImpl.cpp @@ -24,7 +24,8 @@ #include -#include +#include +#include using namespace ::chip::DeviceLayer; using namespace chip::DeviceLayer::Internal; @@ -32,9 +33,7 @@ using namespace chip::DeviceLayer::Internal; namespace chip { namespace Dnssd { -#define LOCAL_DOMAIN_STRING_SIZE 7 -#define ARPA_DOMAIN_STRING_SIZE 22 -#define MATTER_DNS_TXT_SIZE 128 +#define USE_MDNS_NEXT_SERVICE_API 1 // Support both operational and commissionable discovery, so buffers sizes must be worst case. static constexpr uint8_t kMaxMdnsServiceTxtEntriesNumber = @@ -47,6 +46,9 @@ static constexpr size_t kTotalMdnsServiceTxtKeySize = static constexpr size_t kTotalMdnsServiceTxtBufferSize = kTotalMdnsServiceTxtKeySize + kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtValueSize; +// For each fabric we can register one _matter._tcp and one _matterc._udp service +static constexpr uint32_t kServiceListSize = CHIP_CONFIG_MAX_FABRICS * 2; + static const char * GetProtocolString(DnssdServiceProtocol protocol) { return protocol == DnssdServiceProtocol::kDnssdProtocolUdp ? "_udp" : "_tcp"; @@ -63,99 +65,192 @@ struct mDnsQueryCtx void * matterCtx; chip::Dnssd::DnssdService mMdnsService; DnsServiceTxtEntries mServiceTxtEntry; - char mServiceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + 1]; + char mServiceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1]; CHIP_ERROR error; + union + { + otMdnsBrowser mBrowseInfo; + otMdnsSrvResolver mSrvInfo; + otMdnsTxtResolver mTxtInfo; + otMdnsAddressResolver mAddrInfo; + }; + union + { + DnsBrowseCallback mDnsBrowseCallback; + DnsResolveCallback mDnsResolveCallback; + }; - mDnsQueryCtx(void * context, CHIP_ERROR aError) + mDnsQueryCtx(void * context, DnsBrowseCallback aBrowseCallback) { - matterCtx = context; - error = aError; + matterCtx = context; + mDnsBrowseCallback = aBrowseCallback; + error = CHIP_NO_ERROR; } + mDnsQueryCtx(void * context, DnsResolveCallback aResolveCallback) + { + matterCtx = context; + mDnsResolveCallback = aResolveCallback; + error = CHIP_NO_ERROR; + } +}; + +enum ResolveStep : uint8_t +{ + kResolveStepSrv = 0, + kResolveStepTxt, + kResolveStepIpAddr, }; static const char * GetProtocolString(DnssdServiceProtocol protocol); -static void OtBrowseCallback(otError aError, const otDnsBrowseResponse * aResponse, void * aContext); -static void OtServiceCallback(otError aError, const otDnsServiceResponse * aResponse, void * aContext); +static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult); +static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult); +static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult); +static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult); static void DispatchBrowseEmpty(intptr_t context); static void DispatchBrowse(intptr_t context); -static void DispatchBrowseNoMemory(intptr_t context); -void DispatchAddressResolve(intptr_t context); -void DispatchResolve(intptr_t context); -void DispatchResolveNoMemory(intptr_t context); +static void DispatchTxtResolve(intptr_t context); +static void DispatchAddressResolve(intptr_t context); +static void DispatchResolve(intptr_t context); +static void DispatchResolveError(intptr_t context); -static DnsBrowseCallback mDnsBrowseCallback; -static DnsResolveCallback mDnsResolveCallback; +static void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType); -CHIP_ERROR ResolveBySrp(DnssdService * mdnsReq, otInstance * thrInstancePtr, char * instanceName, void * context); -CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, void * context); +static CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq); +static CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context); +static CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, + const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, + DnsServiceTxtEntries & serviceTxtEntries); -CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, - const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, - DnsServiceTxtEntries & serviceTxtEntries); +static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType); static bool bBrowseInProgress = false; +// ID 0 is reserved for host +static uint32_t mRegisterServiceId = 1; +static uint8_t mNetifIndex = 0; + +// Matter currently only supports one browse and resolve operation at a time so there is no need to create a list +// If the Matter implementation evolves in the future this functionality can be extended to a list. +static mDnsQueryCtx * mBrowseContext = nullptr; +static mDnsQueryCtx * mResolveContext = nullptr; + +#if USE_MDNS_NEXT_SERVICE_API +static otMdnsService * mServiceList[kServiceListSize]; +static uint32_t mServiceListFreeIndex; +#endif CHIP_ERROR ChipDnssdInit(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context) { CHIP_ERROR error = CHIP_NO_ERROR; otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + struct netif * extNetif = (ConnectivityManagerImpl().GetExternalInterface()).GetPlatformInterface(); - uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; - MutableByteSpan mac(macBuffer); - char hostname[kHostNameMaxLength + LOCAL_DOMAIN_STRING_SIZE + 1] = ""; - ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac)); - MakeHostName(hostname, sizeof(hostname), mac); - snprintf(hostname + strlen(hostname), sizeof(hostname), ".local."); + // Don't try to do anything until the mDNS server is started + VerifyOrExit(otMdnsIsEnabled(thrInstancePtr), error = CHIP_ERROR_INCORRECT_STATE); - error = MapOpenThreadError(otMdnsServerSetHostName(thrInstancePtr, hostname)); + mNetifIndex = netif_get_index(extNetif); +exit: initCallback(context, error); return error; } void ChipDnssdShutdown() { - otMdnsServerStop(ThreadStackMgrImpl().OTInstance()); + otMdnsSetEnabled(ThreadStackMgrImpl().OTInstance(), false, 0); } +#if USE_MDNS_NEXT_SERVICE_API +CHIP_ERROR ChipDnssdRemoveServices() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + otMdnsIterator * iterator = nullptr; + ChipError error = CHIP_NO_ERROR; + otError otError = OT_ERROR_NONE; + otMdnsEntryState state; + + const char * hostName = ConnectivityManagerImpl().GetHostName(); + + iterator = otMdnsAllocateIterator(thrInstancePtr); + VerifyOrExit(iterator != nullptr, error = CHIP_ERROR_NO_MEMORY); + + mServiceListFreeIndex = 0; + + while (mServiceListFreeIndex <= kServiceListSize) + { + // allocate memory for new entry if the entry is not allready allocated from previous iteration + if (mServiceList[mServiceListFreeIndex] == nullptr) + { + mServiceList[mServiceListFreeIndex] = static_cast(Platform::MemoryAlloc(sizeof(otMdnsService))); + VerifyOrExit(mServiceList[mServiceListFreeIndex] != nullptr, error = CHIP_ERROR_NO_MEMORY); + } + + otError = otMdnsGetNextService(thrInstancePtr, iterator, mServiceList[mServiceListFreeIndex], &state); + if (otError == OT_ERROR_NOT_FOUND) + { + Platform::MemoryFree(mServiceList[mServiceListFreeIndex]); + mServiceList[mServiceListFreeIndex] = nullptr; + break; + } + + if ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mHostName, hostName)) && + ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matter._tcp")) || + (0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matterc._udp")))) + { + mServiceListFreeIndex++; + } + } +exit: + if (iterator != nullptr) + { + otMdnsFreeIterator(thrInstancePtr, iterator); + } + return error; +} +#else CHIP_ERROR ChipDnssdRemoveServices() { otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + + otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); - otMdnsServerMarkServiceForRemoval(thrInstancePtr, nullptr, "_matter._tcp.local."); - otMdnsServerMarkServiceForRemoval(thrInstancePtr, nullptr, "_matterc._udp.local."); + otServiceData.mServiceType = "_matter._tcp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); + otServiceData.mServiceType = "_matterc._udp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); return CHIP_NO_ERROR; } +#endif CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCallback callback, void * context) { ReturnErrorCodeIf(service == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otError otErr; - otDnsTxtEntry aTxtEntry; - uint32_t txtBufferOffset = 0; + uint32_t txtBufferOffset = 0; + otError otErr = OT_ERROR_NONE; + otMdnsService otServiceData = { 0 }; + +#if USE_MDNS_NEXT_SERVICE_API + bool bRegisterService = true; +#endif + + char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1] = ""; + snprintf(serviceType, sizeof(serviceType), "%s.%s", service->mType, GetProtocolString(service->mProtocol)); - char fullInstName[Common::kInstanceNameMaxLength + chip::Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + 1] = - ""; - char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + 1] = ""; // secure space for the raw TXT data in the worst-case scenario relevant for Matter: // each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data uint8_t txtBuffer[kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtBufferSize] = { 0 }; - if ((strcmp(service->mHostName, "") != 0) && (nullptr == otMdnsServerGetHostName(thrInstancePtr))) - { - char hostname[kHostNameMaxLength + LOCAL_DOMAIN_STRING_SIZE + 1] = ""; - snprintf(hostname, sizeof(hostname), "%s.local.", service->mHostName); - otMdnsServerSetHostName(thrInstancePtr, hostname); - } - - snprintf(serviceType, sizeof(serviceType), "%s.%s.local.", service->mType, GetProtocolString(service->mProtocol)); - snprintf(fullInstName, sizeof(fullInstName), "%s.%s", service->mName, serviceType); + // Don't try to do anything until the mDNS server is started + VerifyOrReturnValue(otMdnsIsEnabled(thrInstancePtr), CHIP_NO_ERROR); + // Create TXT Data as one string from multiple key entries for (uint32_t i = 0; i < service->mTextEntrySize; i++) { uint32_t keySize = strlen(service->mTextEntries[i].mKey); @@ -174,56 +269,124 @@ CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCal txtBufferOffset += service->mTextEntries[i].mDataSize; } } - aTxtEntry.mKey = nullptr; - aTxtEntry.mValue = txtBuffer; - aTxtEntry.mValueLength = txtBufferOffset; - otErr = otMdnsServerAddService(thrInstancePtr, fullInstName, serviceType, service->mSubTypes, service->mSubTypeSize, - service->mPort, &aTxtEntry, 1); - // Ignore duplicate error and threat it as error none - if (otErr == OT_ERROR_DUPLICATED) - otErr = OT_ERROR_NONE; +#if USE_MDNS_NEXT_SERVICE_API + for (uint32_t i = 0; i < mServiceListFreeIndex; i++) + { + if ((0 == strcmp(mServiceList[i]->mHostName, service->mHostName)) && + (0 == strcmp(mServiceList[i]->mServiceInstance, service->mName)) && + (0 == strcmp(mServiceList[i]->mServiceType, serviceType))) + { + if ((mServiceList[i]->mTxtDataLength == txtBufferOffset) && + (0 == memcmp(txtBuffer, mServiceList[i]->mTxtData, txtBufferOffset))) + { + // In this case the service is + bRegisterService = false; + } + Platform::MemoryFree(mServiceList[i]); + if (i < --mServiceListFreeIndex) + { + // move last element in place of the removed one + mServiceList[i] = mServiceList[mServiceListFreeIndex]; + mServiceList[mServiceListFreeIndex] = nullptr; + } + else + { + mServiceList[i] = nullptr; + } + break; + } + } +#endif + if (bRegisterService) + { + if (strcmp(service->mHostName, "") != 0) + { + otServiceData.mHostName = service->mHostName; + } + + otServiceData.mServiceInstance = service->mName; + otServiceData.mServiceType = serviceType; + otServiceData.mSubTypeLabels = service->mSubTypes; + otServiceData.mSubTypeLabelsLength = service->mSubTypeSize; + otServiceData.mPort = service->mPort; + otServiceData.mTtl = service->mTtlSeconds; + otServiceData.mTxtData = txtBuffer; + otServiceData.mTxtDataLength = txtBufferOffset; + + otErr = otMdnsRegisterService(thrInstancePtr, &otServiceData, mRegisterServiceId++, NULL); + } return MapOpenThreadError(otErr); } +#if USE_MDNS_NEXT_SERVICE_API +CHIP_ERROR ChipDnssdFinalizeServiceUpdate() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + + for (uint32_t i = 0; i < mServiceListFreeIndex; i++) + { + if (mServiceList[i] != nullptr) + { + otMdnsUnregisterService(thrInstancePtr, mServiceList[i]); + Platform::MemoryFree(mServiceList[i]); + mServiceList[i] = nullptr; + } + } + + mServiceListFreeIndex = 0; + return CHIP_NO_ERROR; +} + +#else CHIP_ERROR ChipDnssdFinalizeServiceUpdate() { - otMdnsServerRemoveMarkedServices(ThreadStackMgrImpl().OTInstance()); + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + + otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); + + otServiceData.mServiceType = "_matter._tcp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); + otServiceData.mServiceType = "_matterc._udp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); + return CHIP_NO_ERROR; } +#endif CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, Inet::IPAddressType addressType, Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, intptr_t * browseIdentifier) { - *browseIdentifier = reinterpret_cast(nullptr); - CHIP_ERROR error = CHIP_NO_ERROR; - CHIP_ERROR srpBrowseError = CHIP_NO_ERROR; - char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + ARPA_DOMAIN_STRING_SIZE + 1] = ""; // +1 for null-terminator + *browseIdentifier = reinterpret_cast(nullptr); + CHIP_ERROR error = CHIP_NO_ERROR; + CHIP_ERROR srpBrowseError = CHIP_NO_ERROR; + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); if (type == nullptr || callback == nullptr) return CHIP_ERROR_INVALID_ARGUMENT; - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - mDnsBrowseCallback = callback; - - mDnsQueryCtx * browseContext = Platform::New(context, CHIP_NO_ERROR); - VerifyOrReturnError(browseContext != nullptr, CHIP_ERROR_NO_MEMORY); + mBrowseContext = Platform::New(context, callback); + VerifyOrReturnError(mBrowseContext != nullptr, CHIP_ERROR_NO_MEMORY); - // First try to browse the service in the SRP cache, use default.service.arpa as domain name - snprintf(serviceType, sizeof(serviceType), "%s.%s.default.service.arpa.", type, GetProtocolString(protocol)); + // First try to browse the service in the SRP cache + snprintf(mBrowseContext->mServiceType, sizeof(mBrowseContext->mServiceType), "%s.%s", type, GetProtocolString(protocol)); // After browsing in the SRP cache we will continue with regular mDNS browse - srpBrowseError = BrowseBySrp(thrInstancePtr, serviceType, context); + srpBrowseError = BrowseBySrp(thrInstancePtr, mBrowseContext->mServiceType, mBrowseContext); // Proceed to generate a mDNS query - snprintf(browseContext->mServiceType, sizeof(browseContext->mServiceType), "%s.%s.local.", type, GetProtocolString(protocol)); + mBrowseContext->mBrowseInfo.mServiceType = mBrowseContext->mServiceType; + mBrowseContext->mBrowseInfo.mSubTypeLabel = nullptr; + mBrowseContext->mBrowseInfo.mInfraIfIndex = mNetifIndex; + mBrowseContext->mBrowseInfo.mCallback = OtBrowseCallback; - error = MapOpenThreadError(otMdnsServerBrowse(thrInstancePtr, browseContext->mServiceType, OtBrowseCallback, browseContext)); + error = MapOpenThreadError(otMdnsStartBrowser(thrInstancePtr, &mBrowseContext->mBrowseInfo)); if (CHIP_NO_ERROR == error) { bBrowseInProgress = true; - *browseIdentifier = reinterpret_cast(browseContext); + *browseIdentifier = reinterpret_cast(mBrowseContext); } else { @@ -231,12 +394,13 @@ CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, Ine { // In this case, we need to send a final browse indication to signal the Matter App that there are no more // browse results coming - browseContext->error = error; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(browseContext)); + mBrowseContext->error = error; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(mBrowseContext)); } else { - Platform::Delete(browseContext); + Platform::Delete(mBrowseContext); + mBrowseContext = nullptr; } } return error; @@ -249,54 +413,73 @@ CHIP_ERROR ChipDnssdStopBrowse(intptr_t browseIdentifier) otError error = OT_ERROR_INVALID_ARGS; // browseContext is only valid when bBrowseInProgress is true. The Matter stack can call this function even with a browseContext - // that has been freed in DispatchBrowseEmpty before. + // that has been freed in DispatchBrowseEmpty. if ((true == bBrowseInProgress) && (browseContext)) { - browseContext->error = MapOpenThreadError(otMdnsServerStopQuery(thrInstancePtr, browseContext->mServiceType)); + browseContext->error = MapOpenThreadError(otMdnsStopBrowser(thrInstancePtr, &browseContext->mBrowseInfo)); // browse context will be freed in DispatchBrowseEmpty - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(browseContext)); + DispatchBrowseEmpty(reinterpret_cast(browseContext)); } return MapOpenThreadError(error); } CHIP_ERROR ChipDnssdResolve(DnssdService * browseResult, Inet::InterfaceId interface, DnssdResolveCallback callback, void * context) { - ChipError error; + ChipError error = CHIP_ERROR_NOT_FOUND; + if (browseResult == nullptr || callback == nullptr) return CHIP_ERROR_INVALID_ARGUMENT; otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - mDnsResolveCallback = callback; - char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + ARPA_DOMAIN_STRING_SIZE + 1] = ""; // +1 for null-terminator - char fullInstName[Common::kInstanceNameMaxLength + chip::Dnssd::kDnssdTypeAndProtocolMaxSize + ARPA_DOMAIN_STRING_SIZE + 1] = - ""; + mResolveContext = Platform::New(context, callback); + VerifyOrReturnError(mResolveContext != nullptr, CHIP_ERROR_NO_MEMORY); // First try to find the service in the SRP cache, use default.service.arpa as domain name - snprintf(serviceType, sizeof(serviceType), "%s.%s.default.service.arpa.", browseResult->mType, + snprintf(mResolveContext->mServiceType, sizeof(mResolveContext->mServiceType), "%s.%s", browseResult->mType, GetProtocolString(browseResult->mProtocol)); - snprintf(fullInstName, sizeof(fullInstName), "%s.%s", browseResult->mName, serviceType); - error = ResolveBySrp(browseResult, thrInstancePtr, fullInstName, context); + error = ResolveBySrp(thrInstancePtr, mResolveContext->mServiceType, mResolveContext, browseResult); + // If the SRP cache returns not found, proceed to generate a MDNS query if (CHIP_ERROR_NOT_FOUND == error) { - // If the SRP cache returns not found, proceed to generate a MDNS query - memset(serviceType, 0, sizeof(serviceType)); - memset(fullInstName, 0, sizeof(fullInstName)); + // The otMdnsSrvResolver structure contains only pointers to instance name and service type strings + // Use the memory from mMdnsService.mName to store the instance name string we are looking for + Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), browseResult->mName); - snprintf(serviceType, sizeof(serviceType), "%s.%s.local.", browseResult->mType, GetProtocolString(browseResult->mProtocol)); - snprintf(fullInstName, sizeof(fullInstName), "%s.%s", browseResult->mName, serviceType); + mResolveContext->mSrvInfo.mInfraIfIndex = mNetifIndex; + mResolveContext->mSrvInfo.mCallback = OtServiceCallback; + mResolveContext->mSrvInfo.mServiceInstance = mResolveContext->mMdnsService.mName; + mResolveContext->mSrvInfo.mServiceType = mResolveContext->mServiceType; - return MapOpenThreadError(otMdnsServerResolveService(thrInstancePtr, fullInstName, OtServiceCallback, context)); + return MapOpenThreadError(otMdnsStartSrvResolver(thrInstancePtr, &mResolveContext->mSrvInfo)); } else { return error; } } +void ChipDnssdResolveNoLongerNeeded(const char * instanceName) +{ + if (mResolveContext != nullptr) + { + if (strcmp(instanceName, mResolveContext->mMdnsService.mName) == 0) + { + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &mResolveContext->mSrvInfo); + + Platform::Delete(mResolveContext); + mResolveContext = nullptr; + } + } +} + +CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress address, chip::Inet::InterfaceId interface) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} -CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, void * context) +CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context) { const otSrpServerHost * host = nullptr; const otSrpServerService * service = nullptr; @@ -304,24 +487,26 @@ CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, void * c while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) { - service = otSrpServerHostFindNextService(host, service, OT_SRP_SERVER_FLAGS_ANY_TYPE_ACTIVE_SERVICE, serviceName, nullptr); - if (service != nullptr) + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) { - mDnsQueryCtx * serviceContext; - - serviceContext = Platform::New(context, CHIP_NO_ERROR); - if (serviceContext != nullptr) + if ((false == otSrpServerServiceIsDeleted(service)) && + (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName)))) { - if (CHIP_NO_ERROR == - FromSrpCacheToMdnsData(service, host, nullptr, serviceContext->mMdnsService, serviceContext->mServiceTxtEntry)) + mDnsQueryCtx * serviceContext = Platform::New(context->matterCtx, context->mDnsBrowseCallback); + if (serviceContext != nullptr) { - // Set error to CHIP_NO_ERROR to signal that there was at least one service found in the cache - error = CHIP_NO_ERROR; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(serviceContext)); - } - else - { - Platform::Delete(serviceContext); + if (CHIP_NO_ERROR == + FromSrpCacheToMdnsData(service, host, nullptr, serviceContext->mMdnsService, + serviceContext->mServiceTxtEntry)) + { + // Set error to CHIP_NO_ERROR to signal that there was at least one service found in the cache + error = CHIP_NO_ERROR; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(serviceContext)); + } + else + { + Platform::Delete(serviceContext); + } } } } @@ -329,7 +514,7 @@ CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, void * c return error; } -CHIP_ERROR ResolveBySrp(DnssdService * mdnsReq, otInstance * thrInstancePtr, char * instanceName, void * context) +CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq) { const otSrpServerHost * host = nullptr; const otSrpServerService * service = nullptr; @@ -337,34 +522,27 @@ CHIP_ERROR ResolveBySrp(DnssdService * mdnsReq, otInstance * thrInstancePtr, cha while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) { - service = otSrpServerHostFindNextService( - host, service, (OT_SRP_SERVER_SERVICE_FLAG_BASE_TYPE | OT_SRP_SERVER_SERVICE_FLAG_ACTIVE), nullptr, instanceName); - if (service != nullptr) + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) { - error = CHIP_NO_ERROR; - mDnsQueryCtx * serviceContext; - - serviceContext = Platform::New(context, CHIP_NO_ERROR); - if (serviceContext != nullptr) + if ((false == otSrpServerServiceIsDeleted(service)) && + (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName))) && + (0 == strncmp(otSrpServerServiceGetInstanceName(service), mdnsReq->mName, strlen(mdnsReq->mName)))) { - error = - FromSrpCacheToMdnsData(service, host, mdnsReq, serviceContext->mMdnsService, serviceContext->mServiceTxtEntry); + error = FromSrpCacheToMdnsData(service, host, mdnsReq, context->mMdnsService, context->mServiceTxtEntry); if (error == CHIP_NO_ERROR) { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(serviceContext)); - } - else - { - Platform::Delete(serviceContext); + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(context)); } + break; } - else - { - error = CHIP_ERROR_NO_MEMORY; - } + } + + if (error == CHIP_NO_ERROR) + { break; } } + return error; } @@ -480,35 +658,36 @@ CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSr return CHIP_NO_ERROR; } -CHIP_ERROR FromOtDnsResponseToMdnsData(otDnsServiceInfo & serviceInfo, const char * serviceType, - chip::Dnssd::DnssdService & mdnsService, DnsServiceTxtEntries & serviceTxtEntries, - otError error) +static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType) { char protocol[chip::Dnssd::kDnssdProtocolTextMaxSize + 1]; + const char * protocolSubstringStart; + size_t substringSize; - if (strchr(serviceType, '.') == nullptr) - return CHIP_ERROR_INVALID_ARGUMENT; - - // Extract from the ... the part. - size_t substringSize = strchr(serviceType, '.') - serviceType; + // Extract from the . the part. + substringSize = strchr(aServiceType, '.') - aServiceType; if (substringSize >= ArraySize(mdnsService.mType)) { return CHIP_ERROR_INVALID_ARGUMENT; } - Platform::CopyString(mdnsService.mType, substringSize + 1, serviceType); + Platform::CopyString(mdnsService.mType, ArraySize(mdnsService.mType), aServiceType); - // Extract from the ... the part. - const char * protocolSubstringStart = serviceType + substringSize + 1; + // Extract from the .. the . part. + protocolSubstringStart = aServiceType + substringSize; + // Check that the protocolSubstringStart starts wit a '.' to be sure we are in the right place if (strchr(protocolSubstringStart, '.') == nullptr) + { return CHIP_ERROR_INVALID_ARGUMENT; + } - substringSize = strchr(protocolSubstringStart, '.') - protocolSubstringStart; + // Jump over '.' in protocolSubstringStart and substract the string terminator from the size + substringSize = strlen(++protocolSubstringStart) - 1; if (substringSize >= ArraySize(protocol)) { return CHIP_ERROR_INVALID_ARGUMENT; } - Platform::CopyString(protocol, substringSize + 1, protocolSubstringStart); + Platform::CopyString(protocol, ArraySize(protocol), protocolSubstringStart); if (strncmp(protocol, "_udp", chip::Dnssd::kDnssdProtocolTextMaxSize) == 0) { @@ -523,274 +702,236 @@ CHIP_ERROR FromOtDnsResponseToMdnsData(otDnsServiceInfo & serviceInfo, const cha mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUnknown; } - // Check if SRV record was included in DNS response. - if (error != OT_ERROR_NOT_FOUND) - { - if (strchr(serviceInfo.mHostNameBuffer, '.') == nullptr) - return CHIP_ERROR_INVALID_ARGUMENT; + return CHIP_NO_ERROR; +} - // Extract from the .. the part. - substringSize = strchr(serviceInfo.mHostNameBuffer, '.') - serviceInfo.mHostNameBuffer; - if (substringSize >= ArraySize(mdnsService.mHostName)) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - Platform::CopyString(mdnsService.mHostName, substringSize + 1, serviceInfo.mHostNameBuffer); +static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult) +{ + CHIP_ERROR error; - mdnsService.mPort = serviceInfo.mPort; - } + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); - // All mDNS replies come from the External Netif - mdnsService.mInterface = ConnectivityManagerImpl().GetExternalInterface(); + mDnsQueryCtx * tmpContext = Platform::New(mBrowseContext->matterCtx, mBrowseContext->mDnsBrowseCallback); + VerifyOrReturn(tmpContext != nullptr); - // Check if AAAA record was included in DNS response. - if (!otIp6IsAddressUnspecified(&serviceInfo.mHostAddress)) - { - mdnsService.mAddressType = Inet::IPAddressType::kIPv6; - mdnsService.mAddress = std::optional(ToIPAddress(serviceInfo.mHostAddress)); - } + Platform::CopyString(tmpContext->mMdnsService.mName, sizeof(tmpContext->mMdnsService.mName), aResult->mServiceInstance); + error = FromServiceTypeToMdnsData(tmpContext->mMdnsService, aResult->mServiceType); - // Check if TXT record was included in DNS response. - if (serviceInfo.mTxtDataSize != 0) + if (CHIP_NO_ERROR == error) { - otDnsTxtEntryIterator iterator; - otDnsInitTxtEntryIterator(&iterator, serviceInfo.mTxtData, serviceInfo.mTxtDataSize); - - otDnsTxtEntry txtEntry; - chip::FixedBufferAllocator alloc(serviceTxtEntries.mBuffer); - - uint8_t entryIndex = 0; - while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) - { - if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) - continue; - - serviceTxtEntries.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); - serviceTxtEntries.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); - serviceTxtEntries.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; - entryIndex++; - } - - ReturnErrorCodeIf(alloc.AnyAllocFailed(), CHIP_ERROR_BUFFER_TOO_SMALL); - - mdnsService.mTextEntries = serviceTxtEntries.mTxtEntries; - mdnsService.mTextEntrySize = entryIndex; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(tmpContext)); } else { - mdnsService.mTextEntrySize = 0; + Platform::Delete(tmpContext); } - - return CHIP_NO_ERROR; -} - -void ChipDnssdResolveNoLongerNeeded(const char * instanceName) {} - -CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress address, chip::Inet::InterfaceId interface) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; } -static void OtBrowseCallback(otError aError, const otDnsBrowseResponse * aResponse, void * aContext) +static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult) { CHIP_ERROR error; - // type buffer size is kDnssdTypeAndProtocolMaxSize + . + kMaxDomainNameSize + . + termination character - char type[Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + 3]; - // hostname buffer size is kHostNameMaxLength + . + kMaxDomainNameSize + . + termination character - char hostname[Dnssd::kHostNameMaxLength + LOCAL_DOMAIN_STRING_SIZE + 3]; - // secure space for the raw TXT data in the worst-case scenario relevant for Matter: - // each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data - uint8_t txtBuffer[kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtBufferSize]; - mDnsQueryCtx * browseContext = reinterpret_cast(aContext); - otDnsServiceInfo serviceInfo; - uint16_t index = 0; + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); + + VerifyOrReturn(mResolveContext != nullptr); + + error = FromServiceTypeToMdnsData(mResolveContext->mMdnsService, aResult->mServiceType); + mResolveContext->error = error; + + if (CHIP_NO_ERROR == error) + { + Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), + aResult->mServiceInstance); + Platform::CopyString(mResolveContext->mMdnsService.mHostName, sizeof(mResolveContext->mMdnsService.mHostName), + aResult->mHostName); - /// TODO: check this code, might be remvoed, or if not free browseContext - if (mDnsBrowseCallback == nullptr) + mResolveContext->mMdnsService.mPort = aResult->mPort; + mResolveContext->mMdnsService.mTtlSeconds = aResult->mTtl; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchTxtResolve, reinterpret_cast(mResolveContext)); + } + else { - ChipLogError(DeviceLayer, "Invalid dns browse callback"); - return; + HandleResolveCleanup(*mResolveContext, kResolveStepSrv); } +} - VerifyOrExit(aError == OT_ERROR_NONE, error = MapOpenThreadError(aError)); +static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult) +{ + bool bSendDispatch = true; - error = MapOpenThreadError(otDnsBrowseResponseGetServiceName(aResponse, type, sizeof(type))); + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); - VerifyOrExit(error == CHIP_NO_ERROR, ); + VerifyOrReturn(mResolveContext != nullptr); - char serviceName[Dnssd::Common::kInstanceNameMaxLength + 1]; - while (otDnsBrowseResponseGetServiceInstance(aResponse, index, serviceName, sizeof(serviceName)) == OT_ERROR_NONE) + // Check if TXT record was included in the response. + if (aResult->mTxtDataLength != 0) { - serviceInfo.mHostNameBuffer = hostname; - serviceInfo.mHostNameBufferSize = sizeof(hostname); - serviceInfo.mTxtData = txtBuffer; - serviceInfo.mTxtDataSize = sizeof(txtBuffer); - - otError err = otDnsBrowseResponseGetServiceInfo(aResponse, serviceName, &serviceInfo); - error = MapOpenThreadError(err); + otDnsTxtEntryIterator iterator; + otDnsInitTxtEntryIterator(&iterator, aResult->mTxtData, aResult->mTxtDataLength); - VerifyOrExit(err == OT_ERROR_NOT_FOUND || err == OT_ERROR_NONE, ); + otDnsTxtEntry txtEntry; + chip::FixedBufferAllocator alloc(mResolveContext->mServiceTxtEntry.mBuffer); - mDnsQueryCtx * tmpContext = Platform::New(browseContext->matterCtx, CHIP_NO_ERROR); + uint8_t entryIndex = 0; + while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) + { + if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) + continue; - VerifyOrExit(tmpContext != nullptr, error = CHIP_ERROR_NO_MEMORY); + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; + entryIndex++; + } - error = FromOtDnsResponseToMdnsData(serviceInfo, type, tmpContext->mMdnsService, tmpContext->mServiceTxtEntry, err); - if (CHIP_NO_ERROR == error) + if (alloc.AnyAllocFailed()) { - // Invoke callback for every service one by one instead of for the whole - // list due to large memory size needed to allocate on stack. - static_assert(ArraySize(tmpContext->mMdnsService.mName) >= ArraySize(serviceName), - "The target buffer must be big enough"); - Platform::CopyString(tmpContext->mMdnsService.mName, serviceName); - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(tmpContext)); + bSendDispatch = false; } else { - Platform::Delete(tmpContext); + mResolveContext->mMdnsService.mTextEntries = mResolveContext->mServiceTxtEntry.mTxtEntries; + mResolveContext->mMdnsService.mTextEntrySize = entryIndex; } - index++; } - -exit: - // Invoke callback to notify about end-of-browse when OT_ERROR_RESPONSE_TIMEOUT is received, otherwise ignore errors - if (aError == OT_ERROR_RESPONSE_TIMEOUT) + else { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(browseContext)); + mResolveContext->mMdnsService.mTextEntrySize = 0; } -} -static void OtServiceCallback(otError aError, const otDnsServiceResponse * aResponse, void * aContext) -{ - CHIP_ERROR error; - otError otErr; - otDnsServiceInfo serviceInfo; - mDnsQueryCtx * serviceContext; - bool bStopQuery = false; - - // If error is timeout we don't need to inform the Matter app and we can just exit - VerifyOrReturn(aError != OT_ERROR_RESPONSE_TIMEOUT, ); - - bStopQuery = true; - serviceContext = Platform::New(aContext, MapOpenThreadError(aError)); - VerifyOrExit(serviceContext != nullptr, error = CHIP_ERROR_NO_MEMORY); - - // type buffer size is kDnssdTypeAndProtocolMaxSize + . + kMaxDomainNameSize + . + termination character - char type[Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + 3]; - // hostname buffer size is kHostNameMaxLength + . + kMaxDomainNameSize + . + termination character - char hostname[Dnssd::kHostNameMaxLength + LOCAL_DOMAIN_STRING_SIZE + 3]; - // secure space for the raw TXT data in the worst-case scenario relevant for Matter: - // each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data - uint8_t txtBuffer[kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtBufferSize]; - if (mDnsResolveCallback == nullptr) + if (bSendDispatch) { - ChipLogError(DeviceLayer, "Invalid dns resolve callback"); - return; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchAddressResolve, reinterpret_cast(mResolveContext)); } - - VerifyOrExit(aError == OT_ERROR_NONE, error = MapOpenThreadError(aError)); - - error = MapOpenThreadError(otDnsServiceResponseGetServiceName(aResponse, serviceContext->mMdnsService.mName, - sizeof(serviceContext->mMdnsService.mName), type, sizeof(type))); - - VerifyOrExit(error == CHIP_NO_ERROR, ); - - serviceInfo.mHostNameBuffer = hostname; - serviceInfo.mHostNameBufferSize = sizeof(hostname); - serviceInfo.mTxtData = txtBuffer; - serviceInfo.mTxtDataSize = sizeof(txtBuffer); - - otErr = otDnsServiceResponseGetServiceInfo(aResponse, &serviceInfo); - error = MapOpenThreadError(otErr); - - VerifyOrExit(error == CHIP_NO_ERROR, ); - - error = FromOtDnsResponseToMdnsData(serviceInfo, type, serviceContext->mMdnsService, serviceContext->mServiceTxtEntry, otErr); - -exit: - if (serviceContext == nullptr) + else { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveNoMemory, reinterpret_cast(aContext)); - return; + HandleResolveCleanup(*mResolveContext, kResolveStepTxt); } +} - serviceContext->error = error; +static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult) +{ + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn((aResult->mAddressesLength > 0) && (aResult->mAddresses[0].mTtl > 0)); - // If IPv6 address in unspecified (AAAA record not present), send additional DNS query to obtain IPv6 address. - if (otIp6IsAddressUnspecified(&serviceInfo.mHostAddress)) - { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchAddressResolve, reinterpret_cast(serviceContext)); - } - else - { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(serviceContext)); - } + VerifyOrReturn(mResolveContext != nullptr); - if (bStopQuery) - { - char fullInstName[Common::kInstanceNameMaxLength + chip::Dnssd::kDnssdTypeAndProtocolMaxSize + LOCAL_DOMAIN_STRING_SIZE + - 1] = ""; - snprintf(fullInstName, sizeof(fullInstName), "%s.%s", serviceContext->mMdnsService.mName, type); + mResolveContext->mMdnsService.mAddressType = Inet::IPAddressType::kIPv6; + mResolveContext->mMdnsService.mAddress = std::optional(ToIPAddress(aResult->mAddresses[0].mAddress)); - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otMdnsServerStopQuery(thrInstancePtr, fullInstName); - } + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(mResolveContext)); } -void DispatchBrowseEmpty(intptr_t context) +static void DispatchBrowseEmpty(intptr_t context) { auto * browseContext = reinterpret_cast(context); - mDnsBrowseCallback(browseContext->matterCtx, nullptr, 0, true, browseContext->error); + browseContext->mDnsBrowseCallback(browseContext->matterCtx, nullptr, 0, true, browseContext->error); Platform::Delete(browseContext); + mBrowseContext = nullptr; bBrowseInProgress = false; } -void DispatchBrowse(intptr_t context) +static void DispatchBrowse(intptr_t context) { auto * browseContext = reinterpret_cast(context); - mDnsBrowseCallback(browseContext->matterCtx, &browseContext->mMdnsService, 1, false, browseContext->error); + browseContext->mDnsBrowseCallback(browseContext->matterCtx, &browseContext->mMdnsService, 1, false, browseContext->error); Platform::Delete(browseContext); } -void DispatchBrowseNoMemory(intptr_t context) +static void DispatchTxtResolve(intptr_t context) { - mDnsBrowseCallback(reinterpret_cast(context), nullptr, 0, true, CHIP_ERROR_NO_MEMORY); + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + otError error; + + // Stop SRV resolver before starting TXT one, ignore error as it will only happen if mMDS module is not initialized + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mSrvInfo); + + resolveContext->mTxtInfo.mServiceInstance = resolveContext->mMdnsService.mName; + resolveContext->mTxtInfo.mServiceType = resolveContext->mServiceType; + resolveContext->mTxtInfo.mCallback = OtTxtCallback; + resolveContext->mTxtInfo.mInfraIfIndex = mNetifIndex; + + error = otMdnsStartTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); + if (error != OT_ERROR_NONE) + { + resolveContext->error = MapOpenThreadError(error); + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); + } } -void DispatchAddressResolve(intptr_t context) +static void DispatchAddressResolve(intptr_t context) { - CHIP_ERROR error = CHIP_ERROR_NO_MEMORY; // ResolveAddress(context, OnDnsAddressResolveResult); + otError error; + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + // Stop TXT resolver before starting address one, ignore error as it will only happen if mMDS module is not initialized + otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); - // In case of address resolve failure, fill the error code field and dispatch method to end resolve process. - if (error != CHIP_NO_ERROR) - { - mDnsQueryCtx * resolveContext = reinterpret_cast(context); - resolveContext->error = error; + resolveContext->mAddrInfo.mCallback = OtAddressCallback; + resolveContext->mAddrInfo.mHostName = resolveContext->mMdnsService.mHostName; + resolveContext->mAddrInfo.mInfraIfIndex = mNetifIndex; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(resolveContext)); + error = otMdnsStartIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); + if (error != OT_ERROR_NONE) + { + resolveContext->error = MapOpenThreadError(error); + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); } } -void DispatchResolve(intptr_t context) +static void DispatchResolve(intptr_t context) { mDnsQueryCtx * resolveContext = reinterpret_cast(context); Dnssd::DnssdService & service = resolveContext->mMdnsService; Span ipAddrs; + // Stop Address resolver, we have finished resolving the service + otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); + if (service.mAddress.has_value()) { ipAddrs = Span(&*service.mAddress, 1); } - mDnsResolveCallback(resolveContext->matterCtx, &service, ipAddrs, resolveContext->error); + // Signal that the context will be freed and that the resolve operation is stopped because Matter will + // try do stop it again on the mDnsResolveCallback + mResolveContext = nullptr; + + resolveContext->mDnsResolveCallback(resolveContext->matterCtx, &service, ipAddrs, resolveContext->error); Platform::Delete(resolveContext); } -void DispatchResolveNoMemory(intptr_t context) +static void DispatchResolveError(intptr_t context) { + mDnsQueryCtx * resolveContext = reinterpret_cast(context); Span ipAddrs; - mDnsResolveCallback(reinterpret_cast(context), nullptr, ipAddrs, CHIP_ERROR_NO_MEMORY); + + // Signal that the context will be freed and that the resolve operation is stopped because Matter will + // try do stop it again on the mDnsResolveCallback + mResolveContext = nullptr; + + resolveContext->mDnsResolveCallback(resolveContext->matterCtx, nullptr, ipAddrs, resolveContext->error); + Platform::Delete(resolveContext); +} + +void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType) +{ + switch (stepType) + { + case kResolveStepSrv: + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mSrvInfo); + break; + case kResolveStepTxt: + otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mTxtInfo); + break; + case kResolveStepIpAddr: + otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mAddrInfo); + break; + } + + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(&resolveContext)); } } // namespace Dnssd diff --git a/src/platform/nxp/common/NXPConfig.h b/src/platform/nxp/common/NXPConfig.h index 432acfa196abbb..03d6174763fb69 100644 --- a/src/platform/nxp/common/NXPConfig.h +++ b/src/platform/nxp/common/NXPConfig.h @@ -59,7 +59,7 @@ namespace Internal { constexpr inline uint16_t config_key(uint8_t chipId, uint8_t pdmId) { - return static_cast(chipId) << 8 | pdmId; + return (uint16_t) (static_cast(chipId) << 8 | pdmId); } /** diff --git a/src/platform/nxp/common/ram_storage.c b/src/platform/nxp/common/ram_storage.c index bfd1869710ebf6..b966b38816e2a7 100644 --- a/src/platform/nxp/common/ram_storage.c +++ b/src/platform/nxp/common/ram_storage.c @@ -319,13 +319,9 @@ int ramStorageSavetoFlash(const char * file_name, uint8_t * buffer, uint32_t buf void ramStorageDump(const ramBufferDescriptor * pBuffer) { - uint16_t i = 0; - uint16_t j = 0; - uint16_t valueLength = 0; - uint16_t readLength; - int currentIndex = 0; + uint16_t i = 0; + uint16_t j = 0; const struct settingsBlock * currentBlock; - rsError error = RS_ERROR_NOT_FOUND; (void) OSA_MutexLock((osa_mutex_handle_t) mRamStorageMutexId, osaWaitForever_c); diff --git a/src/platform/nxp/k32w1/BLEManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.cpp similarity index 98% rename from src/platform/nxp/k32w1/BLEManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.cpp index fe3ebd0c0b5027..1eefdf5ef16ffc 100644 --- a/src/platform/nxp/k32w1/BLEManagerImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.cpp @@ -28,7 +28,7 @@ messaging_t gHci2Host_TaskQueue; /*! Event for the Host Task Queue */ OSA_EVENT_HANDLE_DEFINE(gHost_TaskEvent); -#include +#include extern "C" bleResult_t Hci_Reset(void); diff --git a/src/platform/nxp/k32w1/BLEManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w1/BLEManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.h diff --git a/src/platform/nxp/k32w1/BUILD.gn b/src/platform/nxp/mcxw71_k32w1/BUILD.gn similarity index 96% rename from src/platform/nxp/k32w1/BUILD.gn rename to src/platform/nxp/mcxw71_k32w1/BUILD.gn index 89e9ad06e918f4..9e190474031296 100644 --- a/src/platform/nxp/k32w1/BUILD.gn +++ b/src/platform/nxp/mcxw71_k32w1/BUILD.gn @@ -24,7 +24,7 @@ import("${nxp_sdk_build_root}/nxp_sdk.gni") import("${nxp_sdk_build_root}/${nxp_sdk_name}/${nxp_sdk_name}.gni") assert(chip_device_platform == "nxp") -assert(nxp_platform == "k32w1") +assert(nxp_platform == "mcxw71_k32w1") assert(chip_with_low_power == 0 || (chip_with_low_power == 1 && chip_with_ot_cli == 0), @@ -43,7 +43,7 @@ source_set("nxp_factory_data") { "${chip_root}/src/credentials/CertificationDeclaration.h", ] - defines = [ "PLATFORM_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/k32w1/FactoryDataProviderImpl.h\"" ] + defines = [ "PLATFORM_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.h\"" ] deps = [ ":nxp_platform", @@ -151,8 +151,8 @@ static_library("nxp_platform") { "${chip_root}/src/credentials/examples/DeviceAttestationCredsExample.h", "${chip_root}/src/credentials/examples/ExampleDACs.h", "${chip_root}/src/credentials/examples/ExamplePAI.h", - "${chip_root}/src/platform/nxp/k32w1/BLEManagerImpl.h", - "${chip_root}/src/platform/nxp/k32w1/SMU2Manager.h", + "${chip_root}/src/platform/nxp/mcxw71_k32w1/BLEManagerImpl.h", + "${chip_root}/src/platform/nxp/mcxw71_k32w1/SMU2Manager.h", ] public_deps = [ "${chip_root}/src/platform:platform_base" ] diff --git a/src/platform/nxp/k32w1/BlePlatformConfig.h b/src/platform/nxp/mcxw71_k32w1/BlePlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w1/BlePlatformConfig.h rename to src/platform/nxp/mcxw71_k32w1/BlePlatformConfig.h diff --git a/src/platform/nxp/k32w1/CHIPCryptoPalK32W1.cpp b/src/platform/nxp/mcxw71_k32w1/CHIPCryptoPalK32W1.cpp similarity index 100% rename from src/platform/nxp/k32w1/CHIPCryptoPalK32W1.cpp rename to src/platform/nxp/mcxw71_k32w1/CHIPCryptoPalK32W1.cpp diff --git a/src/platform/nxp/k32w1/CHIPDevicePlatformConfig.h b/src/platform/nxp/mcxw71_k32w1/CHIPDevicePlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w1/CHIPDevicePlatformConfig.h rename to src/platform/nxp/mcxw71_k32w1/CHIPDevicePlatformConfig.h diff --git a/src/platform/nxp/k32w1/CHIPDevicePlatformEvent.h b/src/platform/nxp/mcxw71_k32w1/CHIPDevicePlatformEvent.h similarity index 100% rename from src/platform/nxp/k32w1/CHIPDevicePlatformEvent.h rename to src/platform/nxp/mcxw71_k32w1/CHIPDevicePlatformEvent.h diff --git a/src/platform/nxp/k32w1/CHIPPlatformConfig.h b/src/platform/nxp/mcxw71_k32w1/CHIPPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w1/CHIPPlatformConfig.h rename to src/platform/nxp/mcxw71_k32w1/CHIPPlatformConfig.h diff --git a/src/platform/nxp/k32w1/ConfigurationManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.cpp similarity index 99% rename from src/platform/nxp/k32w1/ConfigurationManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.cpp index fc6815d20fd157..34e7faa8e57531 100644 --- a/src/platform/nxp/k32w1/ConfigurationManagerImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.cpp @@ -30,7 +30,7 @@ #include #include #if defined(USE_SMU2_DYNAMIC) -#include +#include #endif // #include diff --git a/src/platform/nxp/k32w1/ConfigurationManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.h similarity index 98% rename from src/platform/nxp/k32w1/ConfigurationManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.h index ba6dd2e721340b..c732ad6230b828 100644 --- a/src/platform/nxp/k32w1/ConfigurationManagerImpl.h +++ b/src/platform/nxp/mcxw71_k32w1/ConfigurationManagerImpl.h @@ -26,7 +26,7 @@ #pragma once #if (CHIP_PLAT_NVM_SUPPORT == 1) -#include +#include #else #include #endif diff --git a/src/platform/nxp/k32w1/ConnectivityManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/ConnectivityManagerImpl.cpp similarity index 100% rename from src/platform/nxp/k32w1/ConnectivityManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/ConnectivityManagerImpl.cpp diff --git a/src/platform/nxp/k32w1/ConnectivityManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/ConnectivityManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w1/ConnectivityManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/ConnectivityManagerImpl.h diff --git a/src/platform/nxp/k32w1/DiagnosticDataProviderImpl.cpp b/src/platform/nxp/mcxw71_k32w1/DiagnosticDataProviderImpl.cpp similarity index 99% rename from src/platform/nxp/k32w1/DiagnosticDataProviderImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/DiagnosticDataProviderImpl.cpp index 090feb53adde4a..9b60fabfca98bf 100644 --- a/src/platform/nxp/k32w1/DiagnosticDataProviderImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/DiagnosticDataProviderImpl.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #if CHIP_SYSTEM_CONFIG_USE_LWIP #include diff --git a/src/platform/nxp/k32w1/DiagnosticDataProviderImpl.h b/src/platform/nxp/mcxw71_k32w1/DiagnosticDataProviderImpl.h similarity index 100% rename from src/platform/nxp/k32w1/DiagnosticDataProviderImpl.h rename to src/platform/nxp/mcxw71_k32w1/DiagnosticDataProviderImpl.h diff --git a/src/platform/nxp/k32w1/FactoryDataDriverImpl.cpp b/src/platform/nxp/mcxw71_k32w1/FactoryDataDriverImpl.cpp similarity index 98% rename from src/platform/nxp/k32w1/FactoryDataDriverImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/FactoryDataDriverImpl.cpp index ae50e2361b8257..473c4932ee1ba1 100644 --- a/src/platform/nxp/k32w1/FactoryDataDriverImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/FactoryDataDriverImpl.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include using namespace chip::DeviceLayer::PersistedStorage; diff --git a/src/platform/nxp/k32w1/FactoryDataDriverImpl.h b/src/platform/nxp/mcxw71_k32w1/FactoryDataDriverImpl.h similarity index 100% rename from src/platform/nxp/k32w1/FactoryDataDriverImpl.h rename to src/platform/nxp/mcxw71_k32w1/FactoryDataDriverImpl.h diff --git a/src/platform/nxp/k32w1/FactoryDataProviderImpl.cpp b/src/platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.cpp similarity index 99% rename from src/platform/nxp/k32w1/FactoryDataProviderImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.cpp index f3af97803b13d0..c55940e8838395 100644 --- a/src/platform/nxp/k32w1/FactoryDataProviderImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ #include -#include +#include #include #include "fsl_adapter_flash.h" diff --git a/src/platform/nxp/k32w1/FactoryDataProviderImpl.h b/src/platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.h similarity index 100% rename from src/platform/nxp/k32w1/FactoryDataProviderImpl.h rename to src/platform/nxp/mcxw71_k32w1/FactoryDataProviderImpl.h diff --git a/src/platform/nxp/k32w1/InetPlatformConfig.h b/src/platform/nxp/mcxw71_k32w1/InetPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w1/InetPlatformConfig.h rename to src/platform/nxp/mcxw71_k32w1/InetPlatformConfig.h diff --git a/src/platform/nxp/k32w1/K32W1Config.cpp b/src/platform/nxp/mcxw71_k32w1/K32W1Config.cpp similarity index 99% rename from src/platform/nxp/k32w1/K32W1Config.cpp rename to src/platform/nxp/mcxw71_k32w1/K32W1Config.cpp index 6f578f8ed01624..c4ac984244d6bd 100644 --- a/src/platform/nxp/k32w1/K32W1Config.cpp +++ b/src/platform/nxp/mcxw71_k32w1/K32W1Config.cpp @@ -25,7 +25,7 @@ /* this file behaves like a config.h, comes first */ #include -#include +#include #include #include diff --git a/src/platform/nxp/k32w1/K32W1Config.h b/src/platform/nxp/mcxw71_k32w1/K32W1Config.h similarity index 100% rename from src/platform/nxp/k32w1/K32W1Config.h rename to src/platform/nxp/mcxw71_k32w1/K32W1Config.h diff --git a/src/platform/nxp/k32w1/K32W1PersistentStorageOpKeystore.cpp b/src/platform/nxp/mcxw71_k32w1/K32W1PersistentStorageOpKeystore.cpp similarity index 100% rename from src/platform/nxp/k32w1/K32W1PersistentStorageOpKeystore.cpp rename to src/platform/nxp/mcxw71_k32w1/K32W1PersistentStorageOpKeystore.cpp diff --git a/src/platform/nxp/k32w1/K32W1PersistentStorageOpKeystore.h b/src/platform/nxp/mcxw71_k32w1/K32W1PersistentStorageOpKeystore.h similarity index 100% rename from src/platform/nxp/k32w1/K32W1PersistentStorageOpKeystore.h rename to src/platform/nxp/mcxw71_k32w1/K32W1PersistentStorageOpKeystore.h diff --git a/src/platform/nxp/k32w1/KeyValueStoreManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/KeyValueStoreManagerImpl.cpp similarity index 99% rename from src/platform/nxp/k32w1/KeyValueStoreManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/KeyValueStoreManagerImpl.cpp index f70c6abb6c9e83..5b1d89de4e263e 100644 --- a/src/platform/nxp/k32w1/KeyValueStoreManagerImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/KeyValueStoreManagerImpl.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/src/platform/nxp/k32w1/KeyValueStoreManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/KeyValueStoreManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w1/KeyValueStoreManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/KeyValueStoreManagerImpl.h diff --git a/src/platform/nxp/k32w1/Logging.cpp b/src/platform/nxp/mcxw71_k32w1/Logging.cpp similarity index 100% rename from src/platform/nxp/k32w1/Logging.cpp rename to src/platform/nxp/mcxw71_k32w1/Logging.cpp diff --git a/src/platform/nxp/k32w1/LowPowerHooks.cpp b/src/platform/nxp/mcxw71_k32w1/LowPowerHooks.cpp similarity index 100% rename from src/platform/nxp/k32w1/LowPowerHooks.cpp rename to src/platform/nxp/mcxw71_k32w1/LowPowerHooks.cpp diff --git a/src/platform/nxp/k32w1/OTAFirmwareProcessor.cpp b/src/platform/nxp/mcxw71_k32w1/OTAFirmwareProcessor.cpp similarity index 98% rename from src/platform/nxp/k32w1/OTAFirmwareProcessor.cpp rename to src/platform/nxp/mcxw71_k32w1/OTAFirmwareProcessor.cpp index 33eed513ba033c..2ea4d47cc655a1 100644 --- a/src/platform/nxp/k32w1/OTAFirmwareProcessor.cpp +++ b/src/platform/nxp/mcxw71_k32w1/OTAFirmwareProcessor.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include "OtaSupport.h" diff --git a/src/platform/nxp/k32w1/OTAFirmwareProcessor.h b/src/platform/nxp/mcxw71_k32w1/OTAFirmwareProcessor.h similarity index 100% rename from src/platform/nxp/k32w1/OTAFirmwareProcessor.h rename to src/platform/nxp/mcxw71_k32w1/OTAFirmwareProcessor.h diff --git a/src/platform/nxp/k32w1/OTAHooks.cpp b/src/platform/nxp/mcxw71_k32w1/OTAHooks.cpp similarity index 97% rename from src/platform/nxp/k32w1/OTAHooks.cpp rename to src/platform/nxp/mcxw71_k32w1/OTAHooks.cpp index 3bbabaa274fba4..c476e705fd67be 100644 --- a/src/platform/nxp/k32w1/OTAHooks.cpp +++ b/src/platform/nxp/mcxw71_k32w1/OTAHooks.cpp @@ -21,10 +21,10 @@ #include -#include +#include #if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR #include -#include +#include #endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR #include "OtaSupport.h" diff --git a/src/platform/nxp/k32w1/PlatformManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/PlatformManagerImpl.cpp similarity index 96% rename from src/platform/nxp/k32w1/PlatformManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/PlatformManagerImpl.cpp index 964884e77523c6..9a52321e48fce8 100644 --- a/src/platform/nxp/k32w1/PlatformManagerImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/PlatformManagerImpl.cpp @@ -33,10 +33,10 @@ #ifdef EXTERNAL_CONFIGURATIONMANAGERIMPL_HEADER #include EXTERNAL_CONFIGURATIONMANAGERIMPL_HEADER #else -#include +#include #endif -#include -#include +#include +#include #if CHIP_SYSTEM_CONFIG_USE_LWIP #include diff --git a/src/platform/nxp/k32w1/PlatformManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/PlatformManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w1/PlatformManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/PlatformManagerImpl.h diff --git a/src/platform/nxp/k32w1/SMU2Manager.cpp b/src/platform/nxp/mcxw71_k32w1/SMU2Manager.cpp similarity index 100% rename from src/platform/nxp/k32w1/SMU2Manager.cpp rename to src/platform/nxp/mcxw71_k32w1/SMU2Manager.cpp diff --git a/src/platform/nxp/k32w1/SMU2Manager.h b/src/platform/nxp/mcxw71_k32w1/SMU2Manager.h similarity index 100% rename from src/platform/nxp/k32w1/SMU2Manager.h rename to src/platform/nxp/mcxw71_k32w1/SMU2Manager.h diff --git a/src/platform/nxp/k32w1/SystemPlatformConfig.h b/src/platform/nxp/mcxw71_k32w1/SystemPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w1/SystemPlatformConfig.h rename to src/platform/nxp/mcxw71_k32w1/SystemPlatformConfig.h diff --git a/src/platform/nxp/k32w1/SystemTimeSupport.cpp b/src/platform/nxp/mcxw71_k32w1/SystemTimeSupport.cpp similarity index 100% rename from src/platform/nxp/k32w1/SystemTimeSupport.cpp rename to src/platform/nxp/mcxw71_k32w1/SystemTimeSupport.cpp diff --git a/src/platform/nxp/k32w1/ThreadStackManagerImpl.cpp b/src/platform/nxp/mcxw71_k32w1/ThreadStackManagerImpl.cpp similarity index 98% rename from src/platform/nxp/k32w1/ThreadStackManagerImpl.cpp rename to src/platform/nxp/mcxw71_k32w1/ThreadStackManagerImpl.cpp index c7b16ffd3e5c6a..b85052bf993920 100644 --- a/src/platform/nxp/k32w1/ThreadStackManagerImpl.cpp +++ b/src/platform/nxp/mcxw71_k32w1/ThreadStackManagerImpl.cpp @@ -35,7 +35,7 @@ #include #if defined(USE_SMU2_DYNAMIC) -#include +#include #endif #include diff --git a/src/platform/nxp/k32w1/ThreadStackManagerImpl.h b/src/platform/nxp/mcxw71_k32w1/ThreadStackManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w1/ThreadStackManagerImpl.h rename to src/platform/nxp/mcxw71_k32w1/ThreadStackManagerImpl.h diff --git a/src/platform/nxp/k32w1/args.gni b/src/platform/nxp/mcxw71_k32w1/args.gni similarity index 89% rename from src/platform/nxp/k32w1/args.gni rename to src/platform/nxp/mcxw71_k32w1/args.gni index 1c984c386ea086..68e1cdeeec672e 100644 --- a/src/platform/nxp/k32w1/args.gni +++ b/src/platform/nxp/mcxw71_k32w1/args.gni @@ -19,26 +19,18 @@ import("//build_overrides/openthread.gni") declare_args() { chip_with_ot_cli = 0 chip_with_low_power = 0 - sdk_release = false - k32w1_sdk_root = "" # The key storage solution. Developers can select between "littlefs", "nvs" # and the older "fwk_nvm". chip_key_storage = "nvs" chip_use_plain_dac_key = false - - k32w1_sdk_root = "${nxp_sdk_matter_support_root}/github_sdk/common_sdk/repo" -} - -if (sdk_release || getenv("NXP_SDK_ROOT") != "") { - k32w1_sdk_root = getenv("NXP_SDK_ROOT") } openthread_root = "//third_party/connectedhomeip/third_party/openthread/ot-nxp/openthread" -nxp_platform = "k32w1" -nxp_sdk_name = "k32w1_sdk" +nxp_platform = "mcxw71_k32w1" +nxp_sdk_name = "mcxw71_k32w1_sdk" nxp_device_layer = "nxp/${nxp_platform}" nxp_use_lwip = false diff --git a/src/platform/nxp/k32w1/ble_function_mux.c b/src/platform/nxp/mcxw71_k32w1/ble_function_mux.c similarity index 100% rename from src/platform/nxp/k32w1/ble_function_mux.c rename to src/platform/nxp/mcxw71_k32w1/ble_function_mux.c diff --git a/src/platform/nxp/k32w1/ble_function_mux.h b/src/platform/nxp/mcxw71_k32w1/ble_function_mux.h similarity index 100% rename from src/platform/nxp/k32w1/ble_function_mux.h rename to src/platform/nxp/mcxw71_k32w1/ble_function_mux.h diff --git a/src/platform/nxp/k32w1/gatt_db.h b/src/platform/nxp/mcxw71_k32w1/gatt_db.h similarity index 100% rename from src/platform/nxp/k32w1/gatt_db.h rename to src/platform/nxp/mcxw71_k32w1/gatt_db.h diff --git a/src/platform/nxp/k32w1/gatt_uuid128.h b/src/platform/nxp/mcxw71_k32w1/gatt_uuid128.h similarity index 100% rename from src/platform/nxp/k32w1/gatt_uuid128.h rename to src/platform/nxp/mcxw71_k32w1/gatt_uuid128.h diff --git a/src/platform/nxp/k32w1/k32w1-chip-mbedtls-config.h b/src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h similarity index 100% rename from src/platform/nxp/k32w1/k32w1-chip-mbedtls-config.h rename to src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h diff --git a/src/platform/nxp/k32w1/ram_storage.c b/src/platform/nxp/mcxw71_k32w1/ram_storage.c similarity index 100% rename from src/platform/nxp/k32w1/ram_storage.c rename to src/platform/nxp/mcxw71_k32w1/ram_storage.c diff --git a/src/platform/nxp/k32w1/ram_storage.h b/src/platform/nxp/mcxw71_k32w1/ram_storage.h similarity index 100% rename from src/platform/nxp/k32w1/ram_storage.h rename to src/platform/nxp/mcxw71_k32w1/ram_storage.h diff --git a/src/platform/nxp/rt/rw61x/BUILD.gn b/src/platform/nxp/rt/rw61x/BUILD.gn index 1793b50884dd30..447ef2905bb300 100644 --- a/src/platform/nxp/rt/rw61x/BUILD.gn +++ b/src/platform/nxp/rt/rw61x/BUILD.gn @@ -13,11 +13,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//build_overrides/build.gni") import("//build_overrides/chip.gni") import("//build_overrides/nxp_sdk.gni") import("//build_overrides/openthread.gni") import("${chip_root}/src/platform/device.gni") -import("${nxp_sdk_build_root}/${nxp_sdk_name}/${nxp_sdk_name}.gni") + +# If external SDK is used, do not import ${nxp_sdk_name}.gni +if (!nxp_external_sdk) { + import("${nxp_sdk_build_root}/${nxp_sdk_name}/${nxp_sdk_name}.gni") +} + import("${nxp_sdk_build_root}/nxp_sdk.gni") assert(chip_device_platform == "nxp") @@ -43,8 +49,16 @@ config("nxp_platform_config") { "CONFIG_CHIP_ENCRYPTED_FACTORY_DATA=1", ] - if (chip_enable_secure_dac_private_key_storage == 1) { + if (chip_enable_secure_dac_private_key_storage) { + assert(chip_enable_secure_dac_private_key_storage && + !chip_enable_secure_whole_factory_data, + "please select only one protection solution") defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderImpl.h\"" ] + } else if (chip_enable_secure_whole_factory_data) { + assert(chip_enable_secure_whole_factory_data && + !chip_enable_secure_dac_private_key_storage, + "please select only one protection solution") + defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h\"" ] } else { defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/common/factory_data/FactoryDataProviderFwkImpl.h\"" ] } @@ -56,6 +70,11 @@ config("nxp_platform_config") { } static_library("nxp_platform") { + output_name = "libCHIP_NXP_Port_RW61x" + cflags = [ + "-Wno-conversion", + "-Wno-sign-compare", + ] deps = [] defines = [] sources = [ @@ -78,20 +97,22 @@ static_library("nxp_platform") { "PlatformManagerImpl.cpp", ] - if (rt_nvm_component == "nvm_fwk" || rt_nvm_component == "littlefs") { + if (nxp_nvm_component == "nvm_fwk" || nxp_nvm_component == "littlefs") { sources += [ "../../common/NXPConfig.cpp", "../../common/ram_storage.c", "../../common/ram_storage.h", ] - } else if (rt_nvm_component == "key_storage") { + } else if (nxp_nvm_component == "key_storage") { sources += [ "../../common/NXPConfigKS.cpp" ] + } else if (nxp_nvm_component == "nvs") { + sources += [ "../../common/NXPConfigNVS.cpp" ] } if (chip_enable_ble) { sources += [ # Adding random file which defines the function sys_csrand_get which is called by BLEManagerImpl from Zephyr - "${nxp_sdk_build_root}/${nxp_sdk_name}/sdk_hook/zephyr/random/random.cpp", + "${nxp_sdk_build_root}/rt_sdk/sdk_hook/zephyr/random/random.cpp", "../../common/ble_zephyr/BLEAdvertisingArbiter.cpp", "../../common/ble_zephyr/BLEManagerImpl.cpp", "../../common/ble_zephyr/BLEManagerImpl.h", @@ -100,14 +121,17 @@ static_library("nxp_platform") { public_deps = [ "${chip_root}/src/platform:platform_base" ] - deps += [ "${chip_root}/src/platform/logging:headers" ] + deps += [ + "${chip_root}/src/lib/dnssd:constants", + "${chip_root}/src/platform/logging:headers", + ] # define CHIP_PLAT_NVM_SUPPORT - See NXPConfig.cpp for definition - if (rt_nvm_component == "nvm_fwk") { + if (nxp_nvm_component == "nvm_fwk") { defines += [ "CHIP_PLAT_NVM_SUPPORT=1" ] - } else if (rt_nvm_component == "littlefs") { + } else if (nxp_nvm_component == "littlefs") { defines += [ "CHIP_PLAT_NVM_SUPPORT=2" ] - } else if (rt_nvm_component == "key_storage") { + } else if (nxp_nvm_component == "key_storage") { defines += [ "CHIP_PLAT_NVM_SUPPORT=3" ] } @@ -157,14 +181,16 @@ static_library("nxp_platform") { "../../common/factory_data/FactoryDataProvider.cpp", "../../common/factory_data/FactoryDataProvider.h", ] - if (chip_enable_secure_dac_private_key_storage == 1) { + if (chip_enable_secure_dac_private_key_storage) { sources += [ - # TO BE MOVED TO THE SDK - "ELSFactoryData.c", - "ELSFactoryData.h", "FactoryDataProviderImpl.cpp", "FactoryDataProviderImpl.h", ] + } else if (chip_enable_secure_whole_factory_data) { + sources += [ + "FactoryDataProviderEncImpl.cpp", + "FactoryDataProviderEncImpl.h", + ] } else { sources += [ "../../common/factory_data/FactoryDataProviderFwkImpl.cpp", @@ -175,10 +201,6 @@ static_library("nxp_platform") { deps += [ "${chip_root}/src/credentials:credentials_header" ] } - if (chip_convert_dac_private_key == 1) { - defines += [ "CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY=1" ] - } - deps += [ "${nxp_sdk_build_root}:nxp_sdk" ] public_deps += [ diff --git a/src/platform/nxp/rt/rw61x/CHIPPlatformConfig.h b/src/platform/nxp/rt/rw61x/CHIPPlatformConfig.h index caa7e32a9e3000..45b080fe52e9b3 100644 --- a/src/platform/nxp/rt/rw61x/CHIPPlatformConfig.h +++ b/src/platform/nxp/rt/rw61x/CHIPPlatformConfig.h @@ -35,7 +35,7 @@ /* In src/crypto/CHIPCryptoPALmbedTLS.cpp we verify kMAX_Hash_SHA256_Context_Size >= sizeof(mbedtls_sha256_context) * sizeof(mbedtls_sha256_context) is 392 bytes with els_pkc mbedtls port */ -#define CHIP_CONFIG_SHA256_CONTEXT_SIZE (sizeof(unsigned int) * 98) +#define CHIP_CONFIG_SHA256_CONTEXT_SIZE (sizeof(unsigned int) * 120) // ==================== Security Adaptations ==================== diff --git a/src/platform/nxp/rt/rw61x/ELSFactoryData.c b/src/platform/nxp/rt/rw61x/ELSFactoryData.c deleted file mode 100644 index a440c42569ffbd..00000000000000 --- a/src/platform/nxp/rt/rw61x/ELSFactoryData.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright 2023 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "ELSFactoryData.h" - -uint8_t * append_u32(uint8_t * pos, uint32_t val) -{ - *pos++ = 4; - *pos++ = (val >> 24) & 0xFF; - *pos++ = (val >> 16) & 0xFF; - *pos++ = (val >> 8) & 0xFF; - *pos++ = val & 0xFF; - return pos; -} - -uint8_t * append_u16(uint8_t * pos, uint32_t val) -{ - *pos++ = 2; - *pos++ = (val >> 8) & 0xFF; - *pos++ = val & 0xFF; - return pos; -} - -void write_uint32_msb_first(uint8_t * pos, uint32_t data) -{ - pos[0] = ((data) >> 24) & 0xFF; - pos[1] = ((data) >> 16) & 0xFF; - pos[2] = ((data) >> 8) & 0xFF; - pos[3] = ((data) >> 0) & 0xFF; -} - -void printf_buffer(const char * name, const unsigned char * buffer, size_t size) -{ -#define PP_BYTES_PER_LINE (32) - char line_buffer[PP_BYTES_PER_LINE * 2 + 2]; - const unsigned char * pos = buffer; - size_t remaining = size; - while (remaining > 0) - { - size_t block_size = remaining > PP_BYTES_PER_LINE ? PP_BYTES_PER_LINE : remaining; - uint32_t len = 0; - for (size_t i = 0; i < block_size; i++) - { - line_buffer[len++] = nibble_to_char[((*pos) & 0xf0) >> 4]; - line_buffer[len++] = nibble_to_char[(*pos++) & 0x0f]; - } - line_buffer[len++] = '\n'; - line_buffer[len++] = '\0'; - PRINTF("%s (%p): %s", name, pos, line_buffer); - remaining -= block_size; - } -} - -uint32_t get_required_keyslots(mcuxClEls_KeyProp_t prop) -{ - return prop.bits.ksize == MCUXCLELS_KEYPROPERTY_KEY_SIZE_128 ? 1U : 2U; -} - -bool els_is_active_keyslot(mcuxClEls_KeyIndex_t keyIdx) -{ - mcuxClEls_KeyProp_t key_properties; - key_properties.word.value = ((const volatile uint32_t *) (&ELS->ELS_KS0))[keyIdx]; - return key_properties.bits.kactv; -} - -status_t els_enable() -{ - PLOG_INFO("Enabling ELS..."); - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_Enable_Async()); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Enable_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_Enable_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -status_t els_get_key_properties(mcuxClEls_KeyIndex_t key_index, mcuxClEls_KeyProp_t * key_properties) -{ - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_GetKeyProperties(key_index, key_properties)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_GetKeyProperties) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_GetKeyProperties failed: 0x%08lx", result); - return STATUS_ERROR_GENERIC; - } - - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -mcuxClEls_KeyIndex_t els_get_free_keyslot(uint32_t required_keyslots) -{ - for (mcuxClEls_KeyIndex_t keyIdx = 0U; keyIdx <= (MCUXCLELS_KEY_SLOTS - required_keyslots); keyIdx++) - { - bool is_valid_keyslot = true; - for (uint32_t i = 0U; i < required_keyslots; i++) - { - if (els_is_active_keyslot(keyIdx + i)) - { - is_valid_keyslot = false; - break; - } - } - - if (is_valid_keyslot) - { - return keyIdx; - } - } - return MCUXCLELS_KEY_SLOTS; -} - -status_t els_derive_key(mcuxClEls_KeyIndex_t src_key_index, mcuxClEls_KeyProp_t key_prop, const uint8_t * dd, - mcuxClEls_KeyIndex_t * dst_key_index) -{ - uint32_t required_keyslots = get_required_keyslots(key_prop); - - *dst_key_index = els_get_free_keyslot(required_keyslots); - - if (!(*dst_key_index < MCUXCLELS_KEY_SLOTS)) - { - PLOG_ERROR("no free keyslot found"); - return STATUS_ERROR_GENERIC; - } - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_Ckdf_Sp800108_Async(src_key_index, *dst_key_index, key_prop, dd)); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Ckdf_Sp800108_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_Ckdf_Sp800108_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -status_t els_delete_key(mcuxClEls_KeyIndex_t key_index) -{ - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_KeyDelete_Async(key_index)); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_KeyDelete_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_KeyDelete_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -status_t els_import_key(const uint8_t * wrapped_key, size_t wrapped_key_size, mcuxClEls_KeyProp_t key_prop, - mcuxClEls_KeyIndex_t unwrap_key_index, mcuxClEls_KeyIndex_t * dst_key_index) -{ - uint32_t required_keyslots = get_required_keyslots(key_prop); - *dst_key_index = els_get_free_keyslot(required_keyslots); - - if (!(*dst_key_index < MCUXCLELS_KEY_SLOTS)) - { - PLOG_ERROR("no free keyslot found"); - return STATUS_ERROR_GENERIC; - } - - mcuxClEls_KeyImportOption_t options; - options.bits.kfmt = MCUXCLELS_KEYIMPORT_KFMT_RFC3394; - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN( - result, token, mcuxClEls_KeyImport_Async(options, wrapped_key, wrapped_key_size, unwrap_key_index, *dst_key_index)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_KeyImport_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_KeyImport_Async failed: 0x%08lx", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08lx", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -status_t els_keygen(mcuxClEls_KeyIndex_t key_index, uint8_t * public_key, size_t * public_key_size) -{ - status_t status = STATUS_SUCCESS; - - mcuxClEls_EccKeyGenOption_t key_gen_options; - key_gen_options.word.value = 0u; - key_gen_options.bits.kgsign = MCUXCLELS_ECC_PUBLICKEY_SIGN_DISABLE; - key_gen_options.bits.kgsrc = MCUXCLELS_ECC_OUTPUTKEY_DETERMINISTIC; - key_gen_options.bits.skip_pbk = MCUXCLELS_ECC_GEN_PUBLIC_KEY; - - mcuxClEls_KeyProp_t key_properties; - status = els_get_key_properties(key_index, &key_properties); - STATUS_SUCCESS_OR_EXIT_MSG("get_key_properties failed: 0x%08x", status); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN( - result, token, - mcuxClEls_EccKeyGen_Async(key_gen_options, (mcuxClEls_KeyIndex_t) 0, key_index, key_properties, NULL, &public_key[0])); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccKeyGen_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PRINTF("Css_EccKeyGen_Async failed: 0x%08lx\r\n", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PRINTF("Css_EccKeyGen_Async WaitForOperation failed: 0x%08lx\r\n", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); -exit: - return status; -} - -status_t calculate_psa_import_blob_cmac(uint8_t * psa_import_blob, size_t psa_import_blob_length_before_mac, - size_t psa_import_blob_size) -{ - status_t status = STATUS_SUCCESS; - mcuxClEls_KeyIndex_t mac_key_index = MCUXCLELS_KEY_SLOTS; - - assert(psa_import_blob_size >= psa_import_blob_length_before_mac + AES_BLOCK_SIZE); - - uint8_t * pos = &psa_import_blob[psa_import_blob_length_before_mac]; - uint8_t mac[AES_BLOCK_SIZE] = { 0 }; - uint32_t missing_bytes_to_fill_block = AES_BLOCK_SIZE - (psa_import_blob_length_before_mac % AES_BLOCK_SIZE); - - mcuxClEls_CmacOption_t cmac_options = { 0U }; - cmac_options.bits.initialize = MCUXCLELS_CMAC_INITIALIZE_ENABLE; - cmac_options.bits.finalize = MCUXCLELS_CMAC_FINALIZE_ENABLE; - cmac_options.bits.extkey = MCUXCLELS_CMAC_EXTERNAL_KEY_DISABLE; - // ELS needs us to pad the message, it does not do that itself :-( - if (missing_bytes_to_fill_block != 0) - { - memset(pos, 0, missing_bytes_to_fill_block); - *pos = 0x80; - } - - PLOG_INFO("Deriving cmac key for integrity protection on key blob..."); - status = els_derive_key(DIE_INT_MK_SK_INDEX, mac_key_prop, ckdf_derivation_data_mac, &mac_key_index); - STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN( - result, token, - mcuxClEls_Cmac_Async(cmac_options, mac_key_index, NULL, 0, psa_import_blob, psa_import_blob_length_before_mac, mac)); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_Cmac_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_Cmac_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x\n", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - status = els_delete_key(mac_key_index); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - - memcpy(pos, mac, sizeof(mac)); -exit: - return status; -} - -status_t create_psa_import_blob(const uint8_t * els_key_blob, size_t els_key_blob_size, const psa_key_attributes_t * attributes, - uint8_t * output, size_t * output_size) -{ - assert(els_key_blob_size <= 48); - assert(sizeof(key_blob_magic) < 0x80); - - status_t status = STATUS_SUCCESS; - // clang-format off - size_t required_output_size = 0 - + 2 + sizeof(key_blob_magic) - + 2 + 4 // key_id - + 2 + 4 // algorithms - + 2 + 4 // usage - + 2 + 2 // type - + 2 + 4 // bits - + 2 + 4 // lifetime - + 2 + 4 // device lifecycle - + 2 + 4 // wrapping key id - + 2 + 4 // wrapping algorithm - + 2 + 4 // signing key id - + 2 + 4 // signing algorithm - + 2 + els_key_blob_size // key blob from S50 - + 2 + AES_BLOCK_SIZE; // CMAC - // clang-format on - - if (*output_size < required_output_size) - { - PLOG_ERROR("key blob buffer too small"); - return STATUS_ERROR_GENERIC; - } - *output_size = required_output_size; - - uint32_t key_id = psa_get_key_id(attributes); - uint32_t key_alg = psa_get_key_algorithm(attributes); - uint32_t key_usage = psa_get_key_usage_flags(attributes); - uint16_t key_type = psa_get_key_type(attributes); - uint32_t key_bits = psa_get_key_bits(attributes); - uint32_t key_lifetime = psa_get_key_lifetime(attributes); - uint32_t device_lifecycle = 0x1; // 0x01: OPEN, 0x02: CLOSED, 0x04: CLOSED_LOCKED - uint32_t wrapping_key_id = NXP_DIE_INT_IMPORT_KEK_SK; - uint32_t signing_key_id = NXP_DIE_INT_IMPORT_AUTH_SK; - - PLOG_INFO("Creating key blob..."); - uint8_t * pos = output; - - *pos++ = 0x40; - *pos++ = sizeof(key_blob_magic); - memcpy(pos, key_blob_magic, sizeof(key_blob_magic)); - pos += sizeof(key_blob_magic); - - *pos++ = 0x41; - pos = append_u32(pos, key_id); - - *pos++ = 0x42; - pos = append_u32(pos, key_alg); - - *pos++ = 0x43; - pos = append_u32(pos, key_usage); - - *pos++ = 0x44; - pos = append_u16(pos, key_type); - - *pos++ = 0x45; - pos = append_u32(pos, key_bits); - - *pos++ = 0x46; - pos = append_u32(pos, key_lifetime); - - *pos++ = 0x47; - pos = append_u32(pos, device_lifecycle); - - *pos++ = 0x50; - pos = append_u32(pos, wrapping_key_id); - - *pos++ = 0x51; - pos = append_u32(pos, 0x01); // ELS RFC3394 wrapping - - *pos++ = 0x53; - pos = append_u32(pos, signing_key_id); - - *pos++ = 0x54; - pos = append_u32(pos, 0x01); // CMAC - - *pos++ = 0x55; - *pos++ = els_key_blob_size; - memcpy(pos, els_key_blob, els_key_blob_size); - pos += els_key_blob_size; - - // signature - *pos++ = 0x5E; - *pos++ = AES_BLOCK_SIZE; - size_t psa_import_blob_length_before_mac = pos - output; - - status = calculate_psa_import_blob_cmac(output, psa_import_blob_length_before_mac, *output_size); - return status; -} - -status_t import_die_int_wrapped_key_into_els(const uint8_t * wrapped_key, size_t wrapped_key_size, - mcuxClEls_KeyProp_t key_properties, mcuxClEls_KeyIndex_t * index_output) -{ - status_t status = STATUS_SUCCESS; - mcuxClEls_KeyIndex_t index_unwrap = MCUXCLELS_KEY_SLOTS; - - PLOG_INFO("Deriving wrapping key for import of die_int wrapped key on ELS..."); - status = els_derive_key(DIE_INT_MK_SK_INDEX, wrap_out_key_prop, ckdf_derivation_data_wrap_out, &index_unwrap); - STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); - - status = els_import_key(wrapped_key, wrapped_key_size, key_properties, index_unwrap, index_output); - STATUS_SUCCESS_OR_EXIT_MSG("import_wrapped_key failed: 0x%08x", status); - - status = els_delete_key(index_unwrap); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - index_unwrap = MCUXCLELS_KEY_SLOTS; - -exit: - if (index_unwrap < MCUXCLELS_KEY_SLOTS) - { - (void) els_delete_key(index_unwrap); - } - return status; -} - -status_t ELS_sign_hash(uint8_t * digest, mcuxClEls_EccByte_t * ecc_signature, mcuxClEls_EccSignOption_t * sign_options, - mcuxClEls_KeyIndex_t key_index) -{ - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, - mcuxClEls_EccSign_Async( // Perform signature generation. - *sign_options, // Set the prepared configuration. - key_index, // Set index of private key in keystore. - digest, NULL, (size_t) 0U, // Pre-hashed data to sign. Note that inputLength parameter is - // ignored since pre-hashed data has a fixed length. - ecc_signature // Output buffer, which the operation will write the signature to. - )); - PLOG_DEBUG_BUFFER("mcuxClEls_EccSign_Async ecc_signature", ecc_signature, MCUXCLELS_ECC_SIGNATURE_SIZE); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccSign_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_EccSign_Async failed. token: 0x%08x, result: 0x%08x", token, result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed. token: 0x%08x, result: 0x%08x", token, result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} diff --git a/src/platform/nxp/rt/rw61x/ELSFactoryData.h b/src/platform/nxp/rt/rw61x/ELSFactoryData.h deleted file mode 100644 index 0ac259a66a4158..00000000000000 --- a/src/platform/nxp/rt/rw61x/ELSFactoryData.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2023 NXP - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef __ELS_FACTORY_DATA_H__ -#define __ELS_FACTORY_DATA_H__ - -#include -#include - -#include "fsl_common.h" -#include "mbedtls/bignum.h" -#include "mbedtls/ecp.h" -#include "mcuxClAes.h" -#include "mcuxClEls_Cipher.h" -#include "mcuxClEls_Cmac.h" -#include "mcuxClEls_Ecc.h" -#include "mcuxClEls_Hash.h" -#include "mcuxClEls_Kdf.h" -#include "mcuxClEls_KeyManagement.h" -#include "mcuxClEls_Rng.h" -#include "mcuxClEls_Types.h" -#include "mcuxClHash_Constants.h" - -#include "psa/crypto.h" -#include "psa/crypto_values.h" - -#include "mbedtls/ecdh.h" -#include "mbedtls/entropy.h" -#include "mbedtls/nist_kw.h" - -#define BLOCK_SIZE_16_BYTES 16 -#define SHA256_OUTPUT_SIZE 32 -#define HASH_ID 0xCE47BA5E -#define HASH_LEN 4 -#define CBC_INITIAL_VECTOR_SIZE 16 - -#define STATUS_SUCCESS 0 -#define STATUS_ERROR_GENERIC 1 - -#define AES_BLOCK_SIZE 16U -#define DIE_INT_MK_SK_INDEX 0U - -#define ELS_BLOB_METADATA_SIZE 8 -#define MAX_ELS_KEY_SIZE 32 -#define ELS_WRAP_OVERHEAD 8 - -#if FACTORY_DATA_PROVIDER_LOG -#define PLOG_ERROR(...) \ - for (;;) \ - { \ - PRINTF("ERROR "); \ - PRINTF(__VA_ARGS__); \ - PRINTF(" (%s:%d)\n", __FILE__, __LINE__); \ - break; \ - } -#else -#define PLOG_ERROR(...) -#endif - -#if FACTORY_DATA_PROVIDER_LOG -#define PLOG_INFO(...) \ - for (;;) \ - { \ - PRINTF("INFO "); \ - PRINTF(__VA_ARGS__); \ - PRINTF("\n"); \ - break; \ - } -#else -#define PLOG_INFO(...) -#endif - -#if FACTORY_DATA_PROVIDER_LOG -#define PLOG_DEBUG(...) \ - for (;;) \ - { \ - PRINTF("DEBUG "); \ - PRINTF(__VA_ARGS__); \ - PRINTF("\n"); \ - break; \ - } -#else -#define PLOG_DEBUG(...) -#endif - -#if FACTORY_DATA_PROVIDER_LOG -#define PLOG_DEBUG_BUFFER(...) printf_buffer(__VA_ARGS__) -#else -#define PLOG_DEBUG_BUFFER(...) -#endif - -#define RET_MBEDTLS_SUCCESS_OR_EXIT_MSG(MSG, ...) \ - if (0 != ret) \ - { \ - status = STATUS_ERROR_GENERIC; \ - PLOG_ERROR(MSG, __VA_ARGS__); \ - goto exit; \ - } - -#define STATUS_SUCCESS_OR_EXIT_MSG(MSG, ...) \ - if (STATUS_SUCCESS != status) \ - { \ - PLOG_ERROR(MSG, __VA_ARGS__); \ - goto exit; \ - } - -// common flags -#define PSA_KEY_LOCATION_NXP_FLAG 0x400000U -#define PSA_KEY_LOCATION_EL2GO_FLAG 0x200000U -#define PSA_KEY_LOCATION_S50_FLAG 0x000001U -#define PSA_KEY_LOCATION_COMMON_FLAG \ - (PSA_KEY_LOCATION_VENDOR_FLAG | PSA_KEY_LOCATION_NXP_FLAG | PSA_KEY_LOCATION_EL2GO_FLAG | PSA_KEY_LOCATION_S50_FLAG) - -// key/data -#define PSA_KEY_LOCATION_KEY_FLAG 0x000000 -#define PSA_KEY_LOCATION_DATA_FLAG 0x008000 - -// blob/encrypted -#define PSA_KEY_LOCATION_BLOB_STORAGE_FLAG 0x000000 -#define PSA_KEY_LOCATION_ENC_STORAGE_FLAG 0x000100 -#define PSA_KEY_LOCATION_TEMP_STORAGE_FLAG 0x000200 -#define PSA_KEY_LOCATION_KEY_GEN_STORAGE_FLAG 0x000300 - -#define PSA_KEY_LOCATION_S50_BLOB_STORAGE \ - ((PSA_KEY_LOCATION_COMMON_FLAG | PSA_KEY_LOCATION_BLOB_STORAGE_FLAG | PSA_KEY_LOCATION_KEY_FLAG)) -#define MCUXCLPSADRIVER_IS_S50_BLOB_STORAGE(location) ((location) == PSA_KEY_LOCATION_S50_BLOB_STORAGE) -#define PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location) ((location) << 8 | (persistence)) - -#define NXP_DIE_INT_IMPORT_KEK_SK 0x7FFF817CU -#define NXP_DIE_INT_IMPORT_AUTH_SK 0x7FFF817EU - -const mcuxClEls_KeyProp_t keypair_prop = { .bits = { - .ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_256, - .upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE, - .upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE, - - } }; - -const mcuxClEls_KeyProp_t shared_secret_prop = { - .bits = - { - .ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_128, - .uckdf = MCUXCLELS_KEYPROPERTY_CKDF_TRUE, - .upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE, - .upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE, - - - }, -}; - -const mcuxClEls_KeyProp_t wrap_in_key_prop = { - .bits = - { - .ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_128, - .kactv = MCUXCLELS_KEYPROPERTY_ACTIVE_TRUE, - .ukuok = MCUXCLELS_KEYPROPERTY_KUOK_TRUE, - .upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE, - .upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE, - - }, -}; - -const uint8_t ckdf_derivation_data_wrap_in[12] = { - 0xc8, 0xac, 0x48, 0x88, 0xa6, 0x1b, 0x3d, 0x9b, 0x56, 0xa9, 0x75, 0xe7, -}; - -const mcuxClEls_KeyProp_t wrap_out_key_prop = { - .bits = - { - .ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_256, - .kactv = MCUXCLELS_KEYPROPERTY_ACTIVE_TRUE, - .ukwk = MCUXCLELS_KEYPROPERTY_KWK_TRUE, - .upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE, - .upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE, - - - }, -}; - -const uint8_t ckdf_derivation_data_wrap_out[12] = { - 0x4e, 0x5f, 0x0a, 0x1c, 0x43, 0x37, 0x2c, 0xd0, 0x54, 0x8e, 0x46, 0xc9, -}; - -const mcuxClEls_KeyProp_t mac_key_prop = { - .bits = - { - .ksize = MCUXCLELS_KEYPROPERTY_KEY_SIZE_256, - .kactv = MCUXCLELS_KEYPROPERTY_ACTIVE_TRUE, - .ucmac = MCUXCLELS_KEYPROPERTY_CMAC_TRUE, - .upprot_priv = MCUXCLELS_KEYPROPERTY_PRIVILEGED_TRUE, - .upprot_sec = MCUXCLELS_KEYPROPERTY_SECURE_TRUE, - }, -}; - -const uint8_t ckdf_derivation_data_mac[12] = { - 0xea, 0x93, 0x05, 0x7a, 0x50, 0xb6, 0x4d, 0x58, 0x0a, 0xe6, 0x6b, 0x57, -}; - -const uint8_t import_die_int_ecdh_sk[32] = { - 0x82, 0x9b, 0xb4, 0x4a, 0x3b, 0x6d, 0x73, 0x35, 0x09, 0x5e, 0xd9, 0x8d, 0xf6, 0x09, 0x89, 0x98, - 0xac, 0x63, 0xab, 0x4e, 0x4e, 0x78, 0xf6, 0x0a, 0x70, 0xea, 0x64, 0x92, 0xd4, 0xfc, 0xe4, 0x92, -}; - -const uint8_t import_die_int_ecdh_pk[64] = { - 0x8c, 0xe2, 0x3a, 0x89, 0xe7, 0xc5, 0xe9, 0xb1, 0x3e, 0x89, 0xed, 0xdb, 0x69, 0xb9, 0x22, 0xf8, - 0xc2, 0x8f, 0x5d, 0xcc, 0x59, 0x3e, 0x5f, 0x7b, 0x6e, 0x5a, 0x6c, 0xb3, 0x62, 0xc0, 0x17, 0x8a, - 0x2f, 0xda, 0xe8, 0x72, 0x67, 0x7b, 0xdf, 0xfe, 0xdb, 0x4a, 0x6e, 0x39, 0x2a, 0x1b, 0xae, 0xf8, - 0x88, 0x8f, 0xc5, 0x11, 0xc3, 0x67, 0x85, 0x5a, 0xc5, 0x54, 0xbb, 0xeb, 0x19, 0xf6, 0x52, 0x66, -}; - -const uint8_t key_blob_magic[7] = { 'k', 'e', 'y', 'b', 'l', 'o', 'b' }; - -const size_t s50_blob_size = 100; - -const char nibble_to_char[16] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', -}; - -uint8_t * append_u32(uint8_t * pos, uint32_t val); -uint8_t * append_u16(uint8_t * pos, uint32_t val); -void write_uint32_msb_first(uint8_t * pos, uint32_t data); -void printf_buffer(const char * name, const unsigned char * buffer, size_t size); -uint32_t get_required_keyslots(mcuxClEls_KeyProp_t prop); -bool els_is_active_keyslot(mcuxClEls_KeyIndex_t keyIdx); -status_t els_enable(); -status_t els_get_key_properties(mcuxClEls_KeyIndex_t key_index, mcuxClEls_KeyProp_t * key_properties); -mcuxClEls_KeyIndex_t els_get_free_keyslot(uint32_t required_keyslots); -status_t els_derive_key(mcuxClEls_KeyIndex_t src_key_index, mcuxClEls_KeyProp_t key_prop, const uint8_t * dd, - mcuxClEls_KeyIndex_t * dst_key_index); -status_t els_delete_key(mcuxClEls_KeyIndex_t key_index); -status_t els_import_key(const uint8_t * wrapped_key, size_t wrapped_key_size, mcuxClEls_KeyProp_t key_prop, - mcuxClEls_KeyIndex_t unwrap_key_index, mcuxClEls_KeyIndex_t * dst_key_index); -status_t els_keygen(mcuxClEls_KeyIndex_t key_index, uint8_t * public_key, size_t * public_key_size); -status_t calculate_psa_import_blob_cmac(uint8_t * psa_import_blob, size_t psa_import_blob_length_before_mac, - size_t psa_import_blob_size); -status_t create_psa_import_blob(const uint8_t * els_key_blob, size_t els_key_blob_size, const psa_key_attributes_t * attributes, - uint8_t * output, size_t * output_size); -status_t import_die_int_wrapped_key_into_els(const uint8_t * wrapped_key, size_t wrapped_key_size, - mcuxClEls_KeyProp_t key_properties, mcuxClEls_KeyIndex_t * index_output); -status_t ELS_sign_hash(uint8_t * digest, mcuxClEls_EccByte_t * ecc_signature, mcuxClEls_EccSignOption_t * sign_options, - mcuxClEls_KeyIndex_t key_index); - -#endif diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp b/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp new file mode 100644 index 00000000000000..b57a48883bbb41 --- /dev/null +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp @@ -0,0 +1,481 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2023 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FactoryDataProviderEncImpl.h" + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#include "ELSFactoryData.h" +#include "mflash_drv.h" + +#include "fsl_adapter_flash.h" + +/* mbedtls */ +#include "mbedtls/aes.h" +#include "mbedtls/sha256.h" + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#ifndef FACTORY_DATA_PROVIDER_LOG +#define FACTORY_DATA_PROVIDER_LOG 0 +#endif + +#if FACTORY_DATA_PROVIDER_LOG +#include "fsl_debug_console.h" +#define FACTORY_DATA_PROVIDER_PRINTF(...) \ + PRINTF("[%s] ", __FUNCTION__); \ + PRINTF(__VA_ARGS__); \ + PRINTF("\n\r"); +#else +#define FACTORY_DATA_PROVIDER_PRINTF(...) +#endif + +/* Grab symbol for the base address from the linker file. */ +extern uint32_t __FACTORY_DATA_START_OFFSET[]; +extern uint32_t __FACTORY_DATA_SIZE[]; +extern uint32_t __FACTORY_DATA_END[]; + +using namespace ::chip::Credentials; +using namespace ::chip::Crypto; + +namespace chip { +namespace DeviceLayer { + +FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; + +static constexpr size_t kAesKeyBlobLength = Crypto::kP256_PrivateKey_Length + ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD; + +#define TAG_ID_FOR_AES_KEY_BOLB 0xFE +#define MEM_ALIGN_4(size) ((size + 4) / 4 * 4) + +CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr) +{ + CHIP_ERROR err = CHIP_ERROR_NOT_FOUND; + uint8_t type = 0; + uint32_t index = 0; + uint8_t * addrContent = NULL; + uint8_t * factoryDataAddress = &factoryDataRamBuffer[0]; + uint32_t factoryDataSize = sizeof(factoryDataRamBuffer); + uint16_t currentLen = 0; + + while (index < factoryDataSize) + { + /* Read the type */ + memcpy((uint8_t *) &type, factoryDataAddress + index, sizeof(type)); + index += sizeof(type); + + /* Read the len */ + memcpy((uint8_t *) ¤tLen, factoryDataAddress + index, sizeof(currentLen)); + index += sizeof(currentLen); + + /* Check if the type gotten is the expected one */ + if (searchedType == type) + { + FACTORY_DATA_PROVIDER_PRINTF("type = %d, currentLen = %d, bufLength =%d", type, currentLen, bufLength); + /* If pBuf is null it means that we only want to know if the Type has been found */ + if (pBuf != NULL) + { + /* If the buffer given is too small, fill only the available space */ + if (bufLength < currentLen) + { + currentLen = bufLength; + } + memcpy((uint8_t *) pBuf, factoryDataAddress + index, currentLen); + } + length = currentLen; + if (contentAddr != NULL) + { + *contentAddr = (uint32_t) factoryDataAddress + index; + } + err = CHIP_NO_ERROR; + break; + } + else if (type == 0) + { + /* No more type available , break the loop */ + break; + } + else + { + /* Jump to next data */ + index += currentLen; + } + } + + return err; +} + +CHIP_ERROR FactoryDataProviderImpl::ELS_ImportWrappedKeyAndDecrypt(MutableByteSpan & key, uint8_t * encrypt, uint16_t size, + uint8_t * decrypt) +{ + uint8_t els_key_blob[kAesKeyBlobLength]; + size_t els_key_blob_size = sizeof(els_key_blob); + status_t status = STATUS_SUCCESS; + mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; + uint8_t public_key[64] = { 0 }; + size_t public_key_size = sizeof(public_key); + + mcuxClEls_KeyProp_t plain_key_properties = { + .word = { .value = MCUXCLELS_KEYPROPERTY_VALUE_SECURE | MCUXCLELS_KEYPROPERTY_VALUE_PRIVILEGED | + MCUXCLELS_KEYPROPERTY_VALUE_KEY_SIZE_256 | MCUXCLELS_KEYPROPERTY_VALUE_AES } + }; + + if (key.data() == NULL) + return CHIP_ERROR_INTERNAL; + + memcpy(els_key_blob, key.data(), key.size()); + + PLOG_DEBUG_BUFFER("els key blob", els_key_blob, els_key_blob_size); + + /* Import blob DAC key into SE50 (reserved key slot) */ + status = import_die_int_wrapped_key_into_els(els_key_blob, els_key_blob_size, plain_key_properties, &key_index); + STATUS_SUCCESS_OR_EXIT_MSG("import_die_int_wrapped_key_into_els failed: 0x%08x", status); + + ELS_Cipher_Aes_Ecb_Decrypt(key_index, encrypt, size, decrypt); + + els_delete_key(key_index); + + return CHIP_NO_ERROR; +exit: + els_delete_key(key_index); + return CHIP_ERROR_INVALID_SIGNATURE; +} + +CHIP_ERROR FactoryDataProviderImpl::LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair) +{ + Crypto::P256SerializedKeypair serialized_keypair; + ReturnErrorOnFailure(serialized_keypair.SetLength(privateKey.size() + publicKey.size())); + memcpy(serialized_keypair.Bytes(), publicKey.data(), publicKey.size()); + memcpy(serialized_keypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size()); + return keypair.Deserialize(serialized_keypair); +} + +CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) +{ + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + + VerifyOrReturnError(IsSpanUsable(outSignBuffer), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsSpanUsable(digestToSign), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + // In a non-exemplary implementation, the public key is not needed here. It is used here merely because + // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present. + Crypto::P256PublicKey dacPublicKey; + uint16_t certificateSize = 0; + uint32_t certificateAddr; + ReturnLogErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, NULL, 0, certificateSize, &certificateAddr)); + MutableByteSpan dacCertSpan((uint8_t *) certificateAddr, certificateSize); + + /* Extract Public Key of DAC certificate from itself */ + ReturnLogErrorOnFailure(Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); + + /* Get private key of DAC certificate from reserved section */ + uint16_t keySize = 0; + uint32_t keyAddr; + ReturnLogErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, keySize, &keyAddr)); + MutableByteSpan dacPrivateKeySpan((uint8_t *) keyAddr, keySize); + + ReturnLogErrorOnFailure(LoadKeypairFromRaw(ByteSpan(dacPrivateKeySpan.data(), dacPrivateKeySpan.size()), + ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); + + ReturnLogErrorOnFailure(keypair.ECDSA_sign_msg(digestToSign.data(), digestToSign.size(), signature)); + + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); +} + +CHIP_ERROR FactoryDataProviderImpl::ReadAndCheckFactoryDataInFlash(void) +{ + status_t status; + uint32_t factoryDataAddress = (uint32_t) __FACTORY_DATA_START_OFFSET; + uint32_t factoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; + uint32_t hashId; + + uint16_t i; + + /* Init mflash */ + status = mflash_drv_init(); + + if (status != kStatus_Success || factoryDataSize > sizeof(factoryDataRamBuffer)) + return CHIP_ERROR_INTERNAL; + + /* Load the factory data into RAM buffer */ + if (mflash_drv_read(factoryDataAddress, (uint32_t *) &factoryDataRamBuffer[0], factoryDataSize) != kStatus_Success) + { + return CHIP_ERROR_INTERNAL; + } + + memcpy(&mHeader, factoryDataRamBuffer, sizeof(mHeader)); + + if (mHeader.hashId != HASH_ID) + { + return CHIP_ERROR_NOT_FOUND; + } + + /* remove the header section */ + memmove(&factoryDataRamBuffer[0], &factoryDataRamBuffer[sizeof(mHeader)], mHeader.size); + + return CHIP_NO_ERROR; +} + +/* the factory data must be sencrypted by AES-256 */ +CHIP_ERROR FactoryDataProviderImpl::DecryptAndCheckFactoryData(void) +{ + status_t status; + bool encrypted = false; + uint16_t i = 0; + uint32_t factoryDataSize = mHeader.size; + uint8_t calculatedHash[SHA256_OUTPUT_SIZE]; + uint8_t currentBlock[BLOCK_SIZE_16_BYTES]; + CHIP_ERROR res; + uint8_t type; + uint16_t len; + + while (i < factoryDataSize) + { + type = factoryDataRamBuffer[i]; + len = factoryDataRamBuffer[i + 1] + (factoryDataRamBuffer[i + 2] << 8); + i += len; + if ((type > kMaxId) || (i > factoryDataSize)) + { + ChipLogProgress(DeviceLayer, "factory data is encrypted\n"); + encrypted = true; + break; + } + } + + if (encrypted) + { + mbedtls_aes_context aesCtx; + int status = 0; + do + { + mbedtls_aes_init(&aesCtx); + if (mbedtls_aes_setkey_dec(&aesCtx, pAesKey, 256U) != 0) + { + status = -1; + break; + } + for (i = 0; i < factoryDataSize / BLOCK_SIZE_16_BYTES; i++) + { + if (mbedtls_aes_crypt_ecb(&aesCtx, MBEDTLS_AES_DECRYPT, &factoryDataRamBuffer[i * 16], ¤tBlock[0]) != 0) + { + status = -2; + break; + } + memcpy(&factoryDataRamBuffer[i * 16], ¤tBlock[0], sizeof(currentBlock)); + } + mbedtls_aes_free(&aesCtx); + } while (false); + + if (status < 0) + { + ChipLogError(DeviceLayer, "factory data decryption Failure, status:%d", status); + return CHIP_ERROR_WRONG_ENCRYPTION_TYPE; + } + ChipLogProgress(DeviceLayer, "factory data decryption is successful!"); + } + else + { + ChipLogError(DeviceLayer, "factory data is in plain text!"); + } + + /* Calculate SHA256 value over the factory data and compare with stored value */ + res = Hash_SHA256(&factoryDataRamBuffer[0], mHeader.size, &calculatedHash[0]); + + if (res != CHIP_NO_ERROR) + return res; + + if (memcmp(&calculatedHash[0], &mHeader.hash[0], HASH_LEN) != 0) + { + return CHIP_ERROR_NOT_FOUND; + } + + ChipLogProgress(DeviceLayer, "factory data hash check is successful!"); + + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVerifierId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kVerifierId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSaltId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kSaltId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kIcId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kIcId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kDacPrivateKeyId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kDacCertificateId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPaiCertificateId, NULL, 0, len)); + FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kPaiCertificateId, len); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDiscriminatorId, NULL, 0, len)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::Init(void) +{ + uint8_t type; + ReturnLogErrorOnFailure(ReadAndCheckFactoryDataInFlash()); + + els_enable(); + + ChipLogProgress(DeviceLayer, "init: protect whole factory data\n"); + + /* check if AES Key blob attached in the tail of factory data*/ + uint16_t size = MEM_ALIGN_4(sizeof(uint8_t) + sizeof(uint16_t) + kAesKeyBlobLength); + uint16_t len; + type = factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE - size]; + len = factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE - size + kLengthOffset] + + (factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE - size + kLengthOffset + 1] << 8); + ChipLogProgress(DeviceLayer, "aes key blob type:%x, len:%d", type, len); + if ((type == TAG_ID_FOR_AES_KEY_BOLB) && (len == kAesKeyBlobLength)) + { + MutableByteSpan key(&factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE - size + kValueOffset], len); + mcuxClEls_KeyIndex_t index; + + uint8_t * data = static_cast(chip::Platform::MemoryAlloc(mHeader.size)); + memset(data, 0, mHeader.size); + + /* will provision the wrapping key to edgelock and decrypt the factory data */ + ReturnLogErrorOnFailure(ELS_ImportWrappedKeyAndDecrypt(key, &factoryDataRamBuffer[0], mHeader.size, data)); + + memcpy(factoryDataRamBuffer, data, FACTORY_DATA_MAX_SIZE); + chip::Platform::MemoryFree(data); + } + else + { + /* This situation is usually in production mode, the AES key is passed through Uart and only runs once. + The AES Key is provisioined into Edge Lock, and the returned wrapped key is store in the end the factory data in TLV mode. + Here we take the precondition that we already got the AES Key, and check whether the decrypted factory data is right and + provision it into Edge Lock if right. */ + /* pAesKey should be pointed to a real key in advance on app layer, so should not be NULL. + Currently the fwk_factory_data_provider module supports only ecb mode. Therefore return an error if encrypt mode is not ecb + */ + if (pAesKey == NULL || encryptMode != encrypt_ecb) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + ReturnLogErrorOnFailure(DecryptAndCheckFactoryData()); + ReturnLogErrorOnFailure(ELS_SaveAesKeyBlob()); + + ChipLogProgress(DeviceLayer, "System restarting"); + // Restart the system. + NVIC_SystemReset(); + while (1) + { + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::ELS_SaveAesKeyBlob() +{ + size_t blobSize = kAesKeyBlobLength; + uint8_t blob[kAesKeyBlobLength] = { 0 }; + uint32_t factoryDataAddress = (uint32_t) __FACTORY_DATA_START_OFFSET; + uint32_t factoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; + + VerifyOrReturnError(factoryDataRamBuffer != nullptr, CHIP_ERROR_INTERNAL); + + uint8_t type = TAG_ID_FOR_AES_KEY_BOLB; + ReturnErrorOnFailure(ELS_ExportBlob(blob, &blobSize)); + PLOG_DEBUG_BUFFER("els key blob", blob, blobSize); + ChipLogProgress(DeviceLayer, "SSS: extracted blob from factory data AES key"); + + /* Read all factory data */ + hal_flash_status_t status = + HAL_FlashRead(factoryDataAddress + MFLASH_BASE_ADDRESS, FACTORY_DATA_MAX_SIZE, &factoryDataRamBuffer[0]); + VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); + ChipLogError(DeviceLayer, "SSS: cached factory data in RAM"); + + /* save the Aes Key Blob in the end of factory data region */ + uint16_t size = MEM_ALIGN_4(sizeof(uint8_t) + sizeof(uint16_t) + kAesKeyBlobLength); + memcpy(&factoryDataRamBuffer[factoryDataSize - size], &type, sizeof(uint8_t)); + memcpy(&factoryDataRamBuffer[factoryDataSize - size + kLengthOffset], &blobSize, sizeof(uint16_t)); + memcpy(&factoryDataRamBuffer[factoryDataSize - size + kValueOffset], blob, blobSize); + ChipLogError(DeviceLayer, "SSS: attach wrapped key in the end of factory data in tlv format"); + + /* Erase flash factory data sectors */ + status = HAL_FlashEraseSector(factoryDataAddress + MFLASH_BASE_ADDRESS, FACTORY_DATA_MAX_SIZE); + VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); + /* Write new factory data into flash */ + status = HAL_FlashProgramUnaligned(factoryDataAddress + MFLASH_BASE_ADDRESS, FACTORY_DATA_MAX_SIZE, factoryDataRamBuffer); + VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); + ChipLogError(DeviceLayer, "SSS: updated factory data"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::ELS_ExportBlob(uint8_t * data, size_t * dataLen) +{ + status_t status = STATUS_SUCCESS; + mcuxClEls_KeyProp_t plain_key_properties = { + .word = { .value = MCUXCLELS_KEYPROPERTY_VALUE_SECURE | MCUXCLELS_KEYPROPERTY_VALUE_PRIVILEGED | + MCUXCLELS_KEYPROPERTY_VALUE_KEY_SIZE_256 | MCUXCLELS_KEYPROPERTY_VALUE_AES } + }; + + mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; + /* Import plain DAC key into S50 */ + status = import_plain_key_into_els(pAesKey, Crypto::kP256_PrivateKey_Length, plain_key_properties, &key_index); + STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); + + /* ELSĀ generate key blob. The blob created here is one that can be directly imported into ELS again. */ + status = export_key_from_els(key_index, data, dataLen); + STATUS_SUCCESS_OR_EXIT_MSG("export_key_from_els failed: 0x%08x", status); + + status = els_delete_key(key_index); + STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); +exit: + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::SetAes256Key(const uint8_t * keyAes256) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + if (keyAes256 != nullptr) + { + pAesKey = keyAes256; + error = CHIP_NO_ERROR; + } + + return error; +} + +CHIP_ERROR FactoryDataProviderImpl::SetEncryptionMode(EncryptionMode mode) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + + /* + * Currently the fwk_factory_data_provider module supports only ecb mode. + * Therefore return an error if encrypt mode is not ecb + */ + if (mode == encrypt_ecb) + { + encryptMode = mode; + error = CHIP_NO_ERROR; + } + return error; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h b/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h new file mode 100644 index 00000000000000..7a41eb6fbfd752 --- /dev/null +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2023 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#define FACTORY_DATA_MAX_SIZE 4096 + +namespace chip { +namespace DeviceLayer { + +/** + * @brief This class provides Commissionable data and Device Attestation Credentials. + * + * This implementation allows to use the ELS hardware module to load the Matter factory + * dataset in RAM at the boot. + * + * + */ + +class FactoryDataProviderImpl : public FactoryDataProvider +{ +public: + static FactoryDataProviderImpl sInstance; + + CHIP_ERROR Init(void); + CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr = NULL); + CHIP_ERROR LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair); + CHIP_ERROR SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer); + + CHIP_ERROR SetAes256Key(const uint8_t * keyAes256); + CHIP_ERROR SetEncryptionMode(EncryptionMode mode); + +private: + struct Header + { + uint32_t hashId; + uint32_t size; + uint8_t hash[4]; + }; + uint8_t factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE]; + Header mHeader; + + /* TLV offset */ + static constexpr uint32_t kLengthOffset = 1; + static constexpr uint32_t kValueOffset = 3; + + CHIP_ERROR ELS_ExportBlob(uint8_t * data, size_t * dataLen); + CHIP_ERROR ELS_SaveAesKeyBlob(); + + CHIP_ERROR ReadAndCheckFactoryDataInFlash(void); + CHIP_ERROR DecryptAndCheckFactoryData(void); + CHIP_ERROR ELS_ImportWrappedKeyAndDecrypt(MutableByteSpan & key, uint8_t * encrypt, uint16_t size, uint8_t * decrypt); + + const uint8_t * pAesKey = nullptr; + EncryptionMode encryptMode = encrypt_ecb; +}; + +inline FactoryDataProvider & FactoryDataPrvd() +{ + return FactoryDataProviderImpl::sInstance; +} + +inline FactoryDataProviderImpl & FactoryDataPrvdImpl() +{ + return FactoryDataProviderImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp index 299a018fabd092..73155af65eb48c 100644 --- a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp @@ -25,13 +25,11 @@ extern "C" { #include "ELSFactoryData.h" #include "mflash_drv.h" -#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY #include "fsl_adapter_flash.h" -#endif -#ifndef FACTORY_DATA_PROVIDER_RUN_TESTS -#define FACTORY_DATA_PROVIDER_RUN_TESTS 0 -#endif +/* mbedtls */ +#include "mbedtls/aes.h" +#include "mbedtls/sha256.h" #if defined(__cplusplus) } @@ -63,6 +61,8 @@ namespace DeviceLayer { FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; +static constexpr size_t kPrivateKeyBlobLength = Crypto::kP256_PrivateKey_Length + ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD; + CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, uint32_t * contentAddr) { @@ -123,16 +123,13 @@ CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) { - uint8_t els_key_blob[MAX_ELS_KEY_SIZE + ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD]; - uint16_t keySize = 0; - uint32_t keyAddr; - status_t status = STATUS_SUCCESS; + uint8_t els_key_blob[kPrivateKeyBlobLength]; size_t els_key_blob_size = sizeof(els_key_blob); + uint16_t keySize = 0; + status_t status = STATUS_SUCCESS; uint8_t digest[kSHA256_Hash_Length]; - uint8_t public_key[64] = { 0 }; - size_t public_key_size = sizeof(public_key); - mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; + mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; mcuxClEls_KeyProp_t plain_key_properties = { .word = { .value = MCUXCLELS_KEYPROPERTY_VALUE_SECURE | MCUXCLELS_KEYPROPERTY_VALUE_PRIVILEGED | MCUXCLELS_KEYPROPERTY_VALUE_KEY_SIZE_256 | MCUXCLELS_KEYPROPERTY_VALUE_KGSRC } @@ -140,39 +137,15 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign mcuxClEls_EccSignOption_t sign_options = { 0 }; mcuxClEls_EccByte_t ecc_signature[MCUXCLELS_ECC_SIGNATURE_SIZE]; - uint8_t psa_import_blob[256]; - size_t psa_import_blob_size = sizeof(psa_import_blob); + + uint8_t public_key[64] = { 0 }; + size_t public_key_size = sizeof(public_key); /* Search key ID FactoryDataId::kDacPrivateKeyId */ - ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, keySize, &keyAddr)); - memcpy(els_key_blob, (uint8_t *) keyAddr, keySize); + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, els_key_blob, els_key_blob_size, keySize)); PLOG_DEBUG_BUFFER("els_key_blob", els_key_blob, els_key_blob_size); - /* Calculate message HASH to sign */ - memset(&digest[0], 0, sizeof(digest)); - ReturnErrorOnFailure(Hash_SHA256(digestToSign.data(), digestToSign.size(), &digest[0])); - - PLOG_DEBUG_BUFFER("digestToSign", digestToSign.data(), digestToSign.size()); - - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attributes, 256); - psa_set_key_lifetime( - &attributes, - PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_PERSISTENT, PSA_KEY_LOCATION_S50_BLOB_STORAGE)); - psa_set_key_id(&attributes, 0x3E000021); - - /*To satisfy PSA APIs and to bind key attributes on PSA level to the key, a TLV structure is created - containing the els_key_blob and metadata. That TLV structure gets a CMAC. This structure is quasi - identical to what EdgeLock 2GO is creating. Note that the TLV structure is not used below but - required in case a blob shall be imported into TF-M for RW61x. */ - status = create_psa_import_blob(els_key_blob, els_key_blob_size, &attributes, psa_import_blob, &psa_import_blob_size); - STATUS_SUCCESS_OR_EXIT_MSG("export_key_from_els failed: 0x%08x", status); - PLOG_DEBUG_BUFFER("psa_import_blob", psa_import_blob, psa_import_blob_size); - /* Import blob DAC key into SE50 (reserved key slot) */ status = import_die_int_wrapped_key_into_els(els_key_blob, els_key_blob_size, plain_key_properties, &key_index); STATUS_SUCCESS_OR_EXIT_MSG("import_die_int_wrapped_key_into_els failed: 0x%08x", status); @@ -187,6 +160,12 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign /* The key is usable for signing. */ PLOG_DEBUG_BUFFER("public_key", public_key, public_key_size); + /* Calculate message HASH to sign */ + memset(&digest[0], 0, sizeof(digest)); + ReturnErrorOnFailure(Hash_SHA256(digestToSign.data(), digestToSign.size(), &digest[0])); + + PLOG_DEBUG_BUFFER("digestToSign", digestToSign.data(), digestToSign.size()); + /* ECC sign message hash with the key index slot reserved during the blob importation */ ELS_sign_hash(digest, ecc_signature, &sign_options, key_index); @@ -195,26 +174,19 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign /* Generate MutableByteSpan with ECC signature and ECC signature size */ return CopySpanToMutableSpan(ByteSpan{ ecc_signature, MCUXCLELS_ECC_SIGNATURE_SIZE }, outSignBuffer); + exit: els_delete_key(key_index); return CHIP_ERROR_INVALID_SIGNATURE; } -CHIP_ERROR FactoryDataProviderImpl::Init(void) +CHIP_ERROR FactoryDataProviderImpl::ReadAndCheckFactoryDataInFlash(void) { -#if FACTORY_DATA_PROVIDER_RUN_TESTS - unittest(); -#else - els_enable(); - - uint16_t len; status_t status; uint32_t factoryDataAddress = (uint32_t) __FACTORY_DATA_START_OFFSET; uint32_t factoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; uint32_t hashId; - uint8_t currentBlock[BLOCK_SIZE_16_BYTES]; uint8_t calculatedHash[SHA256_OUTPUT_SIZE]; - uint16_t i; CHIP_ERROR res; /* Init mflash */ @@ -223,35 +195,21 @@ CHIP_ERROR FactoryDataProviderImpl::Init(void) if (status != kStatus_Success || factoryDataSize > sizeof(factoryDataRamBuffer)) return CHIP_ERROR_INTERNAL; - /* Read hash id saved in flash */ - if (mflash_drv_read(factoryDataAddress, (uint32_t *) &mHeader, sizeof(mHeader)) != kStatus_Success) + /* Load the factory data into RAM buffer */ + if (mflash_drv_read(factoryDataAddress, (uint32_t *) &factoryDataRamBuffer[0], factoryDataSize) != kStatus_Success) { return CHIP_ERROR_INTERNAL; } - + memcpy(&mHeader, factoryDataRamBuffer, sizeof(mHeader)); if (mHeader.hashId != HASH_ID) { return CHIP_ERROR_NOT_FOUND; } - - /* Update address to start after hash id to read size of factory data */ - factoryDataAddress += sizeof(mHeader); - - /* Load the buffer into RAM by reading each 16 bytes blocks */ - for (i = 0; i < (factoryDataSize / BLOCK_SIZE_16_BYTES); i++) - { - if (mflash_drv_read(factoryDataAddress + i * BLOCK_SIZE_16_BYTES, (uint32_t *) ¤tBlock[0], sizeof(currentBlock)) != - kStatus_Success) - { - return CHIP_ERROR_INTERNAL; - } - - /* Store the block unencrypted */ - memcpy(&factoryDataRamBuffer[i * BLOCK_SIZE_16_BYTES], ¤tBlock[0], sizeof(currentBlock)); - } + /* remove the header section */ + memmove(&factoryDataRamBuffer[0], &factoryDataRamBuffer[sizeof(mHeader)], mHeader.size); /* Calculate SHA256 value over the factory data and compare with stored value */ - res = Hash256(&factoryDataRamBuffer[0], mHeader.size, &calculatedHash[0]); + res = Hash_SHA256(&factoryDataRamBuffer[0], mHeader.size, &calculatedHash[0]); if (res != CHIP_NO_ERROR) return res; @@ -261,107 +219,63 @@ CHIP_ERROR FactoryDataProviderImpl::Init(void) return CHIP_ERROR_NOT_FOUND; } - ReturnErrorOnFailure(SearchForId(FactoryDataId::kVerifierId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kVerifierId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kSaltId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kSaltId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kIcId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kIcId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kDacPrivateKeyId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kDacCertificateId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kPaiCertificateId, NULL, 0, len)); - FACTORY_DATA_PROVIDER_PRINTF("[%d] len = %d", FactoryDataId::kPaiCertificateId, len); - ReturnErrorOnFailure(SearchForId(FactoryDataId::kDiscriminatorId, NULL, 0, len)); - -#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY - ReturnErrorOnFailure(ELS_ConvertDacKey()); -#endif -#endif + ChipLogProgress(DeviceLayer, "factory data hash check is successful!"); return CHIP_NO_ERROR; } -CHIP_ERROR FactoryDataProviderImpl::Hash256(const uint8_t * input, size_t inputSize, uint8_t * output) -{ - CHIP_ERROR res; - res = Hash_SHA256(input, inputSize, output); - - return res; -} - -#if CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY -static inline uint32_t els_get_key_size(mcuxClEls_KeyIndex_t keyIdx) +CHIP_ERROR FactoryDataProviderImpl::Init(void) { - mcuxClEls_KeyProp_t key_properties; - key_properties.word.value = ((const volatile uint32_t *) (&ELS->ELS_KS0))[keyIdx]; - return (key_properties.bits.ksize == MCUXCLELS_KEYPROPERTY_KEY_SIZE_256) ? (256U / 8U) : (128U / 8U); -} + uint16_t len; + uint8_t type; + uint16_t keySize = 0; -static status_t els_export_key(mcuxClEls_KeyIndex_t src_key_index, mcuxClEls_KeyIndex_t wrap_key_index, uint8_t * els_key_out_blob, - size_t * els_key_out_blob_size) + ReturnLogErrorOnFailure(ReadAndCheckFactoryDataInFlash()); -{ - uint32_t key_size = els_get_key_size(src_key_index); - uint32_t required_blob_size = ELS_BLOB_METADATA_SIZE + key_size + ELS_WRAP_OVERHEAD; - assert(required_blob_size <= *els_key_out_blob_size); + els_enable(); - *els_key_out_blob_size = required_blob_size; + ChipLogProgress(DeviceLayer, "init: only protect DAC private key\n"); - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_KeyExport_Async(wrap_key_index, src_key_index, els_key_out_blob)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_KeyExport_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) + /* check whether the kDacPrivateKeyId data is converted or not*/ + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, NULL, 0, keySize)); + if (keySize == kPrivateKeyBlobLength) { - PLOG_ERROR("mcuxClEls_KeyExport_Async failed: 0x%08lx", result); - return STATUS_ERROR_GENERIC; + /* the kDacPrivateKeyId data is converted already, do nothing */ + ChipLogProgress(DeviceLayer, "SSS: DAC private key already converted to blob"); + return CHIP_NO_ERROR; } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) + else { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08lx", result); - return STATUS_ERROR_GENERIC; + /* provison the dac private key into Edge Lock and the returned wrapped key is stored the previous area of factory data, + update the hash and re-write the factory data in Flash */ + ChipLogProgress(DeviceLayer, "SSS: convert DAC private key to blob"); + ReturnLogErrorOnFailure(ELS_ConvertDacKey()); + ChipLogProgress(DeviceLayer, "System restarting"); + // Restart the system. + NVIC_SystemReset(); + while (1) + { + } } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} -static status_t export_key_from_els(mcuxClEls_KeyIndex_t key_index, uint8_t * output, size_t * output_size) -{ - assert(output != NULL); - status_t status = STATUS_SUCCESS; - - mcuxClEls_KeyIndex_t key_wrap_out_index = MCUXCLELS_KEY_SLOTS; - PLOG_INFO("Deriving wrapping key for export on ELS..."); - status = els_derive_key(DIE_INT_MK_SK_INDEX, wrap_out_key_prop, ckdf_derivation_data_wrap_out, &key_wrap_out_index); - STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); - - PLOG_INFO("Exporting/wrapping key..."); - status = els_export_key(key_index, key_wrap_out_index, output, output_size); - STATUS_SUCCESS_OR_EXIT_MSG("export_key failed: 0x%08x", status); - - status = els_delete_key(key_wrap_out_index); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - key_wrap_out_index = MCUXCLELS_KEY_SLOTS; -exit: - return status; + return CHIP_NO_ERROR; } CHIP_ERROR FactoryDataProviderImpl::ELS_ConvertDacKey() { - size_t blobSize = MAX_ELS_KEY_SIZE + ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD; - size_t newSize = sizeof(Header) + mHeader.size + (ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD); - uint8_t blob[Crypto::kP256_PrivateKey_Length + (ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD)] = { 0 }; + size_t blobSize = kPrivateKeyBlobLength; + size_t newSize = sizeof(Header) + mHeader.size + (ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD); + uint8_t blob[kPrivateKeyBlobLength] = { 0 }; uint32_t KeyAddr; uint32_t factoryDataAddress = (uint32_t) __FACTORY_DATA_START_OFFSET; uint32_t factoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; - uint8_t * data = static_cast(chip::Platform::MemoryAlloc(newSize)); VerifyOrReturnError(factoryDataRamBuffer != nullptr, CHIP_ERROR_INTERNAL); + uint8_t * data = static_cast(chip::Platform::MemoryAlloc(newSize)); /* Import pain DAC key and generate the blob */ ReturnErrorOnFailure(ELS_ExportBlob(blob, &blobSize, KeyAddr)); - ChipLogError(DeviceLayer, "SSS: extracted blob from DAC private key"); + ChipLogProgress(DeviceLayer, "SSS: extracted blob from DAC private key"); + PLOG_DEBUG_BUFFER("blob", blob, blobSize); /* Read all factory data */ hal_flash_status_t status = @@ -373,7 +287,6 @@ CHIP_ERROR FactoryDataProviderImpl::ELS_ConvertDacKey() */ ReturnErrorOnFailure(ReplaceWithBlob(data, blob, blobSize, KeyAddr)); ChipLogError(DeviceLayer, "SSS: replaced DAC private key with secured blob"); - PLOG_DEBUG_BUFFER("ReplaceWithBlob", data, newSize); /* Erase flash factory data sectors */ status = HAL_FlashEraseSector(factoryDataAddress + MFLASH_BASE_ADDRESS, factoryDataSize); @@ -383,387 +296,21 @@ CHIP_ERROR FactoryDataProviderImpl::ELS_ConvertDacKey() VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); ChipLogError(DeviceLayer, "SSS: updated factory data"); + chip::Platform::MemoryFree(data); return CHIP_NO_ERROR; } -static status_t els_generate_keypair(mcuxClEls_KeyIndex_t * dst_key_index, uint8_t * public_key, size_t * public_key_size) -{ - if (*public_key_size < 64) - { - PLOG_ERROR("insufficient space for public key"); - return STATUS_ERROR_GENERIC; - } - - mcuxClEls_EccKeyGenOption_t options = { 0 }; - options.bits.kgsrc = MCUXCLELS_ECC_OUTPUTKEY_RANDOM; - options.bits.kgtypedh = MCUXCLELS_ECC_OUTPUTKEY_KEYEXCHANGE; - - uint32_t keypair_required_keyslots = get_required_keyslots(keypair_prop); - *dst_key_index = (mcuxClEls_KeyIndex_t) els_get_free_keyslot(keypair_required_keyslots); - - if (!(*dst_key_index < MCUXCLELS_KEY_SLOTS)) - { - PLOG_ERROR("no free keyslot found"); - return STATUS_ERROR_GENERIC; - } - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN( - result, token, - mcuxClEls_EccKeyGen_Async(options, (mcuxClEls_KeyIndex_t) 0U, *dst_key_index, keypair_prop, NULL, public_key)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccKeyGen_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_EccKeyGen_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - *public_key_size = 64; - return STATUS_SUCCESS; -} - -static status_t els_get_random(unsigned char * out, size_t out_size) -{ - /* Get random IV for sector metadata encryption. */ - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Rng_DrbgRequest_Async(out, out_size)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Rng_DrbgRequest_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PRINTF("mcuxClCss_Rng_DrbgRequest_Async failed: 0x%08lx\r\n", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PRINTF("Css_EccKeyGen_Async WaitForOperation failed: 0x%08lx\r\n", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - return STATUS_SUCCESS; -} - -static int get_random_mbedtls_callback(void * ctx, unsigned char * out, size_t out_size) -{ - status_t status = els_get_random(out, out_size); - if (status != STATUS_SUCCESS) - { - return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; - } - return 0; -} - -static status_t host_perform_key_agreement(const uint8_t * public_key, size_t public_key_size, uint8_t * shared_secret, - size_t * shared_secret_size) -{ - assert(public_key != NULL); - assert(public_key_size == 64); - assert(shared_secret != NULL); - assert(*shared_secret_size >= 32); - - status_t status = STATUS_SUCCESS; - - int ret = 0; - mbedtls_ecp_group grp; - mbedtls_ecp_point qB; - mbedtls_mpi dA, zA; - mbedtls_ecp_group_init(&grp); - mbedtls_ecp_point_init(&qB); - mbedtls_mpi_init(&dA); - mbedtls_mpi_init(&zA); - - unsigned char strbuf[128] = { 0 }; - size_t strlen = sizeof(strbuf); - - uint8_t public_key_compressed[65] = { 0 }; - public_key_compressed[0] = 0x04; - - *shared_secret_size = 32; - ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_ecp_group_load failed: 0x%08x", ret); - - ret = mbedtls_mpi_read_binary(&dA, import_die_int_ecdh_sk, sizeof(import_die_int_ecdh_sk)); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_mpi_read_binary failed: 0x%08x", ret); - - memcpy(&public_key_compressed[1], public_key, public_key_size); - - ret = mbedtls_ecp_point_read_binary(&grp, &qB, public_key_compressed, sizeof(public_key_compressed)); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_ecp_point_read_binary failed: 0x%08x", ret); - - ret = mbedtls_ecdh_compute_shared(&grp, &zA, &qB, &dA, &get_random_mbedtls_callback, NULL); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_ecdh_compute_shared failed: 0x%08x", ret); - - mbedtls_ecp_point_write_binary(&grp, &qB, MBEDTLS_ECP_PF_UNCOMPRESSED, &strlen, &strbuf[0], sizeof(strbuf)); - printf_buffer("public_key", strbuf, strlen); - - mbedtls_mpi_write_binary(&zA, shared_secret, *shared_secret_size); - PLOG_DEBUG_BUFFER("shared_secret", shared_secret, *shared_secret_size); -exit: - return status; -} - -static status_t host_derive_key(const uint8_t * input_key, size_t input_key_size, const uint8_t * derivation_data, - size_t derivation_data_size, uint32_t key_properties, uint8_t * output, size_t * output_size) -{ - status_t status = STATUS_SUCCESS; - - int ret = 0; - uint32_t counter = 1; - mbedtls_cipher_context_t ctx; - memset(&ctx, 0, sizeof(ctx)); - bool ctx_valid = false; - - assert(input_key != NULL); - assert(input_key_size == 32); - assert(derivation_data != NULL); - assert(derivation_data_size == 12); - assert(output != NULL); - assert(*output_size == 32); - - uint32_t lsbit = key_properties & 0x01; - uint32_t length_blocks = 1 + lsbit; - uint32_t length_bytes = length_blocks * AES_BLOCK_SIZE; - assert(*output_size >= length_bytes); - *output_size = length_bytes; - - // KDF in counter mode implementation as described in Section 5.1 - // of NIST SP 800-108, Recommendation for Key Derivation Using Pseudorandom Functions - // Derivation data[191:0](sic!) = software_derivation_data[95:0] || 64'h0 || requested_ - // properties[31:0 || length[31:0] || counter[31:0] - - uint8_t dd[32] = { 0 }; - memcpy(&dd[0], derivation_data, derivation_data_size); - memset(&dd[12], 0, 8); - write_uint32_msb_first(&dd[20], key_properties); - write_uint32_msb_first(&dd[24], length_bytes * 8); // expected in bits! - write_uint32_msb_first(&dd[28], counter); - - mbedtls_cipher_type_t mbedtls_cipher_type = MBEDTLS_CIPHER_AES_256_ECB; - const mbedtls_cipher_info_t * cipher_info = mbedtls_cipher_info_from_type(mbedtls_cipher_type); - - PLOG_DEBUG_BUFFER("input_key", input_key, input_key_size); - PLOG_DEBUG_BUFFER("dd", dd, sizeof(dd)); - - uint8_t * pos = output; - do - { - mbedtls_cipher_init(&ctx); - ctx_valid = true; - - ret = mbedtls_cipher_setup(&ctx, cipher_info); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_cipher_setup failed: 0x%08x", ret); - - ret = mbedtls_cipher_cmac_starts(&ctx, input_key, input_key_size * 8); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_cipher_cmac_starts failed: 0x%08x", ret); - - ret = mbedtls_cipher_cmac_update(&ctx, dd, sizeof(dd)); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_cipher_cmac_update failed: 0x%08x", ret); - - ret = mbedtls_cipher_cmac_finish(&ctx, pos); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_cipher_cmac_finish failed: 0x%08x", ret); - - mbedtls_cipher_free(&ctx); - ctx_valid = false; - - write_uint32_msb_first(&dd[28], ++counter); - pos += AES_BLOCK_SIZE; - } while (counter * AES_BLOCK_SIZE <= length_bytes); - - PLOG_DEBUG_BUFFER("output", output, length_bytes); - -exit: - if (ctx_valid) - { - mbedtls_cipher_free(&ctx); - ctx_valid = false; - } - - return status; -} - -static status_t host_wrap_key(const uint8_t * data, size_t data_size, const uint8_t * key, size_t key_size, uint8_t * output, - size_t * output_size) -{ - status_t status = STATUS_SUCCESS; - int ret = 0; - mbedtls_nist_kw_context ctx; - mbedtls_nist_kw_init(&ctx); - ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, key_size * 8, true); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_nist_kw_setkey failed: 0x%08x", ret); - ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, data, data_size, output, output_size, *output_size); - RET_MBEDTLS_SUCCESS_OR_EXIT_MSG("mbedtls_nist_kw_wrap failed: 0x%08x", ret); - PLOG_DEBUG_BUFFER("wrapped buffer", output, *output_size); -exit: - mbedtls_nist_kw_free(&ctx); - return status; -} - -static status_t create_els_import_keyblob(const uint8_t * plain_key, size_t plain_key_size, mcuxClEls_KeyProp_t plain_key_prop, - const uint8_t * key_wrap_in, size_t key_wrap_in_size, uint8_t * blob, size_t * blob_size) -{ - assert(plain_key_size == 16 || plain_key_size == 32); - assert(key_wrap_in_size == 16); - - uint8_t buffer[ELS_BLOB_METADATA_SIZE + MAX_ELS_KEY_SIZE] = { 0 }; - size_t buffer_size = ELS_BLOB_METADATA_SIZE + plain_key_size; - - // Enforce the wrpok bit - the key needs to be re-wrappable! - plain_key_prop.bits.wrpok = MCUXCLELS_KEYPROPERTY_WRAP_TRUE; - - // This is what ELS documentation says. It does not work though?? - // memset(&buffer[0], 0xA6, 8); - // write_uint32_msb_first(&buffer[8], plain_key_prop.word.value); - // memset(&buffer[12], 0, 4); - // memcpy(&buffer[16], plain_key, plain_key_size); - - write_uint32_msb_first(&buffer[0], plain_key_prop.word.value); - memset(&buffer[4], 0, 4); - memcpy(&buffer[8], plain_key, plain_key_size); - PLOG_DEBUG_BUFFER("plain buffer before wrapping for import", buffer, buffer_size); - - status_t status = host_wrap_key(buffer, buffer_size, key_wrap_in, key_wrap_in_size, blob, blob_size); - return status; -} - -static status_t els_perform_key_agreement(mcuxClEls_KeyIndex_t keypair_index, mcuxClEls_KeyProp_t shared_secret_prop, - mcuxClEls_KeyIndex_t * dst_key_index, const uint8_t * public_key, size_t public_key_size) -{ - uint32_t shared_secret_required_keyslots = get_required_keyslots(shared_secret_prop); - *dst_key_index = els_get_free_keyslot(shared_secret_required_keyslots); - - if (!(*dst_key_index < MCUXCLELS_KEY_SLOTS)) - { - PLOG_ERROR("no free keyslot found"); - return STATUS_ERROR_GENERIC; - } - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, - mcuxClEls_EccKeyExchange_Async(keypair_index, public_key, *dst_key_index, shared_secret_prop)); - - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_EccKeyExchange_Async) != token) || (MCUXCLELS_STATUS_OK_WAIT != result)) - { - PLOG_ERROR("mcuxClEls_EccKeyExchange_Async failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClEls_WaitForOperation(MCUXCLELS_ERROR_FLAGS_CLEAR)); - if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEls_WaitForOperation) != token) || (MCUXCLELS_STATUS_OK != result)) - { - PLOG_ERROR("mcuxClEls_WaitForOperation failed: 0x%08x", result); - return STATUS_ERROR_GENERIC; - } - MCUX_CSSL_FP_FUNCTION_CALL_END(); - - return STATUS_SUCCESS; -} - -static status_t import_plain_key_into_els(const uint8_t * plain_key, size_t plain_key_size, mcuxClEls_KeyProp_t key_properties, - mcuxClEls_KeyIndex_t * index_output) -{ - status_t status = STATUS_SUCCESS; - mcuxClEls_KeyIndex_t index_plain = MCUXCLELS_KEY_SLOTS; - mcuxClEls_KeyIndex_t index_shared_secret = MCUXCLELS_KEY_SLOTS; - mcuxClEls_KeyIndex_t index_unwrap = MCUXCLELS_KEY_SLOTS; - mcuxClEls_KeyIndex_t * potentially_used_key_indices[] = { &index_plain, &index_shared_secret, &index_unwrap }; - - uint8_t els_key_in_blob[ELS_BLOB_METADATA_SIZE + MAX_ELS_KEY_SIZE + ELS_WRAP_OVERHEAD]; - size_t els_key_in_blob_size = sizeof(els_key_in_blob); - - uint8_t shared_secret[32] = { 0 }; - size_t shared_secret_len = sizeof(shared_secret); - - uint8_t key_wrap_in[32]; - size_t key_wrap_in_size = sizeof(key_wrap_in); - - PLOG_INFO("Generating random ECC keypair..."); - uint8_t public_key[64] = { 0u }; - size_t public_key_size = sizeof(public_key); - status = els_generate_keypair(&index_plain, &public_key[0], &public_key_size); - STATUS_SUCCESS_OR_EXIT_MSG("generate_keypair failed: 0x%08x", status); - - PLOG_INFO("Calculating shared secret on host..."); - status = host_perform_key_agreement(public_key, public_key_size, &shared_secret[0], &shared_secret_len); - STATUS_SUCCESS_OR_EXIT_MSG("perform_key_agreement_host failed: 0x%08x", status); - - PLOG_INFO("Deriving wrapping key for import on host..."); - status = host_derive_key(shared_secret, shared_secret_len, ckdf_derivation_data_wrap_in, sizeof(ckdf_derivation_data_wrap_in), - wrap_in_key_prop.word.value, &key_wrap_in[0], &key_wrap_in_size); - STATUS_SUCCESS_OR_EXIT_MSG("ckdf_host failed: 0x%08x", status); - - PLOG_INFO("Creating ELS keyblob for import..."); - - status = create_els_import_keyblob(plain_key, plain_key_size, key_properties, key_wrap_in, key_wrap_in_size, - &els_key_in_blob[0], &els_key_in_blob_size); - STATUS_SUCCESS_OR_EXIT_MSG("create_els_import_keyblob failed: 0x%08x", status); - - PLOG_INFO("Calculating shared secret on ELS..."); - status = els_perform_key_agreement(index_plain, shared_secret_prop, &index_shared_secret, import_die_int_ecdh_pk, - sizeof(import_die_int_ecdh_pk)); - STATUS_SUCCESS_OR_EXIT_MSG("perform_key_agreement failed: 0x%08x", status); - - status = els_delete_key(index_plain); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - index_plain = MCUXCLELS_KEY_SLOTS; - - PLOG_INFO("Deriving wrapping key for import on ELS..."); - status = els_derive_key(index_shared_secret, wrap_in_key_prop, ckdf_derivation_data_wrap_in, &index_unwrap); - STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); - - status = els_delete_key(index_shared_secret); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - index_shared_secret = MCUXCLELS_KEY_SLOTS; - - PLOG_INFO("Importing wrapped key..."); - status = els_import_key(els_key_in_blob, els_key_in_blob_size, key_properties, index_unwrap, index_output); - STATUS_SUCCESS_OR_EXIT_MSG("import_wrapped_key failed: 0x%08x", status); - - status = els_delete_key(index_unwrap); - STATUS_SUCCESS_OR_EXIT_MSG("delete_key failed: 0x%08x", status); - index_unwrap = MCUXCLELS_KEY_SLOTS; - -exit: - for (size_t i = 0; i < ARRAY_SIZE(potentially_used_key_indices); i++) - { - mcuxClEls_KeyIndex_t key_index = *(potentially_used_key_indices[i]); - if (key_index < MCUXCLELS_KEY_SLOTS) - { - (void) els_delete_key(key_index); - } - } - return status; -} - CHIP_ERROR FactoryDataProviderImpl::ELS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & addr) { + status_t status = STATUS_SUCCESS; uint8_t keyBuf[Crypto::kP256_PrivateKey_Length]; - MutableByteSpan dacPrivateKeySpan(keyBuf); uint16_t keySize = 0; - - status_t status = STATUS_SUCCESS; - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attributes, 256); - psa_set_key_lifetime( - &attributes, - PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_LIFETIME_PERSISTENT, PSA_KEY_LOCATION_S50_BLOB_STORAGE)); - psa_set_key_id(&attributes, 0x3E000021); + MutableByteSpan keySpan(keyBuf); /* Search key ID FactoryDataId::kDacPrivateKeyId */ - ReturnErrorOnFailure( - SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize, &addr)); - dacPrivateKeySpan.reduce_size(keySize); - PLOG_DEBUG_BUFFER("Private DAC key plain", dacPrivateKeySpan.data(), dacPrivateKeySpan.size()); - + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacPrivateKeyId, keySpan.data(), keySpan.size(), keySize, &addr)); + keySpan.reduce_size(keySize); + PLOG_DEBUG_BUFFER("Private DAC key plain", keySpan.data(), keySpan.size()); mcuxClEls_KeyProp_t plain_key_properties = { .word = { .value = MCUXCLELS_KEYPROPERTY_VALUE_SECURE | MCUXCLELS_KEYPROPERTY_VALUE_PRIVILEGED | MCUXCLELS_KEYPROPERTY_VALUE_KEY_SIZE_256 | MCUXCLELS_KEYPROPERTY_VALUE_KGSRC } @@ -771,7 +318,7 @@ CHIP_ERROR FactoryDataProviderImpl::ELS_ExportBlob(uint8_t * data, size_t * data mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; /* Import plain DAC key into S50 */ - status = import_plain_key_into_els(dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), plain_key_properties, &key_index); + status = import_plain_key_into_els(keySpan.data(), keySpan.size(), plain_key_properties, &key_index); STATUS_SUCCESS_OR_EXIT_MSG("derive_key failed: 0x%08x", status); /* ELSĀ generate key blob. The blob created here is one that can be directly imported into ELS again. */ @@ -807,94 +354,5 @@ CHIP_ERROR FactoryDataProviderImpl::ReplaceWithBlob(uint8_t * data, uint8_t * bl return CHIP_NO_ERROR; } -#endif // CHIP_DEVICE_CONFIG_SECURE_DAC_PRIVATE_KEY - -CHIP_ERROR FactoryDataProviderImpl::unittest(void) -{ -#if FACTORY_DATA_PROVIDER_RUN_TESTS - CHIP_ERROR res; - - uint8_t ecc_message[295] = { - 0x15, 0x30, 0x01, 0xec, 0x30, 0x81, 0xe9, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x81, - 0xdb, 0x30, 0x81, 0xd8, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, - 0x02, 0x01, 0x30, 0x45, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x38, 0x04, 0x36, 0x15, - 0x24, 0x00, 0x01, 0x25, 0x01, 0x37, 0x10, 0x36, 0x02, 0x05, 0x26, 0xa2, 0x18, 0x25, 0x03, 0x01, 0x03, 0x2c, 0x04, 0x13, - 0x5a, 0x49, 0x47, 0x32, 0x30, 0x31, 0x34, 0x32, 0x5a, 0x42, 0x33, 0x33, 0x30, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x34, 0x24, - 0x05, 0x00, 0x24, 0x06, 0x00, 0x25, 0x07, 0x76, 0x98, 0x24, 0x08, 0x01, 0x18, 0x31, 0x7d, 0x30, 0x7b, 0x02, 0x01, 0x03, - 0x80, 0x14, 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd, 0xf5, 0x04, 0xf3, - 0x71, 0x60, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xc3, 0xbf, 0xd1, 0xcb, 0xed, 0x21, - 0x1e, 0x54, 0x76, 0x81, 0xa6, 0xfa, 0x08, 0x8f, 0x26, 0xce, 0x14, 0x8c, 0x72, 0xae, 0x1b, 0x6f, 0x61, 0x18, 0x0f, 0x6f, - 0x01, 0xc2, 0x75, 0xad, 0x6e, 0x5e, 0x02, 0x20, 0x31, 0x11, 0x00, 0x88, 0xcc, 0xc9, 0x98, 0x55, 0x0e, 0xf1, 0xd2, 0x42, - 0x07, 0x7a, 0xaa, 0x41, 0x0c, 0xd2, 0xd3, 0xd4, 0x76, 0xab, 0xd5, 0xaf, 0x32, 0x2c, 0x45, 0x75, 0xfa, 0xcc, 0x51, 0x5b, - 0x30, 0x02, 0x20, 0x73, 0x09, 0xbb, 0x01, 0xa5, 0xae, 0x2f, 0xfc, 0x0b, 0x7f, 0xee, 0xcb, 0xa0, 0xc4, 0x94, 0xf1, 0xd3, - 0x61, 0xce, 0x4a, 0x83, 0x21, 0x5e, 0x84, 0x07, 0xcf, 0x42, 0xc5, 0xee, 0xea, 0x1a, 0x2e, 0x24, 0x03, 0x00, 0x18, 0x90, - 0x75, 0x48, 0x87, 0x85, 0x5f, 0x73, 0xb0, 0xcb, 0x3e, 0x38, 0xa7, 0xbd, 0xad, 0x22, 0xf4 - }; - - const uint8_t kDevelopmentDAC_Cert_FFF1_8002[492] = { - 0x30, 0x82, 0x01, 0xe8, 0x30, 0x82, 0x01, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x52, 0x72, 0x4d, 0x21, 0xe2, - 0xc1, 0x74, 0xaf, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x3d, 0x31, 0x25, 0x30, - 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x50, - 0x41, 0x49, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x20, 0x6e, 0x6f, 0x20, 0x50, 0x49, 0x44, 0x31, 0x14, 0x30, 0x12, - 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x30, 0x20, - 0x17, 0x0d, 0x32, 0x32, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, - 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, - 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x44, 0x41, 0x43, 0x20, - 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x2f, 0x30, 0x78, 0x38, 0x30, 0x30, 0x32, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, - 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x31, 0x14, 0x30, 0x12, 0x06, - 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x02, 0x0c, 0x04, 0x38, 0x30, 0x30, 0x32, 0x30, 0x59, 0x30, - 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, - 0x03, 0x42, 0x00, 0x04, 0xda, 0x93, 0xf1, 0x67, 0x36, 0x25, 0x67, 0x50, 0xd9, 0x03, 0xb0, 0x34, 0xba, 0x45, 0x88, 0xab, - 0xaf, 0x58, 0x95, 0x4f, 0x77, 0xaa, 0x9f, 0xd9, 0x98, 0x9d, 0xfd, 0x40, 0x0d, 0x7a, 0xb3, 0xfd, 0xc9, 0x75, 0x3b, 0x3b, - 0x92, 0x1b, 0x29, 0x4c, 0x95, 0x0f, 0xd9, 0xd2, 0x80, 0xd1, 0x4c, 0x43, 0x86, 0x2f, 0x16, 0xdc, 0x85, 0x4b, 0x00, 0xed, - 0x39, 0xe7, 0x50, 0xba, 0xbf, 0x1d, 0xc4, 0xca, 0xa3, 0x60, 0x30, 0x5e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, - 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, - 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xef, 0x06, 0x56, 0x11, 0x9c, 0x1c, 0x91, - 0xa7, 0x9a, 0x94, 0xe6, 0xdc, 0xf3, 0x79, 0x79, 0xdb, 0xd0, 0x7f, 0xf8, 0xa3, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, - 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x63, 0x54, 0x0e, 0x47, 0xf6, 0x4b, 0x1c, 0x38, 0xd1, 0x38, 0x84, 0xa4, 0x62, 0xd1, - 0x6c, 0x19, 0x5d, 0x8f, 0xfb, 0x3c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, - 0x00, 0x30, 0x45, 0x02, 0x20, 0x46, 0x86, 0x81, 0x07, 0x33, 0xbf, 0x0d, 0xc8, 0xff, 0x4c, 0xb5, 0x14, 0x5a, 0x6b, 0xfa, - 0x1a, 0xec, 0xff, 0xa8, 0xb6, 0xda, 0xb6, 0xc3, 0x51, 0xaa, 0xee, 0xcd, 0xaf, 0xb8, 0xbe, 0x95, 0x7d, 0x02, 0x21, 0x00, - 0xe8, 0xc2, 0x8d, 0x6b, 0xfc, 0xc8, 0x7a, 0x7d, 0x54, 0x2e, 0xad, 0x6e, 0xda, 0xca, 0x14, 0x8d, 0x5f, 0xa5, 0x06, 0x1e, - 0x51, 0x7c, 0xbe, 0x4f, 0x24, 0xa7, 0x20, 0xe1, 0xc0, 0x59, 0xde, 0x1a, - }; - const uint8_t kDevelopmentDAC_PublicKey_FFF1_8002[65] = { - 0x04, 0xda, 0x93, 0xf1, 0x67, 0x36, 0x25, 0x67, 0x50, 0xd9, 0x03, 0xb0, 0x34, 0xba, 0x45, 0x88, 0xab, - 0xaf, 0x58, 0x95, 0x4f, 0x77, 0xaa, 0x9f, 0xd9, 0x98, 0x9d, 0xfd, 0x40, 0x0d, 0x7a, 0xb3, 0xfd, 0xc9, - 0x75, 0x3b, 0x3b, 0x92, 0x1b, 0x29, 0x4c, 0x95, 0x0f, 0xd9, 0xd2, 0x80, 0xd1, 0x4c, 0x43, 0x86, 0x2f, - 0x16, 0xdc, 0x85, 0x4b, 0x00, 0xed, 0x39, 0xe7, 0x50, 0xba, 0xbf, 0x1d, 0xc4, 0xca, - }; - - /* Sign using the example attestation private key */ - P256ECDSASignature da_signature; - MutableByteSpan out_sig_span(da_signature.Bytes(), da_signature.Capacity()); - CHIP_ERROR err = SignWithDacKey(ByteSpan{ ecc_message, sizeof(ecc_message) }, out_sig_span); - assert(err == CHIP_NO_ERROR); - - assert(out_sig_span.size() == kP256_ECDSA_Signature_Length_Raw); - da_signature.SetLength(out_sig_span.size()); - - /* Get DAC from the provider */ - uint8_t dac_cert_buf[kMaxDERCertLength]; - MutableByteSpan dac_cert_span(dac_cert_buf); - - memcpy(dac_cert_span.data(), kDevelopmentDAC_Cert_FFF1_8002, 492); - - /* Extract public key from DAC, prior to signature verification */ - P256PublicKey dac_public_key; - err = ExtractPubkeyFromX509Cert(dac_cert_span, dac_public_key); - assert(err == CHIP_NO_ERROR); - assert(dac_public_key.Length() == 65); - assert(0 == memcmp(dac_public_key.ConstBytes(), kDevelopmentDAC_PublicKey_FFF1_8002, 65)); - - /* Verify round trip signature */ - err = dac_public_key.ECDSA_validate_msg_signature(&ecc_message[0], sizeof(ecc_message), da_signature); - assert(err == CHIP_NO_ERROR); - PRINTF("ECDSA signature validated with SUCCESS \n"); -#endif - return CHIP_NO_ERROR; -} - } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h index 43a759fa8ee15c..4fc4785328aaf4 100644 --- a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h @@ -57,12 +57,12 @@ class FactoryDataProviderImpl : public FactoryDataProvider /* TLV offset */ static constexpr uint32_t kLengthOffset = 1; static constexpr uint32_t kValueOffset = 3; - CHIP_ERROR Hash256(const uint8_t * input, size_t inputSize, uint8_t * output); - CHIP_ERROR unittest(void); CHIP_ERROR ReplaceWithBlob(uint8_t * data, uint8_t * blob, size_t blobLen, uint32_t offset); CHIP_ERROR ELS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset); CHIP_ERROR ELS_ConvertDacKey(); + + CHIP_ERROR ReadAndCheckFactoryDataInFlash(void); }; inline FactoryDataProvider & FactoryDataPrvd() diff --git a/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp b/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp index 085a10ea5f5fa3..c17e7df36c616c 100644 --- a/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp +++ b/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp @@ -112,7 +112,6 @@ void PlatformManagerImpl::HardwareInit(void) CHIP_ERROR PlatformManagerImpl::ServiceInit(void) { status_t status; - hal_rng_status_t rngStatus; CHIP_ERROR chipRes = CHIP_NO_ERROR; status = CRYPTO_InitHardware(); @@ -196,9 +195,6 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) err = ServiceInit(); SuccessOrExit(err); -#ifdef SPINEL_INTERFACE_RPMSG - otPlatRadioInitSpinelInterface(); -#endif /* SPINEL_INTERFACE_RPMSG */ PLATFORM_InitOt(); /* * Initialize the RCP here: the WiFi initialization requires to enable/disable @@ -211,7 +207,7 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) #endif #if CHIP_DEVICE_CONFIG_ENABLE_WPA - osError = os_setup_idle_function(chip::DeviceLayer::PlatformManagerImpl::IdleHook); + osError = OSA_SetupIdleFunction(chip::DeviceLayer::PlatformManagerImpl::IdleHook); if (osError != WM_SUCCESS) { ChipLogError(DeviceLayer, "Failed to setup idle function"); diff --git a/src/platform/nxp/rt/rw61x/args.gni b/src/platform/nxp/rt/rw61x/args.gni index 0c2d183aca8646..5561196ea3a323 100644 --- a/src/platform/nxp/rt/rw61x/args.gni +++ b/src/platform/nxp/rt/rw61x/args.gni @@ -42,12 +42,6 @@ declare_args() { # if rw610_mbedtls_port_els_pkc is set to false software mbedtls is used instead rw610_mbedtls_port_els_pkc = true - - # Enable DAC private key secure usage, chip_with_factory_data must be set to 1 - chip_enable_secure_dac_private_key_storage = 0 - - # Generate DAC private key blob for factory data, chip_enable_secure_dac_private_key_storage must be set to 1 - chip_convert_dac_private_key = 0 } # TODO : Enable the OTA Requestor by default. @@ -60,6 +54,10 @@ declare_args() { no_mcuboot = true } +# By default nxp_nvm_component is set to "littlefs" in nxp_sdk.gni, +# here we override it to set it to "nvs" for RW61x platform +nxp_nvm_component = "nvs" + mbedtls_target = "${nxp_sdk_build_root}:nxp_mbedtls" openthread_external_mbedtls = mbedtls_target diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support index 2aad9239944047..f6329bb2280c8b 160000 --- a/third_party/nxp/nxp_matter_support +++ b/third_party/nxp/nxp_matter_support @@ -1 +1 @@ -Subproject commit 2aad9239944047012e525caf52119a5c84b704d3 +Subproject commit f6329bb2280c8bc3f50f6d39e79191499e67cffa diff --git a/third_party/openthread/ot-nxp b/third_party/openthread/ot-nxp index f45fe4dd8687f0..0a3248f5c8ec5a 160000 --- a/third_party/openthread/ot-nxp +++ b/third_party/openthread/ot-nxp @@ -1 +1 @@ -Subproject commit f45fe4dd8687f0feddf063a33214c2196b463d3e +Subproject commit 0a3248f5c8ec5a9fd05541974872323f26d5182f diff --git a/third_party/openthread/platforms/nxp/k32w1/BUILD.gn b/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn similarity index 93% rename from third_party/openthread/platforms/nxp/k32w1/BUILD.gn rename to third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn index 38a2f231cb811c..b7dc6d35983c40 100644 --- a/third_party/openthread/platforms/nxp/k32w1/BUILD.gn +++ b/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn @@ -80,14 +80,14 @@ source_set("libopenthread-k32w1") { ] if (chip_crypto == "platform") { - sources += [ "${openthread_nxp_root}/src/k32w1/k32w1/ecdsa_sss.cpp" ] + sources += [ "${openthread_nxp_root}/src/common/crypto/ecdsa_sss.cpp" ] if (use_hw_sha256) { - sources += [ "${openthread_nxp_root}/src/k32w1/k32w1/sha256_sss.cpp" ] + sources += [ "${openthread_nxp_root}/src/common/crypto/sha256_sss.cpp" ] } if (use_hw_aes) { - sources += [ "${openthread_nxp_root}/src/k32w1/k32w1/aes_sss.cpp" ] + sources += [ "${openthread_nxp_root}/src/common/crypto/aes_sss.cpp" ] } if (chip_key_storage == "fwk_nvm") { diff --git a/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn b/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn index c8054103122357..6d4854f53a9160 100644 --- a/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn +++ b/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn @@ -43,21 +43,24 @@ config("openthread_rw61x_config") { "OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE=1", "OPENTHREAD_CONFIG_COMMISSIONER_ENABLE=1", "OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE=1", - "OPENTHREAD_CONFIG_MDNS_SERVER_ENABLE=1", "OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE=1", "OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE=1", "OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS=3", "OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE=1", "OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE=1", "OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE=1", - "OT_APP_BR_LWIP_HOOKS_EN=1", "OPENTHREAD_CONFIG_GENERIC_TASKLET_ENABLE=1", + "OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE=1", + "OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE=1", + "OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE=1", + "OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF=0", + "OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE=1", + "OT_APP_BR_LWIP_HOOKS_EN=1", ] } + # ot cli configs - defines += [ - "OPENTHREAD_CONFIG_PING_SENDER_ENABLE=1" - ] + defines += [ "OPENTHREAD_CONFIG_PING_SENDER_ENABLE=1" ] } #Config used by the openthread stack to get the path to OpenthreadConfig.h @@ -70,9 +73,9 @@ source_set("libopenthread-rw61x") { deps = [] sources = [ "${openthread_nxp_root}/src/common/alarm_freertos.c", + "${openthread_nxp_root}/src/common/diag.c", + "${openthread_nxp_root}/src/common/entropy.c", "${openthread_nxp_root}/src/common/logging.c", - "${openthread_nxp_root}/src/rw/rw612/platform/diag.c", - "${openthread_nxp_root}/src/rw/rw612/platform/entropy.c", ] if (chip_enable_wifi && chip_enable_openthread) { @@ -82,7 +85,9 @@ source_set("libopenthread-rw61x") { "${openthread_nxp_root}/src/common/br/infra_if.c", "${openthread_nxp_root}/src/common/br/lwip_hooks.c", "${openthread_nxp_root}/src/common/br/lwip_mcast.c", + "${openthread_nxp_root}/src/common/br/mdns_socket.c", "${openthread_nxp_root}/src/common/br/udp_plat.c", + "${openthread_nxp_root}/src/common/br/utils.c", ] deps += [ "${nxp_sdk_build_root}:nxp_lwip" ] } @@ -93,6 +98,7 @@ source_set("libopenthread-rw61x") { "${openthread_nxp_root}/src/common/spinel/spinel_hdlc.cpp", "${openthread_nxp_root}/src/common/spinel/system.c", "${openthread_root}/src/lib/hdlc/hdlc.cpp", + "${openthread_root}/src/lib/url/url.cpp", ] } else { sources += [ @@ -102,12 +108,14 @@ source_set("libopenthread-rw61x") { ] } - if (rt_nvm_component == "nvm_fwk") { + if (nxp_nvm_component == "nvm_fwk") { sources += [ "${openthread_nxp_root}/src/common/flash_nvm.c" ] - } else if (rt_nvm_component == "littlefs") { + } else if (nxp_nvm_component == "littlefs") { sources += [ "${openthread_nxp_root}/src/common/flash_littlefs.c" ] - } else if (rt_nvm_component == "key_storage") { + } else if (nxp_nvm_component == "key_storage") { sources += [ "${openthread_nxp_root}/src/common/flash_fsa.c" ] + } else if (nxp_nvm_component == "nvs") { + sources += [ "${openthread_nxp_root}/src/common/flash_nvs.c" ] } defines = [