From ed8688190560b3db674eceaecc31d68ce48b97fd Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk <66371704+kkasperczyk-no@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:31:57 +0200 Subject: [PATCH] V1.3 nrf cherry picks (#33134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [nrfconnect][zephyr] Improvements and Fixes for WiFi according to NCS 2.6.0 (#32711) * [nrfconnect] wifi: avoid unwanted connect request It's pointless to issue a connect request in case no valid SSID has been found. Signed-off-by: Marcin Kajor * [nrfconnect] wifi: Fix 5GHz association Wi-Fi stack recently introduced a check for valid band value and the default value of 0 (memset) means only 2.4GHz, so, 5GHz Wi-Fi associations will fail. Fix the default to Unknown to scan all supported bands. * [zephyr][nrfconnect] Make Wi-Fi manager use Wi-Fi interface only Find the Wi-Fi interface at the Wi-Fi manager initialization and use that interface instead of the default interface when calling Wi-Fi management functions. Signed-off-by: Damian Krolik * [nrfconnect] fix handling of LastNetworkID in Wi-Fi driver This commit makes sure that correct Network ID is provided to the Network Commissioning cluster from the platform's Wi-Fi driver. Signed-off-by: Łukasz Duda * [inet] Combine platform handlers for joining/leaving mcast group Instead, use a single handler for both joining and leaving a multicast group to reduce the code duplication. Signed-off-by: Damian Krolik * [zephyr][nrfconnect] Move handler for joining/leaving mcast group Move the platform handler for joining and leaving a multicast group to ConnectivityManagerImpl to support Matter stack on a system with multiple network interfaces (Thread + Wi-Fi). Signed-off-by: Damian Krolik * [nrfconnect] Added DNS server refresh after adding new IPv6 address The Wi-Fi device does not update mDNS queries after obtaining new IPv6 GUA address, so for some time after assigning prefix, the Thread Border Routers still use cached link-local address, which is not routable. Signed-off-by: Kamil Kasperczyk * [nrfconnect] [zephyr] Disable synchronous printk Disable synchronous printk to avoid blocking IRQs which may affect time sensitive components (like 15.4 radio). Signed-off-by: Marcin Kajor * [nrfconnect] Fix various Wi-Fi issues with error code handling This commit handles a few issues with Wi-Fi connection or scanning: - Use wifi_status structure instead of incompatible WiFiRequestStatus - On connect error value > 2 do not report success - On scan error value > 1 do not report success - Provide value of mandatory LastConnectErrorValue attribute Signed-off-by: Łukasz Duda * [nrfconnect] Minor Wi-Fi refinements * error code handling unification * added GetWantedNetwork getter and use it when handling network status change * minor refactoring Signed-off-by: Marcin Kajor * Restyled by clang-format * [nrfconnect] Provide a workaround for nrfconnect Posix unit tests. We need to disable all dependencies to the Zephyr net_if module until we switch unit tests to it. * Restyled by gn * Use Enum to indicate an operation instead of bool in MulticastGroupHandler --------- Signed-off-by: Marcin Kajor Signed-off-by: Damian Krolik Signed-off-by: Łukasz Duda Signed-off-by: Kamil Kasperczyk Co-authored-by: Marcin Kajor Co-authored-by: Damian Krolik Co-authored-by: Łukasz Duda Co-authored-by: Kamil Kasperczyk Co-authored-by: Restyled.io * [nrfconnect] Improve CHIP_MEMORY_PROFILING config (#32827) - Enabled the full SHELL option when memory profiling is enabled. * [dnssd] Allow selecting DNS-SD implementation at runtime (#32829) Add Resolver::SetInstance() and ServiceAdvertiser::SetInstance() methods for dynamically changing the system-wide DNS-SD implementation used by Matter. Also, allow for building "minimal" and "platform" DNS-SD implementations together. Co-authored-by: Damian Krolik * [scripts] Fixed nrfconnect factory generation scripts (#32892) The factory_data.hex file is not generated as an intermediate product of factory generation process. In result, factory generation works only if merging with firmware is used or scripts are manually invoked. Added optional --size and --offset arguments to generate_nrfconnect_chip_factory_data.py script that results in calling nrfconnect_generate_partition.py internally. It solves an issue and additionally simplifies manual generation process (if selected). * [nrfconnect] Implemented WiFiNetworkDiagnostics events generation (#32962) * Added generation of optional events from WiFiNetworkDiagnostics cluster. * Improved handler methods to validate the input data size * [zephyr] Fix CHIPDevicePlatformEvent.h include dependency (#33004) Currently the CHIPDevicePlatformEvent depends on the SystemPacketBuffer which is included in the CHIPDeviceEvent.h too late. The problem is silently worked around in the application when the include is preceded by other headers that pull in SystemPacketBuffer.h, but we need a proper fix. Signed-off-by: Marcin Kajor * [zephyr] Added Bluetooth LE Extended Advertisement option (#33005) This commit implements platform solution for a Bluetooth LE extended advertising. Additionally, for the CommissioningWindowManager types were changed from Seconds16 to Seconds32, because the current implementation overflows for 48h duration. Co-authored-by: Patryk Lipinski * [clusters] Implemented ThreadDiagnosticDelegate (#32964) Added ThreadDiagnosticDelegate to enable generation of optional events from ThreadNetworkDiagnostics cluster. Additionally implemented generation of ConnectionStatus and NetworkFaultChanged events when Thread link state is changed. --------- Signed-off-by: Marcin Kajor Signed-off-by: Damian Krolik Signed-off-by: Łukasz Duda Signed-off-by: Kamil Kasperczyk Co-authored-by: Arkadiusz Bałys Co-authored-by: Marcin Kajor Co-authored-by: Damian Krolik Co-authored-by: Łukasz Duda Co-authored-by: Restyled.io Co-authored-by: Patryk Lipinski --- config/nrfconnect/chip-module/CMakeLists.txt | 8 +- .../nrfconnect/chip-module/Kconfig.defaults | 6 +- .../nrfconnect/chip-module/Kconfig.features | 9 +- .../chip-module/generate_factory_data.cmake | 83 ++---- config/zephyr/Kconfig | 18 ++ config/zephyr/chip-module/Kconfig.defaults | 4 +- .../nrfconnect_factory_data_configuration.md | 77 +++-- .../generate_nrfconnect_chip_factory_data.py | 35 ++- .../thread-network-diagnostics-server.cpp | 59 ++++ src/app/server/CommissioningWindowManager.cpp | 8 +- src/app/server/CommissioningWindowManager.h | 22 +- src/app/tests/TestCommissionManager.cpp | 2 +- src/include/platform/ConnectivityManager.h | 5 +- src/include/platform/DiagnosticDataProvider.h | 28 +- src/inet/UDPEndPointImplSockets.cpp | 8 +- src/inet/UDPEndPointImplSockets.h | 15 +- src/lib/dnssd/Advertiser.cpp | 41 +++ src/lib/dnssd/Advertiser.h | 21 +- src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp | 6 +- src/lib/dnssd/Advertiser_ImplNone.cpp | 6 +- src/lib/dnssd/BUILD.gn | 26 +- src/lib/dnssd/Discovery_ImplPlatform.cpp | 8 +- src/lib/dnssd/Resolver.cpp | 41 +++ src/lib/dnssd/Resolver.h | 19 +- src/lib/dnssd/Resolver_ImplMinimalMdns.cpp | 6 +- src/lib/dnssd/Resolver_ImplNone.cpp | 6 +- ...GenericThreadStackManagerImpl_OpenThread.h | 2 + ...nericThreadStackManagerImpl_OpenThread.hpp | 17 ++ src/platform/Zephyr/BLEManagerImpl.cpp | 72 ++++- src/platform/Zephyr/BLEManagerImpl.h | 4 +- .../Zephyr/CHIPDevicePlatformConfig.h | 6 + src/platform/Zephyr/CHIPDevicePlatformEvent.h | 2 +- .../Zephyr/ConfigurationManagerImpl.cpp | 4 +- src/platform/Zephyr/InetUtils.cpp | 11 +- src/platform/Zephyr/InetUtils.h | 5 +- .../Zephyr/ThreadStackManagerImpl.cpp | 23 -- src/platform/Zephyr/wifi/WiFiManager.cpp | 48 +-- src/platform/device.gni | 6 + src/platform/nrfconnect/BUILD.gn | 11 +- .../nrfconnect/CHIPDevicePlatformConfig.h | 6 + .../nrfconnect/ConnectivityManagerImpl.cpp | 81 ++++- .../nrfconnect/wifi/NrfWiFiDriver.cpp | 45 ++- src/platform/nrfconnect/wifi/NrfWiFiDriver.h | 4 +- src/platform/nrfconnect/wifi/WiFiManager.cpp | 280 ++++++++++++------ src/platform/nrfconnect/wifi/WiFiManager.h | 35 ++- .../telink/ThreadStackManagerImpl.cpp | 32 +- 46 files changed, 901 insertions(+), 360 deletions(-) create mode 100644 src/lib/dnssd/Advertiser.cpp create mode 100644 src/lib/dnssd/Resolver.cpp diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt index d132d8249d76b1..98295406628cc1 100644 --- a/config/nrfconnect/chip-module/CMakeLists.txt +++ b/config/nrfconnect/chip-module/CMakeLists.txt @@ -140,6 +140,8 @@ matter_add_gn_arg_bool ("chip_system_config_provide_statistics" CONFIG_CHIP_ST matter_add_gn_arg_bool ("chip_enable_icd_server" CONFIG_CHIP_ENABLE_ICD_SUPPORT) matter_add_gn_arg_bool ("chip_enable_factory_data" CONFIG_CHIP_FACTORY_DATA) matter_add_gn_arg_bool ("chip_enable_read_client" CONFIG_CHIP_ENABLE_READ_CLIENT) +matter_add_gn_arg_bool ("chip_mdns_minimal" CONFIG_WIFI_NRF700X) +matter_add_gn_arg_bool ("chip_mdns_platform" CONFIG_NET_L2_OPENTHREAD) if (CONFIG_CHIP_ENABLE_ICD_SUPPORT) matter_add_gn_arg_bool ("chip_enable_icd_lit" CONFIG_CHIP_ICD_LIT_SUPPORT) @@ -157,10 +159,10 @@ if (CONFIG_CHIP_ROTATING_DEVICE_ID) matter_add_gn_arg_bool("chip_enable_additional_data_advertising" TRUE) endif() -if (CONFIG_NET_L2_OPENTHREAD) - matter_add_gn_arg_string("chip_mdns" "platform") -elseif(CONFIG_WIFI_NRF700X) +if(CONFIG_WIFI_NRF700X) matter_add_gn_arg_string("chip_mdns" "minimal") +elseif (CONFIG_NET_L2_OPENTHREAD) + matter_add_gn_arg_string("chip_mdns" "platform") else() matter_add_gn_arg_string("chip_mdns" "none") endif() diff --git a/config/nrfconnect/chip-module/Kconfig.defaults b/config/nrfconnect/chip-module/Kconfig.defaults index f1c1f71e49acaf..d7bcfbd2fb0516 100644 --- a/config/nrfconnect/chip-module/Kconfig.defaults +++ b/config/nrfconnect/chip-module/Kconfig.defaults @@ -452,10 +452,10 @@ config SHELL_STACK_SIZE default 2616 if CHIP_WIFI config SHELL_MINIMAL - default y + default y if !CHIP_MEMORY_PROFILING config KERNEL_SHELL - default n + default n if !CHIP_MEMORY_PROFILING config SENSOR_SHELL default n @@ -482,7 +482,7 @@ config HWINFO_SHELL default n config OPENTHREAD_SHELL - default n + default n if !CHIP_MEMORY_PROFILING endif # SHELL diff --git a/config/nrfconnect/chip-module/Kconfig.features b/config/nrfconnect/chip-module/Kconfig.features index a6c2ea99ad431d..369f992c9a5070 100644 --- a/config/nrfconnect/chip-module/Kconfig.features +++ b/config/nrfconnect/chip-module/Kconfig.features @@ -75,15 +75,20 @@ endif # CHIP_SPI_NOR config CHIP_MEMORY_PROFILING bool "Enable features for tracking memory usage" + # Matter stack select CHIP_STATISTICS + # Heap select CHIP_MALLOC_SYS_HEAP_WATERMARKS_SUPPORT if CHIP_MALLOC_SYS_HEAP + select SYS_HEAP_RUNTIME_STATS if CHIP_MALLOC_SYS_HEAP + # Crypto select MBEDTLS_MEMORY_DEBUG if !CHIP_CRYPTO_PSA - select SYS_HEAP_RUNTIME_STATS if CHIP_MALLOC_SYS_HEAP - select KERNEL_SHELL + # Network select NET_STATISTICS select NET_SHELL select NET_BUF_POOL_USAGE select OPENTHREAD_SHELL if !CHIP_WIFI + # Zephyr + select KERNEL_SHELL help Enables features for tracking memory usage in Matter. diff --git a/config/nrfconnect/chip-module/generate_factory_data.cmake b/config/nrfconnect/chip-module/generate_factory_data.cmake index 3c286fc21dddee..21f7360cd03f10 100644 --- a/config/nrfconnect/chip-module/generate_factory_data.cmake +++ b/config/nrfconnect/chip-module/generate_factory_data.cmake @@ -15,25 +15,29 @@ # -# Create a JSON file based on factory data given via kConfigs. +# Create a .hex file in CBOR format based on factory data given via kConfigs. # # This function creates a list of arguments for external script and then run it to write a JSON file. # Created JSON file can be checked using JSON SCHEMA file if it is provided. +# Next, the resulting .hex file is generated based on previously created JSON file. # # This script can be manipulated using following kConfigs: # - To merge generated factory data with final zephyr.hex file set kConfig CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=y # - To use default certification paths set CONFIG_CHIP_FACTORY_DATA_USE_DEFAULTS_CERTS_PATH=y # -# During generation process a some file will be created in zephyr's build directory: +# During generation process the following files will be created in zephyr's build directory: # - .json a file containing all factory data written in JSON format. +# - .hex a file containing all factory data in CBOR format. +# - .bin a binary file containing all raw factory data in CBOR format. +# - .cbor a file containing all factory data in CBOR format. # # [Args]: # factory_data_target - a name for target to generate factory_data. # script_path - a path to script that makes a JSON factory data file from given arguments. # schema_path - a path to JSON schema file which can be used to verify generated factory data JSON file. # This argument is optional, if you don't want to verify the JSON file put it empty "". -# output_path - a path to output directory, where created JSON file will be stored. -function(nrfconnect_create_factory_data_json factory_data_target script_path schema_path output_path) +# output_path - a path to output directory, where created hex and JSON files will be stored. +function(nrfconnect_create_factory_data factory_data_target script_path schema_path output_path) # set script args for future purpose set(script_args) @@ -120,62 +124,25 @@ if(CONFIG_CHIP_DEVICE_ENABLE_KEY) string(APPEND script_args "--enable_key \"${CONFIG_CHIP_DEVICE_ENABLE_KEY}\"\n") endif() -# Set output JSON file and path to SCHEMA file to validate generated factory data -set(factory_data_json ${output_path}/${factory_data_target}.json) -string(APPEND script_args "-o \"${factory_data_json}\"\n") +# Set output path and path to SCHEMA file to validate generated factory data +set(factory_data_output_path ${output_path}/${factory_data_target}) +string(APPEND script_args "-o \"${factory_data_output_path}\"\n") string(APPEND script_args "-s \"${schema_path}\"\n") +# Add optional offset and size arguments to generate both .hex and .json files. +string(APPEND script_args "--offset $\n") +string(APPEND script_args "--size $\n") + # execute first script to create a JSON file separate_arguments(separated_script_args NATIVE_COMMAND ${script_args}) add_custom_command( - OUTPUT ${factory_data_json} + OUTPUT ${factory_data_output_path}.hex DEPENDS ${FACTORY_DATA_SCRIPT_PATH} COMMAND ${Python3_EXECUTABLE} ${FACTORY_DATA_SCRIPT_PATH} ${separated_script_args} COMMENT "Generating new Factory Data..." ) add_custom_target(${factory_data_target} ALL - DEPENDS ${factory_data_json} - ) - -endfunction() - - -# Create a .hex file with factory data in CBOR format. -# -# This function creates a .hex and .cbor files from given JSON factory data file. -# -# -# During generation process some files will be created in zephyr's build directory: -# - .hex a file containing all factory data in CBOR format. -# - .bin a binary file containing all raw factory data in CBOR format. -# - .cbor a file containing all factory data in CBOR format. -# -# [Args]: -# factory_data_hex_target - a name for target to generate factory data HEX file. -# factory_data_target - a name for target to generate factory data JSON file. -# script_path - a path to script that makes a factory data .hex file from given arguments. -# output_path - a path to output directory, where created JSON file will be stored. -function(nrfconnect_create_factory_data_hex_file factory_data_hex_target factory_data_target script_path output_path) - -# Pass the argument list via file -set(cbor_script_args "-i ${output_path}/${factory_data_target}.json\n") -string(APPEND cbor_script_args "-o ${output_path}/${factory_data_target}\n") -# get partition address and offset from partition manager during compilation -string(APPEND cbor_script_args "--offset $\n") -string(APPEND cbor_script_args "--size $\n") -string(APPEND cbor_script_args "-r\n") - -# execute second script to create a hex file containing factory data in cbor format -separate_arguments(separated_cbor_script_args NATIVE_COMMAND ${cbor_script_args}) -set(factory_data_hex ${output_path}/${factory_data_target}.hex) - -add_custom_command(OUTPUT ${factory_data_hex} - COMMAND ${Python3_EXECUTABLE} ${script_path} ${separated_cbor_script_args} - COMMENT "Generating factory data HEX file..." - DEPENDS ${factory_data_target} ${script_path} - ) -add_custom_target(${factory_data_hex_target} - DEPENDS ${factory_data_hex} + DEPENDS ${factory_data_output_path}.hex ) endfunction() @@ -202,22 +169,16 @@ set(GENERATE_CBOR_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/nrfconnect/nrfconnect_g set(FACTORY_DATA_SCHEMA_PATH ${CHIP_ROOT}/scripts/tools/nrfconnect/nrfconnect_factory_data.schema) set(OUTPUT_FILE_PATH ${APPLICATION_BINARY_DIR}/zephyr) -# create a JSON file with all factory data -nrfconnect_create_factory_data_json(factory_data - ${FACTORY_DATA_SCRIPT_PATH} - ${FACTORY_DATA_SCHEMA_PATH} - ${OUTPUT_FILE_PATH}) - # create a .hex file with factory data in CBOR format based on the JSON file created previously -nrfconnect_create_factory_data_hex_file(factory_data_hex - factory_data - ${GENERATE_CBOR_SCRIPT_PATH} - ${OUTPUT_FILE_PATH}) +nrfconnect_create_factory_data(factory_data + ${FACTORY_DATA_SCRIPT_PATH} + ${FACTORY_DATA_SCHEMA_PATH} + ${OUTPUT_FILE_PATH}) if(CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE) # set custom target for merging factory_data hex file set_property(GLOBAL PROPERTY factory_data_PM_HEX_FILE ${OUTPUT_FILE_PATH}/factory_data.hex) - set_property(GLOBAL PROPERTY factory_data_PM_TARGET factory_data_hex) + set_property(GLOBAL PROPERTY factory_data_PM_TARGET factory_data) endif() diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig index ad36a663b5fd1f..bdfa709592adff 100644 --- a/config/zephyr/Kconfig +++ b/config/zephyr/Kconfig @@ -533,4 +533,22 @@ config CHIP_OTA_IMAGE_EXTRA_ARGS endif +config CHIP_BLE_EXT_ADVERTISING + bool "Bluetooth LE extended advertising" + help + Enable Bluetooth LE extended advertising, which allows the device to advertise + Matter service over Bluetooth LE for a period of time longer than 15 minutes. + If this config is true, + CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS define can be set up to 172800 seconds (48h). + +config CHIP_BLE_ADVERTISING_DURATION + int "Bluetooth LE advertising duration in minutes" + range 15 2880 if CHIP_BLE_EXT_ADVERTISING + range 0 15 + default 15 + help + Specify how long the device will advertise Matter service over Bluetooth LE in minutes. + If CHIP_BLE_EXT_ADVERTISING is set to false, the maximum duration time is 15 minutes, + else the maximum duration time can be extended to 2880 minutes (48h). + endif diff --git a/config/zephyr/chip-module/Kconfig.defaults b/config/zephyr/chip-module/Kconfig.defaults index 4cf4edea17a939..d21562cd4d3e16 100644 --- a/config/zephyr/chip-module/Kconfig.defaults +++ b/config/zephyr/chip-module/Kconfig.defaults @@ -40,9 +40,11 @@ config LOG_DEFAULT_LEVEL endif +# disable synchronous printk to avoid blocking IRQs which +# may affect time sensitive components config PRINTK_SYNC bool - default y + default n config ASSERT bool diff --git a/docs/guides/nrfconnect_factory_data_configuration.md b/docs/guides/nrfconnect_factory_data_configuration.md index e4c3be4899df4e..212963d5266b66 100644 --- a/docs/guides/nrfconnect_factory_data_configuration.md +++ b/docs/guides/nrfconnect_factory_data_configuration.md @@ -37,7 +37,7 @@ data secure by applying hardware write protection. - [Appearance field description](#appearance-field-description) - [Enabling factory data support](#enabling-factory-data-support) - [Generating factory data](#generating-factory-data) - - [Creating the factory data JSON file with the first script](#creating-the-factory-data-json-file-with-the-first-script) + - [Creating the factory data JSON and HEX files with the first script](#creating-the-factory-data-json-and-hex-files-with-the-first-script) - [How to set user data](#how-to-set-user-data) - [How to handle user data](#how-to-handle-user-data) - [Verifying using the JSON Schema tool](#verifying-using-the-json-schema-tool) @@ -218,14 +218,19 @@ file written in another way. To make sure that the JSON file is correct and the device is able to read out parameters, [verify the file using the JSON schema tool](#verifying-using-the-json-schema-tool). -### Creating the factory data JSON file with the first script +You can also use only the first script to generate both JSON and HEX files, by +providing optional `offset` and `size` arguments, which results in invoking the +script internally. Such option is the recommended one, but invoking two scripts +one by one is also supported to provide backward compatibility. + +### Creating the factory data JSON and HEX files with the first script A Matter device needs a proper factory data partition stored in the flash memory to read out all required parameters during startup. To simplify the factory data generation, you can use the [generate_nrfconnect_chip_factory_data.py](../../scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py) Python script to provide all required parameters and generate a human-readable -JSON file. +JSON file and save it to a HEX file. To use this script, complete the following steps: @@ -245,10 +250,10 @@ To use this script, complete the following steps: --sn --vendor_id, --product_id, --vendor_name, --product_name, --date, --hw_ver, --hw_ver_str, --spake2_it, --spake2_salt, --discriminator ``` - b. Add output file path: + b. Add output path to store .json file, e.g. my_dir/output: ``` - -o + -o ``` c. Generate SPAKE2 verifier using one of the following methods: @@ -341,6 +346,34 @@ To use this script, complete the following steps: > `chip-cert` executable. See the note at the end of this section to learn > how to get it. + k. (optional) Partition offset that is an address in device's NVM memory, + where factory data will be stored. + + ``` + --offset + ``` + + > **Note:** To generate a HEX file with factory data, you need to provide + > both `offset` and `size` optional arguments. As a result, + > `factory_data.hex` and `factory_data.bin` files are created in the + > `output` directory. The first file contains the required memory offset. + > For this reason, it can be programmed directly to the device using a + > programmer (for example, `nrfjprog`). + + l. (optional) The maximum partition size in device's NVM memory, where + factory data will be stored. + + ``` + --size + ``` + + > **Note:** To generate a HEX file with factory data, you need to provide + > both `offset` and `size` optional arguments. As a result, + > `factory_data.hex` and `factory_data.bin` files are created in the + > `output` directory. The first file contains the required memory offset. + > For this reason, it can be programmed directly to the device using a + > programmer (for example, `nrfjprog`). + 4. Run the script using the prepared list of arguments: ``` @@ -370,8 +403,10 @@ $ python scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py \ --passcode 20202021 \ --product_finish "matte" \ --product_color "black" \ ---out "build.json" \ ---schema "scripts/tools/nrfconnect/nrfconnect_factory_data.schema" +--out "build" \ +--schema "scripts/tools/nrfconnect/nrfconnect_factory_data.schema" \ +--offset 0xf7000 \ +--size 0x1000 ``` As the result of the above example, a unique ID for the rotating device ID is @@ -570,7 +605,7 @@ To generate a manual pairing code and a QR code, complete the following steps: ``` 2. Complete steps 1, 2, and 3 from the - [Creating the factory data JSON file with the first script](#creating-the-factory-data-json-file-with-the-first-script) + [Creating the factory data JSON and HEX files with the first script](#creating-the-factory-data-json-and-hex-files-with-the-first-script) section to prepare the final invocation of the Python script. 3. Add the `--generate_onboarding` argument to the Python script final @@ -686,10 +721,15 @@ The output will look similar to the following one: ### Creating a factory data partition with the second script To store the factory data set in the device's persistent storage, convert the -data from the JSON file to its binary representation in the CBOR format. To do -this, use the +data from the JSON file to its binary representation in the CBOR format. This is +done by the +[generate_nrfconnect_chip_factory_data.py](../../scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py), +if you provide optional `offset` and `size` arguments. If you provided these +arguments, skip the following steps of this section. + +You can skip these optional arguments and do this, using the [nrfconnect_generate_partition.py](../../scripts/tools/nrfconnect/nrfconnect_generate_partition.py) -to generate the factory data partition: +script, but this is obsolete solution kept only for backward compatibility: 1. Navigate to the _connectedhomeip_ root directory 2. Run the following command pattern: @@ -924,14 +964,13 @@ $ west flash ## Using own factory data implementation The [factory data generation process](#generating-factory-data) described above -is only an example valid for the nRF Connect platform. You can also create a HEX -file containing all components from the -[factory data component table](#factory-data-component-table) in any format and -then implement a parser to read out all parameters and pass them to a provider. -Each manufacturer can implement a factory data set on its own by implementing a -parser and a factory data accessor inside the Matter stack. Use the -[nRF Connect Provider](../../src/platform/nrfconnect/FactoryDataProvider.h) and -[FactoryDataParser](../../src/platform/nrfconnect/FactoryDataParser.h) as +is only an example valid for the nRF Connect platform. You can well create a HEX +file containing all [factory data components](#factory-data-component-table) in +any format and then implement a parser to read out all parameters and pass them +to a provider. Each manufacturer can implement a factory data set on its own by +implementing a parser and a factory data accessor inside the Matter stack. Use +the [nRF Connect Provider](../../src/platform/nrfconnect/FactoryDataProvider.h) +and [FactoryDataParser](../../src/platform/nrfconnect/FactoryDataParser.h) as examples. You can read the factory data set from the device's flash memory in different diff --git a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py index 724484058029d1..78212cefd81e6e 100644 --- a/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py +++ b/scripts/tools/nrfconnect/generate_nrfconnect_chip_factory_data.py @@ -28,6 +28,7 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import load_der_private_key +from nrfconnect_generate_partition import PartitionCreator try: import qrcode @@ -228,6 +229,10 @@ def __init__(self, arguments) -> None: self._factory_data = list() self._user_data = dict() + # If .json extension is included in the output path, remove it, as script adds it automatically. + if self._args.output.endswith(".json"): + self._args.output = self._args.output[:-len(".json")] + try: self._validate_args() except AssertionError as e: @@ -244,8 +249,6 @@ def _validate_args(self): "Cannot find Spake2+ verifier, to generate a new one please provide passcode (--passcode)" assert ((self._args.gen_certs and self._args.chip_cert_path) or (self._args.dac_cert and self._args.pai_cert and self._args.dac_key)), \ "Cannot find paths to DAC or PAI certificates .der files. To generate a new ones please provide a path to chip-cert executable (--chip_cert_path) and add --gen_certs argument" - assert self._args.output.endswith(".json"), \ - "Output path doesn't contain .json file path. ({})".format(self._args.output) assert self._args.passcode not in INVALID_PASSCODES, \ "Provided invalid passcode!" @@ -310,9 +313,9 @@ def generate_json(self): sys.exit(-1) try: - json_file = open(self._args.output, "w+") + json_file = open(self._args.output+".json", "w+") except FileNotFoundError: - print("Cannot create JSON file in this location: {}".format(self._args.output)) + print("Cannot create JSON file in this location: {}".format(self._args.output+".json")) sys.exit(-1) with json_file: # serialize data @@ -422,11 +425,11 @@ def _generate_onboarding_data(self): flow=CommissioningFlow.Standard, vid=self._args.vendor_id, pid=self._args.product_id) - with open(self._args.output[:-len(".json")] + ".txt", "w") as manual_code_file: + with open(self._args.output + ".txt", "w") as manual_code_file: manual_code_file.write("Manualcode : " + setup_payload.generate_manualcode() + "\n") manual_code_file.write("QRCode : " + setup_payload.generate_qrcode()) qr = qrcode.make(setup_payload.generate_qrcode()) - qr.save(self._args.output[:-len(".json")] + ".png") + qr.save(self._args.output + ".png") def main(): @@ -441,7 +444,10 @@ def base64_str(s): return base64.b64decode(s) parser.add_argument("-s", "--schema", type=str, help="JSON schema file to validate JSON output data") parser.add_argument("-o", "--output", type=str, required=True, - help="Output path to store .json file, e.g. my_dir/output.json") + help="Output path to store .json file, e.g. my_dir/output." + "The .json extension will be automatically added by the script and does not need to be provided." + "If provided, an extension will not be added." + "If optional --size and --offset arguments are provided, the script also generates .hex file with factory data.") parser.add_argument("-v", "--verbose", action="store_true", help="Run this script with DEBUG logging level") parser.add_argument("--include_passcode", action="store_true", @@ -543,6 +549,10 @@ def base64_str(s): return base64.b64decode(s) help="[string] Provide one of the product finishes") optional_arguments.add_argument("--product_color", type=str, choices=PRODUCT_COLOR_ENUM.keys(), help="[string] Provide one of the product colors.") + optional_arguments.add_argument("--offset", type=allow_any_int, + help="Partition offset - an address in device's NVM memory, where factory data will be stored.") + optional_arguments.add_argument("--size", type=allow_any_int, + help="The maximum partition size.") args = parser.parse_args() if args.verbose: @@ -551,9 +561,9 @@ def base64_str(s): return base64.b64decode(s) log.basicConfig(format='[%(levelname)s] %(message)s', level=log.INFO) # check if json file already exist - if (exists(args.output) and not args.overwrite): + if (exists(args.output + ".json") and not args.overwrite): log.error(("Output file: {} already exist, to create a new one add argument '--overwrite'. " - "By default overwriting is disabled").format(args.output)) + "By default overwriting is disabled").format(args.output+".json")) return if args.schema and no_jsonschema_module: @@ -572,6 +582,13 @@ def base64_str(s): return base64.b64decode(s) generator = FactoryDataGenerator(args) generator.generate_json() + # If optional partition's offset and size were provided, generate factory data output .hex file. + if args.offset and args.size: + partition_creator = PartitionCreator(args.offset, args.size, args.output + ".json", args.output) + cbor_data = partition_creator.generate_cbor() + partition_creator.create_hex(cbor_data) + partition_creator.create_bin() + if __name__ == "__main__": main() diff --git a/src/app/clusters/thread-network-diagnostics-server/thread-network-diagnostics-server.cpp b/src/app/clusters/thread-network-diagnostics-server/thread-network-diagnostics-server.cpp index cae2948e8e970e..89bae019a87f93 100644 --- a/src/app/clusters/thread-network-diagnostics-server/thread-network-diagnostics-server.cpp +++ b/src/app/clusters/thread-network-diagnostics-server/thread-network-diagnostics-server.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,9 @@ #include #include #include +#include +#include +#include using namespace chip; using namespace chip::app; @@ -133,6 +137,60 @@ CHIP_ERROR ThreadDiagosticsAttrAccess::Read(const ConcreteReadAttributePath & aP return CHIP_NO_ERROR; } +class ThreadDiagnosticsDelegate : public DeviceLayer::ThreadDiagnosticsDelegate +{ + // Notified when the Node’s connection status to a Thread network has changed. + void OnConnectionStatusChanged(ConnectionStatusEnum newConnectionStatus) override + { + ChipLogProgress(Zcl, "ThreadDiagnosticsDelegate: OnConnectionStatusChanged"); + + Events::ConnectionStatus::Type event{ newConnectionStatus }; + + // ThreadNetworkDiagnostics cluster should exist only for endpoint 0. + if (emberAfContainsServer(kRootEndpointId, ThreadNetworkDiagnostics::Id)) + { + // If Thread Network Diagnostics cluster is implemented on this endpoint + EventNumber eventNumber; + + if (CHIP_NO_ERROR != LogEvent(event, kRootEndpointId, eventNumber)) + { + ChipLogError(Zcl, "ThreadDiagnosticsDelegate: Failed to record ConnectionStatus event"); + } + } + } + + // Notified when the Node’s faults related to a Thread network have changed. + void OnNetworkFaultChanged(const GeneralFaults & previous, + const GeneralFaults & current) override + { + ChipLogProgress(Zcl, "ThreadDiagnosticsDelegate: OnNetworkFaultChanged"); + + /* Verify that the data size matches the expected one. */ + static_assert(sizeof(*current.data()) == sizeof(NetworkFaultEnum)); + + DataModel::List currentList(reinterpret_cast(current.data()), + current.size()); + DataModel::List previousList(reinterpret_cast(previous.data()), + previous.size()); + + Events::NetworkFaultChange::Type event{ currentList, previousList }; + + // ThreadNetworkDiagnostics cluster should exist only for endpoint 0. + if (emberAfContainsServer(kRootEndpointId, ThreadNetworkDiagnostics::Id)) + { + // If Thread Network Diagnostics cluster is implemented on this endpoint + EventNumber eventNumber; + + if (CHIP_NO_ERROR != LogEvent(event, kRootEndpointId, eventNumber)) + { + ChipLogError(Zcl, "ThreadDiagnosticsDelegate: Failed to record NetworkFaultChange event"); + } + } + } +}; + +ThreadDiagnosticsDelegate gDiagnosticDelegate; + } // anonymous namespace bool emberAfThreadNetworkDiagnosticsClusterResetCountsCallback(app::CommandHandler * commandObj, @@ -147,4 +205,5 @@ bool emberAfThreadNetworkDiagnosticsClusterResetCountsCallback(app::CommandHandl void MatterThreadNetworkDiagnosticsPluginServerInitCallback() { registerAttributeAccessOverride(&gAttrAccess); + GetDiagnosticDataProvider().SetThreadDiagnosticsDelegate(&gDiagnosticDelegate); } diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index c523564382904c..6faeb9ad735b6f 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -227,7 +227,7 @@ void CommissioningWindowManager::OnSessionEstablished(const SessionHandle & sess } } -CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow(Seconds16 commissioningTimeout) +CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow(Seconds32 commissioningTimeout) { VerifyOrReturnError(commissioningTimeout <= MaxCommissioningTimeout() && commissioningTimeout >= MinCommissioningTimeout(), CHIP_ERROR_INVALID_ARGUMENT); @@ -287,7 +287,7 @@ CHIP_ERROR CommissioningWindowManager::AdvertiseAndListenForPASE() return CHIP_NO_ERROR; } -CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds16 commissioningTimeout, +CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds32 commissioningTimeout, CommissioningWindowAdvertisement advertisementMode) { RestoreDiscriminator(); @@ -315,7 +315,7 @@ CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds16 co CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindowForAdministratorCommissioningCluster( - System::Clock::Seconds16 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId) + System::Clock::Seconds32 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId) { ReturnErrorOnFailure(OpenBasicCommissioningWindow(commissioningTimeout, CommissioningWindowAdvertisement::kDnssdOnly)); @@ -325,7 +325,7 @@ CommissioningWindowManager::OpenBasicCommissioningWindowForAdministratorCommissi return CHIP_NO_ERROR; } -CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds16 commissioningTimeout, uint16_t discriminator, +CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds32 commissioningTimeout, uint16_t discriminator, Spake2pVerifier & verifier, uint32_t iterations, ByteSpan salt, FabricIndex fabricIndex, VendorId vendorId) { diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h index 26a2f9ceb19b71..3f0f7d036a65db 100644 --- a/src/app/server/CommissioningWindowManager.h +++ b/src/app/server/CommissioningWindowManager.h @@ -57,21 +57,21 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, return CHIP_NO_ERROR; } - static constexpr System::Clock::Seconds16 MaxCommissioningTimeout() + static constexpr System::Clock::Seconds32 MaxCommissioningTimeout() { #if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING // Specification section 2.3.1 - Extended Announcement Duration up to 48h - return System::Clock::Seconds16(60 * 60 * 48); + return System::Clock::Seconds32(60 * 60 * 48); #else // Specification section 5.4.2.3. Announcement Duration says 15 minutes. - return System::Clock::Seconds16(15 * 60); + return System::Clock::Seconds32(15 * 60); #endif } - System::Clock::Seconds16 MinCommissioningTimeout() const + System::Clock::Seconds32 MinCommissioningTimeout() const { // Specification section 5.4.2.3. Announcement Duration says 3 minutes. - return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds16(3 * 60)); + return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds32(3 * 60)); } void SetAppDelegate(AppDelegate * delegate) { mAppDelegate = delegate; } @@ -81,7 +81,7 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, */ CHIP_ERROR OpenBasicCommissioningWindow( - System::Clock::Seconds16 commissioningTimeout = System::Clock::Seconds16(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS), + System::Clock::Seconds32 commissioningTimeout = System::Clock::Seconds32(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS), CommissioningWindowAdvertisement advertisementMode = chip::CommissioningWindowAdvertisement::kAllSupported); /** @@ -89,10 +89,10 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, * the Administrator Commmissioning cluster implementation. */ CHIP_ERROR - OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds16 commissioningTimeout, + OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds32 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId); - CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds16 commissioningTimeout, uint16_t discriminator, + CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds32 commissioningTimeout, uint16_t discriminator, Spake2pVerifier & verifier, uint32_t iterations, chip::ByteSpan salt, FabricIndex fabricIndex, VendorId vendorId); @@ -127,7 +127,7 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, // For tests only, allow overriding the spec-defined minimum value of the // commissioning window timeout. - void OverrideMinCommissioningTimeout(System::Clock::Seconds16 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); } + void OverrideMinCommissioningTimeout(System::Clock::Seconds32 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); } private: //////////// SessionDelegate Implementation /////////////// @@ -145,7 +145,7 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, // Start a timer that will call HandleCommissioningWindowTimeout, and then // start advertising and listen for PASE. - CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds16 commissioningTimeout); + CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds32 commissioningTimeout); // Start advertising and listening for PASE connections. Should only be // called when a commissioning window timeout timer is running. @@ -218,7 +218,7 @@ class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler, // For tests only, so that we can test the commissioning window timeout // without having to wait 3 minutes. - Optional mMinCommissioningTimeoutOverride; + Optional mMinCommissioningTimeoutOverride; // The PASE session we are using, so we can handle CloseSession properly. SessionHolderWithDelegate mPASESession; diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp index a12ec42ec3c49a..545ec596421e9f 100644 --- a/src/app/tests/TestCommissionManager.cpp +++ b/src/app/tests/TestCommissionManager.cpp @@ -234,7 +234,7 @@ void CheckCommissioningWindowManagerWindowTimeoutTask(intptr_t context) NL_TEST_ASSERT(suite, !sAdminVendorIdDirty); CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager(); - constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(1); + constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds32(1); constexpr uint16_t kTimeoutMs = 1000; constexpr unsigned kSleepPadding = 100; commissionMgr.OverrideMinCommissioningTimeout(kTimeoutSeconds); diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h index ed881f78cc2c3c..a8643402226d7c 100644 --- a/src/include/platform/ConnectivityManager.h +++ b/src/include/platform/ConnectivityManager.h @@ -147,8 +147,9 @@ class ConnectivityManager enum BLEAdvertisingMode { - kFastAdvertising = 0, - kSlowAdvertising = 1, + kFastAdvertising = 0, + kSlowAdvertising = 1, + kExtendedAdvertising = 2, }; enum class SEDIntervalMode diff --git a/src/include/platform/DiagnosticDataProvider.h b/src/include/platform/DiagnosticDataProvider.h index a99ca6ee61beb1..2430673bc55724 100644 --- a/src/include/platform/DiagnosticDataProvider.h +++ b/src/include/platform/DiagnosticDataProvider.h @@ -91,6 +91,29 @@ class WiFiDiagnosticsDelegate virtual void OnConnectionStatusChanged(uint8_t connectionStatus) {} }; +/** + * Defines the Thread Diagnostics Delegate class to notify Thread network events. + */ +class ThreadDiagnosticsDelegate +{ +public: + virtual ~ThreadDiagnosticsDelegate() {} + + /** + * @brief + * Called when the Node’s connection status to a Thread network has changed. + */ + virtual void OnConnectionStatusChanged(app::Clusters::ThreadNetworkDiagnostics::ConnectionStatusEnum newConnectionStatus) {} + + /** + * @brief + * Called when the Node detects change in the set of current Thread network faults. + */ + virtual void OnNetworkFaultChanged(const GeneralFaults & previous, + const GeneralFaults & current) + {} +}; + /** * Provides access to runtime and build-time configuration information for a chip device. */ @@ -99,6 +122,8 @@ class DiagnosticDataProvider public: void SetWiFiDiagnosticsDelegate(WiFiDiagnosticsDelegate * delegate) { mWiFiDiagnosticsDelegate = delegate; } WiFiDiagnosticsDelegate * GetWiFiDiagnosticsDelegate() const { return mWiFiDiagnosticsDelegate; } + void SetThreadDiagnosticsDelegate(ThreadDiagnosticsDelegate * delegate) { mThreadDiagnosticsDelegate = delegate; } + ThreadDiagnosticsDelegate * GetThreadDiagnosticsDelegate() const { return mThreadDiagnosticsDelegate; } /** * General Diagnostics methods. @@ -238,7 +263,8 @@ class DiagnosticDataProvider virtual ~DiagnosticDataProvider() = default; private: - WiFiDiagnosticsDelegate * mWiFiDiagnosticsDelegate = nullptr; + WiFiDiagnosticsDelegate * mWiFiDiagnosticsDelegate = nullptr; + ThreadDiagnosticsDelegate * mThreadDiagnosticsDelegate = nullptr; // No copy, move or assignment. DiagnosticDataProvider(const DiagnosticDataProvider &) = delete; diff --git a/src/inet/UDPEndPointImplSockets.cpp b/src/inet/UDPEndPointImplSockets.cpp index f5e89e69fc10fe..23190c15846e88 100644 --- a/src/inet/UDPEndPointImplSockets.cpp +++ b/src/inet/UDPEndPointImplSockets.cpp @@ -170,8 +170,7 @@ CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port) } // anonymous namespace #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API -UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sJoinMulticastGroupHandler; -UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sLeaveMulticastGroupHandler; +UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sMulticastGroupHandler; #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface) @@ -801,10 +800,9 @@ CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId a CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) { #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API - MulticastGroupHandler handler = join ? sJoinMulticastGroupHandler : sLeaveMulticastGroupHandler; - if (handler != nullptr) + if (sMulticastGroupHandler != nullptr) { - return handler(aInterfaceId, aAddress); + return sMulticastGroupHandler(aInterfaceId, aAddress, MulticastOperation::kJoin); } #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API diff --git a/src/inet/UDPEndPointImplSockets.h b/src/inet/UDPEndPointImplSockets.h index c078722fbb4bdd..b4e16e859b04ed 100644 --- a/src/inet/UDPEndPointImplSockets.h +++ b/src/inet/UDPEndPointImplSockets.h @@ -63,13 +63,18 @@ class UDPEndPointImplSockets : public UDPEndPoint, public EndPointStateSockets #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API public: - using MulticastGroupHandler = CHIP_ERROR (*)(InterfaceId, const IPAddress &); - static void SetJoinMulticastGroupHandler(MulticastGroupHandler handler) { sJoinMulticastGroupHandler = handler; } - static void SetLeaveMulticastGroupHandler(MulticastGroupHandler handler) { sLeaveMulticastGroupHandler = handler; } + enum class MulticastOperation + { + kJoin, + kLeave + }; + + using MulticastGroupHandler = CHIP_ERROR (*)(InterfaceId, const IPAddress &, MulticastOperation operation); + + static void SetMulticastGroupHandler(MulticastGroupHandler handler) { sMulticastGroupHandler = handler; } private: - static MulticastGroupHandler sJoinMulticastGroupHandler; - static MulticastGroupHandler sLeaveMulticastGroupHandler; + static MulticastGroupHandler sMulticastGroupHandler; #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API }; diff --git a/src/lib/dnssd/Advertiser.cpp b/src/lib/dnssd/Advertiser.cpp new file mode 100644 index 00000000000000..1898d115ce10ce --- /dev/null +++ b/src/lib/dnssd/Advertiser.cpp @@ -0,0 +1,41 @@ +/* + * + * 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. + */ + +#include "Advertiser.h" + +namespace chip { +namespace Dnssd { + +ServiceAdvertiser * ServiceAdvertiser::sInstance = nullptr; + +ServiceAdvertiser & ServiceAdvertiser::Instance() +{ + if (sInstance == nullptr) + { + sInstance = &GetDefaultAdvertiser(); + } + + return *sInstance; +} + +void ServiceAdvertiser::SetInstance(ServiceAdvertiser & advertiser) +{ + sInstance = &advertiser; +} + +} // namespace Dnssd +} // namespace chip diff --git a/src/lib/dnssd/Advertiser.h b/src/lib/dnssd/Advertiser.h index ddd8df259b1364..64fa9ec3fd5d33 100644 --- a/src/lib/dnssd/Advertiser.h +++ b/src/lib/dnssd/Advertiser.h @@ -375,9 +375,28 @@ class ServiceAdvertiser */ virtual CHIP_ERROR UpdateCommissionableInstanceName() = 0; - /// Provides the system-wide implementation of the service advertiser + /** + * Returns the system-wide implementation of the service advertiser. + * + * The method returns a reference to the advertiser object configured by + * a user using the \c ServiceAdvertiser::SetInstance() method, or the + * default advertiser returned by the \c GetDefaultAdvertiser() function. + */ static ServiceAdvertiser & Instance(); + + /** + * Sets the system-wide implementation of the service advertiser. + */ + static void SetInstance(ServiceAdvertiser & advertiser); + +private: + static ServiceAdvertiser * sInstance; }; +/** + * Returns the default implementation of the service advertiser. + */ +extern ServiceAdvertiser & GetDefaultAdvertiser(); + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp b/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp index 4c80723738bcaa..f29ff25d63f0e1 100644 --- a/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp @@ -975,10 +975,14 @@ void AdvertiserMinMdns::AdvertiseRecords(BroadcastAdvertiseType type) AdvertiserMinMdns gAdvertiser; } // namespace -ServiceAdvertiser & ServiceAdvertiser::Instance() +#if CHIP_DNSSD_DEFAULT_MINIMAL + +ServiceAdvertiser & GetDefaultAdvertiser() { return gAdvertiser; } +#endif // CHIP_DNSSD_DEFAULT_MINIMAL + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/Advertiser_ImplNone.cpp b/src/lib/dnssd/Advertiser_ImplNone.cpp index 94935247694e53..2c1ed7f09b575b 100644 --- a/src/lib/dnssd/Advertiser_ImplNone.cpp +++ b/src/lib/dnssd/Advertiser_ImplNone.cpp @@ -77,10 +77,14 @@ NoneAdvertiser gAdvertiser; } // namespace -ServiceAdvertiser & ServiceAdvertiser::Instance() +#if CHIP_DNSSD_DEFAULT_NONE + +ServiceAdvertiser & GetDefaultAdvertiser() { return gAdvertiser; } +#endif // CHIP_DNSSD_DEFAULT_NONE + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/BUILD.gn b/src/lib/dnssd/BUILD.gn index 405c499b18d14e..9447821ddcab19 100644 --- a/src/lib/dnssd/BUILD.gn +++ b/src/lib/dnssd/BUILD.gn @@ -68,9 +68,11 @@ static_library("dnssd") { ] sources = [ + "Advertiser.cpp", "Advertiser.h", "IPAddressSorter.cpp", "IPAddressSorter.h", + "Resolver.cpp", "Resolver.h", "ResolverProxy.cpp", "ResolverProxy.h", @@ -78,12 +80,18 @@ static_library("dnssd") { "TxtFields.h", ] + assert( + chip_mdns == "none" || chip_mdns == "minimal" || chip_mdns == "platform", + "Please select a valid value for chip_mdns") + if (chip_mdns == "none") { sources += [ "Advertiser_ImplNone.cpp", "Resolver_ImplNone.cpp", ] - } else if (chip_mdns == "minimal") { + } + + if (chip_mdns_minimal) { sources += [ "ActiveResolveAttempts.cpp", "ActiveResolveAttempts.h", @@ -100,15 +108,25 @@ static_library("dnssd") { "${chip_root}/src/tracing", "${chip_root}/src/tracing:macros", ] - } else if (chip_mdns == "platform") { + } + + if (chip_mdns_platform) { sources += [ "Discovery_ImplPlatform.cpp", "Discovery_ImplPlatform.h", ] public_deps += [ "${chip_root}/src/platform" ] - } else { - assert(false, "Unknown Dnssd advertiser implementation.") } + _chip_dnssd_default_none = chip_mdns == "none" + _chip_dnssd_default_minimal = chip_mdns == "minimal" + _chip_dnssd_default_platform = chip_mdns == "platform" + + defines = [ + "CHIP_DNSSD_DEFAULT_NONE=${_chip_dnssd_default_none}", + "CHIP_DNSSD_DEFAULT_MINIMAL=${_chip_dnssd_default_minimal}", + "CHIP_DNSSD_DEFAULT_PLATFORM=${_chip_dnssd_default_platform}", + ] + cflags = [ "-Wconversion" ] } diff --git a/src/lib/dnssd/Discovery_ImplPlatform.cpp b/src/lib/dnssd/Discovery_ImplPlatform.cpp index 3369f8c00b3b3b..6904480a4d1691 100644 --- a/src/lib/dnssd/Discovery_ImplPlatform.cpp +++ b/src/lib/dnssd/Discovery_ImplPlatform.cpp @@ -769,15 +769,19 @@ DiscoveryImplPlatform & DiscoveryImplPlatform::GetInstance() return sManager.get(); } -ServiceAdvertiser & chip::Dnssd::ServiceAdvertiser::Instance() +#if CHIP_DNSSD_DEFAULT_PLATFORM + +ServiceAdvertiser & GetDefaultAdvertiser() { return DiscoveryImplPlatform::GetInstance(); } -Resolver & chip::Dnssd::Resolver::Instance() +Resolver & GetDefaultResolver() { return DiscoveryImplPlatform::GetInstance(); } +#endif // CHIP_DNSSD_DEFAULT_PLATFORM + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/Resolver.cpp b/src/lib/dnssd/Resolver.cpp new file mode 100644 index 00000000000000..19b94464d9d7b6 --- /dev/null +++ b/src/lib/dnssd/Resolver.cpp @@ -0,0 +1,41 @@ +/* + * + * 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. + */ + +#include "Resolver.h" + +namespace chip { +namespace Dnssd { + +Resolver * Resolver::sInstance = nullptr; + +Resolver & Resolver::Instance() +{ + if (sInstance == nullptr) + { + sInstance = &GetDefaultResolver(); + } + + return *sInstance; +} + +void Resolver::SetInstance(Resolver & resolver) +{ + sInstance = &resolver; +} + +} // namespace Dnssd +} // namespace chip diff --git a/src/lib/dnssd/Resolver.h b/src/lib/dnssd/Resolver.h index d2541205bafd6d..6f9827b82218a6 100644 --- a/src/lib/dnssd/Resolver.h +++ b/src/lib/dnssd/Resolver.h @@ -206,10 +206,27 @@ class Resolver virtual CHIP_ERROR ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId) = 0; /** - * Provides the system-wide implementation of the service resolver + * Returns the system-wide implementation of the service resolver. + * + * The method returns a reference to the resolver object configured by + * a user using the \c Resolver::SetInstance() method, or the default + * resolver returned by the \c GetDefaultResolver() function. */ static Resolver & Instance(); + + /** + * Overrides the default implementation of the service resolver + */ + static void SetInstance(Resolver & resolver); + +private: + static Resolver * sInstance; }; +/** + * Returns the default implementation of the service resolver. + */ +extern Resolver & GetDefaultResolver(); + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp b/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp index 7625286dd31b38..93a637839a91de 100644 --- a/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp +++ b/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp @@ -772,10 +772,14 @@ MinMdnsResolver gResolver; } // namespace -Resolver & chip::Dnssd::Resolver::Instance() +#if CHIP_DNSSD_DEFAULT_MINIMAL + +Resolver & GetDefaultResolver() { return gResolver; } +#endif // CHIP_DNSSD_DEFAULT_MINIMAL + } // namespace Dnssd } // namespace chip diff --git a/src/lib/dnssd/Resolver_ImplNone.cpp b/src/lib/dnssd/Resolver_ImplNone.cpp index 9a1f40f3008dff..36e2bd9aead89f 100644 --- a/src/lib/dnssd/Resolver_ImplNone.cpp +++ b/src/lib/dnssd/Resolver_ImplNone.cpp @@ -59,10 +59,14 @@ NoneResolver gResolver; } // namespace -Resolver & chip::Dnssd::Resolver::Instance() +#if CHIP_DNSSD_DEFAULT_NONE + +Resolver & GetDefaultResolver() { return gResolver; } +#endif // CHIP_DNSSD_DEFAULT_NONE + } // namespace Dnssd } // namespace chip diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index aa3d2e1951ce7e..0276ce193bc1a0 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -40,6 +40,7 @@ #include #include #include +#include #include namespace chip { @@ -231,6 +232,7 @@ class GenericThreadStackManagerImpl_OpenThread DnsBrowseCallback mDnsBrowseCallback; DnsResolveCallback mDnsResolveCallback; + GeneralFaults mNetworkFaults; struct DnsServiceTxtEntries { diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index 707e1f710743ec..68c550723de141 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,22 @@ void GenericThreadStackManagerImpl_OpenThread::_OnPlatformEvent(const { ChipLogError(DeviceLayer, "Failed to post Thread connectivity change: %" CHIP_ERROR_FORMAT, status.Format()); } + + ThreadDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetThreadDiagnosticsDelegate(); + + if (mIsAttached) + { + delegate->OnConnectionStatusChanged(app::Clusters::ThreadNetworkDiagnostics::ConnectionStatusEnum::kConnected); + } + else + { + delegate->OnConnectionStatusChanged(app::Clusters::ThreadNetworkDiagnostics::ConnectionStatusEnum::kNotConnected); + + GeneralFaults current; + current.add(to_underlying(chip::app::Clusters::ThreadNetworkDiagnostics::NetworkFaultEnum::kLinkDown)); + delegate->OnNetworkFaultChanged(mNetworkFaults, current); + mNetworkFaults = current; + } } #if CHIP_DETAIL_LOGGING diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp index 54cf69dc5e50fc..d4e83332452a06 100644 --- a/src/platform/Zephyr/BLEManagerImpl.cpp +++ b/src/platform/Zephyr/BLEManagerImpl.cpp @@ -252,18 +252,39 @@ inline CHIP_ERROR BLEManagerImpl::PrepareAdvertisingRequest() Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val); ReturnErrorOnFailure(ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo)); +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + if (mFlags.Has(Flags::kExtendedAdvertisingEnabled)) + { + serviceData.deviceIdInfo.SetVendorId(DEVICE_HANDLE_NULL); + serviceData.deviceIdInfo.SetProductId(DEVICE_HANDLE_NULL); + serviceData.deviceIdInfo.SetExtendedAnnouncementFlag(true); + } +#endif + advertisingData[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags)); advertisingData[1] = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData)); scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize); - mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; - mAdvertisingRequest.options = kAdvertisingOptions; - mAdvertisingRequest.minInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) - ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; - mAdvertisingRequest.maxInterval = mFlags.Has(Flags::kFastAdvertisingEnabled) - ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX - : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY; + mAdvertisingRequest.options = kAdvertisingOptions; + + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; + } +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + else if (mFlags.Has(Flags::kExtendedAdvertisingEnabled)) + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX; + } +#endif + else + { + mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } mAdvertisingRequest.advertisingData = Span(advertisingData); mAdvertisingRequest.scanResponseData = nameSize ? Span(scanResponseData) : Span{}; @@ -322,10 +343,17 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising() if (mFlags.Has(Flags::kFastAdvertisingEnabled)) { - // Start timer to change advertising interval. + // Start timer to change advertising interval from fast to slow. DeviceLayer::SystemLayer().StartTimer( System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME), - HandleBLEAdvertisementIntervalChange, this); + HandleSlowBLEAdvertisementInterval, this); + +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + // Start timer to schedule start of the extended advertising + DeviceLayer::SystemLayer().StartTimer( + System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS), + HandleExtendedBLEAdvertisementInterval, this); +#endif } } @@ -342,6 +370,10 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising() mFlags.Clear(Flags::kAdvertising); mFlags.Set(Flags::kFastAdvertisingEnabled, true); +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + mFlags.Clear(Flags::kExtendedAdvertisingEnabled); +#endif + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); // Post a CHIPoBLEAdvertisingChange(Stopped) event. @@ -353,7 +385,8 @@ CHIP_ERROR BLEManagerImpl::StopAdvertising() } // Cancel timer event changing CHIPoBLE advertisement interval - DeviceLayer::SystemLayer().CancelTimer(HandleBLEAdvertisementIntervalChange, this); + DeviceLayer::SystemLayer().CancelTimer(HandleSlowBLEAdvertisementInterval, this); + DeviceLayer::SystemLayer().CancelTimer(HandleExtendedBLEAdvertisementInterval, this); } return CHIP_NO_ERROR; @@ -366,6 +399,9 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) ChipLogDetail(DeviceLayer, "CHIPoBLE advertising set to %s", val ? "on" : "off"); mFlags.Set(Flags::kAdvertisingEnabled, val); + // Ensure that each enabling/disabling of the standard advertising clears + // the extended mode flag. + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); PlatformMgr().ScheduleWork(DriveBLEState, 0); } @@ -378,8 +414,14 @@ CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode) { case BLEAdvertisingMode::kFastAdvertising: mFlags.Set(Flags::kFastAdvertisingEnabled, true); + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); break; case BLEAdvertisingMode::kSlowAdvertising: + mFlags.Set(Flags::kFastAdvertisingEnabled, false); + mFlags.Set(Flags::kExtendedAdvertisingEnabled, false); + break; + case BLEAdvertisingMode::kExtendedAdvertising: + mFlags.Set(Flags::kExtendedAdvertisingEnabled, true); mFlags.Set(Flags::kFastAdvertisingEnabled, false); break; default: @@ -570,12 +612,18 @@ CHIP_ERROR BLEManagerImpl::PrepareC3CharData() } #endif -void BLEManagerImpl::HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param) +void BLEManagerImpl::HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param) { BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to slow"); } +void BLEManagerImpl::HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param) +{ + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kExtendedAdvertising); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to extended"); +} + void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/platform/Zephyr/BLEManagerImpl.h b/src/platform/Zephyr/BLEManagerImpl.h index 7db469f4a5df93..4fb3352a01ee2b 100644 --- a/src/platform/Zephyr/BLEManagerImpl.h +++ b/src/platform/Zephyr/BLEManagerImpl.h @@ -91,6 +91,7 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla kAdvertisingRefreshNeeded = 0x0010, /**< The advertising state/configuration has changed, but the SoftDevice has yet to be updated. */ kChipoBleGattServiceRegister = 0x0020, /**< The system has currently CHIPoBLE GATT service registered. */ + kExtendedAdvertisingEnabled = 0x0040, /**< The application has enabled extended advertising. */ }; struct ServiceData; @@ -129,7 +130,8 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla static void HandleTXIndicated(bt_conn * conn, bt_gatt_indicate_params * attr, uint8_t err); static void HandleConnect(bt_conn * conn, uint8_t err); static void HandleDisconnect(bt_conn * conn, uint8_t reason); - static void HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param); + static void HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param); + static void HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param); // ===== Members for internal use by the following friends. diff --git a/src/platform/Zephyr/CHIPDevicePlatformConfig.h b/src/platform/Zephyr/CHIPDevicePlatformConfig.h index 3296f3aa8f1c55..e7622f60ddf9fc 100644 --- a/src/platform/Zephyr/CHIPDevicePlatformConfig.h +++ b/src/platform/Zephyr/CHIPDevicePlatformConfig.h @@ -130,3 +130,9 @@ #ifdef CONFIG_CHIP_EXTENDED_DISCOVERY #define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 #endif // CONFIG_CHIP_EXTENDED_DISCOVERY + +#ifdef CONFIG_CHIP_BLE_EXT_ADVERTISING +#define CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING 1 +#endif // CONFIG_CHIP_BLE_EXT_ADVERTISING + +#define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS (CONFIG_CHIP_BLE_ADVERTISING_DURATION * 60) diff --git a/src/platform/Zephyr/CHIPDevicePlatformEvent.h b/src/platform/Zephyr/CHIPDevicePlatformEvent.h index ff329ec7590ea0..8291c5d3a3a355 100644 --- a/src/platform/Zephyr/CHIPDevicePlatformEvent.h +++ b/src/platform/Zephyr/CHIPDevicePlatformEvent.h @@ -23,7 +23,7 @@ #pragma once -#include +#include #include diff --git a/src/platform/Zephyr/ConfigurationManagerImpl.cpp b/src/platform/Zephyr/ConfigurationManagerImpl.cpp index 1c357a92a952f3..f41eed0492080f 100644 --- a/src/platform/Zephyr/ConfigurationManagerImpl.cpp +++ b/src/platform/Zephyr/ConfigurationManagerImpl.cpp @@ -209,8 +209,8 @@ void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) CHIP_ERROR ConfigurationManagerImpl::GetPrimaryWiFiMACAddress(uint8_t * buf) { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI - const net_if * const iface = InetUtils::GetInterface(); - VerifyOrReturnError(iface != nullptr && iface->if_dev != nullptr, CHIP_ERROR_INTERNAL); + const net_if * const iface = InetUtils::GetWiFiInterface(); + VerifyOrReturnError(iface != nullptr, CHIP_ERROR_INTERNAL); const auto linkAddrStruct = iface->if_dev->link_addr; memcpy(buf, linkAddrStruct.addr, linkAddrStruct.len); diff --git a/src/platform/Zephyr/InetUtils.cpp b/src/platform/Zephyr/InetUtils.cpp index 1169cf6362ad88..07d2a302dacbf3 100644 --- a/src/platform/Zephyr/InetUtils.cpp +++ b/src/platform/Zephyr/InetUtils.cpp @@ -17,11 +17,13 @@ #include "InetUtils.h" +#include + namespace chip { namespace DeviceLayer { namespace InetUtils { -in6_addr ToZephyrAddr(const chip::Inet::IPAddress & address) +in6_addr ToZephyrAddr(const Inet::IPAddress & address) { in6_addr zephyrAddr; @@ -31,11 +33,16 @@ in6_addr ToZephyrAddr(const chip::Inet::IPAddress & address) return zephyrAddr; } -net_if * GetInterface(chip::Inet::InterfaceId ifaceId) +net_if * GetInterface(Inet::InterfaceId ifaceId) { return ifaceId.IsPresent() ? net_if_get_by_index(ifaceId.GetPlatformInterface()) : net_if_get_default(); } +net_if * GetWiFiInterface() +{ + return net_if_get_first_wifi(); +} + } // namespace InetUtils } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Zephyr/InetUtils.h b/src/platform/Zephyr/InetUtils.h index ad7c5e1dc9028f..0ba3da651a1670 100644 --- a/src/platform/Zephyr/InetUtils.h +++ b/src/platform/Zephyr/InetUtils.h @@ -24,8 +24,9 @@ namespace chip { namespace DeviceLayer { namespace InetUtils { -in6_addr ToZephyrAddr(const chip::Inet::IPAddress & address); -net_if * GetInterface(chip::Inet::InterfaceId ifaceId = chip::Inet::InterfaceId::Null()); +in6_addr ToZephyrAddr(const Inet::IPAddress & address); +net_if * GetInterface(Inet::InterfaceId ifaceId = Inet::InterfaceId::Null()); +net_if * GetWiFiInterface(); } // namespace InetUtils } // namespace DeviceLayer diff --git a/src/platform/Zephyr/ThreadStackManagerImpl.cpp b/src/platform/Zephyr/ThreadStackManagerImpl.cpp index 95bdfc8ea7044a..a7b39298e16735 100644 --- a/src/platform/Zephyr/ThreadStackManagerImpl.cpp +++ b/src/platform/Zephyr/ThreadStackManagerImpl.cpp @@ -27,16 +27,13 @@ #include #include -#include #include -#include #include namespace chip { namespace DeviceLayer { using namespace ::chip::DeviceLayer::Internal; -using namespace ::chip::Inet; ThreadStackManagerImpl ThreadStackManagerImpl::sInstance; @@ -46,26 +43,6 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() ReturnErrorOnFailure(GenericThreadStackManagerImpl_OpenThread::DoInit(instance)); - UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](InterfaceId, const IPAddress & address) { - const otIp6Address otAddress = ToOpenThreadIP6Address(address); - - ThreadStackMgr().LockThreadStack(); - const auto otError = otIp6SubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); - ThreadStackMgr().UnlockThreadStack(); - - return MapOpenThreadError(otError); - }); - - UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](InterfaceId, const IPAddress & address) { - const otIp6Address otAddress = ToOpenThreadIP6Address(address); - - ThreadStackMgr().LockThreadStack(); - const auto otError = otIp6UnsubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); - ThreadStackMgr().UnlockThreadStack(); - - return MapOpenThreadError(otError); - }); - #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT k_sem_init(&mSrpClearAllSemaphore, 0, 1); #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT diff --git a/src/platform/Zephyr/wifi/WiFiManager.cpp b/src/platform/Zephyr/wifi/WiFiManager.cpp index 8b6fdf64bbe8d9..69d2943235cdbd 100644 --- a/src/platform/Zephyr/wifi/WiFiManager.cpp +++ b/src/platform/Zephyr/wifi/WiFiManager.cpp @@ -159,33 +159,33 @@ void WiFiManager::WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mg CHIP_ERROR WiFiManager::Init() { // TODO: consider moving these to ConnectivityManagerImpl to be prepared for handling multiple interfaces on a single device. - Inet::UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { - const in6_addr addr = InetUtils::ToZephyrAddr(address); - net_if * iface = InetUtils::GetInterface(interfaceId); - VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + Inet::UDPEndPointImplSockets::SetMulticastGroupHandler( + [](Inet::InterfaceId interfaceId, const Inet::IPAddress & address, UDPEndPointImplSockets::MulticastOperation operation) { + const in6_addr addr = InetUtils::ToZephyrAddr(address); + net_if * iface = InetUtils::GetInterface(interfaceId); + VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &addr); - - if (maddr && !net_if_ipv6_maddr_is_joined(maddr) && !net_ipv6_is_addr_mcast_link_all_nodes(&addr)) - { - net_if_ipv6_maddr_join(iface, maddr); - } - - return CHIP_NO_ERROR; - }); - - Inet::UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { - const in6_addr addr = InetUtils::ToZephyrAddr(address); - net_if * iface = InetUtils::GetInterface(interfaceId); - VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + if (operation == UDPEndPointImplSockets::MulticastOperation::kJoin) + { + net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &addr); - if (!net_ipv6_is_addr_mcast_link_all_nodes(&addr) && !net_if_ipv6_maddr_rm(iface, &addr)) - { - return CHIP_ERROR_INVALID_ADDRESS; - } + if (maddr && !net_if_ipv6_maddr_is_joined(maddr) && !net_ipv6_is_addr_mcast_link_all_nodes(&addr)) + { + net_if_ipv6_maddr_join(iface, maddr); + } + } + else if (operation == UDPEndPointImplSockets::MulticastOperation::kLeave) + { + VerifyOrReturnError(net_ipv6_is_addr_mcast_link_all_nodes(&addr) || net_if_ipv6_maddr_rm(iface, &addr), + CHIP_ERROR_INVALID_ADDRESS); + } + else + { + return CHIP_ERROR_INCORRECT_STATE; + } - return CHIP_NO_ERROR; - }); + return CHIP_NO_ERROR; + }); net_mgmt_init_event_callback(&mWiFiMgmtClbk, WifiMgmtEventHandler, kWifiManagementEvents); net_mgmt_add_event_callback(&mWiFiMgmtClbk); diff --git a/src/platform/device.gni b/src/platform/device.gni index 5dc4c812c0c648..01358d4880f876 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -126,6 +126,12 @@ if (chip_device_platform == "nxp" && chip_enable_openthread) { chip_mdns = "minimal" } +declare_args() { + # Select DNS-SD components to build + chip_mdns_minimal = chip_mdns == "minimal" + chip_mdns_platform = chip_mdns == "platform" +} + _chip_device_layer = "none" if (chip_device_platform == "cc13x2_26x2") { _chip_device_layer = "cc13xx_26xx/cc13x2_26x2" diff --git a/src/platform/nrfconnect/BUILD.gn b/src/platform/nrfconnect/BUILD.gn index f6807b3f8dd4e0..5eb866391a0aff 100644 --- a/src/platform/nrfconnect/BUILD.gn +++ b/src/platform/nrfconnect/BUILD.gn @@ -77,6 +77,13 @@ static_library("nrfconnect") { ] } + if (chip_enable_openthread || chip_enable_wifi) { + sources += [ + "../Zephyr/InetUtils.cpp", + "../Zephyr/InetUtils.h", + ] + } + if (chip_enable_openthread) { sources += [ "../OpenThread/OpenThreadUtils.cpp", @@ -84,7 +91,7 @@ static_library("nrfconnect") { "ThreadStackManagerImpl.h", ] - if (chip_mdns == "platform") { + if (chip_mdns_platform) { sources += [ "../OpenThread/DnssdImpl.cpp", "../OpenThread/OpenThreadDnssdImpl.cpp", @@ -96,8 +103,6 @@ static_library("nrfconnect") { if (chip_enable_wifi) { sources += [ - "../Zephyr/InetUtils.cpp", - "../Zephyr/InetUtils.h", "OTAImageProcessorImplWiFi.h", "wifi/ConnectivityManagerImplWiFi.cpp", "wifi/ConnectivityManagerImplWiFi.h", diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h index 7461d3650d86a6..f9e445f35fb3d4 100644 --- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h +++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h @@ -212,6 +212,12 @@ #define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1 #endif // CONFIG_CHIP_EXTENDED_DISCOVERY +#ifdef CONFIG_CHIP_BLE_EXT_ADVERTISING +#define CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING 1 +#endif // CONFIG_CHIP_BLE_EXT_ADVERTISING + +#define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS (CONFIG_CHIP_BLE_ADVERTISING_DURATION * 60) + #ifndef CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH #ifdef CONFIG_CHIP_FACTORY_DATA // UID will be copied from the externally programmed factory data, so we don't know the actual length and we need to assume some max diff --git a/src/platform/nrfconnect/ConnectivityManagerImpl.cpp b/src/platform/nrfconnect/ConnectivityManagerImpl.cpp index 504b0d0460ccde..ecd185200c78f7 100644 --- a/src/platform/nrfconnect/ConnectivityManagerImpl.cpp +++ b/src/platform/nrfconnect/ConnectivityManagerImpl.cpp @@ -17,11 +17,12 @@ #include -#include -#include - +#include #include #include +#include +#include +#include #include @@ -34,16 +35,64 @@ #endif #if CHIP_DEVICE_CONFIG_ENABLE_THREAD +#include #include #endif -using namespace ::chip; -using namespace ::chip::TLV; +using namespace ::chip::Inet; using namespace ::chip::DeviceLayer::Internal; namespace chip { namespace DeviceLayer { +namespace { +CHIP_ERROR JoinLeaveMulticastGroup(net_if * iface, const Inet::IPAddress & address, + UDPEndPointImplSockets::MulticastOperation operation) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD + if (net_if_l2(iface) == &NET_L2_GET_NAME(OPENTHREAD)) + { + const otIp6Address otAddress = ToOpenThreadIP6Address(address); + const auto handler = operation == UDPEndPointImplSockets::MulticastOperation::kJoin ? otIp6SubscribeMulticastAddress + : otIp6UnsubscribeMulticastAddress; + otError error; + + ThreadStackMgr().LockThreadStack(); + error = handler(openthread_get_default_instance(), &otAddress); + ThreadStackMgr().UnlockThreadStack(); + + return MapOpenThreadError(error); + } +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + // The following code should also be valid for other interface types, such as Ethernet, + // but they are not officially supported, so for now enable it for Wi-Fi only. + const in6_addr in6Addr = InetUtils::ToZephyrAddr(address); + + if (operation == UDPEndPointImplSockets::MulticastOperation::kJoin) + { + net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &in6Addr); + + if (maddr && !net_if_ipv6_maddr_is_joined(maddr)) + { + net_if_ipv6_maddr_join(iface, maddr); + } + } + else if (operation == UDPEndPointImplSockets::MulticastOperation::kLeave) + { + VerifyOrReturnError(net_if_ipv6_maddr_rm(iface, &in6Addr), CHIP_ERROR_INVALID_ADDRESS); + } + else + { + return CHIP_ERROR_INCORRECT_STATE; + } +#endif + + return CHIP_NO_ERROR; +} +} // namespace + ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; CHIP_ERROR ConnectivityManagerImpl::_Init() @@ -54,6 +103,28 @@ CHIP_ERROR ConnectivityManagerImpl::_Init() #if CHIP_DEVICE_CONFIG_ENABLE_WIFI ReturnErrorOnFailure(InitWiFi()); #endif + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD || CHIP_DEVICE_CONFIG_ENABLE_WIFI + UDPEndPointImplSockets::SetMulticastGroupHandler( + [](InterfaceId interfaceId, const IPAddress & address, UDPEndPointImplSockets::MulticastOperation operation) { + if (interfaceId.IsPresent()) + { + net_if * iface = InetUtils::GetInterface(interfaceId); + VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + + return JoinLeaveMulticastGroup(iface, address, operation); + } + + // If the interface is not specified, join or leave the multicast group on all interfaces. + for (int i = 1; net_if * iface = net_if_get_by_index(i); i++) + { + ReturnErrorOnFailure(JoinLeaveMulticastGroup(iface, address, operation)); + } + + return CHIP_NO_ERROR; + }); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD || CHIP_DEVICE_CONFIG_ENABLE_WIFI + return CHIP_NO_ERROR; } diff --git a/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp b/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp index 1efe5c863f8753..0cf1b383d295ad 100644 --- a/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp +++ b/src/platform/nrfconnect/wifi/NrfWiFiDriver.cpp @@ -106,8 +106,9 @@ CHIP_ERROR NrfWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChange if (mStagingNetwork.IsConfigured()) { - WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, - [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + WiFiManager::ConnectionHandling handling{ [](const wifi_conn_status & connStatus) { + Instance().OnNetworkConnStatusChanged(connStatus); + }, System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; ReturnErrorOnFailure( WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling)); @@ -116,8 +117,11 @@ CHIP_ERROR NrfWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChange return CHIP_NO_ERROR; } -void NrfWiFiDriver::OnNetworkStatusChanged(Status status) +void NrfWiFiDriver::OnNetworkConnStatusChanged(const wifi_conn_status & connStatus) { + // TODO: check if we can report more accurate errors + Status status = connStatus ? Status::kUnknownError : Status::kSuccess; + if (status == Status::kSuccess) { ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled); @@ -125,7 +129,23 @@ void NrfWiFiDriver::OnNetworkStatusChanged(Status status) if (mpNetworkStatusChangeCallback) { - mpNetworkStatusChangeCallback->OnNetworkingStatusChange(status, NullOptional, NullOptional); + const uint8_t * ssid{}; + size_t ssidLen{}; + WiFiManager::WiFiInfo wifiInfo; + + if (CHIP_NO_ERROR == WiFiManager::Instance().GetWiFiInfo(wifiInfo)) + { + ssid = wifiInfo.mSsid; + ssidLen = wifiInfo.mSsidLen; + } + else + { + ssid = WiFiManager::Instance().GetWantedNetwork().ssid; + ssidLen = WiFiManager::Instance().GetWantedNetwork().ssidLen; + } + mpNetworkStatusChangeCallback->OnNetworkingStatusChange(status, MakeOptional(ByteSpan(wifiInfo.mSsid, wifiInfo.mSsidLen)), + connStatus ? MakeOptional(static_cast(connStatus)) + : NullOptional); } if (mpConnectCallback) @@ -167,8 +187,9 @@ CHIP_ERROR NrfWiFiDriver::RevertConfiguration() if (mStagingNetwork.IsConfigured()) { - WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, - [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + WiFiManager::ConnectionHandling handling{ [](const wifi_conn_status & connStatus) { + Instance().OnNetworkConnStatusChanged(connStatus); + }, System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; ReturnErrorOnFailure( WiFiManager::Instance().Connect(mStagingNetwork.GetSsidSpan(), mStagingNetwork.GetPassSpan(), handling)); @@ -221,8 +242,9 @@ Status NrfWiFiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableC void NrfWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) { Status status = Status::kSuccess; - WiFiManager::ConnectionHandling handling{ [] { Instance().OnNetworkStatusChanged(Status::kSuccess); }, - [] { Instance().OnNetworkStatusChanged(Status::kUnknownError); }, + WiFiManager::ConnectionHandling handling{ [](const wifi_conn_status & connStatus) { + Instance().OnNetworkConnStatusChanged(connStatus); + }, System::Clock::Seconds32{ kWiFiConnectNetworkTimeoutSeconds } }; VerifyOrExit(mpConnectCallback == nullptr, status = Status::kUnknownError); @@ -252,11 +274,10 @@ void NrfWiFiDriver::LoadFromStorage() mStagingNetwork = network; } -void NrfWiFiDriver::OnScanWiFiNetworkDone(WiFiManager::WiFiRequestStatus status) +void NrfWiFiDriver::OnScanWiFiNetworkDone(const WiFiManager::ScanDoneStatus & status) { VerifyOrReturn(mScanCallback != nullptr); - mScanCallback->OnFinished(status == WiFiManager::WiFiRequestStatus::SUCCESS ? Status::kSuccess : Status::kUnknownError, - CharSpan(), &mScanResponseIterator); + mScanCallback->OnFinished(status ? Status::kUnknownError : Status::kSuccess, CharSpan(), &mScanResponseIterator); mScanCallback = nullptr; } @@ -270,7 +291,7 @@ void NrfWiFiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callb mScanCallback = callback; CHIP_ERROR error = WiFiManager::Instance().Scan( ssid, [](const WiFiScanResponse & response) { Instance().OnScanWiFiNetworkResult(response); }, - [](WiFiManager::WiFiRequestStatus status) { Instance().OnScanWiFiNetworkDone(status); }); + [](const WiFiManager::ScanDoneStatus & status) { Instance().OnScanWiFiNetworkDone(status); }); if (error != CHIP_NO_ERROR) { diff --git a/src/platform/nrfconnect/wifi/NrfWiFiDriver.h b/src/platform/nrfconnect/wifi/NrfWiFiDriver.h index 7fe1ff1695351d..5422e4eb485610 100644 --- a/src/platform/nrfconnect/wifi/NrfWiFiDriver.h +++ b/src/platform/nrfconnect/wifi/NrfWiFiDriver.h @@ -94,9 +94,9 @@ class NrfWiFiDriver final : public WiFiDriver return sInstance; } - void OnNetworkStatusChanged(Status status); + void OnNetworkConnStatusChanged(const wifi_conn_status & connStatus); void OnScanWiFiNetworkResult(const WiFiScanResponse & result); - void OnScanWiFiNetworkDone(WiFiManager::WiFiRequestStatus status); + void OnScanWiFiNetworkDone(const WiFiManager::ScanDoneStatus & status); private: void LoadFromStorage(); diff --git a/src/platform/nrfconnect/wifi/WiFiManager.cpp b/src/platform/nrfconnect/wifi/WiFiManager.cpp index c3435a954fab50..d5783fa060c558 100644 --- a/src/platform/nrfconnect/wifi/WiFiManager.cpp +++ b/src/platform/nrfconnect/wifi/WiFiManager.cpp @@ -23,10 +23,9 @@ #include "WiFiManager.h" #include -#include -#include #include #include +#include #include #include @@ -138,57 +137,43 @@ const Map { WIFI_STATE_GROUP_HANDSHAKE, WiFiManager::StationStatus::PROVISIONING }, { WIFI_STATE_COMPLETED, WiFiManager::StationStatus::FULLY_PROVISIONED } }); -const Map - WiFiManager::sEventHandlerMap({ { NET_EVENT_WIFI_SCAN_RESULT, WiFiManager::ScanResultHandler }, - { NET_EVENT_WIFI_SCAN_DONE, WiFiManager::ScanDoneHandler }, - { NET_EVENT_WIFI_CONNECT_RESULT, WiFiManager::ConnectHandler }, - { NET_EVENT_WIFI_DISCONNECT_RESULT, WiFiManager::DisconnectHandler }, - { NET_EVENT_WIFI_DISCONNECT_COMPLETE, WiFiManager::DisconnectHandler } }); +const Map WiFiManager::sEventHandlerMap({ + { NET_EVENT_WIFI_SCAN_RESULT, WiFiManager::ScanResultHandler }, + { NET_EVENT_WIFI_SCAN_DONE, WiFiManager::ScanDoneHandler }, + { NET_EVENT_WIFI_CONNECT_RESULT, WiFiManager::ConnectHandler }, + { NET_EVENT_WIFI_DISCONNECT_RESULT, WiFiManager::DisconnectHandler }, + { NET_EVENT_WIFI_DISCONNECT_COMPLETE, WiFiManager::DisconnectHandler }, +}); void WiFiManager::WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface) { - if (0 == strcmp(iface->if_dev->dev->name, "wlan0")) + if (iface == Instance().mNetIf) { Platform::UniquePtr eventData(new uint8_t[cb->info_length]); VerifyOrReturn(eventData); memcpy(eventData.get(), cb->info, cb->info_length); - sEventHandlerMap[mgmtEvent](std::move(eventData)); + sEventHandlerMap[mgmtEvent](std::move(eventData), cb->info_length); } } -CHIP_ERROR WiFiManager::Init() +void WiFiManager::IPv6MgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface) { - // TODO: consider moving these to ConnectivityManagerImpl to be prepared for handling multiple interfaces on a single device. - Inet::UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { - const in6_addr addr = InetUtils::ToZephyrAddr(address); - net_if * iface = InetUtils::GetInterface(interfaceId); - VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - - net_if_mcast_addr * maddr = net_if_ipv6_maddr_add(iface, &addr); - - if (maddr && !net_if_ipv6_maddr_is_joined(maddr) && !net_ipv6_is_addr_mcast_link_all_nodes(&addr)) - { - net_if_ipv6_maddr_join(iface, maddr); - } - - return CHIP_NO_ERROR; - }); - - Inet::UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](Inet::InterfaceId interfaceId, const Inet::IPAddress & address) { - const in6_addr addr = InetUtils::ToZephyrAddr(address); - net_if * iface = InetUtils::GetInterface(interfaceId); - VerifyOrReturnError(iface != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - - if (!net_ipv6_is_addr_mcast_link_all_nodes(&addr) && !net_if_ipv6_maddr_rm(iface, &addr)) - { - return CHIP_ERROR_INVALID_ADDRESS; - } + if (((mgmtEvent == NET_EVENT_IPV6_ADDR_ADD) || (mgmtEvent == NET_EVENT_IPV6_ADDR_DEL)) && cb->info) + { + IPv6AddressChangeHandler(cb->info); + } +} - return CHIP_NO_ERROR; - }); +CHIP_ERROR WiFiManager::Init() +{ + mNetIf = InetUtils::GetWiFiInterface(); + VerifyOrReturnError(mNetIf != nullptr, INET_ERROR_UNKNOWN_INTERFACE); net_mgmt_init_event_callback(&mWiFiMgmtClbk, WifiMgmtEventHandler, kWifiManagementEvents); + net_mgmt_init_event_callback(&mIPv6MgmtClbk, IPv6MgmtEventHandler, kIPv6ManagementEvents); + net_mgmt_add_event_callback(&mWiFiMgmtClbk); + net_mgmt_add_event_callback(&mIPv6MgmtClbk); ChipLogDetail(DeviceLayer, "WiFiManager has been initialized"); @@ -197,9 +182,6 @@ CHIP_ERROR WiFiManager::Init() CHIP_ERROR WiFiManager::Scan(const ByteSpan & ssid, ScanResultCallback resultCallback, ScanDoneCallback doneCallback, bool internalScan) { - net_if * iface = InetUtils::GetInterface(); - VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); - mInternalScan = internalScan; mScanResultCallback = resultCallback; mScanDoneCallback = doneCallback; @@ -207,7 +189,7 @@ CHIP_ERROR WiFiManager::Scan(const ByteSpan & ssid, ScanResultCallback resultCal mWiFiState = WIFI_STATE_SCANNING; mSsidFound = false; - if (0 != net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) + if (0 != net_mgmt(NET_REQUEST_WIFI_SCAN, mNetIf, NULL, 0)) { ChipLogError(DeviceLayer, "Scan request failed"); return CHIP_ERROR_INTERNAL; @@ -229,9 +211,7 @@ CHIP_ERROR WiFiManager::Connect(const ByteSpan & ssid, const ByteSpan & credenti { ChipLogDetail(DeviceLayer, "Connecting to WiFi network: %*s", ssid.size(), ssid.data()); - mHandling.mOnConnectionSuccess = handling.mOnConnectionSuccess; - mHandling.mOnConnectionFailed = handling.mOnConnectionFailed; - mHandling.mConnectionTimeout = handling.mConnectionTimeout; + mHandling = handling; mWiFiState = WIFI_STATE_ASSOCIATING; @@ -248,11 +228,8 @@ CHIP_ERROR WiFiManager::Connect(const ByteSpan & ssid, const ByteSpan & credenti CHIP_ERROR WiFiManager::Disconnect() { - net_if * iface = InetUtils::GetInterface(); - VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); - mApplicationDisconnectRequested = true; - int status = net_mgmt(NET_REQUEST_WIFI_DISCONNECT, iface, NULL, 0); + int status = net_mgmt(NET_REQUEST_WIFI_DISCONNECT, mNetIf, NULL, 0); if (status) { @@ -277,11 +254,9 @@ CHIP_ERROR WiFiManager::Disconnect() CHIP_ERROR WiFiManager::GetWiFiInfo(WiFiInfo & info) const { - net_if * iface = InetUtils::GetInterface(); - VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); - struct wifi_iface_status status = { 0 }; + wifi_iface_status status = { 0 }; - if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status, sizeof(struct wifi_iface_status))) + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, mNetIf, &status, sizeof(wifi_iface_status))) { ChipLogError(DeviceLayer, "Status request failed"); return CHIP_ERROR_INTERNAL; @@ -306,7 +281,7 @@ CHIP_ERROR WiFiManager::GetWiFiInfo(WiFiInfo & info) const CHIP_ERROR WiFiManager::GetNetworkStatistics(NetworkStatistics & stats) const { net_stats_wifi data{}; - net_mgmt(NET_REQUEST_STATS_GET_WIFI, InetUtils::GetInterface(), &data, sizeof(data)); + net_mgmt(NET_REQUEST_STATS_GET_WIFI, mNetIf, &data, sizeof(data)); stats.mPacketMulticastRxCount = data.multicast.rx; stats.mPacketMulticastTxCount = data.multicast.tx; @@ -318,10 +293,13 @@ CHIP_ERROR WiFiManager::GetNetworkStatistics(NetworkStatistics & stats) const return CHIP_NO_ERROR; } -void WiFiManager::ScanResultHandler(Platform::UniquePtr data) +void WiFiManager::ScanResultHandler(Platform::UniquePtr data, size_t length) { + // Validate that input data size matches the expected one. + VerifyOrReturn(length == sizeof(wifi_scan_result)); + // Contrary to other handlers, offload accumulating of the scan results from the CHIP thread to the caller's thread - const struct wifi_scan_result * scanResult = reinterpret_cast(data.get()); + const wifi_scan_result * scanResult = reinterpret_cast(data.get()); if (Instance().mInternalScan && Instance().mWantedNetwork.GetSsidSpan().data_equal(ByteSpan(scanResult->ssid, scanResult->ssid_length))) @@ -352,6 +330,7 @@ void WiFiManager::ScanResultHandler(Platform::UniquePtr data) Instance().mWiFiParams.mParams.timeout = Instance().mHandling.mConnectionTimeout.count(); Instance().mWiFiParams.mParams.channel = WIFI_CHANNEL_ANY; Instance().mWiFiParams.mRssi = scanResult->rssi; + Instance().mWiFiParams.mParams.band = WIFI_FREQ_BAND_UNKNOWN; Instance().mSsidFound = true; } } @@ -362,26 +341,29 @@ void WiFiManager::ScanResultHandler(Platform::UniquePtr data) } } -void WiFiManager::ScanDoneHandler(Platform::UniquePtr data) +void WiFiManager::ScanDoneHandler(Platform::UniquePtr data, size_t length) { + // Validate that input data size matches the expected one. + VerifyOrReturn(length == sizeof(wifi_status)); + CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] { Platform::UniquePtr safePtr(capturedData); - uint8_t * rawData = safePtr.get(); - const wifi_status * status = reinterpret_cast(rawData); - WiFiRequestStatus requestStatus = static_cast(status->status); + uint8_t * rawData = safePtr.get(); + const wifi_status * status = reinterpret_cast(rawData); + ScanDoneStatus scanDoneStatus = status->status; - if (requestStatus == WiFiRequestStatus::FAILURE) + if (scanDoneStatus) { - ChipLogError(DeviceLayer, "Wi-Fi scan finalization failure (%d)", status->status); + ChipLogError(DeviceLayer, "Wi-Fi scan finalization failure (%d)", scanDoneStatus); } else { - ChipLogProgress(DeviceLayer, "Wi-Fi scan done (%d)", status->status); + ChipLogProgress(DeviceLayer, "Wi-Fi scan done"); } if (Instance().mScanDoneCallback && !Instance().mInternalScan) { - Instance().mScanDoneCallback(requestStatus); + Instance().mScanDoneCallback(scanDoneStatus); // restore the connection state from before the scan request was issued Instance().mWiFiState = Instance().mCachedWiFiState; return; @@ -397,18 +379,18 @@ void WiFiManager::ScanDoneHandler(Platform::UniquePtr data) ChipLogProgress(DeviceLayer, "Starting connection recover: re-scanning... (next attempt in %d ms)", currentTimeout.count()); DeviceLayer::SystemLayer().StartTimer(currentTimeout, Recover, nullptr); + return; } Instance().mWiFiState = WIFI_STATE_ASSOCIATING; - net_if * iface = InetUtils::GetInterface(); - VerifyOrReturn(nullptr != iface, CHIP_ERROR_INTERNAL); - if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &(Instance().mWiFiParams.mParams), sizeof(wifi_connect_req_params))) + if (net_mgmt(NET_REQUEST_WIFI_CONNECT, Instance().mNetIf, &(Instance().mWiFiParams.mParams), + sizeof(wifi_connect_req_params))) { ChipLogError(DeviceLayer, "Connection request failed"); - if (Instance().mHandling.mOnConnectionFailed) + if (Instance().mHandling.mOnConnectionDone) { - Instance().mHandling.mOnConnectionFailed(); + Instance().mHandling.mOnConnectionDone(WIFI_STATUS_CONN_FAIL); } Instance().mWiFiState = WIFI_STATE_DISCONNECTED; return; @@ -428,38 +410,65 @@ void WiFiManager::ScanDoneHandler(Platform::UniquePtr data) void WiFiManager::SendRouterSolicitation(System::Layer * layer, void * param) { - net_if * iface = InetUtils::GetInterface(); - if (iface && iface->if_dev->link_addr.type == NET_LINK_ETHERNET) + net_if_start_rs(Instance().mNetIf); + Instance().mRouterSolicitationCounter++; + if (Instance().mRouterSolicitationCounter < kRouterSolicitationMaxCount) { - net_if_start_rs(iface); - Instance().mRouterSolicitationCounter++; - if (Instance().mRouterSolicitationCounter < kRouterSolicitationMaxCount) - { - DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kRouterSolicitationIntervalMs), - SendRouterSolicitation, nullptr); - } - else - { - Instance().mRouterSolicitationCounter = 0; - } + DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kRouterSolicitationIntervalMs), SendRouterSolicitation, + nullptr); + } + else + { + Instance().mRouterSolicitationCounter = 0; } } -void WiFiManager::ConnectHandler(Platform::UniquePtr data) +void WiFiManager::ConnectHandler(Platform::UniquePtr data, size_t length) { + using app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum; + + // Validate that input data size matches the expected one. + VerifyOrReturn(length == sizeof(wifi_status)); + CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] { Platform::UniquePtr safePtr(capturedData); - uint8_t * rawData = safePtr.get(); - const wifi_status * status = reinterpret_cast(rawData); - WiFiRequestStatus requestStatus = static_cast(status->status); + uint8_t * rawData = safePtr.get(); + const wifi_status * status = reinterpret_cast(rawData); + wifi_conn_status connStatus = status->conn_status; - if (requestStatus == WiFiRequestStatus::FAILURE || requestStatus == WiFiRequestStatus::TERMINATED) + if (connStatus) { ChipLogProgress(DeviceLayer, "Connection to WiFi network failed or was terminated by another request"); Instance().mWiFiState = WIFI_STATE_DISCONNECTED; - if (Instance().mHandling.mOnConnectionFailed) + if (Instance().mHandling.mOnConnectionDone) + { + Instance().mHandling.mOnConnectionDone(connStatus); + } + + WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); + if (delegate) { - Instance().mHandling.mOnConnectionFailed(); + uint16_t reason = Instance().GetLastDisconnectReason(); + uint8_t associationFailureCause; + + switch (connStatus) + { + case WIFI_STATUS_CONN_WRONG_PASSWORD: + associationFailureCause = to_underlying(AssociationFailureCauseEnum::kAuthenticationFailed); + break; + case WIFI_STATUS_CONN_FAIL: + case WIFI_STATUS_CONN_TIMEOUT: + associationFailureCause = to_underlying(AssociationFailureCauseEnum::kAssociationFailed); + break; + case WIFI_STATUS_CONN_AP_NOT_FOUND: + associationFailureCause = to_underlying(AssociationFailureCauseEnum::kSsidNotFound); + break; + default: + associationFailureCause = to_underlying(AssociationFailureCauseEnum::kUnknown); + break; + } + + delegate->OnAssociationFailureDetected(associationFailureCause, reason); } } else // The connection has been established successfully. @@ -471,9 +480,9 @@ void WiFiManager::ConnectHandler(Platform::UniquePtr data) ChipLogProgress(DeviceLayer, "Connected to WiFi network"); Instance().mWiFiState = WIFI_STATE_COMPLETED; - if (Instance().mHandling.mOnConnectionSuccess) + if (Instance().mHandling.mOnConnectionDone) { - Instance().mHandling.mOnConnectionSuccess(); + Instance().mHandling.mOnConnectionDone(connStatus); } Instance().PostConnectivityStatusChange(kConnectivity_Established); @@ -486,6 +495,13 @@ void WiFiManager::ConnectHandler(Platform::UniquePtr data) { ChipLogError(DeviceLayer, "Cannot post event [error: %s]", ErrorStr(error)); } + + WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); + if (delegate) + { + delegate->OnConnectionStatusChanged( + to_underlying(app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kConnected)); + } } // cleanup the provisioning data as it is configured per each connect request Instance().ClearStationProvisioningData(); @@ -498,13 +514,74 @@ void WiFiManager::ConnectHandler(Platform::UniquePtr data) } } -void WiFiManager::DisconnectHandler(Platform::UniquePtr) +void WiFiManager::DisconnectHandler(Platform::UniquePtr data, size_t length) { - SystemLayer().ScheduleLambda([] { + // Validate that input data size matches the expected one. + VerifyOrReturn(length == sizeof(wifi_status)); + + CHIP_ERROR err = SystemLayer().ScheduleLambda([capturedData = data.get()] { + Platform::UniquePtr safePtr(capturedData); + uint8_t * rawData = safePtr.get(); + const wifi_status * status = reinterpret_cast(rawData); + uint16_t reason; + + switch (status->disconn_reason) + { + case WIFI_REASON_DISCONN_UNSPECIFIED: + reason = WLAN_REASON_UNSPECIFIED; + break; + case WIFI_REASON_DISCONN_USER_REQUEST: + reason = WLAN_REASON_DEAUTH_LEAVING; + break; + case WIFI_REASON_DISCONN_AP_LEAVING: + reason = WLAN_REASON_DEAUTH_LEAVING; + break; + case WIFI_REASON_DISCONN_INACTIVITY: + reason = WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY; + break; + default: + reason = WLAN_REASON_UNSPECIFIED; + break; + } + Instance().SetLastDisconnectReason(reason); + ChipLogProgress(DeviceLayer, "WiFi station disconnected"); Instance().mWiFiState = WIFI_STATE_DISCONNECTED; Instance().PostConnectivityStatusChange(kConnectivity_Lost); + + WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); + if (delegate) + { + delegate->OnConnectionStatusChanged( + to_underlying(app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kNotConnected)); + delegate->OnDisconnectionDetected(reason); + } }); + + if (CHIP_NO_ERROR == err) + { + // the ownership has been transferred to the worker thread - release the buffer + data.release(); + } +} + +void WiFiManager::IPv6AddressChangeHandler(const void * data) +{ + const in6_addr * addr = reinterpret_cast(data); + + // Filter out link-local addresses that are not routable outside of a local network. + if (!net_ipv6_is_ll_addr(addr)) + { + // This is needed to send mDNS queries containing updated IPv6 addresses. + ChipDeviceEvent event; + event.Type = DeviceEventType::kDnssdRestartNeeded; + + CHIP_ERROR error = PlatformMgr().PostEvent(&event); + if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Cannot post event: %" CHIP_ERROR_FORMAT, error.Format()); + } + } } WiFiManager::StationStatus WiFiManager::GetStationStatus() const @@ -570,11 +647,10 @@ System::Clock::Milliseconds32 WiFiManager::CalculateNextRecoveryTime() CHIP_ERROR WiFiManager::SetLowPowerMode(bool onoff) { - net_if * iface = InetUtils::GetInterface(); - VerifyOrReturnError(nullptr != iface, CHIP_ERROR_INTERNAL); + VerifyOrReturnError(nullptr != mNetIf, CHIP_ERROR_INTERNAL); wifi_ps_config currentConfig{}; - if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, iface, ¤tConfig, sizeof(currentConfig))) + if (net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, mNetIf, ¤tConfig, sizeof(currentConfig))) { ChipLogError(DeviceLayer, "Get current low power mode config request failed"); return CHIP_ERROR_INTERNAL; @@ -584,7 +660,7 @@ CHIP_ERROR WiFiManager::SetLowPowerMode(bool onoff) (currentConfig.ps_params.enabled == WIFI_PS_DISABLED && onoff == true)) { wifi_ps_params params{ .enabled = onoff ? WIFI_PS_ENABLED : WIFI_PS_DISABLED }; - if (net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params))) + if (net_mgmt(NET_REQUEST_WIFI_PS, mNetIf, ¶ms, sizeof(params))) { ChipLogError(DeviceLayer, "Set low power mode request failed"); return CHIP_ERROR_INTERNAL; @@ -597,5 +673,15 @@ CHIP_ERROR WiFiManager::SetLowPowerMode(bool onoff) return CHIP_NO_ERROR; } +void WiFiManager::SetLastDisconnectReason(uint16_t reason) +{ + mLastDisconnectedReason = reason; +} + +uint16_t WiFiManager::GetLastDisconnectReason() +{ + return mLastDisconnectedReason; +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nrfconnect/wifi/WiFiManager.h b/src/platform/nrfconnect/wifi/WiFiManager.h index 248f7dccc67bc7..a4e3a8afb39256 100644 --- a/src/platform/nrfconnect/wifi/WiFiManager.h +++ b/src/platform/nrfconnect/wifi/WiFiManager.h @@ -88,16 +88,10 @@ class Map class WiFiManager { public: - enum WiFiRequestStatus : int - { - SUCCESS = 0, - FAILURE = 1, - TERMINATED = 2 - }; - + using ScanDoneStatus = decltype(wifi_status::status); using ScanResultCallback = void (*)(const NetworkCommissioning::WiFiScanResponse &); - using ScanDoneCallback = void (*)(WiFiRequestStatus); - using ConnectionCallback = void (*)(); + using ScanDoneCallback = void (*)(const ScanDoneStatus &); + using ConnectionCallback = void (*)(const wifi_conn_status &); enum class StationStatus : uint8_t { @@ -120,8 +114,7 @@ class WiFiManager struct ConnectionHandling { - ConnectionCallback mOnConnectionSuccess{}; - ConnectionCallback mOnConnectionFailed{}; + ConnectionCallback mOnConnectionDone{}; System::Clock::Seconds32 mConnectionTimeout{}; }; @@ -182,12 +175,15 @@ class WiFiManager CHIP_ERROR ClearStationProvisioningData(); CHIP_ERROR Disconnect(); CHIP_ERROR GetWiFiInfo(WiFiInfo & info) const; + const WiFiNetwork & GetWantedNetwork() const { return mWantedNetwork; } CHIP_ERROR GetNetworkStatistics(NetworkStatistics & stats) const; void AbortConnectionRecovery(); CHIP_ERROR SetLowPowerMode(bool onoff); + void SetLastDisconnectReason(uint16_t reason); + uint16_t GetLastDisconnectReason(); private: - using NetEventHandler = void (*)(Platform::UniquePtr); + using NetEventHandler = void (*)(Platform::UniquePtr, size_t); struct ConnectionParams { @@ -198,14 +194,18 @@ class WiFiManager constexpr static uint32_t kWifiManagementEvents = NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE | NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | NET_EVENT_WIFI_IFACE_STATUS; + constexpr static uint32_t kIPv6ManagementEvents = NET_EVENT_IPV6_ADDR_ADD | NET_EVENT_IPV6_ADDR_DEL; + // Event handling static void WifiMgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface); - static void ScanResultHandler(Platform::UniquePtr data); - static void ScanDoneHandler(Platform::UniquePtr data); - static void ConnectHandler(Platform::UniquePtr data); - static void DisconnectHandler(Platform::UniquePtr data); + static void IPv6MgmtEventHandler(net_mgmt_event_callback * cb, uint32_t mgmtEvent, net_if * iface); + static void ScanResultHandler(Platform::UniquePtr data, size_t length); + static void ScanDoneHandler(Platform::UniquePtr data, size_t length); + static void ConnectHandler(Platform::UniquePtr data, size_t length); + static void DisconnectHandler(Platform::UniquePtr data, size_t length); static void PostConnectivityStatusChange(ConnectivityChange changeType); static void SendRouterSolicitation(System::Layer * layer, void * param); + static void IPv6AddressChangeHandler(const void * data); // Connection Recovery feature // This feature allows re-scanning and re-connecting the connection to the known network after @@ -220,11 +220,13 @@ class WiFiManager void ResetRecoveryTime(); System::Clock::Milliseconds32 CalculateNextRecoveryTime(); + net_if * mNetIf{ nullptr }; ConnectionParams mWiFiParams{}; ConnectionHandling mHandling; wifi_iface_state mWiFiState; wifi_iface_state mCachedWiFiState; net_mgmt_event_callback mWiFiMgmtClbk{}; + net_mgmt_event_callback mIPv6MgmtClbk{}; ScanResultCallback mScanResultCallback{ nullptr }; ScanDoneCallback mScanDoneCallback{ nullptr }; WiFiNetwork mWantedNetwork{}; @@ -234,6 +236,7 @@ class WiFiManager uint32_t mConnectionRecoveryCounter{ 0 }; uint32_t mConnectionRecoveryTimeMs{ kConnectionRecoveryMinIntervalMs }; bool mApplicationDisconnectRequested{ false }; + uint16_t mLastDisconnectedReason = WLAN_REASON_UNSPECIFIED; static const Map sStatusMap; static const Map sEventHandlerMap; diff --git a/src/platform/telink/ThreadStackManagerImpl.cpp b/src/platform/telink/ThreadStackManagerImpl.cpp index 13ba8be424563b..2ec9b02ca0b67c 100644 --- a/src/platform/telink/ThreadStackManagerImpl.cpp +++ b/src/platform/telink/ThreadStackManagerImpl.cpp @@ -48,25 +48,19 @@ CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() ReturnErrorOnFailure(GenericThreadStackManagerImpl_OpenThread::DoInit(instance)); - UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](InterfaceId, const IPAddress & address) { - const otIp6Address otAddress = ToOpenThreadIP6Address(address); - - ThreadStackMgr().LockThreadStack(); - const auto otError = otIp6SubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); - ThreadStackMgr().UnlockThreadStack(); - - return MapOpenThreadError(otError); - }); - - UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](InterfaceId, const IPAddress & address) { - const otIp6Address otAddress = ToOpenThreadIP6Address(address); - - ThreadStackMgr().LockThreadStack(); - const auto otError = otIp6UnsubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); - ThreadStackMgr().UnlockThreadStack(); - - return MapOpenThreadError(otError); - }); + UDPEndPointImplSockets::SetMulticastGroupHandler( + [](InterfaceId, const IPAddress & address, UDPEndPointImplSockets::MulticastOperation operation) { + const otIp6Address otAddress = ToOpenThreadIP6Address(address); + const auto handler = operation == UDPEndPointImplSockets::MulticastOperation::kJoin ? otIp6SubscribeMulticastAddress + : otIp6UnsubscribeMulticastAddress; + otError error; + + ThreadStackMgr().LockThreadStack(); + error = handler(openthread_get_default_instance(), &otAddress); + ThreadStackMgr().UnlockThreadStack(); + + return MapOpenThreadError(error); + }); #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT k_sem_init(&mSrpClearAllSemaphore, 0, 1);