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);