From e4943505764a498ea23e98a1b5df66464dee85de Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 26 Oct 2023 05:08:24 -0700 Subject: [PATCH 1/9] [core] define `core/instance` folder for `instance` modules (#9561) This commit moves the `instance` module to a newly added folder `core/instance` (from `core/common`. Header file `extension.hpp` and its example is also moved to the same folder. --- script/check-simulation-build-cmake | 4 ++-- src/cli/cli.hpp | 2 +- src/core/BUILD.gn | 8 ++++---- src/core/CMakeLists.txt | 4 ++-- src/core/api/border_router_api.cpp | 2 +- src/core/api/border_routing_api.cpp | 2 +- src/core/api/dns_api.cpp | 2 +- src/core/api/dns_server_api.cpp | 2 +- src/core/api/logging_api.cpp | 3 ++- src/core/api/nat64_api.cpp | 2 +- src/core/api/trel_api.cpp | 2 +- src/core/backbone_router/bbr_leader.cpp | 2 +- src/core/backbone_router/bbr_local.cpp | 2 +- src/core/backbone_router/bbr_manager.cpp | 2 +- src/core/backbone_router/multicast_listeners_table.cpp | 2 +- src/core/border_router/infra_if.cpp | 2 +- src/core/border_router/routing_manager.cpp | 2 +- src/core/coap/coap.cpp | 2 +- src/core/coap/coap_message.cpp | 2 +- src/core/coap/coap_secure.cpp | 2 +- src/core/common/heap.cpp | 2 +- src/core/common/locator_getters.hpp | 2 +- src/core/common/log.cpp | 2 +- src/core/common/message.cpp | 2 +- src/core/common/settings.cpp | 2 +- src/core/common/time_ticker.cpp | 2 +- src/core/common/timer.cpp | 2 +- src/core/common/uptime.cpp | 2 +- src/core/crypto/crypto_platform.cpp | 2 +- src/core/diags/factory_diags.cpp | 2 +- src/core/{common => instance}/extension.hpp | 0 src/core/{common => instance}/extension_example.cpp | 2 +- src/core/{common => instance}/instance.cpp | 0 src/core/{common => instance}/instance.hpp | 2 +- src/core/mac/data_poll_handler.cpp | 2 +- src/core/mac/data_poll_sender.cpp | 2 +- src/core/mac/link_raw.cpp | 2 +- src/core/mac/mac.cpp | 2 +- src/core/mac/mac_links.cpp | 2 +- src/core/mac/sub_mac.cpp | 2 +- src/core/mac/sub_mac_callbacks.cpp | 2 +- src/core/meshcop/announce_begin_client.cpp | 2 +- src/core/meshcop/border_agent.cpp | 2 +- src/core/meshcop/commissioner.cpp | 2 +- src/core/meshcop/dataset.cpp | 2 +- src/core/meshcop/dataset_local.cpp | 2 +- src/core/meshcop/dataset_manager.cpp | 2 +- src/core/meshcop/dataset_manager_ftd.cpp | 2 +- src/core/meshcop/dataset_updater.cpp | 2 +- src/core/meshcop/dtls.cpp | 2 +- src/core/meshcop/energy_scan_client.cpp | 2 +- src/core/meshcop/joiner.cpp | 2 +- src/core/meshcop/joiner_router.cpp | 2 +- src/core/meshcop/meshcop_leader.cpp | 2 +- src/core/meshcop/panid_query_client.cpp | 2 +- src/core/net/dhcp6_client.cpp | 2 +- src/core/net/dhcp6_server.cpp | 2 +- src/core/net/dns_client.cpp | 2 +- src/core/net/dns_dso.cpp | 2 +- src/core/net/dns_platform.cpp | 2 +- src/core/net/dns_types.cpp | 2 +- src/core/net/dnssd_server.cpp | 2 +- src/core/net/icmp6.cpp | 2 +- src/core/net/ip6.cpp | 2 +- src/core/net/ip6_address.cpp | 2 +- src/core/net/ip6_filter.cpp | 2 +- src/core/net/ip6_mpl.cpp | 2 +- src/core/net/netif.cpp | 2 +- src/core/net/sntp_client.cpp | 2 +- src/core/net/srp_client.cpp | 2 +- src/core/net/srp_server.cpp | 2 +- src/core/net/tcp6.cpp | 2 +- src/core/net/udp6.cpp | 2 +- src/core/radio/radio_callbacks.cpp | 2 +- src/core/radio/radio_platform.cpp | 2 +- src/core/radio/trel_interface.cpp | 2 +- src/core/radio/trel_link.cpp | 2 +- src/core/radio/trel_packet.cpp | 2 +- src/core/thread/address_resolver.cpp | 2 +- src/core/thread/announce_begin_server.cpp | 2 +- src/core/thread/announce_sender.cpp | 2 +- src/core/thread/anycast_locator.cpp | 2 +- src/core/thread/child.cpp | 2 +- src/core/thread/child_supervision.cpp | 2 +- src/core/thread/child_table.cpp | 2 +- src/core/thread/discover_scanner.cpp | 2 +- src/core/thread/dua_manager.cpp | 2 +- src/core/thread/energy_scan_server.cpp | 2 +- src/core/thread/indirect_sender.cpp | 2 +- src/core/thread/key_manager.cpp | 2 +- src/core/thread/link_metrics.cpp | 2 +- src/core/thread/link_quality.cpp | 2 +- src/core/thread/lowpan.cpp | 2 +- src/core/thread/mesh_forwarder.cpp | 2 +- src/core/thread/mle.cpp | 2 +- src/core/thread/mle_router.cpp | 2 +- src/core/thread/mlr_manager.cpp | 2 +- src/core/thread/neighbor.cpp | 2 +- src/core/thread/neighbor_table.cpp | 2 +- src/core/thread/network_data.cpp | 2 +- src/core/thread/network_data_leader.cpp | 2 +- src/core/thread/network_data_leader_ftd.cpp | 2 +- src/core/thread/network_data_local.cpp | 2 +- src/core/thread/network_data_notifier.cpp | 2 +- src/core/thread/network_data_publisher.cpp | 2 +- src/core/thread/network_data_service.cpp | 2 +- src/core/thread/network_data_types.cpp | 2 +- src/core/thread/network_diagnostic.cpp | 2 +- src/core/thread/panid_query_server.cpp | 2 +- src/core/thread/radio_selector.cpp | 2 +- src/core/thread/router.cpp | 2 +- src/core/thread/router_table.cpp | 2 +- src/core/thread/src_match_controller.cpp | 2 +- src/core/thread/thread_netif.cpp | 2 +- src/core/thread/time_sync_service.cpp | 2 +- src/core/utils/channel_manager.cpp | 2 +- src/core/utils/flash.cpp | 2 +- src/core/utils/history_tracker.cpp | 2 +- src/core/utils/jam_detector.cpp | 2 +- src/core/utils/mesh_diag.cpp | 2 +- src/core/utils/slaac_address.cpp | 2 +- src/core/utils/srp_client_buffers.cpp | 2 +- src/ncp/ncp_base.hpp | 2 +- src/ncp/ncp_base_ftd.cpp | 2 +- src/ncp/ncp_base_mtd.cpp | 2 +- src/ncp/ncp_base_radio.cpp | 2 +- src/ncp/ncp_hdlc.cpp | 2 +- src/ncp/ncp_spi.cpp | 2 +- tests/unit/test_array.cpp | 2 +- tests/unit/test_checksum.cpp | 2 +- tests/unit/test_child.cpp | 2 +- tests/unit/test_child_table.cpp | 2 +- tests/unit/test_cmd_line_parser.cpp | 2 +- tests/unit/test_dns.cpp | 2 +- tests/unit/test_dns_client.cpp | 2 +- tests/unit/test_dso.cpp | 2 +- tests/unit/test_hdlc.cpp | 2 +- tests/unit/test_link_metrics_manager.cpp | 2 +- tests/unit/test_linked_list.cpp | 2 +- tests/unit/test_lowpan.hpp | 2 +- tests/unit/test_message.cpp | 2 +- tests/unit/test_message_queue.cpp | 2 +- tests/unit/test_multicast_listeners_table.cpp | 2 +- tests/unit/test_nat64.cpp | 2 +- tests/unit/test_ndproxy_table.cpp | 2 +- tests/unit/test_netif.cpp | 2 +- tests/unit/test_network_data.cpp | 2 +- tests/unit/test_platform.h | 2 +- tests/unit/test_pool.cpp | 2 +- tests/unit/test_priority_queue.cpp | 2 +- tests/unit/test_routing_manager.cpp | 2 +- tests/unit/test_spinel_buffer.cpp | 2 +- tests/unit/test_spinel_decoder.cpp | 2 +- tests/unit/test_spinel_encoder.cpp | 2 +- tests/unit/test_srp_server.cpp | 2 +- tests/unit/test_timer.cpp | 2 +- tests/unit/test_tlv.cpp | 2 +- tests/unit/test_trickle_timer.cpp | 2 +- 158 files changed, 162 insertions(+), 161 deletions(-) rename src/core/{common => instance}/extension.hpp (100%) rename src/core/{common => instance}/extension_example.cpp (98%) rename src/core/{common => instance}/instance.cpp (100%) rename src/core/{common => instance}/instance.hpp (99%) diff --git a/script/check-simulation-build-cmake b/script/check-simulation-build-cmake index fc7af8e052..ee1e2ffa59 100755 --- a/script/check-simulation-build-cmake +++ b/script/check-simulation-build-cmake @@ -188,7 +188,7 @@ build_all_features() reset_source "$(dirname "$0")"/cmake-build simulation \ -DOT_THREAD_VERSION=1.1 \ - -DOT_VENDOR_EXTENSION=../../src/core/common/extension_example.cpp + -DOT_VENDOR_EXTENSION=../../src/core/instance/extension_example.cpp # Build Thread 1.3 with no additional features reset_source @@ -249,7 +249,7 @@ build_nest_common() mkdir build && cd build CFLAGS="${cppflags[*]} ${CFLAGS}" CXXFLAGS="${cppflags[*]} ${CXXFLAGS}" \ cmake -GNinja -DOT_PLATFORM=simulation \ - -DOT_VENDOR_EXTENSION=common/extension_example.cpp \ + -DOT_VENDOR_EXTENSION=instance/extension_example.cpp \ -DOT_NCP_VENDOR_HOOK_SOURCE=example_vendor_hook.cpp \ .. ninja diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index a581088a1b..cc16bf1a4f 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -82,8 +82,8 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/type_traits.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index d44f410fdf..abb606ed77 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -396,7 +396,6 @@ openthread_core_files = [ "common/equatable.hpp", "common/error.cpp", "common/error.hpp", - "common/extension.hpp", "common/frame_builder.cpp", "common/frame_builder.hpp", "common/frame_data.cpp", @@ -409,8 +408,6 @@ openthread_core_files = [ "common/heap_data.hpp", "common/heap_string.cpp", "common/heap_string.hpp", - "common/instance.cpp", - "common/instance.hpp", "common/iterator_utils.hpp", "common/linked_list.hpp", "common/locator.hpp", @@ -474,6 +471,9 @@ openthread_core_files = [ "crypto/storage.hpp", "diags/factory_diags.cpp", "diags/factory_diags.hpp", + "instance/extension.hpp", + "instance/instance.cpp", + "instance/instance.hpp", "mac/channel_mask.cpp", "mac/channel_mask.hpp", "mac/data_poll_handler.cpp", @@ -737,7 +737,6 @@ openthread_radio_sources = [ "common/error.hpp", "common/frame_builder.cpp", "common/frame_builder.hpp", - "common/instance.cpp", "common/log.cpp", "common/random.cpp", "common/string.cpp", @@ -749,6 +748,7 @@ openthread_radio_sources = [ "crypto/crypto_platform.cpp", "crypto/storage.cpp", "diags/factory_diags.cpp", + "instance/instance.cpp", "mac/link_raw.cpp", "mac/mac_frame.cpp", "mac/mac_types.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c8e4079ab0..813979ad7a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -106,7 +106,6 @@ set(COMMON_SOURCES common/heap.cpp common/heap_data.cpp common/heap_string.cpp - common/instance.cpp common/log.cpp common/message.cpp common/notifier.cpp @@ -129,6 +128,7 @@ set(COMMON_SOURCES crypto/sha256.cpp crypto/storage.cpp diags/factory_diags.cpp + instance/instance.cpp mac/channel_mask.cpp mac/data_poll_handler.cpp mac/data_poll_sender.cpp @@ -265,7 +265,6 @@ set(RADIO_COMMON_SOURCES common/binary_search.cpp common/error.cpp common/frame_builder.cpp - common/instance.cpp common/log.cpp common/random.cpp common/string.cpp @@ -277,6 +276,7 @@ set(RADIO_COMMON_SOURCES crypto/crypto_platform.cpp crypto/storage.cpp diags/factory_diags.cpp + instance/instance.cpp mac/link_raw.cpp mac/mac_frame.cpp mac/mac_types.cpp diff --git a/src/core/api/border_router_api.cpp b/src/core/api/border_router_api.cpp index 5694768e9b..dcccf5bb6a 100644 --- a/src/core/api/border_router_api.cpp +++ b/src/core/api/border_router_api.cpp @@ -39,7 +39,7 @@ #include "border_router/routing_manager.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/src/core/api/border_routing_api.cpp b/src/core/api/border_routing_api.cpp index 1ed017c575..3a76fa668a 100644 --- a/src/core/api/border_routing_api.cpp +++ b/src/core/api/border_routing_api.cpp @@ -39,7 +39,7 @@ #include #include "border_router/routing_manager.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/src/core/api/dns_api.cpp b/src/core/api/dns_api.cpp index 41be0c4fdb..fe064b6602 100644 --- a/src/core/api/dns_api.cpp +++ b/src/core/api/dns_api.cpp @@ -35,7 +35,7 @@ #include -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" using namespace ot; diff --git a/src/core/api/dns_server_api.cpp b/src/core/api/dns_server_api.cpp index 62e69fc17e..80e88e4327 100644 --- a/src/core/api/dns_server_api.cpp +++ b/src/core/api/dns_server_api.cpp @@ -33,7 +33,7 @@ #include "openthread-core-config.h" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" #include "net/dnssd_server.hpp" diff --git a/src/core/api/logging_api.cpp b/src/core/api/logging_api.cpp index edce6b9201..9fa3e0c750 100644 --- a/src/core/api/logging_api.cpp +++ b/src/core/api/logging_api.cpp @@ -35,9 +35,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "common/string.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/src/core/api/nat64_api.cpp b/src/core/api/nat64_api.cpp index 7405b9d6cd..02aa785b45 100644 --- a/src/core/api/nat64_api.cpp +++ b/src/core/api/nat64_api.cpp @@ -39,7 +39,7 @@ #include "border_router/routing_manager.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/ip4_types.hpp" #include "net/ip6_headers.hpp" #include "net/nat64_translator.hpp" diff --git a/src/core/api/trel_api.cpp b/src/core/api/trel_api.cpp index 29c1563a65..687c1169cc 100644 --- a/src/core/api/trel_api.cpp +++ b/src/core/api/trel_api.cpp @@ -39,7 +39,7 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" using namespace ot; diff --git a/src/core/backbone_router/bbr_leader.cpp b/src/core/backbone_router/bbr_leader.cpp index efced1bb5c..5b605ac5e1 100644 --- a/src/core/backbone_router/bbr_leader.cpp +++ b/src/core/backbone_router/bbr_leader.cpp @@ -35,8 +35,8 @@ #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { namespace BackboneRouter { diff --git a/src/core/backbone_router/bbr_local.cpp b/src/core/backbone_router/bbr_local.cpp index 7c1289b06e..9c922df957 100644 --- a/src/core/backbone_router/bbr_local.cpp +++ b/src/core/backbone_router/bbr_local.cpp @@ -36,10 +36,10 @@ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/backbone_router/bbr_manager.cpp b/src/core/backbone_router/bbr_manager.cpp index 09c1c76561..a677b6d74e 100644 --- a/src/core/backbone_router/bbr_manager.cpp +++ b/src/core/backbone_router/bbr_manager.cpp @@ -37,11 +37,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" #include "thread/thread_tlvs.hpp" diff --git a/src/core/backbone_router/multicast_listeners_table.cpp b/src/core/backbone_router/multicast_listeners_table.cpp index 4f477cdee1..22e4e320a7 100644 --- a/src/core/backbone_router/multicast_listeners_table.cpp +++ b/src/core/backbone_router/multicast_listeners_table.cpp @@ -37,10 +37,10 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" #include "thread/uri_paths.hpp" diff --git a/src/core/border_router/infra_if.cpp b/src/core/border_router/infra_if.cpp index 53e4fc2a69..98f5706675 100644 --- a/src/core/border_router/infra_if.cpp +++ b/src/core/border_router/infra_if.cpp @@ -37,9 +37,9 @@ #include "border_router/routing_manager.hpp" #include "common/as_core_type.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/logging.hpp" +#include "instance/instance.hpp" #include "net/icmp6.hpp" namespace ot { diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 97fbad55fe..2b073b4b98 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -44,13 +44,13 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" #include "common/random.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "meshcop/extended_panid.hpp" #include "net/ip6.hpp" #include "net/nat64_translator.hpp" diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index 38e5618581..696d0fc838 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -32,10 +32,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/udp6.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/coap/coap_message.cpp b/src/core/coap/coap_message.cpp index 72fb6148e7..61c2ae0ab8 100644 --- a/src/core/coap/coap_message.cpp +++ b/src/core/coap/coap_message.cpp @@ -38,9 +38,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/random.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" namespace ot { namespace Coap { diff --git a/src/core/coap/coap_secure.cpp b/src/core/coap/coap_secure.cpp index 3f5730afb1..7d0fbe1b3f 100644 --- a/src/core/coap/coap_secure.cpp +++ b/src/core/coap/coap_secure.cpp @@ -30,10 +30,10 @@ #if OPENTHREAD_CONFIG_DTLS_ENABLE -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/new.hpp" +#include "instance/instance.hpp" #include "meshcop/dtls.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/common/heap.cpp b/src/core/common/heap.cpp index 7b431ee308..cc403467be 100644 --- a/src/core/common/heap.cpp +++ b/src/core/common/heap.cpp @@ -33,7 +33,7 @@ #include "heap.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" namespace ot { namespace Heap { diff --git a/src/core/common/locator_getters.hpp b/src/core/common/locator_getters.hpp index 990b8c6d62..ad9067f54a 100644 --- a/src/core/common/locator_getters.hpp +++ b/src/core/common/locator_getters.hpp @@ -37,9 +37,9 @@ #include "openthread-core-config.h" -#include "common/instance.hpp" #include "common/locator.hpp" #include "common/tasklet.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/common/log.cpp b/src/core/common/log.cpp index 04c74bbb2e..db13ac86fd 100644 --- a/src/core/common/log.cpp +++ b/src/core/common/log.cpp @@ -38,9 +38,9 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" /* * Verify debug UART dependency. diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index bdb513ab88..1c7028d0fa 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -37,11 +37,11 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/heap.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/ip6.hpp" diff --git a/src/core/common/settings.cpp b/src/core/common/settings.cpp index c9b6f3ad7f..504eb7c566 100644 --- a/src/core/common/settings.cpp +++ b/src/core/common/settings.cpp @@ -35,9 +35,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" #include "meshcop/dataset.hpp" #include "thread/mle.hpp" diff --git a/src/core/common/time_ticker.cpp b/src/core/common/time_ticker.cpp index 368650481d..4cc59c1c67 100644 --- a/src/core/common/time_ticker.cpp +++ b/src/core/common/time_ticker.cpp @@ -35,9 +35,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/mle_router.hpp" namespace ot { diff --git a/src/core/common/timer.cpp b/src/core/common/timer.cpp index 7722cae3f9..5484f20d06 100644 --- a/src/core/common/timer.cpp +++ b/src/core/common/timer.cpp @@ -36,8 +36,8 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/common/uptime.cpp b/src/core/common/uptime.cpp index 4cf0a34c78..3d9e6afde5 100644 --- a/src/core/common/uptime.cpp +++ b/src/core/common/uptime.cpp @@ -37,8 +37,8 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/crypto/crypto_platform.cpp b/src/core/crypto/crypto_platform.cpp index 0b9250d42f..2d71d0eebe 100644 --- a/src/core/crypto/crypto_platform.cpp +++ b/src/core/crypto/crypto_platform.cpp @@ -51,12 +51,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/new.hpp" #include "config/crypto.h" #include "crypto/ecdsa.hpp" #include "crypto/hmac_sha256.hpp" #include "crypto/storage.hpp" +#include "instance/instance.hpp" using namespace ot; using namespace Crypto; diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp index 5eed151f39..249594f77a 100644 --- a/src/core/diags/factory_diags.cpp +++ b/src/core/diags/factory_diags.cpp @@ -43,8 +43,8 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "radio/radio.hpp" #include "utils/parse_cmdline.hpp" diff --git a/src/core/common/extension.hpp b/src/core/instance/extension.hpp similarity index 100% rename from src/core/common/extension.hpp rename to src/core/instance/extension.hpp diff --git a/src/core/common/extension_example.cpp b/src/core/instance/extension_example.cpp similarity index 98% rename from src/core/common/extension_example.cpp rename to src/core/instance/extension_example.cpp index f392b31fb6..c1bebfbd5a 100644 --- a/src/core/common/extension_example.cpp +++ b/src/core/instance/extension_example.cpp @@ -37,8 +37,8 @@ #include #include "common/code_utils.hpp" -#include "common/extension.hpp" #include "common/new.hpp" +#include "instance/extension.hpp" namespace ot { namespace Extension { diff --git a/src/core/common/instance.cpp b/src/core/instance/instance.cpp similarity index 100% rename from src/core/common/instance.cpp rename to src/core/instance/instance.cpp diff --git a/src/core/common/instance.hpp b/src/core/instance/instance.hpp similarity index 99% rename from src/core/common/instance.hpp rename to src/core/instance/instance.hpp index d213c692e0..6b26825abd 100644 --- a/src/core/common/instance.hpp +++ b/src/core/instance/instance.hpp @@ -47,7 +47,6 @@ #include "common/array.hpp" #include "common/as_core_type.hpp" #include "common/error.hpp" -#include "common/extension.hpp" #include "common/log.hpp" #include "common/message.hpp" #include "common/non_copyable.hpp" @@ -57,6 +56,7 @@ #include "common/timer.hpp" #include "common/uptime.hpp" #include "diags/factory_diags.hpp" +#include "instance/extension.hpp" #include "mac/link_raw.hpp" #include "radio/radio.hpp" #include "utils/otns.hpp" diff --git a/src/core/mac/data_poll_handler.cpp b/src/core/mac/data_poll_handler.cpp index d832c1c799..226ab087ea 100644 --- a/src/core/mac/data_poll_handler.cpp +++ b/src/core/mac/data_poll_handler.cpp @@ -36,9 +36,9 @@ #if OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/mac/data_poll_sender.cpp b/src/core/mac/data_poll_sender.cpp index 93fad6b83d..80e18f7a5b 100644 --- a/src/core/mac/data_poll_sender.cpp +++ b/src/core/mac/data_poll_sender.cpp @@ -34,11 +34,11 @@ #include "data_poll_sender.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/message.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/netif.hpp" #include "thread/mesh_forwarder.hpp" diff --git a/src/core/mac/link_raw.cpp b/src/core/mac/link_raw.cpp index b9c4f6ee45..be433815fd 100644 --- a/src/core/mac/link_raw.cpp +++ b/src/core/mac/link_raw.cpp @@ -40,10 +40,10 @@ #include #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "mac/mac_frame.hpp" namespace ot { diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index aa13d3a963..3432ce0ae6 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -40,12 +40,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/random.hpp" #include "common/string.hpp" #include "crypto/aes_ccm.hpp" #include "crypto/sha256.hpp" +#include "instance/instance.hpp" #include "mac/mac_frame.hpp" #include "radio/radio.hpp" #include "thread/child.hpp" diff --git a/src/core/mac/mac_links.cpp b/src/core/mac/mac_links.cpp index 19b9df38fe..481f0f0eb3 100644 --- a/src/core/mac/mac_links.cpp +++ b/src/core/mac/mac_links.cpp @@ -34,8 +34,8 @@ #include "mac_links.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { namespace Mac { diff --git a/src/core/mac/sub_mac.cpp b/src/core/mac/sub_mac.cpp index a5b3a5f326..86e58c2765 100644 --- a/src/core/mac/sub_mac.cpp +++ b/src/core/mac/sub_mac.cpp @@ -39,12 +39,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #include "mac/mac_frame.hpp" namespace ot { diff --git a/src/core/mac/sub_mac_callbacks.cpp b/src/core/mac/sub_mac_callbacks.cpp index ba0269e0f3..a6e7615318 100644 --- a/src/core/mac/sub_mac_callbacks.cpp +++ b/src/core/mac/sub_mac_callbacks.cpp @@ -34,8 +34,8 @@ #include "sub_mac.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #if OPENTHREAD_FTD || OPENTHREAD_MTD #include "mac/mac.hpp" diff --git a/src/core/meshcop/announce_begin_client.cpp b/src/core/meshcop/announce_begin_client.cpp index f0cde456fd..5d3b9d9c53 100644 --- a/src/core/meshcop/announce_begin_client.cpp +++ b/src/core/meshcop/announce_begin_client.cpp @@ -38,9 +38,9 @@ #include "coap/coap_message.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/meshcop/border_agent.cpp b/src/core/meshcop/border_agent.cpp index d38d78d8ad..4cacfcbc11 100644 --- a/src/core/meshcop/border_agent.cpp +++ b/src/core/meshcop/border_agent.cpp @@ -38,11 +38,11 @@ #include "coap/coap_message.hpp" #include "common/as_core_type.hpp" #include "common/heap.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/owned_ptr.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 1bc30b0427..1e0223cfa1 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -41,9 +41,9 @@ #include "common/array.hpp" #include "common/as_core_type.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "meshcop/joiner.hpp" #include "meshcop/joiner_router.hpp" #include "meshcop/meshcop.hpp" diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 60aa0dae04..9bab49d33f 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -38,9 +38,9 @@ #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "meshcop/timestamp.hpp" diff --git a/src/core/meshcop/dataset_local.cpp b/src/core/meshcop/dataset_local.cpp index 58370c3fbb..ac1095732c 100644 --- a/src/core/meshcop/dataset_local.cpp +++ b/src/core/meshcop/dataset_local.cpp @@ -37,11 +37,11 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/settings.hpp" #include "crypto/storage.hpp" +#include "instance/instance.hpp" #include "meshcop/dataset.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/mle_tlvs.hpp" diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 043f88c2a2..a4ad59545d 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -37,10 +37,10 @@ #include #include "common/as_core_type.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/notifier.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "radio/radio.hpp" diff --git a/src/core/meshcop/dataset_manager_ftd.cpp b/src/core/meshcop/dataset_manager_ftd.cpp index 0fe978d30a..0ef2b5cdd3 100644 --- a/src/core/meshcop/dataset_manager_ftd.cpp +++ b/src/core/meshcop/dataset_manager_ftd.cpp @@ -44,11 +44,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" #include "meshcop/dataset.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_leader.hpp" diff --git a/src/core/meshcop/dataset_updater.cpp b/src/core/meshcop/dataset_updater.cpp index 114bae5506..0ba5b1db22 100644 --- a/src/core/meshcop/dataset_updater.cpp +++ b/src/core/meshcop/dataset_updater.cpp @@ -37,10 +37,10 @@ #if (OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE || OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE) && OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "meshcop/timestamp.hpp" namespace ot { diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/dtls.cpp index 28337a62e6..e3c2275f16 100644 --- a/src/core/meshcop/dtls.cpp +++ b/src/core/meshcop/dtls.cpp @@ -44,12 +44,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/timer.hpp" #include "crypto/mbedtls.hpp" #include "crypto/sha256.hpp" +#include "instance/instance.hpp" #include "thread/thread_netif.hpp" #if OPENTHREAD_CONFIG_DTLS_ENABLE diff --git a/src/core/meshcop/energy_scan_client.cpp b/src/core/meshcop/energy_scan_client.cpp index 905d8a66f2..beea65caac 100644 --- a/src/core/meshcop/energy_scan_client.cpp +++ b/src/core/meshcop/energy_scan_client.cpp @@ -40,10 +40,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 86bd25ffe7..50b02e9239 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -42,10 +42,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "radio/radio.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index 09616023c3..4794acb67f 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -40,9 +40,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/mle.hpp" diff --git a/src/core/meshcop/meshcop_leader.cpp b/src/core/meshcop/meshcop_leader.cpp index 5f97185d4f..59b50683a6 100644 --- a/src/core/meshcop/meshcop_leader.cpp +++ b/src/core/meshcop/meshcop_leader.cpp @@ -40,10 +40,10 @@ #include "coap/coap_message.hpp" #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/meshcop/panid_query_client.cpp b/src/core/meshcop/panid_query_client.cpp index 8c6a004ef4..431e8c2fab 100644 --- a/src/core/meshcop/panid_query_client.cpp +++ b/src/core/meshcop/panid_query_client.cpp @@ -39,9 +39,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp index db671357ae..680ea049e1 100644 --- a/src/core/net/dhcp6_client.cpp +++ b/src/core/net/dhcp6_client.cpp @@ -38,9 +38,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "mac/mac.hpp" #include "net/dhcp6.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/dhcp6_server.cpp b/src/core/net/dhcp6_server.cpp index 826d5fefcd..dc9ced5d3d 100644 --- a/src/core/net/dhcp6_server.cpp +++ b/src/core/net/dhcp6_server.cpp @@ -39,9 +39,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "thread/mle.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index ef3fb3da20..df7c737a18 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -34,9 +34,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "net/udp6.hpp" #include "thread/network_data_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/dns_dso.cpp b/src/core/net/dns_dso.cpp index 179e57cee0..175afbcda3 100644 --- a/src/core/net/dns_dso.cpp +++ b/src/core/net/dns_dso.cpp @@ -34,11 +34,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" /** * @file diff --git a/src/core/net/dns_platform.cpp b/src/core/net/dns_platform.cpp index ef48077b6d..109f018e7d 100644 --- a/src/core/net/dns_platform.cpp +++ b/src/core/net/dns_platform.cpp @@ -37,8 +37,8 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE diff --git a/src/core/net/dns_types.cpp b/src/core/net/dns_types.cpp index ec640b2944..a9585a22c1 100644 --- a/src/core/net/dns_types.cpp +++ b/src/core/net/dns_types.cpp @@ -35,10 +35,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" namespace ot { namespace Dns { diff --git a/src/core/net/dnssd_server.cpp b/src/core/net/dnssd_server.cpp index 3406c3d908..ea59c08d51 100644 --- a/src/core/net/dnssd_server.cpp +++ b/src/core/net/dnssd_server.cpp @@ -41,10 +41,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "net/srp_server.hpp" #include "net/udp6.hpp" diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index 2f195b0aba..5bcea06c03 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -35,10 +35,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/ip6.hpp" diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 5fc60089f5..9be6ec9514 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -38,11 +38,11 @@ #include "backbone_router/ndproxy_table.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/message.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/icmp6.hpp" #include "net/ip6_address.hpp" diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index e6d924296a..3686c19552 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -39,10 +39,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/ip4_types.hpp" #include "net/netif.hpp" diff --git a/src/core/net/ip6_filter.cpp b/src/core/net/ip6_filter.cpp index 0104fac814..1dae10c71d 100644 --- a/src/core/net/ip6_filter.cpp +++ b/src/core/net/ip6_filter.cpp @@ -36,9 +36,9 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "net/ip6.hpp" #include "net/tcp6.hpp" diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 6fbdf385b3..78922ef6f2 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -35,11 +35,11 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/message.hpp" #include "common/random.hpp" #include "common/serial_number.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" namespace ot { diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index b8a99a1530..5d31906c47 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -35,9 +35,9 @@ #include "common/as_core_type.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" namespace ot { diff --git a/src/core/net/sntp_client.cpp b/src/core/net/sntp_client.cpp index bc79e3d9be..5897a5f3bc 100644 --- a/src/core/net/sntp_client.cpp +++ b/src/core/net/sntp_client.cpp @@ -34,9 +34,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "net/udp6.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index eae23025c7..9663d9299c 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -33,12 +33,12 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/settings.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" /** * @file diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 2a57c9217e..aaaaaa71f8 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -37,13 +37,13 @@ #include "common/as_core_type.hpp" #include "common/const_cast.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/new.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/net/tcp6.cpp b/src/core/net/tcp6.cpp index 74d598a82c..dccb41bb2e 100644 --- a/src/core/net/tcp6.cpp +++ b/src/core/net/tcp6.cpp @@ -40,11 +40,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/error.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/ip6.hpp" #include "net/netif.hpp" diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index 3ddda61cd1..4fff66d35f 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -39,8 +39,8 @@ #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/ip6.hpp" diff --git a/src/core/radio/radio_callbacks.cpp b/src/core/radio/radio_callbacks.cpp index ae85c77806..6a6131c19f 100644 --- a/src/core/radio/radio_callbacks.cpp +++ b/src/core/radio/radio_callbacks.cpp @@ -33,8 +33,8 @@ #include "radio.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/radio/radio_platform.cpp b/src/core/radio/radio_platform.cpp index 7840a867cf..d1f6866ed8 100644 --- a/src/core/radio/radio_platform.cpp +++ b/src/core/radio/radio_platform.cpp @@ -35,7 +35,7 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "radio/radio.hpp" using namespace ot; diff --git a/src/core/radio/trel_interface.cpp b/src/core/radio/trel_interface.cpp index 2f69c7d0a9..acbe3e5e7d 100644 --- a/src/core/radio/trel_interface.cpp +++ b/src/core/radio/trel_interface.cpp @@ -40,10 +40,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" namespace ot { diff --git a/src/core/radio/trel_link.cpp b/src/core/radio/trel_link.cpp index 203e0dfeb5..4735f379e3 100644 --- a/src/core/radio/trel_link.cpp +++ b/src/core/radio/trel_link.cpp @@ -36,9 +36,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" namespace ot { namespace Trel { diff --git a/src/core/radio/trel_packet.cpp b/src/core/radio/trel_packet.cpp index 2847b6001c..f28129f72a 100644 --- a/src/core/radio/trel_packet.cpp +++ b/src/core/radio/trel_packet.cpp @@ -36,8 +36,8 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { namespace Trel { diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index 2337f81859..a779a11588 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -38,10 +38,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "thread/mesh_forwarder.hpp" #include "thread/mle_router.hpp" diff --git a/src/core/thread/announce_begin_server.cpp b/src/core/thread/announce_begin_server.cpp index 1c904e358a..4db912dd2b 100644 --- a/src/core/thread/announce_begin_server.cpp +++ b/src/core/thread/announce_begin_server.cpp @@ -39,9 +39,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" #include "thread/uri_paths.hpp" diff --git a/src/core/thread/announce_sender.cpp b/src/core/thread/announce_sender.cpp index 810939e4cc..4a8ece2c8a 100644 --- a/src/core/thread/announce_sender.cpp +++ b/src/core/thread/announce_sender.cpp @@ -36,10 +36,10 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "radio/radio.hpp" diff --git a/src/core/thread/anycast_locator.cpp b/src/core/thread/anycast_locator.cpp index 88a02d4e18..14e0fd8436 100644 --- a/src/core/thread/anycast_locator.cpp +++ b/src/core/thread/anycast_locator.cpp @@ -37,8 +37,8 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "thread/thread_tlvs.hpp" #include "thread/uri_paths.hpp" diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index 7dbec0c401..008173b6d9 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -36,9 +36,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/child_supervision.cpp b/src/core/thread/child_supervision.cpp index 02ba64ada8..c645afce24 100644 --- a/src/core/thread/child_supervision.cpp +++ b/src/core/thread/child_supervision.cpp @@ -35,9 +35,9 @@ #include "openthread-core-config.h" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "thread/thread_netif.hpp" namespace ot { diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index e5ec209366..cd9cb65492 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -36,8 +36,8 @@ #if OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 0fa311c906..2425e1e3af 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -35,8 +35,8 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "thread/mesh_forwarder.hpp" #include "thread/mle.hpp" #include "thread/mle_router.hpp" diff --git a/src/core/thread/dua_manager.cpp b/src/core/thread/dua_manager.cpp index 934f338700..20fb792e85 100644 --- a/src/core/thread/dua_manager.cpp +++ b/src/core/thread/dua_manager.cpp @@ -37,10 +37,10 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "net/ip6_address.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/thread/energy_scan_server.cpp b/src/core/thread/energy_scan_server.cpp index c207ef9f3a..a53220c54e 100644 --- a/src/core/thread/energy_scan_server.cpp +++ b/src/core/thread/energy_scan_server.cpp @@ -37,9 +37,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/thread/indirect_sender.cpp b/src/core/thread/indirect_sender.cpp index 7549702ff1..89e8869177 100644 --- a/src/core/thread/indirect_sender.cpp +++ b/src/core/thread/indirect_sender.cpp @@ -36,9 +36,9 @@ #if OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "thread/child.hpp" #include "thread/mesh_forwarder.hpp" #include "thread/mle_tlvs.hpp" diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index ddcbf74ef0..8f37d372c2 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -35,12 +35,12 @@ #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/timer.hpp" #include "crypto/hkdf_sha256.hpp" #include "crypto/storage.hpp" +#include "instance/instance.hpp" #include "thread/mle_router.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 8e76990f74..9bf6e9a18f 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -37,11 +37,11 @@ #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/num_utils.hpp" #include "common/numeric_limits.hpp" +#include "instance/instance.hpp" #include "mac/mac.hpp" #include "thread/link_metrics_tlvs.hpp" #include "thread/neighbor_table.hpp" diff --git a/src/core/thread/link_quality.cpp b/src/core/thread/link_quality.cpp index ed5bbb5bf7..bf6b35b42c 100644 --- a/src/core/thread/link_quality.cpp +++ b/src/core/thread/link_quality.cpp @@ -36,9 +36,9 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/lowpan.cpp b/src/core/thread/lowpan.cpp index a31519b3a5..c00506c317 100644 --- a/src/core/thread/lowpan.cpp +++ b/src/core/thread/lowpan.cpp @@ -36,8 +36,8 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/udp6.hpp" #include "thread/network_data_leader.hpp" diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 413321c283..233d653f90 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -36,11 +36,11 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/message.hpp" #include "common/random.hpp" #include "common/time_ticker.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/ip6_filter.hpp" #include "net/netif.hpp" diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index fa67446df9..cc8936c842 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -41,12 +41,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/serial_number.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "net/netif.hpp" diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 414bb75563..e6b24488aa 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -38,12 +38,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" #include "common/random.hpp" #include "common/serial_number.hpp" #include "common/settings.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "meshcop/meshcop.hpp" #include "net/icmp6.hpp" diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 3d988a73ec..4fd5355f49 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -37,9 +37,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "net/ip6_address.hpp" #include "thread/thread_netif.hpp" #include "thread/uri_paths.hpp" diff --git a/src/core/thread/neighbor.cpp b/src/core/thread/neighbor.cpp index 868c762d5a..d86956870d 100644 --- a/src/core/thread/neighbor.cpp +++ b/src/core/thread/neighbor.cpp @@ -36,9 +36,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/neighbor_table.cpp b/src/core/thread/neighbor_table.cpp index 39bd0663dc..2174141212 100644 --- a/src/core/thread/neighbor_table.cpp +++ b/src/core/thread/neighbor_table.cpp @@ -34,8 +34,8 @@ #include "neighbor_table.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "thread/dua_manager.hpp" namespace ot { diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 009e67515e..2599d653ba 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -37,9 +37,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "thread/thread_netif.hpp" #include "thread/thread_tlvs.hpp" diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 5171aa6642..55bbcec99a 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -37,12 +37,12 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/logging.hpp" #include "common/message.hpp" #include "common/random.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "thread/lowpan.hpp" #include "thread/mle_router.hpp" diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index c3f219a9cd..e7696606d1 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -40,11 +40,11 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/message.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "meshcop/meshcop.hpp" #include "thread/lowpan.hpp" diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp index b99900fd59..1e92266c28 100644 --- a/src/core/thread/network_data_local.cpp +++ b/src/core/thread/network_data_local.cpp @@ -37,9 +37,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/thread/network_data_notifier.cpp b/src/core/thread/network_data_notifier.cpp index 657c0e3b54..750b3799b4 100644 --- a/src/core/thread/network_data_notifier.cpp +++ b/src/core/thread/network_data_notifier.cpp @@ -36,9 +36,9 @@ #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "thread/network_data_leader.hpp" #include "thread/network_data_local.hpp" #include "thread/tmf.hpp" diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index 056765cb9c..6094eddef3 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -39,10 +39,10 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/const_cast.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/network_data_local.hpp" #include "thread/network_data_service.hpp" diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 1d2e90dbae..ab1af15e59 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -35,8 +35,8 @@ #include "network_data_service.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" #include "thread/network_data_local.hpp" namespace ot { diff --git a/src/core/thread/network_data_types.cpp b/src/core/thread/network_data_types.cpp index 1793f2b4c1..be349ab907 100644 --- a/src/core/thread/network_data_types.cpp +++ b/src/core/thread/network_data_types.cpp @@ -33,7 +33,7 @@ #include "network_data_types.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "thread/network_data_tlvs.hpp" namespace ot { diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 97926091d5..ae1f15499c 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -39,10 +39,10 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "mac/mac.hpp" #include "net/netif.hpp" #include "thread/mesh_forwarder.hpp" diff --git a/src/core/thread/panid_query_server.cpp b/src/core/thread/panid_query_server.cpp index 01df10af8a..19c40c40c2 100644 --- a/src/core/thread/panid_query_server.cpp +++ b/src/core/thread/panid_query_server.cpp @@ -37,9 +37,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/thread/radio_selector.cpp b/src/core/thread/radio_selector.cpp index 965734a0ca..ea7ea74de3 100644 --- a/src/core/thread/radio_selector.cpp +++ b/src/core/thread/radio_selector.cpp @@ -36,10 +36,10 @@ #if OPENTHREAD_CONFIG_MULTI_RADIO #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/router.cpp b/src/core/thread/router.cpp index c99fec132f..d16d635e54 100644 --- a/src/core/thread/router.cpp +++ b/src/core/thread/router.cpp @@ -36,9 +36,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index b462c69ead..1302ce7884 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -31,10 +31,10 @@ #if OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" #include "thread/mle.hpp" #include "thread/mle_router.hpp" #include "thread/network_data_leader.hpp" diff --git a/src/core/thread/src_match_controller.cpp b/src/core/thread/src_match_controller.cpp index 2d73ce923a..b53db11147 100644 --- a/src/core/thread/src_match_controller.cpp +++ b/src/core/thread/src_match_controller.cpp @@ -37,9 +37,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "radio/radio.hpp" #include "thread/child.hpp" diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index e01d192184..bba16dec63 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -35,9 +35,9 @@ #include "common/code_utils.hpp" #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #include "net/netif.hpp" #include "net/udp6.hpp" diff --git a/src/core/thread/time_sync_service.cpp b/src/core/thread/time_sync_service.cpp index 138c1aa74f..77e3dd3831 100644 --- a/src/core/thread/time_sync_service.cpp +++ b/src/core/thread/time_sync_service.cpp @@ -41,9 +41,9 @@ #include #include -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" #define ABS(value) (((value) >= 0) ? (value) : -(value)) diff --git a/src/core/utils/channel_manager.cpp b/src/core/utils/channel_manager.cpp index 1303509f72..7ed7df4864 100644 --- a/src/core/utils/channel_manager.cpp +++ b/src/core/utils/channel_manager.cpp @@ -37,11 +37,11 @@ #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE && OPENTHREAD_FTD #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "meshcop/dataset_updater.hpp" #include "radio/radio.hpp" diff --git a/src/core/utils/flash.cpp b/src/core/utils/flash.cpp index 243d7d5053..f49e5f6ee8 100644 --- a/src/core/utils/flash.cpp +++ b/src/core/utils/flash.cpp @@ -35,7 +35,7 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/src/core/utils/history_tracker.cpp b/src/core/utils/history_tracker.cpp index 2bcda12fd9..74d8cfb855 100644 --- a/src/core/utils/history_tracker.cpp +++ b/src/core/utils/history_tracker.cpp @@ -38,11 +38,11 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/num_utils.hpp" #include "common/string.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" #include "net/ip6_headers.hpp" namespace ot { diff --git a/src/core/utils/jam_detector.cpp b/src/core/utils/jam_detector.cpp index a628fed6ce..af55ba8243 100644 --- a/src/core/utils/jam_detector.cpp +++ b/src/core/utils/jam_detector.cpp @@ -36,10 +36,10 @@ #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "thread/thread_netif.hpp" namespace ot { diff --git a/src/core/utils/mesh_diag.cpp b/src/core/utils/mesh_diag.cpp index 60d78f15c6..e21cb184c5 100644 --- a/src/core/utils/mesh_diag.cpp +++ b/src/core/utils/mesh_diag.cpp @@ -38,9 +38,9 @@ #include "common/as_core_type.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" +#include "instance/instance.hpp" namespace ot { namespace Utils { diff --git a/src/core/utils/slaac_address.cpp b/src/core/utils/slaac_address.cpp index ade19541c0..dacbbcd55f 100644 --- a/src/core/utils/slaac_address.cpp +++ b/src/core/utils/slaac_address.cpp @@ -37,12 +37,12 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/random.hpp" #include "common/settings.hpp" #include "crypto/sha256.hpp" +#include "instance/instance.hpp" #include "net/ip6_address.hpp" namespace ot { diff --git a/src/core/utils/srp_client_buffers.cpp b/src/core/utils/srp_client_buffers.cpp index cfead0ac2e..098e7ea544 100644 --- a/src/core/utils/srp_client_buffers.cpp +++ b/src/core/utils/srp_client_buffers.cpp @@ -38,8 +38,8 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/locator_getters.hpp" +#include "instance/instance.hpp" namespace ot { namespace Utils { diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index bd1110124e..fa4c856ddb 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -55,8 +55,8 @@ #endif #include "changed_props_set.hpp" -#include "common/instance.hpp" #include "common/tasklet.hpp" +#include "instance/instance.hpp" #include "lib/spinel/spinel.h" #include "lib/spinel/spinel_buffer.hpp" #include "lib/spinel/spinel_decoder.hpp" diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 2ba8751659..b0d7233123 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -50,7 +50,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE #include "meshcop/commissioner.hpp" #endif diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 70d9589823..7d699c7b43 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -70,8 +70,8 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/string.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #if OPENTHREAD_MTD || OPENTHREAD_FTD diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index 11ec6aa0d7..428037e4bc 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -40,7 +40,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "mac/mac_frame.hpp" #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE diff --git a/src/ncp/ncp_hdlc.cpp b/src/ncp/ncp_hdlc.cpp index a18c345cb6..59da424964 100644 --- a/src/ncp/ncp_hdlc.cpp +++ b/src/ncp/ncp_hdlc.cpp @@ -41,8 +41,8 @@ #include "openthread-core-config.h" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/new.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #if OPENTHREAD_CONFIG_NCP_HDLC_ENABLE diff --git a/src/ncp/ncp_spi.cpp b/src/ncp/ncp_spi.cpp index 1cd4f9aab3..c6d1051560 100644 --- a/src/ncp/ncp_spi.cpp +++ b/src/ncp/ncp_spi.cpp @@ -40,8 +40,8 @@ #include "openthread-core-config.h" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/new.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #if OPENTHREAD_CONFIG_NCP_SPI_ENABLE diff --git a/tests/unit/test_array.cpp b/tests/unit/test_array.cpp index 0840f999c7..b185d4170a 100644 --- a/tests/unit/test_array.cpp +++ b/tests/unit/test_array.cpp @@ -36,8 +36,8 @@ #include "common/array.hpp" #include "common/debug.hpp" #include "common/equatable.hpp" -#include "common/instance.hpp" #include "common/type_traits.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_checksum.cpp b/tests/unit/test_checksum.cpp index 82e74fdd7e..c37f5ba62c 100644 --- a/tests/unit/test_checksum.cpp +++ b/tests/unit/test_checksum.cpp @@ -27,9 +27,9 @@ */ #include "common/encoding.hpp" -#include "common/instance.hpp" #include "common/message.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "net/checksum.hpp" #include "net/icmp6.hpp" #include "net/ip4_types.hpp" diff --git a/tests/unit/test_child.cpp b/tests/unit/test_child.cpp index 45fe65a807..0ac2384f31 100644 --- a/tests/unit/test_child.cpp +++ b/tests/unit/test_child.cpp @@ -32,7 +32,7 @@ #include "test_util.h" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "thread/child.hpp" namespace ot { diff --git a/tests/unit/test_child_table.cpp b/tests/unit/test_child_table.cpp index 2fb4583f45..12627f1276 100644 --- a/tests/unit/test_child_table.cpp +++ b/tests/unit/test_child_table.cpp @@ -33,7 +33,7 @@ #include "test_util.h" #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "thread/child_table.hpp" namespace ot { diff --git a/tests/unit/test_cmd_line_parser.cpp b/tests/unit/test_cmd_line_parser.cpp index cc2a935951..048a337ba2 100644 --- a/tests/unit/test_cmd_line_parser.cpp +++ b/tests/unit/test_cmd_line_parser.cpp @@ -32,7 +32,7 @@ #include -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "utils/parse_cmdline.hpp" #include "test_util.hpp" diff --git a/tests/unit/test_dns.cpp b/tests/unit/test_dns.cpp index 2a2597efb9..8e8d6a0fc9 100644 --- a/tests/unit/test_dns.cpp +++ b/tests/unit/test_dns.cpp @@ -34,7 +34,7 @@ #include "test_util.hpp" #include "common/array.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/dns_types.hpp" namespace ot { diff --git a/tests/unit/test_dns_client.cpp b/tests/unit/test_dns_client.cpp index e259ba9ae6..59efab72df 100644 --- a/tests/unit/test_dns_client.cpp +++ b/tests/unit/test_dns_client.cpp @@ -39,9 +39,9 @@ #include "common/arg_macros.hpp" #include "common/array.hpp" -#include "common/instance.hpp" #include "common/string.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE && \ OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE && OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && \ diff --git a/tests/unit/test_dso.cpp b/tests/unit/test_dso.cpp index 2ee18286a9..149a690d6e 100644 --- a/tests/unit/test_dso.cpp +++ b/tests/unit/test_dso.cpp @@ -34,8 +34,8 @@ #include "common/arg_macros.hpp" #include "common/array.hpp" #include "common/as_core_type.hpp" -#include "common/instance.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #include "net/dns_dso.hpp" #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE diff --git a/tests/unit/test_hdlc.cpp b/tests/unit/test_hdlc.cpp index c4c707cb17..4e96310de8 100644 --- a/tests/unit/test_hdlc.cpp +++ b/tests/unit/test_hdlc.cpp @@ -29,7 +29,7 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "lib/hdlc/hdlc.hpp" #include "lib/spinel/multi_frame_buffer.hpp" diff --git a/tests/unit/test_link_metrics_manager.cpp b/tests/unit/test_link_metrics_manager.cpp index 4125680bef..58ef1416ad 100644 --- a/tests/unit/test_link_metrics_manager.cpp +++ b/tests/unit/test_link_metrics_manager.cpp @@ -33,7 +33,7 @@ #include "test_util.h" #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "mac/mac_types.hpp" #include "thread/child_table.hpp" diff --git a/tests/unit/test_linked_list.cpp b/tests/unit/test_linked_list.cpp index 0032ee2c1a..8c581d76f1 100644 --- a/tests/unit/test_linked_list.cpp +++ b/tests/unit/test_linked_list.cpp @@ -34,9 +34,9 @@ #include #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/linked_list.hpp" #include "common/owning_list.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_lowpan.hpp b/tests/unit/test_lowpan.hpp index a9542b9e70..8a6e3976d1 100644 --- a/tests/unit/test_lowpan.hpp +++ b/tests/unit/test_lowpan.hpp @@ -32,7 +32,7 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "mac/mac.hpp" #include "net/ip6_headers.hpp" #include "thread/lowpan.hpp" diff --git a/tests/unit/test_message.cpp b/tests/unit/test_message.cpp index 095536442a..ac1320095a 100644 --- a/tests/unit/test_message.cpp +++ b/tests/unit/test_message.cpp @@ -28,9 +28,9 @@ #include "common/appender.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/message.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "test_platform.h" #include "test_util.hpp" diff --git a/tests/unit/test_message_queue.cpp b/tests/unit/test_message_queue.cpp index 9eb3c77219..33144721e3 100644 --- a/tests/unit/test_message_queue.cpp +++ b/tests/unit/test_message_queue.cpp @@ -33,8 +33,8 @@ #include #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_multicast_listeners_table.cpp b/tests/unit/test_multicast_listeners_table.cpp index 20c810e7f3..6fae2743ba 100644 --- a/tests/unit/test_multicast_listeners_table.cpp +++ b/tests/unit/test_multicast_listeners_table.cpp @@ -38,7 +38,7 @@ #include "test_util.h" #include "backbone_router/multicast_listeners_table.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/tests/unit/test_nat64.cpp b/tests/unit/test_nat64.cpp index d699d83f82..55bd0e0039 100644 --- a/tests/unit/test_nat64.cpp +++ b/tests/unit/test_nat64.cpp @@ -35,8 +35,8 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "net/ip6.hpp" #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE diff --git a/tests/unit/test_ndproxy_table.cpp b/tests/unit/test_ndproxy_table.cpp index 80f5d13dda..81ed9f0edf 100644 --- a/tests/unit/test_ndproxy_table.cpp +++ b/tests/unit/test_ndproxy_table.cpp @@ -38,7 +38,7 @@ #include "test_util.h" #include "backbone_router/ndproxy_table.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" namespace ot { diff --git a/tests/unit/test_netif.cpp b/tests/unit/test_netif.cpp index 1a5c0e1201..c8c9a5dbba 100644 --- a/tests/unit/test_netif.cpp +++ b/tests/unit/test_netif.cpp @@ -34,7 +34,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "net/netif.hpp" #include "test_util.h" diff --git a/tests/unit/test_network_data.cpp b/tests/unit/test_network_data.cpp index 6fcdfd3ec0..d83d840235 100644 --- a/tests/unit/test_network_data.cpp +++ b/tests/unit/test_network_data.cpp @@ -30,7 +30,7 @@ #include "common/array.hpp" #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "thread/network_data_leader.hpp" #include "thread/network_data_local.hpp" #include "thread/network_data_service.hpp" diff --git a/tests/unit/test_platform.h b/tests/unit/test_platform.h index ec5f887094..76a72ba090 100644 --- a/tests/unit/test_platform.h +++ b/tests/unit/test_platform.h @@ -41,7 +41,7 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_pool.cpp b/tests/unit/test_pool.cpp index 51656cdc65..57edc315d3 100644 --- a/tests/unit/test_pool.cpp +++ b/tests/unit/test_pool.cpp @@ -30,8 +30,8 @@ #include -#include "common/instance.hpp" #include "common/pool.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_priority_queue.cpp b/tests/unit/test_priority_queue.cpp index 6348f55c5c..724a61e014 100644 --- a/tests/unit/test_priority_queue.cpp +++ b/tests/unit/test_priority_queue.cpp @@ -29,8 +29,8 @@ #include #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/message.hpp" +#include "instance/instance.hpp" #include "test_platform.h" #include "test_util.h" diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index c5cbb5cdad..42847217a9 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -38,8 +38,8 @@ #include "border_router/routing_manager.hpp" #include "common/arg_macros.hpp" #include "common/array.hpp" -#include "common/instance.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #include "net/icmp6.hpp" #include "net/nd6.hpp" diff --git a/tests/unit/test_spinel_buffer.cpp b/tests/unit/test_spinel_buffer.cpp index 8d4f322572..1cb402a4f3 100644 --- a/tests/unit/test_spinel_buffer.cpp +++ b/tests/unit/test_spinel_buffer.cpp @@ -29,9 +29,9 @@ #include #include "common/code_utils.hpp" -#include "common/instance.hpp" #include "common/message.hpp" #include "common/random.hpp" +#include "instance/instance.hpp" #include "lib/spinel/spinel_buffer.hpp" #include "test_platform.h" diff --git a/tests/unit/test_spinel_decoder.cpp b/tests/unit/test_spinel_decoder.cpp index 1a2249ab71..e8ee85822c 100644 --- a/tests/unit/test_spinel_decoder.cpp +++ b/tests/unit/test_spinel_decoder.cpp @@ -27,7 +27,7 @@ */ #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "lib/spinel/spinel_decoder.hpp" #include "test_util.hpp" diff --git a/tests/unit/test_spinel_encoder.cpp b/tests/unit/test_spinel_encoder.cpp index 4b76d4c6bf..09c8de93e6 100644 --- a/tests/unit/test_spinel_encoder.cpp +++ b/tests/unit/test_spinel_encoder.cpp @@ -27,7 +27,7 @@ */ #include "common/code_utils.hpp" -#include "common/instance.hpp" +#include "instance/instance.hpp" #include "lib/spinel/spinel_encoder.hpp" #include "test_util.hpp" diff --git a/tests/unit/test_srp_server.cpp b/tests/unit/test_srp_server.cpp index 230375902d..7b9b989c91 100644 --- a/tests/unit/test_srp_server.cpp +++ b/tests/unit/test_srp_server.cpp @@ -38,9 +38,9 @@ #include "common/arg_macros.hpp" #include "common/array.hpp" -#include "common/instance.hpp" #include "common/string.hpp" #include "common/time.hpp" +#include "instance/instance.hpp" #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && \ !OPENTHREAD_CONFIG_TIME_SYNC_ENABLE && !OPENTHREAD_PLATFORM_POSIX diff --git a/tests/unit/test_timer.cpp b/tests/unit/test_timer.cpp index b3509f833e..5c8e6eb0a8 100644 --- a/tests/unit/test_timer.cpp +++ b/tests/unit/test_timer.cpp @@ -31,9 +31,9 @@ #include "common/array.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" #include "common/timer.hpp" +#include "instance/instance.hpp" enum { diff --git a/tests/unit/test_tlv.cpp b/tests/unit/test_tlv.cpp index 1af0121be3..703abe3e56 100644 --- a/tests/unit/test_tlv.cpp +++ b/tests/unit/test_tlv.cpp @@ -30,9 +30,9 @@ #include -#include "common/instance.hpp" #include "common/message.hpp" #include "common/tlvs.hpp" +#include "instance/instance.hpp" #include "test_util.h" diff --git a/tests/unit/test_trickle_timer.cpp b/tests/unit/test_trickle_timer.cpp index f5851f2616..166455c71c 100644 --- a/tests/unit/test_trickle_timer.cpp +++ b/tests/unit/test_trickle_timer.cpp @@ -30,9 +30,9 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" -#include "common/instance.hpp" #include "common/num_utils.hpp" #include "common/trickle_timer.hpp" +#include "instance/instance.hpp" static ot::Instance *sInstance; From eb0fc06815ec9356a9a89a2e3babdfad99209fa5 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Wed, 22 Nov 2023 01:48:27 +0800 Subject: [PATCH 2/9] [cli] make linkmetrics cli as a separate module (#9619) --- src/cli/BUILD.gn | 2 + src/cli/CMakeLists.txt | 1 + src/cli/cli.cpp | 451 +---------------------------- src/cli/cli.hpp | 44 +-- src/cli/cli_link_metrics.cpp | 530 +++++++++++++++++++++++++++++++++++ src/cli/cli_link_metrics.hpp | 128 +++++++++ 6 files changed, 670 insertions(+), 486 deletions(-) create mode 100644 src/cli/cli_link_metrics.cpp create mode 100644 src/cli/cli_link_metrics.hpp diff --git a/src/cli/BUILD.gn b/src/cli/BUILD.gn index fb68e8c863..b7ef7312a5 100644 --- a/src/cli/BUILD.gn +++ b/src/cli/BUILD.gn @@ -49,6 +49,8 @@ openthread_cli_sources = [ "cli_history.hpp", "cli_joiner.cpp", "cli_joiner.hpp", + "cli_link_metrics.cpp", + "cli_link_metrics.hpp", "cli_mac_filter.cpp", "cli_mac_filter.hpp", "cli_network_data.cpp", diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index c203c26675..6be47773c0 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -42,6 +42,7 @@ set(COMMON_SOURCES cli_dns.cpp cli_history.cpp cli_joiner.cpp + cli_link_metrics.cpp cli_mac_filter.cpp cli_network_data.cpp cli_output.cpp diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index a2be219021..9dc92a79d9 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -67,9 +67,6 @@ #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE #include #endif -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE -#include -#endif #endif #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE && OPENTHREAD_FTD #include @@ -147,12 +144,12 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE , mHistory(aInstance, *this) #endif +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE + , mLinkMetrics(aInstance, *this) +#endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE , mLocateInProgress(false) #endif -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE - , mLinkMetricsQueryInProgress(false) -#endif #endif // OPENTHREAD_FTD || OPENTHREAD_MTD { #if (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK @@ -3649,241 +3646,8 @@ template <> otError Interpreter::Process(Arg aArgs[]) #endif // OPENTHREAD_FTD #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE -void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, - const otLinkMetricsValues *aMetricsValues, - otLinkMetricsStatus aStatus, - void *aContext) -{ - static_cast(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues, aStatus); -} - -void Interpreter::PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues) -{ - static const char kLinkMetricsTypeAverage[] = "(Exponential Moving Average)"; - - if (aMetricsValues->mMetrics.mPduCount) - { - OutputLine(" - PDU Counter: %lu (Count/Summation)", ToUlong(aMetricsValues->mPduCountValue)); - } - - if (aMetricsValues->mMetrics.mLqi) - { - OutputLine(" - LQI: %u %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage); - } - - if (aMetricsValues->mMetrics.mLinkMargin) - { - OutputLine(" - Margin: %u (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage); - } - - if (aMetricsValues->mMetrics.mRssi) - { - OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage); - } -} - -void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, - const otLinkMetricsValues *aMetricsValues, - otLinkMetricsStatus aStatus) -{ - OutputFormat("Received Link Metrics Report from: "); - OutputIp6AddressLine(*aAddress); - - if (aMetricsValues != nullptr) - { - PrintLinkMetricsValue(aMetricsValues); - } - else - { - OutputLine("Link Metrics Report, status: %s", LinkMetricsStatusToStr(aStatus)); - } - - if (mLinkMetricsQueryInProgress) - { - mLinkMetricsQueryInProgress = false; - OutputResult(OT_ERROR_NONE); - } -} - -void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, - otLinkMetricsStatus aStatus, - void *aContext) -{ - static_cast(aContext)->HandleLinkMetricsMgmtResponse(aAddress, aStatus); -} - -void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus) -{ - OutputFormat("Received Link Metrics Management Response from: "); - OutputIp6AddressLine(*aAddress); - - OutputLine("Status: %s", LinkMetricsStatusToStr(aStatus)); -} - -void Interpreter::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, - const otExtAddress *aExtAddress, - const otLinkMetricsValues *aMetricsValues, - void *aContext) -{ - static_cast(aContext)->HandleLinkMetricsEnhAckProbingIe(aShortAddress, aExtAddress, aMetricsValues); -} - -void Interpreter::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, - const otExtAddress *aExtAddress, - const otLinkMetricsValues *aMetricsValues) -{ - OutputFormat("Received Link Metrics data in Enh Ack from neighbor, short address:0x%02x , extended address:", - aShortAddress); - OutputExtAddressLine(*aExtAddress); - - if (aMetricsValues != nullptr) - { - PrintLinkMetricsValue(aMetricsValues); - } -} - -const char *Interpreter::LinkMetricsStatusToStr(otLinkMetricsStatus aStatus) -{ - static const char *const kStatusStrings[] = { - "Success", // (0) OT_LINK_METRICS_STATUS_SUCCESS - "Cannot support new series", // (1) OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES - "Series ID already registered", // (2) OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED - "Series ID not recognized", // (3) OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED - "No matching series ID", // (4) OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED - }; - - const char *str = "Unknown error"; - - static_assert(0 == OT_LINK_METRICS_STATUS_SUCCESS, "STATUS_SUCCESS is incorrect"); - static_assert(1 == OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES, "CANNOT_SUPPORT_NEW_SERIES is incorrect"); - static_assert(2 == OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED, "SERIESID_ALREADY_REGISTERED is incorrect"); - static_assert(3 == OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED, "SERIESID_NOT_RECOGNIZED is incorrect"); - static_assert(4 == OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED, "NO_MATCHING_FRAMES_RECEIVED is incorrect"); - - if (aStatus < OT_ARRAY_LENGTH(kStatusStrings)) - { - str = kStatusStrings[aStatus]; - } - else if (aStatus == OT_LINK_METRICS_STATUS_OTHER_ERROR) - { - str = "Other error"; - } - - return str; -} - -template <> otError Interpreter::Process(Arg aArgs[]) -{ - otError error = OT_ERROR_INVALID_COMMAND; - if (aArgs[0] == "query") - { - otIp6Address address; - bool isSingle; - bool blocking; - uint8_t seriesId; - otLinkMetrics linkMetrics; - - SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); - - /** - * @cli linkmetrics query single - * @code - * linkmetrics query fe80:0:0:0:3092:f334:1455:1ad2 single qmr - * Done - * > Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2 - * - LQI: 76 (Exponential Moving Average) - * - Margin: 82 (dB) (Exponential Moving Average) - * - RSSI: -18 (dBm) (Exponential Moving Average) - * @endcode - * @cparam linkmetrics query @ca{peer-ipaddr} single [@ca{pqmr}] - * - `peer-ipaddr`: Peer address. - * - [`p`, `q`, `m`, and `r`] map to #otLinkMetrics. - * - `p`: Layer 2 Number of PDUs received. - * - `q`: Layer 2 LQI. - * - `m`: Link Margin. - * - `r`: RSSI. - * @par - * Perform a Link Metrics query (Single Probe). - * @sa otLinkMetricsQuery - */ - if (aArgs[2] == "single") - { - isSingle = true; - SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[3])); - } - /** - * @cli linkmetrics query forward - * @code - * linkmetrics query fe80:0:0:0:3092:f334:1455:1ad2 forward 1 - * Done - * > Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2 - * - PDU Counter: 2 (Count/Summation) - * - LQI: 76 (Exponential Moving Average) - * - Margin: 82 (dB) (Exponential Moving Average) - * - RSSI: -18 (dBm) (Exponential Moving Average) - * @endcode - * @cparam linkmetrics query @ca{peer-ipaddr} forward @ca{series-id} - * - `peer-ipaddr`: Peer address. - * - `series-id`: The Series ID. - * @par - * Perform a Link Metrics query (Forward Tracking Series). - * @sa otLinkMetricsQuery - */ - else if (aArgs[2] == "forward") - { - isSingle = false; - SuccessOrExit(error = aArgs[3].ParseAsUint8(seriesId)); - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - - blocking = (aArgs[4] == "block"); - - SuccessOrExit(error = otLinkMetricsQuery(GetInstancePtr(), &address, isSingle ? 0 : seriesId, - isSingle ? &linkMetrics : nullptr, HandleLinkMetricsReport, this)); - - if (blocking) - { - mLinkMetricsQueryInProgress = true; - error = OT_ERROR_PENDING; - } - } - else if (aArgs[0] == "mgmt") - { - error = ProcessLinkMetricsMgmt(aArgs + 1); - } - /** - * @cli linkmetrics probe - * @code - * linkmetrics probe fe80:0:0:0:3092:f334:1455:1ad2 1 10 - * Done - * @endcode - * @cparam linkmetrics probe @ca{peer-ipaddr} @ca{series-id} @ca{length} - * - `peer-ipaddr`: Peer address. - * - `series-id`: The Series ID for which this Probe message targets. - * - `length`: The length of the Probe message. A valid range is [0, 64]. - * @par api_copy - * #otLinkMetricsSendLinkProbe - */ - else if (aArgs[0] == "probe") - { - otIp6Address address; - uint8_t seriesId; - uint8_t length; - - SuccessOrExit(error = aArgs[1].ParseAsIp6Address(address)); - SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId)); - SuccessOrExit(error = aArgs[3].ParseAsUint8(length)); - - error = otLinkMetricsSendLinkProbe(GetInstancePtr(), &address, seriesId, length); - } - -exit: - return error; -} +template <> otError Interpreter::Process(Arg aArgs[]) { return mLinkMetrics.Process(aArgs); } #if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) @@ -3951,213 +3715,6 @@ template <> otError Interpreter::Process(Arg aArgs[]) } #endif // OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE -otError Interpreter::ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags) -{ - otError error = OT_ERROR_NONE; - - VerifyOrExit(!aFlags.IsEmpty(), error = OT_ERROR_INVALID_ARGS); - - memset(&aLinkMetrics, 0, sizeof(aLinkMetrics)); - - for (const char *arg = aFlags.GetCString(); *arg != '\0'; arg++) - { - switch (*arg) - { - case 'p': - aLinkMetrics.mPduCount = true; - break; - - case 'q': - aLinkMetrics.mLqi = true; - break; - - case 'm': - aLinkMetrics.mLinkMargin = true; - break; - - case 'r': - aLinkMetrics.mRssi = true; - break; - - default: - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - -exit: - return error; -} - -otError Interpreter::ProcessLinkMetricsMgmt(Arg aArgs[]) -{ - otError error; - otIp6Address address; - otLinkMetricsSeriesFlags seriesFlags; - bool clear = false; - - SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address)); - - memset(&seriesFlags, 0, sizeof(otLinkMetricsSeriesFlags)); - - /** - * @cli linkmetrics mgmt forward - * @code - * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 forward 1 dra pqmr - * Done - * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 - * Status: SUCCESS - * @endcode - * @cparam linkmetrics mgmt @ca{peer-ipaddr} forward @ca{series-id} [@ca{ldraX}][@ca{pqmr}] - * - `peer-ipaddr`: Peer address. - * - `series-id`: The Series ID. - * - [`l`, `d`, `r`, and `a`] map to #otLinkMetricsSeriesFlags. `X` represents none of the - * `otLinkMetricsSeriesFlags`, and stops the accounting and removes the series. - * - `l`: MLE Link Probe. - * - `d`: MAC Data. - * - `r`: MAC Data Request. - * - `a`: MAC Ack. - * - `X`: Can only be used without any other flags. - * - [`p`, `q`, `m`, and `r`] map to #otLinkMetricsValues. - * - `p`: Layer 2 Number of PDUs received. - * - `q`: Layer 2 LQI. - * - `m`: Link Margin. - * - `r`: RSSI. - * @par api_copy - * #otLinkMetricsConfigForwardTrackingSeries - */ - if (aArgs[1] == "forward") - { - uint8_t seriesId; - otLinkMetrics linkMetrics; - - memset(&linkMetrics, 0, sizeof(otLinkMetrics)); - SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId)); - VerifyOrExit(!aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - - for (const char *arg = aArgs[3].GetCString(); *arg != '\0'; arg++) - { - switch (*arg) - { - case 'l': - seriesFlags.mLinkProbe = true; - break; - - case 'd': - seriesFlags.mMacData = true; - break; - - case 'r': - seriesFlags.mMacDataRequest = true; - break; - - case 'a': - seriesFlags.mMacAck = true; - break; - - case 'X': - VerifyOrExit(arg == aArgs[3].GetCString() && *(arg + 1) == '\0' && aArgs[4].IsEmpty(), - error = OT_ERROR_INVALID_ARGS); // Ensure the flags only contain 'X' - clear = true; - break; - - default: - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - } - - if (!clear) - { - SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[4])); - VerifyOrExit(aArgs[5].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - } - - error = otLinkMetricsConfigForwardTrackingSeries(GetInstancePtr(), &address, seriesId, seriesFlags, - clear ? nullptr : &linkMetrics, - &Interpreter::HandleLinkMetricsMgmtResponse, this); - } - else if (aArgs[1] == "enhanced-ack") - { - otLinkMetricsEnhAckFlags enhAckFlags; - otLinkMetrics linkMetrics; - otLinkMetrics *pLinkMetrics = &linkMetrics; - - /** - * @cli linkmetrics mgmt enhanced-ack clear - * @code - * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack clear - * Done - * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 - * Status: Success - * @endcode - * @cparam linkmetrics mgmt @ca{peer-ipaddr} enhanced-ack clear - * `peer-ipaddr` should be the Link Local address of the neighboring device. - * @par - * Sends a Link Metrics Management Request to clear an Enhanced-ACK Based Probing. - * @sa otLinkMetricsConfigEnhAckProbing - */ - if (aArgs[2] == "clear") - { - enhAckFlags = OT_LINK_METRICS_ENH_ACK_CLEAR; - pLinkMetrics = nullptr; - } - /** - * @cli linkmetrics mgmt enhanced-ack register - * @code - * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm - * Done - * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 - * Status: Success - * @endcode - * @code - * > linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm r - * Done - * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 - * Status: Cannot support new series - * @endcode - * @cparam linkmetrics mgmt @ca{peer-ipaddr} enhanced-ack register [@ca{qmr}][@ca{r}] - * [`q`, `m`, and `r`] map to #otLinkMetricsValues. Per spec 4.11.3.4.4.6, you can - * only use a maximum of two options at once, for example `q`, or `qm`. - * - `q`: Layer 2 LQI. - * - `m`: Link Margin. - * - `r`: RSSI. - * . - * The additional `r` is optional and only used for reference devices. When this option - * is specified, Type/Average Enum of each Type Id Flags is set to reserved. This is - * used to verify that the Probing Subject correctly handles invalid Type Id Flags, and - * only available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled. - * @par - * Sends a Link Metrics Management Request to register an Enhanced-ACK Based Probing. - * @sa otLinkMetricsConfigEnhAckProbing - */ - else if (aArgs[2] == "register") - { - enhAckFlags = OT_LINK_METRICS_ENH_ACK_REGISTER; - SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[3])); -#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE - if (aArgs[4] == "r") - { - linkMetrics.mReserved = true; - } -#endif - } - else - { - ExitNow(error = OT_ERROR_INVALID_ARGS); - } - - error = otLinkMetricsConfigEnhAckProbing(GetInstancePtr(), &address, enhAckFlags, pLinkMetrics, - &Interpreter::HandleLinkMetricsMgmtResponse, this, - &Interpreter::HandleLinkMetricsEnhAckProbingIe, this); - } - else - { - error = OT_ERROR_INVALID_ARGS; - } - -exit: - return error; -} - #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index cc16bf1a4f..81c5fe7d0a 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -65,6 +65,7 @@ #include "cli/cli_dns.hpp" #include "cli/cli_history.hpp" #include "cli/cli_joiner.hpp" +#include "cli/cli_link_metrics.hpp" #include "cli/cli_mac_filter.hpp" #include "cli/cli_network_data.hpp" #include "cli/cli_output.hpp" @@ -113,6 +114,7 @@ class Interpreter : public OutputImplementer, public Output friend class Commissioner; friend class Dns; friend class Joiner; + friend class LinkMetrics; friend class NetworkData; friend class SrpClient; friend class SrpServer; @@ -412,12 +414,6 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_FTD void OutputEidCacheEntry(const otCacheEntryInfo &aEntry); #endif -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE - otError ProcessLinkMetricsQuery(Arg aArgs[]); - otError ProcessLinkMetricsMgmt(Arg aArgs[]); - otError ProcessLinkMetricsProbe(Arg aArgs[]); - otError ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags); -#endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE static void HandleLocateResult(void *aContext, otError aError, @@ -507,35 +503,6 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE void HandleSntpResponse(uint64_t aTime, otError aResult); #endif -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE - void PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues); - - static void HandleLinkMetricsReport(const otIp6Address *aAddress, - const otLinkMetricsValues *aMetricsValues, - otLinkMetricsStatus aStatus, - void *aContext); - - void HandleLinkMetricsReport(const otIp6Address *aAddress, - const otLinkMetricsValues *aMetricsValues, - otLinkMetricsStatus aStatus); - - static void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, - otLinkMetricsStatus aStatus, - void *aContext); - - void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus); - - static void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, - const otExtAddress *aExtAddress, - const otLinkMetricsValues *aMetricsValues, - void *aContext); - - void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, - const otExtAddress *aExtAddress, - const otLinkMetricsValues *aMetricsValues); - - const char *LinkMetricsStatusToStr(otLinkMetricsStatus aStatus); -#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE static void HandleDetachGracefullyResult(void *aContext); void HandleDetachGracefullyResult(void); @@ -624,6 +591,9 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE History mHistory; #endif +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE + LinkMetrics mLinkMetrics; +#endif #endif // OPENTHREAD_FTD || OPENTHREAD_MTD #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE @@ -632,10 +602,6 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE bool mLocateInProgress : 1; #endif - -#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE - bool mLinkMetricsQueryInProgress : 1; -#endif }; // Specializations of `FormatStringFor()` diff --git a/src/cli/cli_link_metrics.cpp b/src/cli/cli_link_metrics.cpp new file mode 100644 index 0000000000..b8c284611d --- /dev/null +++ b/src/cli/cli_link_metrics.cpp @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the CLI interpreter for Link Metrics function. + */ + +#include "cli_link_metrics.hpp" + +#include + +#include "cli/cli.hpp" +#include "cli/cli_output.hpp" +#include "common/code_utils.hpp" + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE + +namespace ot { +namespace Cli { + +LinkMetrics::LinkMetrics(otInstance *aInstance, OutputImplementer &aOutputImplementer) + : Output(aInstance, aOutputImplementer) + , mLinkMetricsQueryInProgress(false) +{ +} + +template <> otError LinkMetrics::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + otIp6Address address; + bool isSingle; + bool blocking; + uint8_t seriesId; + otLinkMetrics linkMetrics; + + SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address)); + + /** + * @cli linkmetrics query single + * @code + * linkmetrics query fe80:0:0:0:3092:f334:1455:1ad2 single qmr + * Done + * > Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2 + * - LQI: 76 (Exponential Moving Average) + * - Margin: 82 (dB) (Exponential Moving Average) + * - RSSI: -18 (dBm) (Exponential Moving Average) + * @endcode + * @cparam linkmetrics query @ca{peer-ipaddr} single [@ca{pqmr}] + * - `peer-ipaddr`: Peer address. + * - [`p`, `q`, `m`, and `r`] map to #otLinkMetrics. + * - `p`: Layer 2 Number of PDUs received. + * - `q`: Layer 2 LQI. + * - `m`: Link Margin. + * - `r`: RSSI. + * @par + * Perform a Link Metrics query (Single Probe). + * @sa otLinkMetricsQuery + */ + if (aArgs[1] == "single") + { + isSingle = true; + SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[2])); + } + /** + * @cli linkmetrics query forward + * @code + * linkmetrics query fe80:0:0:0:3092:f334:1455:1ad2 forward 1 + * Done + * > Received Link Metrics Report from: fe80:0:0:0:3092:f334:1455:1ad2 + * - PDU Counter: 2 (Count/Summation) + * - LQI: 76 (Exponential Moving Average) + * - Margin: 82 (dB) (Exponential Moving Average) + * - RSSI: -18 (dBm) (Exponential Moving Average) + * @endcode + * @cparam linkmetrics query @ca{peer-ipaddr} forward @ca{series-id} + * - `peer-ipaddr`: Peer address. + * - `series-id`: The Series ID. + * @par + * Perform a Link Metrics query (Forward Tracking Series). + * @sa otLinkMetricsQuery + */ + else if (aArgs[1] == "forward") + { + isSingle = false; + SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId)); + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + + blocking = (aArgs[3] == "block"); + + SuccessOrExit(error = otLinkMetricsQuery(GetInstancePtr(), &address, isSingle ? 0 : seriesId, + isSingle ? &linkMetrics : nullptr, HandleLinkMetricsReport, this)); + + if (blocking) + { + mLinkMetricsQueryInProgress = true; + error = OT_ERROR_PENDING; + } +exit: + return error; +} + +template <> otError LinkMetrics::Process(Arg aArgs[]) +{ + otError error; + otIp6Address address; + otLinkMetricsSeriesFlags seriesFlags; + bool clear = false; + + SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address)); + + memset(&seriesFlags, 0, sizeof(otLinkMetricsSeriesFlags)); + + /** + * @cli linkmetrics mgmt forward + * @code + * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 forward 1 dra pqmr + * Done + * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 + * Status: SUCCESS + * @endcode + * @cparam linkmetrics mgmt @ca{peer-ipaddr} forward @ca{series-id} [@ca{ldraX}][@ca{pqmr}] + * - `peer-ipaddr`: Peer address. + * - `series-id`: The Series ID. + * - [`l`, `d`, `r`, and `a`] map to #otLinkMetricsSeriesFlags. `X` represents none of the + * `otLinkMetricsSeriesFlags`, and stops the accounting and removes the series. + * - `l`: MLE Link Probe. + * - `d`: MAC Data. + * - `r`: MAC Data Request. + * - `a`: MAC Ack. + * - `X`: Can only be used without any other flags. + * - [`p`, `q`, `m`, and `r`] map to #otLinkMetricsValues. + * - `p`: Layer 2 Number of PDUs received. + * - `q`: Layer 2 LQI. + * - `m`: Link Margin. + * - `r`: RSSI. + * @par api_copy + * #otLinkMetricsConfigForwardTrackingSeries + */ + if (aArgs[1] == "forward") + { + uint8_t seriesId; + otLinkMetrics linkMetrics; + + memset(&linkMetrics, 0, sizeof(otLinkMetrics)); + SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId)); + VerifyOrExit(!aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + for (const char *arg = aArgs[3].GetCString(); *arg != '\0'; arg++) + { + switch (*arg) + { + case 'l': + seriesFlags.mLinkProbe = true; + break; + + case 'd': + seriesFlags.mMacData = true; + break; + + case 'r': + seriesFlags.mMacDataRequest = true; + break; + + case 'a': + seriesFlags.mMacAck = true; + break; + + case 'X': + VerifyOrExit(arg == aArgs[3].GetCString() && *(arg + 1) == '\0' && aArgs[4].IsEmpty(), + error = OT_ERROR_INVALID_ARGS); // Ensure the flags only contain 'X' + clear = true; + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + + if (!clear) + { + SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[4])); + VerifyOrExit(aArgs[5].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + } + + error = otLinkMetricsConfigForwardTrackingSeries(GetInstancePtr(), &address, seriesId, seriesFlags, + clear ? nullptr : &linkMetrics, + &LinkMetrics::HandleLinkMetricsMgmtResponse, this); + } + else if (aArgs[1] == "enhanced-ack") + { + otLinkMetricsEnhAckFlags enhAckFlags; + otLinkMetrics linkMetrics; + otLinkMetrics *pLinkMetrics = &linkMetrics; + + /** + * @cli linkmetrics mgmt enhanced-ack clear + * @code + * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack clear + * Done + * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 + * Status: Success + * @endcode + * @cparam linkmetrics mgmt @ca{peer-ipaddr} enhanced-ack clear + * `peer-ipaddr` should be the Link Local address of the neighboring device. + * @par + * Sends a Link Metrics Management Request to clear an Enhanced-ACK Based Probing. + * @sa otLinkMetricsConfigEnhAckProbing + */ + if (aArgs[2] == "clear") + { + enhAckFlags = OT_LINK_METRICS_ENH_ACK_CLEAR; + pLinkMetrics = nullptr; + } + /** + * @cli linkmetrics mgmt enhanced-ack register + * @code + * linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm + * Done + * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 + * Status: Success + * @endcode + * @code + * > linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm r + * Done + * > Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2 + * Status: Cannot support new series + * @endcode + * @cparam linkmetrics mgmt @ca{peer-ipaddr} enhanced-ack register [@ca{qmr}][@ca{r}] + * [`q`, `m`, and `r`] map to #otLinkMetricsValues. Per spec 4.11.3.4.4.6, you can + * only use a maximum of two options at once, for example `q`, or `qm`. + * - `q`: Layer 2 LQI. + * - `m`: Link Margin. + * - `r`: RSSI. + * . + * The additional `r` is optional and only used for reference devices. When this option + * is specified, Type/Average Enum of each Type Id Flags is set to reserved. This is + * used to verify that the Probing Subject correctly handles invalid Type Id Flags, and + * only available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled. + * @par + * Sends a Link Metrics Management Request to register an Enhanced-ACK Based Probing. + * @sa otLinkMetricsConfigEnhAckProbing + */ + else if (aArgs[2] == "register") + { + enhAckFlags = OT_LINK_METRICS_ENH_ACK_REGISTER; + SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[3])); +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + if (aArgs[4] == "r") + { + linkMetrics.mReserved = true; + } +#endif + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + + error = otLinkMetricsConfigEnhAckProbing(GetInstancePtr(), &address, enhAckFlags, pLinkMetrics, + &LinkMetrics::HandleLinkMetricsMgmtResponse, this, + &LinkMetrics::HandleLinkMetricsEnhAckProbingIe, this); + } + else + { + error = OT_ERROR_INVALID_ARGS; + } + +exit: + return error; +} + +template <> otError LinkMetrics::Process(Arg aArgs[]) +{ + /** + * @cli linkmetrics probe + * @code + * linkmetrics probe fe80:0:0:0:3092:f334:1455:1ad2 1 10 + * Done + * @endcode + * @cparam linkmetrics probe @ca{peer-ipaddr} @ca{series-id} @ca{length} + * - `peer-ipaddr`: Peer address. + * - `series-id`: The Series ID for which this Probe message targets. + * - `length`: The length of the Probe message. A valid range is [0, 64]. + * @par api_copy + * #otLinkMetricsSendLinkProbe + */ + otError error = OT_ERROR_NONE; + + otIp6Address address; + uint8_t seriesId; + uint8_t length; + + SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address)); + SuccessOrExit(error = aArgs[1].ParseAsUint8(seriesId)); + SuccessOrExit(error = aArgs[2].ParseAsUint8(length)); + + error = otLinkMetricsSendLinkProbe(GetInstancePtr(), &address, seriesId, length); +exit: + return error; +} + +otError LinkMetrics::Process(Arg aArgs[]) +{ +#define CmdEntry(aCommandString) \ + { \ + aCommandString, &LinkMetrics::Process \ + } + + static constexpr Command kCommands[] = { + CmdEntry("mgmt"), + CmdEntry("probe"), + CmdEntry("query"), + }; + + static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); + + otError error = OT_ERROR_INVALID_COMMAND; + const Command *command; + + if (aArgs[0].IsEmpty() || (aArgs[0] == "help")) + { + OutputCommandTable(kCommands); + ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE); + } + + command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); + VerifyOrExit(command != nullptr); + + error = (this->*command->mHandler)(aArgs + 1); + +exit: + return error; +} + +otError LinkMetrics::ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(!aFlags.IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + memset(&aLinkMetrics, 0, sizeof(aLinkMetrics)); + + for (const char *arg = aFlags.GetCString(); *arg != '\0'; arg++) + { + switch (*arg) + { + case 'p': + aLinkMetrics.mPduCount = true; + break; + + case 'q': + aLinkMetrics.mLqi = true; + break; + + case 'm': + aLinkMetrics.mLinkMargin = true; + break; + + case 'r': + aLinkMetrics.mRssi = true; + break; + + default: + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + } + +exit: + return error; +} + +void LinkMetrics::HandleLinkMetricsReport(const otIp6Address *aAddress, + const otLinkMetricsValues *aMetricsValues, + otLinkMetricsStatus aStatus, + void *aContext) +{ + static_cast(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues, aStatus); +} + +void LinkMetrics::PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues) +{ + static const char kLinkMetricsTypeAverage[] = "(Exponential Moving Average)"; + + if (aMetricsValues->mMetrics.mPduCount) + { + OutputLine(" - PDU Counter: %lu (Count/Summation)", ToUlong(aMetricsValues->mPduCountValue)); + } + + if (aMetricsValues->mMetrics.mLqi) + { + OutputLine(" - LQI: %u %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage); + } + + if (aMetricsValues->mMetrics.mLinkMargin) + { + OutputLine(" - Margin: %u (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage); + } + + if (aMetricsValues->mMetrics.mRssi) + { + OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage); + } +} + +void LinkMetrics::HandleLinkMetricsReport(const otIp6Address *aAddress, + const otLinkMetricsValues *aMetricsValues, + otLinkMetricsStatus aStatus) +{ + OutputFormat("Received Link Metrics Report from: "); + OutputIp6AddressLine(*aAddress); + + if (aMetricsValues != nullptr) + { + PrintLinkMetricsValue(aMetricsValues); + } + else + { + OutputLine("Link Metrics Report, status: %s", LinkMetricsStatusToStr(aStatus)); + } + + if (mLinkMetricsQueryInProgress) + { + mLinkMetricsQueryInProgress = false; + OutputResult(OT_ERROR_NONE); + } +} + +void LinkMetrics::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, + otLinkMetricsStatus aStatus, + void *aContext) +{ + static_cast(aContext)->HandleLinkMetricsMgmtResponse(aAddress, aStatus); +} + +void LinkMetrics::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus) +{ + OutputFormat("Received Link Metrics Management Response from: "); + OutputIp6AddressLine(*aAddress); + + OutputLine("Status: %s", LinkMetricsStatusToStr(aStatus)); +} + +void LinkMetrics::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, + const otExtAddress *aExtAddress, + const otLinkMetricsValues *aMetricsValues, + void *aContext) +{ + static_cast(aContext)->HandleLinkMetricsEnhAckProbingIe(aShortAddress, aExtAddress, aMetricsValues); +} + +void LinkMetrics::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, + const otExtAddress *aExtAddress, + const otLinkMetricsValues *aMetricsValues) +{ + OutputFormat("Received Link Metrics data in Enh Ack from neighbor, short address:0x%02x , extended address:", + aShortAddress); + OutputExtAddressLine(*aExtAddress); + + if (aMetricsValues != nullptr) + { + PrintLinkMetricsValue(aMetricsValues); + } +} + +const char *LinkMetrics::LinkMetricsStatusToStr(otLinkMetricsStatus aStatus) +{ + static const char *const kStatusStrings[] = { + "Success", // (0) OT_LINK_METRICS_STATUS_SUCCESS + "Cannot support new series", // (1) OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES + "Series ID already registered", // (2) OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED + "Series ID not recognized", // (3) OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED + "No matching series ID", // (4) OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED + }; + + const char *str = "Unknown error"; + + static_assert(0 == OT_LINK_METRICS_STATUS_SUCCESS, "STATUS_SUCCESS is incorrect"); + static_assert(1 == OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES, "CANNOT_SUPPORT_NEW_SERIES is incorrect"); + static_assert(2 == OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED, "SERIESID_ALREADY_REGISTERED is incorrect"); + static_assert(3 == OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED, "SERIESID_NOT_RECOGNIZED is incorrect"); + static_assert(4 == OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED, "NO_MATCHING_FRAMES_RECEIVED is incorrect"); + + if (aStatus < OT_ARRAY_LENGTH(kStatusStrings)) + { + str = kStatusStrings[aStatus]; + } + else if (aStatus == OT_LINK_METRICS_STATUS_OTHER_ERROR) + { + str = "Other error"; + } + + return str; +} + +void LinkMetrics::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); } + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE diff --git a/src/cli/cli_link_metrics.hpp b/src/cli/cli_link_metrics.hpp new file mode 100644 index 0000000000..d62be780ea --- /dev/null +++ b/src/cli/cli_link_metrics.hpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file contains definitions for the CLI interpreter for Link Metrics function. + */ + +#ifndef CLI_LINK_METRICS_HPP_ +#define CLI_LINK_METRICS_HPP_ + +#include "openthread-core-config.h" + +#include + +#include "cli/cli_output.hpp" + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE + +namespace ot { +namespace Cli { + +/** + * Implements the Link Metrics CLI interpreter. + * + */ + +class LinkMetrics : private Output +{ +public: + typedef Utils::CmdLineParser::Arg Arg; + + /** + * Constructor + * + * @param[in] aInstance The OpenThread Instance. + * @param[in] aOutputImplementer An `OutputImplementer`. + * + */ + LinkMetrics(otInstance *aInstance, OutputImplementer &aOutputImplementer); + + /** + * Processes a CLI sub-command. + * + * @param[in] aArgs An array of command line arguments. + * + * @retval OT_ERROR_NONE Successfully executed the CLI command. + * @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending. + * @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments. + * @retval ... Error during execution of the CLI command. + * + */ + otError Process(Arg aArgs[]); + +private: + static constexpr uint8_t kIndentSize = 4; + + using Command = CommandEntry; + + template otError Process(Arg aArgs[]); + + otError ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Arg &aFlags); + + void PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues); + + static void HandleLinkMetricsReport(const otIp6Address *aAddress, + const otLinkMetricsValues *aMetricsValues, + otLinkMetricsStatus aStatus, + void *aContext); + + void HandleLinkMetricsReport(const otIp6Address *aAddress, + const otLinkMetricsValues *aMetricsValues, + otLinkMetricsStatus aStatus); + + static void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, + otLinkMetricsStatus aStatus, + void *aContext); + + void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, otLinkMetricsStatus aStatus); + + static void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, + const otExtAddress *aExtAddress, + const otLinkMetricsValues *aMetricsValues, + void *aContext); + + void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress, + const otExtAddress *aExtAddress, + const otLinkMetricsValues *aMetricsValues); + + const char *LinkMetricsStatusToStr(otLinkMetricsStatus aStatus); + + void OutputResult(otError aError); + + bool mLinkMetricsQueryInProgress; +}; + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE + +#endif // CLI_LINK_METRICS_HPP_ From f1f0942de670fafc6b6767e686ed2ae6d732f114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bida?= Date: Mon, 4 Dec 2023 21:09:25 +0100 Subject: [PATCH 3/9] [tcat] initial commit of bluetooth-based commissioning (#9210) This commit introduces first implementation of Bluetooth based comissioning for thread devices. Co-authored-by: Arnulf Rupp Co-authored-by: Piotr Jasinski --- etc/cmake/options.cmake | 1 + etc/gn/openthread.gni | 3 + examples/platforms/simulation/CMakeLists.txt | 1 + examples/platforms/simulation/ble.c | 75 +++ include/openthread/BUILD.gn | 3 + include/openthread/ble_secure.h | 434 ++++++++++++++ include/openthread/instance.h | 2 +- include/openthread/platform/ble.h | 293 ++++++++++ include/openthread/tcat.h | 170 ++++++ script/check-simulation-build-cmake | 3 + src/cli/CMakeLists.txt | 1 + src/cli/README.md | 1 + src/cli/README_TCAT.md | 37 ++ src/cli/cli.cpp | 10 + src/cli/cli.hpp | 4 + src/cli/cli_config.h | 10 + src/cli/cli_tcat.cpp | 178 ++++++ src/cli/cli_tcat.hpp | 89 +++ src/core/BUILD.gn | 15 +- src/core/CMakeLists.txt | 5 +- src/core/api/ble_secure_api.cpp | 184 ++++++ src/core/coap/coap_secure.cpp | 11 +- src/core/coap/coap_secure.hpp | 12 +- src/core/common/message.hpp | 3 +- src/core/config/ip6.h | 2 +- .../config/openthread-core-config-check.h | 2 +- .../config/{dtls.h => secure_transport.h} | 22 +- src/core/instance/instance.cpp | 7 +- src/core/instance/instance.hpp | 13 +- src/core/meshcop/commissioner.hpp | 2 +- src/core/meshcop/joiner.hpp | 2 +- .../{dtls.cpp => secure_transport.cpp} | 421 ++++++++++---- .../{dtls.hpp => secure_transport.hpp} | 199 +++++-- src/core/meshcop/tcat_agent.cpp | 516 +++++++++++++++++ src/core/meshcop/tcat_agent.hpp | 374 ++++++++++++ src/core/openthread-core-config.h | 2 +- src/core/radio/ble_secure.cpp | 544 ++++++++++++++++++ src/core/radio/ble_secure.hpp | 489 ++++++++++++++++ src/core/thread/thread_netif.cpp | 2 +- src/core/thread/tmf.cpp | 4 +- src/core/thread/tmf.hpp | 2 +- src/core/utils/heap.hpp | 2 +- src/posix/platform/CMakeLists.txt | 1 + src/posix/platform/ble.cpp | 75 +++ tests/unit/test_platform.cpp | 87 +++ third_party/mbedtls/mbedtls-config.h | 4 + 46 files changed, 4104 insertions(+), 213 deletions(-) create mode 100644 examples/platforms/simulation/ble.c create mode 100644 include/openthread/ble_secure.h create mode 100644 include/openthread/platform/ble.h create mode 100644 include/openthread/tcat.h create mode 100644 src/cli/README_TCAT.md create mode 100644 src/cli/cli_tcat.cpp create mode 100644 src/cli/cli_tcat.hpp create mode 100644 src/core/api/ble_secure_api.cpp rename src/core/config/{dtls.h => secure_transport.h} (79%) rename src/core/meshcop/{dtls.cpp => secure_transport.cpp} (59%) rename src/core/meshcop/{dtls.hpp => secure_transport.hpp} (65%) create mode 100644 src/core/meshcop/tcat_agent.cpp create mode 100644 src/core/meshcop/tcat_agent.hpp create mode 100644 src/core/radio/ble_secure.cpp create mode 100644 src/core/radio/ble_secure.hpp create mode 100644 src/posix/platform/ble.cpp diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 0c667d0eed..dbc88ab595 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -172,6 +172,7 @@ ot_option(OT_ASSERT OPENTHREAD_CONFIG_ASSERT_ENABLE "assert function OT_ASSERT() ot_option(OT_BACKBONE_ROUTER OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE "backbone router functionality") ot_option(OT_BACKBONE_ROUTER_DUA_NDPROXYING OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE "BBR DUA ND Proxy") ot_option(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE "BBR MR") +ot_option(OT_BLE_TCAT OPENTHREAD_CONFIG_BLE_TCAT_ENABLE "Ble based thread commissioning") ot_option(OT_BORDER_AGENT OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE "border agent") ot_option(OT_BORDER_AGENT_ID OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE "create and save border agent ID") ot_option(OT_BORDER_ROUTER OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE "border router") diff --git a/etc/gn/openthread.gni b/etc/gn/openthread.gni index 9bbb543d25..277ee830df 100644 --- a/etc/gn/openthread.gni +++ b/etc/gn/openthread.gni @@ -81,6 +81,9 @@ if (openthread_enable_core_config_args) { # Enable backbone router functionality openthread_config_backbone_router_enable = false + # Enable BLE based commissioning functionality + openthread_config_ble_tcat_enable = false + # Enable border agent support openthread_config_border_agent_enable = false diff --git a/examples/platforms/simulation/CMakeLists.txt b/examples/platforms/simulation/CMakeLists.txt index c99597d4a0..709ffd8e77 100644 --- a/examples/platforms/simulation/CMakeLists.txt +++ b/examples/platforms/simulation/CMakeLists.txt @@ -59,6 +59,7 @@ set(OT_PLATFORM_DEFINES ${OT_PLATFORM_DEFINES} PARENT_SCOPE) add_library(openthread-simulation alarm.c + ble.c crypto.c diag.c dns.c diff --git a/examples/platforms/simulation/ble.c b/examples/platforms/simulation/ble.c new file mode 100644 index 0000000000..2fe3c64535 --- /dev/null +++ b/examples/platforms/simulation/ble.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +otError otPlatBleEnable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleDisable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aInterval); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStop(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapDisconnect(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aMtu); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aHandle); + OT_UNUSED_VARIABLE(aPacket); + return OT_ERROR_NOT_IMPLEMENTED; +} diff --git a/include/openthread/BUILD.gn b/include/openthread/BUILD.gn index 5bc1c09677..aba31dacea 100644 --- a/include/openthread/BUILD.gn +++ b/include/openthread/BUILD.gn @@ -41,6 +41,7 @@ source_set("openthread") { public = [ "backbone_router.h", "backbone_router_ftd.h", + "ble_secure.h", "border_agent.h", "border_router.h", "border_routing.h", @@ -84,6 +85,7 @@ source_set("openthread") { "ping_sender.h", "platform/alarm-micro.h", "platform/alarm-milli.h", + "platform/ble.h", "platform/border_routing.h", "platform/crypto.h", "platform/debug_uart.h", @@ -114,6 +116,7 @@ source_set("openthread") { "srp_client_buffers.h", "srp_server.h", "tasklet.h", + "tcat.h", "tcp.h", "tcp_ext.h", "thread.h", diff --git a/include/openthread/ble_secure.h b/include/openthread/ble_secure.h new file mode 100644 index 0000000000..98d015640e --- /dev/null +++ b/include/openthread/ble_secure.h @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level functions for the OpenThread BLE Secure implementation. + * + * @note + * The functions in this module require the build-time feature `OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1`. + * + * @note + * To enable cipher suite DTLS_PSK_WITH_AES_128_CCM_8, MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * must be enabled in mbedtls-config.h + * To enable cipher suite DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + * MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED must be enabled in mbedtls-config.h. + */ + +#ifndef OPENTHREAD_BLE_SECURE_H_ +#define OPENTHREAD_BLE_SECURE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup api-ble-secure + * + * @brief + * This module includes functions that control BLE Secure (TLS over BLE) communication. + * + * The functions in this module are available when BLE Secure API feature + * (`OPENTHREAD_CONFIG_BLE_TCAT_ENABLE`) is enabled. + * + * @{ + * + */ + +/** + * Pointer to call when ble secure connection state changes. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aConnected TRUE, if a secure connection was established, FALSE otherwise. + * @param[in] aBleConnectionOpen TRUE if a BLE connection was established to carry a TLS data stream, FALSE + * otherwise. + * @param[in] aContext A pointer to arbitrary context information. + * + */ +typedef void (*otHandleBleSecureConnect)(otInstance *aInstance, + bool aConnected, + bool aBleConnectionOpen, + void *aContext); + +/** + * Pointer to call when data was received over a BLE Secure TLS connection. + * + */ +typedef otHandleTcatApplicationDataReceive otHandleBleSecureReceive; + +/** + * Starts the BLE Secure service. + * When TLV mode is active, the function @p aReceiveHandler will be called once a complete TLV was received and the + * message offset points to the TLV value. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aConnectHandler A pointer to a function that will be called when the connection + * state changes. + * @param[in] aReceiveHandler A pointer to a function that will be called once data has been received + * over the TLS connection. + * @param[in] aTlvMode A boolean value indicating if line mode shall be activated. + * @param[in] aContext A pointer to arbitrary context information. May be NULL if not used. + * + * @retval OT_ERROR_NONE Successfully started the BLE Secure server. + * @retval OT_ERROR_ALREADY The service was stated already. + * + */ +otError otBleSecureStart(otInstance *aInstance, + otHandleBleSecureConnect aConnectHandler, + otHandleBleSecureReceive aReceiveHandler, + bool aTlvMode, + void *aContext); + +/** + * Enables the TCAT protocol over BLE Secure. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method call, may be + * NULL). + * @param[in] aHandler A pointer to a function that is called when the join operation completes. + * + * @retval OT_ERROR_NONE Successfully started the BLE Secure Joiner role. + * @retval OT_ERROR_INVALID_ARGS @p aElevationPsk or @p aVendorInfo is invalid. + * @retval OT_ERROR_INVALID_STATE The BLE function has not been started or line mode is not selected. + * + */ +otError otBleSecureTcatStart(otInstance *aInstance, const otTcatVendorInfo *aVendorInfo, otHandleTcatJoin aHandler); + +/** + * Stops the BLE Secure server. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otBleSecureStop(otInstance *aInstance); + +/** + * Sets the Pre-Shared Key (PSK) and cipher suite + * TLS_PSK_WITH_AES_128_CCM_8. + * + * @note Requires the build-time feature `MBEDTLS_KEY_EXCHANGE_PSK_ENABLED` to be enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aPsk A pointer to the PSK. + * @param[in] aPskLength The PSK length. + * @param[in] aPskIdentity The Identity Name for the PSK. + * @param[in] aPskIdLength The PSK Identity Length. + * + */ +void otBleSecureSetPsk(otInstance *aInstance, + const uint8_t *aPsk, + uint16_t aPskLength, + const uint8_t *aPskIdentity, + uint16_t aPskIdLength); + +/** + * Returns the peer x509 certificate base64 encoded. + * + * @note Requires the build-time features `MBEDTLS_BASE64_C` and + * `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aPeerCert A pointer to the base64 encoded certificate buffer. + * @param[in,out] aCertLength On input, the size the max size of @p aPeerCert. + * On output, the length of the base64 encoded peer certificate. + * + * @retval OT_ERROR_NONE Successfully get the peer certificate. + * @retval OT_ERROR_INVALID_ARGS @p aInstance or @p aCertLength is invalid. + * @retval OT_ERROR_INVALID_STATE Not connected yet. + * @retval OT_ERROR_NO_BUFS Can't allocate memory for certificate. + * + */ +otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength); + +/** + * Returns an attribute value identified by its OID from the subject + * of the peer x509 certificate. The peer OID is provided in binary format. + * The attribute length is set if the attribute was successfully read or zero + * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard + * if the attribute was successfully read. + * + * @note Requires the build-time feature + * `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aOid A pointer to the OID to be found. + * @param[in] aOidLength The length of the OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer. + * + * @retval OT_ERROR_INVALID_STATE Not connected yet. + * @retval OT_ERROR_INVALID_ARGS Invalid attribute length. + * @retval OT_ERROR_NONE Successfully read attribute. + * @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value. + * + */ +otError otBleSecureGetPeerSubjectAttributeByOid(otInstance *aInstance, + const char *aOid, + size_t aOidLength, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength, + int *aAsn1Type); + +/** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @note Requires the build-time feature + * `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval OT_ERROR_NONE Successfully read attribute. + * @retval OT_ERROR_INVALID_ARGS Invalid attribute length. + * @retval OT_NOT_FOUND The requested attribute was not found. + * @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value. + * @retval OT_ERROR_INVALID_STATE Not connected yet. + * @retval OT_ERROR_NOT_IMPLEMENTED The value of aThreadOidDescriptor is >127. + * @retval OT_ERROR_PARSE The certificate extensions could not be parsed. + * + */ +otError otBleSecureGetThreadAttributeFromPeerCertificate(otInstance *aInstance, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength); + +/** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval OT_ERROR_NONE Successfully read attribute. + * @retval OT_ERROR_INVALID_ARGS Invalid attribute length. + * @retval OT_NOT_FOUND The requested attribute was not found. + * @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value. + * @retval OT_ERROR_INVALID_STATE Not connected yet. + * @retval OT_ERROR_NOT_IMPLEMENTED The value of aThreadOidDescriptor is >127. + * @retval OT_ERROR_PARSE The certificate extensions could not be parsed. + * + */ +otError otBleSecureGetThreadAttributeFromOwnCertificate(otInstance *aInstance, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength); + +/** + * Sets the authentication mode for the BLE secure connection. + * + * Disable or enable the verification of peer certificate. + * Must be called before start. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aVerifyPeerCertificate true, to verify the peer certificate. + * + */ +void otBleSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate); + +/** + * Sets the local device's X509 certificate with corresponding private key for + * TLS session with TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8. + * + * @note Requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aX509Cert A pointer to the PEM formatted X509 certificate. + * @param[in] aX509Length The length of certificate. + * @param[in] aPrivateKey A pointer to the PEM formatted private key. + * @param[in] aPrivateKeyLength The length of the private key. + * + */ +void otBleSecureSetCertificate(otInstance *aInstance, + const uint8_t *aX509Cert, + uint32_t aX509Length, + const uint8_t *aPrivateKey, + uint32_t aPrivateKeyLength); + +/** + * Sets the trusted top level CAs. It is needed for validating the + * certificate of the peer. + * + * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. + * + * @note Requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain. + * @param[in] aX509CaCertChainLength The length of chain. + * + */ +void otBleSecureSetCaCertificateChain(otInstance *aInstance, + const uint8_t *aX509CaCertificateChain, + uint32_t aX509CaCertChainLength); + +/** + * Initializes TLS session with a peer using an already open BLE connection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval OT_ERROR_NONE Successfully started TLS connection. + * + */ +otError otBleSecureConnect(otInstance *aInstance); + +/** + * Stops the BLE and TLS connection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otBleSecureDisconnect(otInstance *aInstance); + +/** + * Indicates whether or not the TLS session is active (connected or conneting). + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE If TLS session is active. + * @retval FALSE If TLS session is not active. + * + */ +bool otBleSecureIsConnectionActive(otInstance *aInstance); + +/** + * Indicates whether or not the TLS session is connected. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE The TLS session is connected. + * @retval FALSE The TLS session is not connected. + * + */ +bool otBleSecureIsConnected(otInstance *aInstance); + +/** + * Indicates whether or not the TCAT agent is enabled. + * + * @retval TRUE The TCAT agent is enabled. + * @retval FALSE The TCAT agent is not enabled. + * + */ +bool otBleSecureIsTcatEnabled(otInstance *aInstance); + +/** + * Indicates whether or not a TCAT command class is authorized. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCommandClass A command class to check. + * + * @retval TRUE The command class is authorized. + * @retval FALSE The command class is not authorized. + * + */ +bool otBleSecureIsCommandClassAuthorized(otInstance *aInstance, otTcatCommandClass aCommandClass); + +/** + * Sends a secure BLE message. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMessage A pointer to the message to send. + * + * If the return value is OT_ERROR_NONE, OpenThread takes ownership of @p aMessage, and the caller should no longer + * reference @p aMessage. If the return value is not OT_ERROR_NONE, the caller retains ownership of @p aMessage, + * including freeing @p aMessage if the message buffer is no longer needed. + * + * @retval OT_ERROR_NONE Successfully sent message. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory. + * @retval OT_ERROR_INVALID_STATE TLS connection was not initialized. + * + */ +otError otBleSecureSendMessage(otInstance *aInstance, otMessage *aMessage); + +/** + * Sends a secure BLE data packet. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. + * @param[in] aLength A number indicating the length of the data buffer. + * + * @retval OT_ERROR_NONE Successfully sent data. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory. + * @retval OT_ERROR_INVALID_STATE TLS connection was not initialized. + * + */ +otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength); + +/** + * Sends a secure BLE data packet containing a TCAT Send Application Data TLV. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. + * @param[in] aLength A number indicating the length of the data buffer. + * + * @retval OT_ERROR_NONE Successfully sent data. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory. + * @retval OT_ERROR_INVALID_STATE TLS connection was not initialized. + * + */ +otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength); + +/** + * Flushes the send buffer. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval OT_ERROR_NONE Successfully flushed output buffer. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory. + * @retval OT_ERROR_INVALID_STATE TLS connection was not initialized. + * + */ +otError otBleSecureFlush(otInstance *aInstance); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OPENTHREAD_BLE_SECURE_H_ */ diff --git a/include/openthread/instance.h b/include/openthread/instance.h index d450a02186..9c448ffd21 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (363) +#define OPENTHREAD_API_VERSION (381) /** * @addtogroup api-instance diff --git a/include/openthread/platform/ble.h b/include/openthread/platform/ble.h new file mode 100644 index 0000000000..bf7e48bc42 --- /dev/null +++ b/include/openthread/platform/ble.h @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines a OpenThread BLE GATT peripheral interface driver. + * + */ + +#ifndef OPENTHREAD_PLATFORM_BLE_H_ +#define OPENTHREAD_PLATFORM_BLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include + +/** + * @addtogroup plat-ble + * + * @brief + * This module includes the platform abstraction for BLE Host communication. + * The platform needs to implement Bluetooth LE 4.2 or higher. + * + * @{ + * + */ + +/** + * Time slot duration on PHY layer in microseconds (0.625ms). + * + */ + +#define OT_BLE_TIMESLOT_UNIT 625 + +/** + * Minimum allowed interval for advertising packet in OT_BLE_ADV_INTERVAL_UNIT units (20ms). + * + */ + +#define OT_BLE_ADV_INTERVAL_MIN 0x0020 + +/** + * Maximum allowed interval for advertising packet in OT_BLE_ADV_INTERVAL_UNIT units (10.24s). + * + */ + +#define OT_BLE_ADV_INTERVAL_MAX 0x4000 + +/** + * Default interval for advertising packet (ms). + * + */ + +#define OT_BLE_ADV_INTERVAL_DEFAULT 100 + +/** + * Unit used to calculate interval duration (0.625ms). + * + */ + +#define OT_BLE_ADV_INTERVAL_UNIT OT_BLE_TIMESLOT_UNIT + +/** + * Maximum allowed ATT MTU size (must be >= 23). + * + */ + +#define OT_BLE_ATT_MTU_MAX 67 + +/** + * Default power value for BLE. + */ + +#define OT_BLE_DEFAULT_POWER 0 + +/** + * Represents a BLE packet. + * + */ +typedef struct otBleRadioPacket +{ + uint8_t *mValue; ///< The value of an attribute + uint16_t mLength; ///< Length of the @p mValue. + int8_t mPower; ///< Transmit/receive power in dBm. +} otBleRadioPacket; + +/******************************************************************************* + * @section Bluetooth Low Energy management. + ******************************************************************************/ + +/** + * Enable the Bluetooth Low Energy radio. + * + * @note BLE Device should use the highest ATT_MTU supported that does not + * exceed OT_BLE_ATT_MTU_MAX octets. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @retval OT_ERROR_NONE Successfully enabled. + * @retval OT_ERROR_FAILED The BLE radio could not be enabled. + */ +otError otPlatBleEnable(otInstance *aInstance); + +/** + * Disable the Bluetooth Low Energy radio. + * + * When disabled, the BLE stack will flush event queues and not generate new + * events. The BLE peripheral is turned off or put into a low power sleep + * state. Any dynamic memory used by the stack should be released, + * but static memory may remain reserved. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @retval OT_ERROR_NONE Successfully transitioned to disabled. + * @retval OT_ERROR_FAILED The BLE radio could not be disabled. + * + */ +otError otPlatBleDisable(otInstance *aInstance); + +/**************************************************************************** + * @section Bluetooth Low Energy GAP. + ***************************************************************************/ + +/** + * Starts BLE Advertising procedure. + * + * The BLE device shall use undirected advertising with no filter applied. + * A single BLE Advertising packet must be sent on all advertising + * channels (37, 38 and 39). + * + * @note This function shall be used only for BLE Peripheral role. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aInterval The interval between subsequent advertising packets + * in OT_BLE_ADV_INTERVAL_UNIT units. + * Shall be within OT_BLE_ADV_INTERVAL_MIN and + * OT_BLE_ADV_INTERVAL_MAX range or OT_BLE_ADV_INTERVAL_DEFAULT + * for a default value set at compile time. + * + * @retval OT_ERROR_NONE Advertising procedure has been started. + * @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state. + * @retval OT_ERROR_INVALID_ARGS Invalid interval value has been supplied. + * + */ +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval); + +/** + * Stops BLE Advertising procedure. + * + * @note This function shall be used only for BLE Peripheral role. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @retval OT_ERROR_NONE Advertising procedure has been stopped. + * @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state. + * + */ +otError otPlatBleGapAdvStop(otInstance *aInstance); + +/** + * The BLE driver calls this method to notify OpenThread that a BLE Central Device has + * been connected. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aConnectionId The identifier of the open connection. + * + */ +extern void otPlatBleGapOnConnected(otInstance *aInstance, uint16_t aConnectionId); + +/** + * The BLE driver calls this method to notify OpenThread that the BLE Central Device + * has been disconnected. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aConnectionId The identifier of the closed connection. + * + */ +extern void otPlatBleGapOnDisconnected(otInstance *aInstance, uint16_t aConnectionId); + +/** + * Disconnects BLE connection. + * + * The BLE device shall use the Remote User Terminated Connection (0x13) reason + * code when disconnecting from the peer BLE device.. + * + * @param[in] aInstance The OpenThread instance structure. + * + * @retval OT_ERROR_NONE Disconnection procedure has been started. + * @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state. + * + */ +otError otPlatBleGapDisconnect(otInstance *aInstance); + +/******************************************************************************* + * @section Bluetooth Low Energy GATT Common. + *******************************************************************************/ + +/** + * Reads currently use value of ATT_MTU. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[out] aMtu A pointer to output the current ATT_MTU value. + * + * @retval OT_ERROR_NONE ATT_MTU value has been placed in @p aMtu. + * @retval OT_ERROR_FAILED BLE Device cannot determine its ATT_MTU. + * + */ +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu); + +/** + * The BLE driver calls this method to notify OpenThread that ATT_MTU has been updated. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aMtu The updated ATT_MTU value. + * + */ +extern void otPlatBleGattOnMtuUpdate(otInstance *aInstance, uint16_t aMtu); + +/******************************************************************************* + * @section Bluetooth Low Energy GATT Server. + ******************************************************************************/ + +/** + * Sends ATT Handle Value Indication. + * + * @note This function shall be used only for GATT Server. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aHandle The handle of the attribute to be indicated. + * @param[in] aPacket A pointer to the packet contains value to be indicated. + * + * @retval OT_ERROR_NONE ATT Handle Value Indication has been sent. + * @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state. + * @retval OT_ERROR_INVALID_ARGS Invalid handle value, data or data length has been supplied. + * @retval OT_ERROR_NO_BUFS No available internal buffer found. + * + */ +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket); + +/** + * The BLE driver calls this method to notify OpenThread that an ATT Write Request + * packet has been received. + * + * @note This function shall be used only for GATT Server. + * + * @param[in] aInstance The OpenThread instance structure. + * @param[in] aHandle The handle of the attribute to be written. + * @param[in] aPacket A pointer to the packet contains value to be written to the attribute. + * + */ +extern void otPlatBleGattServerOnWriteRequest(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // end of extern "C" +#endif + +#endif // OPENTHREAD_PLATFORM_BLE_H_ diff --git a/include/openthread/tcat.h b/include/openthread/tcat.h new file mode 100644 index 0000000000..291ce4817f --- /dev/null +++ b/include/openthread/tcat.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level functions for the OpenThread TCAT. + * + * @note + * The functions in this module require the build-time feature `OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1`. + * + * @note + * To enable cipher suite DTLS_PSK_WITH_AES_128_CCM_8, MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * must be enabled in mbedtls-config.h + * To enable cipher suite DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + * MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED must be enabled in mbedtls-config.h. + */ + +#ifndef OPENTHREAD_TCAT_H_ +#define OPENTHREAD_TCAT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup api-ble-secure + * + * @brief + * This module includes functions that implement TCAT communication. + * + * The functions in this module are available when TCAT feature + * (`OPENTHREAD_CONFIG_BLE_TCAT_ENABLE`) is enabled. + * + * @{ + * + */ + +#define OT_TCAT_MAX_SERVICE_NAME_LENGTH \ + 15 ///< Maximum string length of a UDP or TCP service name (does not include null char). + +/** + * Represents TCAT status code. + * + */ +typedef enum otTcatStatusCode +{ + OT_TCAT_STATUS_SUCCESS = 0, ///< Command or request was successfully processed + OT_TCAT_STATUS_UNSUPPORTED = 1, ///< Requested command or received TLV is not supported + OT_TCAT_STATUS_PARSE_ERROR = 2, ///< Request / command could not be parsed correctly + OT_TCAT_STATUS_VALUE_ERROR = 3, ///< The value of the transmitted TLV has an error + OT_TCAT_STATUS_GENERAL_ERROR = 4, ///< An error not matching any other category occurred + OT_TCAT_STATUS_BUSY = 5, ///< Command cannot be executed because the resource is busy + OT_TCAT_STATUS_UNDEFINED = 6, ///< The requested value, data or service is not defined (currently) or not present + OT_TCAT_STATUS_HASH_ERROR = 7, ///< The hash value presented by the commissioner was incorrect + OT_TCAT_STATUS_UNAUTHORIZED = 16, ///< Sender does not have sufficient authorization for the given command + +} otTcatStatusCode; + +/** + * Represents TCAT application protocol. + * + */ +typedef enum otTcatApplicationProtocol +{ + OT_TCAT_APPLICATION_PROTOCOL_NONE = 0, ///< Message which has been sent without activating the TCAT agent + OT_TCAT_APPLICATION_PROTOCOL_STATUS = 1, ///< Message directed to a UDP service + OT_TCAT_APPLICATION_PROTOCOL_TCP = 2, ///< Message directed to a TCP service + +} otTcatApplicationProtocol; + +/** + * Represents a TCAT command class. + * + */ +typedef enum otTcatCommandClass +{ + OT_TCAT_COMMAND_CLASS_GENERAL = 0, ///< TCAT commands related to general operations + OT_TCAT_COMMAND_CLASS_COMMISSIONING = 1, ///< TCAT commands related to commissioning + OT_TCAT_COMMAND_CLASS_EXTRACTION = 2, ///< TCAT commands related to key extraction + OT_TCAT_COMMAND_CLASS_DECOMMISSIONING = 3, ///< TCAT commands related to de-commissioning + OT_TCAT_COMMAND_CLASS_APPLICATION = 4, ///< TCAT commands related to application layer + +} otTcatCommandClass; + +/** + * This structure represents a TCAT vendor information. + * + * The content of this structure MUST persist and remain unchanged while a TCAT session is running. + * + */ +typedef struct otTcatVendorInfo +{ + const char *mProvisioningUrl; ///< Provisioning URL path string + const char *mVendorName; ///< Vendor name string + const char *mVendorModel; ///< Vendor model string + const char *mVendorSwVersion; ///< Vendor software version string + const char *mVendorData; ///< Vendor specific data string + const char *mPskdString; ///< Vendor managed pre-shared key for device + const char *mInstallCode; ///< Vendor managed install code string + const char *mDeviceId; ///< Vendor managed device ID string (if NULL: device ID is set to EUI-64 in binary format) + +} otTcatVendorInfo; + +/** + * Pointer to call when application data was received over a TCAT TLS connection. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMessage A pointer to the message. + * @param[in] aOffset The offset where the application data begins. + * @param[in] aTcatApplicationProtocol The protocol type of the message received. + * @param[in] aServiceName The name of the service the message is direced to. + * @param[in] aContext A pointer to arbitrary context information. + * + */ +typedef void (*otHandleTcatApplicationDataReceive)(otInstance *aInstance, + const otMessage *aMessage, + int32_t aOffset, + otTcatApplicationProtocol aTcatApplicationProtocol, + const char *aServiceName, + void *aContext); + +/** + * Pointer to call to notify the completion of a join operation. + * + * @param[in] aError OT_ERROR_NONE if the join process succeeded. + * OT_ERROR_SECURITY if the join process failed due to security credentials. + * @param[in] aContext A pointer to arbitrary context information. + * + */ +typedef void (*otHandleTcatJoin)(otError aError, void *aContext); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* OPENTHREAD_TCAT_H_ */ diff --git a/script/check-simulation-build-cmake b/script/check-simulation-build-cmake index ee1e2ffa59..eaee3716b8 100755 --- a/script/check-simulation-build-cmake +++ b/script/check-simulation-build-cmake @@ -201,6 +201,9 @@ build_all_features() # Build with RAM settings reset_source "$(dirname "$0")"/cmake-build simulation -DOT_SETTINGS_RAM=ON + + reset_source + "$(dirname "$0")"/cmake-build simulation -DOT_BLE_TCAT=ON } build_nest_common() diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 6be47773c0..022de520b0 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -48,6 +48,7 @@ set(COMMON_SOURCES cli_output.cpp cli_srp_client.cpp cli_srp_server.cpp + cli_tcat.cpp cli_tcp.cpp cli_udp.cpp ) diff --git a/src/cli/README.md b/src/cli/README.md index f10d251000..3b6bb95ebb 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -117,6 +117,7 @@ Done - [sntp](#sntp-query-sntp-server-ip-sntp-server-port) - [state](#state) - [srp](README_SRP.md) +- [tcat](README_TCAT.md) - [tcp](README_TCP.md) - [thread](#thread-start) - [timeinqueue](#timeinqueue) diff --git a/src/cli/README_TCAT.md b/src/cli/README_TCAT.md new file mode 100644 index 0000000000..066a571098 --- /dev/null +++ b/src/cli/README_TCAT.md @@ -0,0 +1,37 @@ +# OpenThread CLI - TCAT Example + +## Command List + +- help [#help] +- start [#start] +- stop [#stop] + +### help + +print help + +```bash +tcat help +help +start +stop +Done +``` + +### start + +Start tcat server and ble advertisement. + +```bash +tcat start +Done +``` + +### stop + +Stop tcat server and ble advertisement. + +```bash +tcat stop +Done +``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 9dc92a79d9..c02555276a 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -147,6 +147,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE , mLinkMetrics(aInstance, *this) #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + , mTcat(aInstance, *this) +#endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE , mLocateInProgress(false) #endif @@ -7273,6 +7276,10 @@ template <> otError Interpreter::Process(Arg aArgs[]) return error; } +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE +template <> otError Interpreter::Process(Arg aArgs[]) { return mTcat.Process(aArgs); } +#endif + #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE template <> otError Interpreter::Process(Arg aArgs[]) { return mTcp.Process(aArgs); } #endif @@ -8542,6 +8549,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[]) CmdEntry("srp"), #endif CmdEntry("state"), +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + CmdEntry("tcat"), +#endif #if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE CmdEntry("tcp"), #endif diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 81c5fe7d0a..f95759e718 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -71,6 +71,7 @@ #include "cli/cli_output.hpp" #include "cli/cli_srp_client.hpp" #include "cli/cli_srp_server.hpp" +#include "cli/cli_tcat.hpp" #include "cli/cli_tcp.hpp" #include "cli/cli_udp.hpp" #if OPENTHREAD_CONFIG_COAP_API_ENABLE @@ -594,6 +595,9 @@ class Interpreter : public OutputImplementer, public Output #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE LinkMetrics mLinkMetrics; #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + Tcat mTcat; +#endif #endif // OPENTHREAD_FTD || OPENTHREAD_MTD #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE diff --git a/src/cli/cli_config.h b/src/cli/cli_config.h index c3762c4a11..ac9b5e1cc3 100644 --- a/src/cli/cli_config.h +++ b/src/cli/cli_config.h @@ -58,6 +58,16 @@ #define OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH 384 #endif +/** + * @def OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + * + * Indicates whether TCAT should be enabled in the CLI tool. + * + */ +#ifndef OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE +#define OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 1 +#endif + /** * @def OPENTHREAD_CONFIG_CLI_TCP_ENABLE * diff --git a/src/cli/cli_tcat.cpp b/src/cli/cli_tcat.cpp new file mode 100644 index 0000000000..e754bca93a --- /dev/null +++ b/src/cli/cli_tcat.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "openthread-core-config.h" + +#include "cli/cli_output.hpp" + +#include "cli/cli_tcat.hpp" + +#include + +#include +#include +#include + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + +#define OT_CLI_TCAT_X509_CERT \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIIBmDCCAT+gAwIBAgIEAQIDBDAKBggqhkjOPQQDAjBvMQswCQYDVQQGEwJYWDEQ\r\n" \ + "MA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQLEwZNeVVu\r\n" \ + "aXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5kb3IuY29t\r\n" \ + "MB4XDTIzMTAxNjEwMzk1NFoXDTI0MTAxNjEwMzk1NFowIjEgMB4GA1UEAxMXbXl2\r\n" \ + "ZW5kb3IuY29tL3RjYXQvbXlkZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\r\n" \ + "aWwFDNj1bpQIdN+Kp2cHWw55U/+fa+OmZnoy1B4BOT+822jdwPBuyXWAQoBdYdQJ\r\n" \ + "ff4RgmhczyV4PhArPIuAoxYwFDASBgkrBgEEAYLfKgMEBQABAQEBMAoGCCqGSM49\r\n" \ + "BAMCA0cAMEQCIBEHxiEDij26y6V77Q311Gj4CZAuZuPGXZpnzL2BLk7bAiAlFk6G\r\n" \ + "mYGzkcrYyssFI9HlPgrisWoMmgummaTtCuvrEw==\r\n" \ + "-----END CERTIFICATE-----\r\n" + +#define OT_CLI_TCAT_PRIV_KEY \ + "-----BEGIN EC PRIVATE KEY-----\r\n" \ + "MHcCAQEEIDeJ6lVQKiOIBxKwTZp6TkU5QVHt9pvXOR9CGpPBI3DhoAoGCCqGSM49\r\n" \ + "AwEHoUQDQgAEAWlsBQzY9W6UCHTfiqdnB1sOeVP/n2vjpmZ6MtQeATk/vNto3cDw\r\n" \ + "bsl1gEKAXWHUCX3+EYJoXM8leD4QKzyLgA==\r\n" \ + "-----END EC PRIVATE KEY-----\r\n" + +#define OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE \ + "-----BEGIN CERTIFICATE-----\r\n" \ + "MIICCDCCAa2gAwIBAgIJAIKxygBXoH+5MAoGCCqGSM49BAMCMG8xCzAJBgNVBAYT\r\n" \ + "AlhYMRAwDgYDVQQIEwdNeVN0YXRlMQ8wDQYDVQQHEwZNeUNpdHkxDzANBgNVBAsT\r\n" \ + "Bk15VW5pdDERMA8GA1UEChMITXlWZW5kb3IxGTAXBgNVBAMTEHd3dy5teXZlbmRv\r\n" \ + "ci5jb20wHhcNMjMxMDE2MTAzMzE1WhcNMjYxMDE2MTAzMzE1WjBvMQswCQYDVQQG\r\n" \ + "EwJYWDEQMA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQL\r\n" \ + "EwZNeVVuaXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5k\r\n" \ + "b3IuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdyzPAXGKeZY94OhHAWX\r\n" \ + "HzJfQIjGSyaOzlgL9OEFw2SoUDncLKPGwfPAUSfuMyEkzszNDM0HHkBsDLqu4n25\r\n" \ + "/6MyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4EynoSw9eDKZEVPkums2\r\n" \ + "IWLAJCowCgYIKoZIzj0EAwIDSQAwRgIhAMYGGL9xShyE6P9wEU+MAYF6W3CzdrwV\r\n" \ + "kuerX1encIH2AiEA5rq490NUobM1Au43roxJq1T6Z43LscPVbGZfULD1Jq0=\r\n" \ + "-----END CERTIFICATE-----\r\n" + +namespace ot { + +namespace Cli { + +otTcatVendorInfo sVendorInfo; +const char kPskdVendor[] = "J01NM3"; +const char kUrl[] = "dummy_url"; + +static void HandleBleSecureReceive(otInstance *aInstance, + const otMessage *aMessage, + int32_t aOffset, + otTcatApplicationProtocol aTcatApplicationProtocol, + const char *aServiceName, + void *aContext) +{ + OT_UNUSED_VARIABLE(aContext); + OT_UNUSED_VARIABLE(aTcatApplicationProtocol); + OT_UNUSED_VARIABLE(aServiceName); + static constexpr int kTextMaxLen = 100; + static constexpr uint8_t kBufPrefixLen = 5; + uint16_t nLen; + uint8_t buf[kTextMaxLen]; + + nLen = otMessageRead(aMessage, (uint16_t)aOffset, buf + kBufPrefixLen, sizeof(buf) - kBufPrefixLen - 1); + + memcpy(buf, "RECV:", kBufPrefixLen); + + buf[nLen + kBufPrefixLen] = 0; + + IgnoreReturnValue(otBleSecureSendApplicationTlv(aInstance, buf, (uint16_t)strlen((char *)buf))); + IgnoreReturnValue(otBleSecureFlush(aInstance)); +} + +template <> otError Tcat::Process(Arg aArgs[]) +{ + OT_UNUSED_VARIABLE(aArgs); + + otError error = OT_ERROR_NONE; + + sVendorInfo.mPskdString = kPskdVendor; + sVendorInfo.mProvisioningUrl = kUrl; + + otBleSecureSetCertificate(GetInstancePtr(), reinterpret_cast(OT_CLI_TCAT_X509_CERT), + sizeof(OT_CLI_TCAT_X509_CERT), reinterpret_cast(OT_CLI_TCAT_PRIV_KEY), + sizeof(OT_CLI_TCAT_PRIV_KEY)); + + otBleSecureSetCaCertificateChain(GetInstancePtr(), + reinterpret_cast(OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE), + sizeof(OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE)); + + otBleSecureSetSslAuthMode(GetInstancePtr(), true); + + SuccessOrExit(error = otBleSecureStart(GetInstancePtr(), nullptr, HandleBleSecureReceive, true, nullptr)); + SuccessOrExit(error = otBleSecureTcatStart(GetInstancePtr(), &sVendorInfo, nullptr)); + +exit: + return error; +} + +template <> otError Tcat::Process(Arg aArgs[]) +{ + OT_UNUSED_VARIABLE(aArgs); + otError error = OT_ERROR_NONE; + + otBleSecureStop(GetInstancePtr()); + + return error; +} + +otError Tcat::Process(Arg aArgs[]) +{ +#define CmdEntry(aCommandString) \ + { \ + aCommandString, &Tcat::Process \ + } + + static constexpr Command kCommands[] = {CmdEntry("start"), CmdEntry("stop")}; + + static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); + + otError error = OT_ERROR_NONE; + const Command *command; + + if (aArgs[0].IsEmpty() || (aArgs[0] == "help")) + { + OutputCommandTable(kCommands); + ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE); + } + + command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); + VerifyOrExit(command != nullptr); + + error = (this->*command->mHandler)(aArgs + 1); + +exit: + return error; +} + +} // namespace Cli +} // namespace ot +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE diff --git a/src/cli/cli_tcat.hpp b/src/cli/cli_tcat.hpp new file mode 100644 index 0000000000..3f1d0be6e6 --- /dev/null +++ b/src/cli/cli_tcat.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CLI_TCAT_HPP_ +#define CLI_TCAT_HPP_ + +#include "openthread-core-config.h" + +#include "cli/cli_output.hpp" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + +namespace ot { + +namespace Cli { + +/** + * Implements the Tcat CLI interpreter. + * + */ +class Tcat : private Output +{ +public: + typedef Utils::CmdLineParser::Arg Arg; + + /** + * Constructor + * + * @param[in] aInstance The OpenThread Instance. + * @param[in] aOutputImplementer An `OutputImplementer`. + * + */ + Tcat(otInstance *aInstance, OutputImplementer &aOutputImplementer) + : Output(aInstance, aOutputImplementer) + { + } + + /** + * Processes a CLI sub-command. + * + * @param[in] aArgs An array of command line arguments. + * + * @retval OT_ERROR_NONE Successfully executed the CLI command. + * @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending. + * @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments. + * @retval ... Error during execution of the CLI command. + * + */ + otError Process(Arg aArgs[]); + +private: + using Command = CommandEntry; + + template otError Process(Arg aArgs[]); +}; + +} // namespace Cli + +} // namespace ot + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + +#endif // CLI_TCAT_HPP_ diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index abb606ed77..0f666dd7b8 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -74,6 +74,10 @@ if (openthread_enable_core_config_args) { defines += [ "OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE=1" ] } + if (openthread_config_ble_tcat_enable) { + defines += [ "OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1" ] + } + if (openthread_config_border_agent_enable) { defines += [ "OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE=1" ] } @@ -301,6 +305,7 @@ config("core_config") { openthread_core_files = [ "api/backbone_router_api.cpp", "api/backbone_router_ftd_api.cpp", + "api/ble_secure_api.cpp", "api/border_agent_api.cpp", "api/border_router_api.cpp", "api/border_routing_api.cpp", @@ -510,8 +515,6 @@ openthread_core_files = [ "meshcop/dataset_manager_ftd.cpp", "meshcop/dataset_updater.cpp", "meshcop/dataset_updater.hpp", - "meshcop/dtls.cpp", - "meshcop/dtls.hpp", "meshcop/energy_scan_client.cpp", "meshcop/energy_scan_client.hpp", "meshcop/extended_panid.cpp", @@ -530,6 +533,10 @@ openthread_core_files = [ "meshcop/network_name.hpp", "meshcop/panid_query_client.cpp", "meshcop/panid_query_client.hpp", + "meshcop/secure_transport.cpp", + "meshcop/secure_transport.hpp", + "meshcop/tcat_agent.cpp", + "meshcop/tcat_agent.hpp", "meshcop/timestamp.cpp", "meshcop/timestamp.hpp", "net/checksum.cpp", @@ -585,6 +592,8 @@ openthread_core_files = [ "net/tcp6_ext.hpp", "net/udp6.cpp", "net/udp6.hpp", + "radio/ble_secure.cpp", + "radio/ble_secure.hpp", "radio/max_power_table.hpp", "radio/radio.cpp", "radio/radio.hpp", @@ -790,7 +799,6 @@ source_set("libopenthread_core_config") { "config/dns_client.h", "config/dns_dso.h", "config/dnssd_server.h", - "config/dtls.h", "config/history_tracker.h", "config/ip6.h", "config/joiner.h", @@ -812,6 +820,7 @@ source_set("libopenthread_core_config") { "config/platform.h", "config/power_calibration.h", "config/radio_link.h", + "config/secure_transport.h", "config/sntp_client.h", "config/srp_client.h", "config/srp_server.h", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 813979ad7a..24ceb22715 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,6 +33,7 @@ set(COMMON_INCLUDES set(COMMON_SOURCES api/backbone_router_api.cpp api/backbone_router_ftd_api.cpp + api/ble_secure_api.cpp api/border_agent_api.cpp api/border_router_api.cpp api/border_routing_api.cpp @@ -148,7 +149,6 @@ set(COMMON_SOURCES meshcop/dataset_manager.cpp meshcop/dataset_manager_ftd.cpp meshcop/dataset_updater.cpp - meshcop/dtls.cpp meshcop/energy_scan_client.cpp meshcop/extended_panid.cpp meshcop/joiner.cpp @@ -158,6 +158,8 @@ set(COMMON_SOURCES meshcop/meshcop_tlvs.cpp meshcop/network_name.cpp meshcop/panid_query_client.cpp + meshcop/secure_transport.cpp + meshcop/tcat_agent.cpp meshcop/timestamp.cpp net/checksum.cpp net/dhcp6_client.cpp @@ -185,6 +187,7 @@ set(COMMON_SOURCES net/tcp6.cpp net/tcp6_ext.cpp net/udp6.cpp + radio/ble_secure.cpp radio/radio.cpp radio/radio_callbacks.cpp radio/radio_platform.cpp diff --git a/src/core/api/ble_secure_api.cpp b/src/core/api/ble_secure_api.cpp new file mode 100644 index 0000000000..d30a7f0aa6 --- /dev/null +++ b/src/core/api/ble_secure_api.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread BLE Secure API. + */ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#include +#include + +#include "common/as_core_type.hpp" +#include "common/code_utils.hpp" +#include "common/locator_getters.hpp" +#include "meshcop/tcat_agent.hpp" +#include "radio/ble_secure.hpp" + +using namespace ot; + +otError otBleSecureStart(otInstance *aInstance, + otHandleBleSecureConnect aConnectHandler, + otHandleBleSecureReceive aReceiveHandler, + bool aTlvMode, + void *aContext) +{ + return AsCoreType(aInstance).Get().Start(aConnectHandler, aReceiveHandler, aTlvMode, aContext); +} + +otError otBleSecureTcatStart(otInstance *aInstance, const otTcatVendorInfo *aVendorInfo, otHandleTcatJoin aHandler) +{ + return AsCoreType(aInstance).Get().TcatStart(AsCoreType(aVendorInfo), aHandler); +} + +void otBleSecureStop(otInstance *aInstance) { AsCoreType(aInstance).Get().Stop(); } + +#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +void otBleSecureSetPsk(otInstance *aInstance, + const uint8_t *aPsk, + uint16_t aPskLength, + const uint8_t *aPskIdentity, + uint16_t aPskIdLength) +{ + AssertPointerIsNotNull(aPsk); + AssertPointerIsNotNull(aPskIdentity); + OT_ASSERT(aPskLength != 0 && aPskIdLength != 0); + + AsCoreType(aInstance).Get().SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength); +} +#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength) +{ + return AsCoreType(aInstance).Get().GetPeerCertificateBase64(aPeerCert, aCertLength); +} +#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +otError otBleSecureGetPeerSubjectAttributeByOid(otInstance *aInstance, + const char *aOid, + size_t aOidLength, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength, + int *aAsn1Type) +{ + return AsCoreType(aInstance).Get().GetPeerSubjectAttributeByOid(aOid, aOidLength, aAttributeBuffer, + aAttributeLength, aAsn1Type); +} + +otError otBleSecureGetThreadAttributeFromPeerCertificate(otInstance *aInstance, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) +{ + return AsCoreType(aInstance).Get().GetThreadAttributeFromPeerCertificate( + aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); +} +#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + +otError otBleSecureGetThreadAttributeFromOwnCertificate(otInstance *aInstance, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) +{ + return AsCoreType(aInstance).Get().GetThreadAttributeFromOwnCertificate( + aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); +} + +void otBleSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate) +{ + AsCoreType(aInstance).Get().SetSslAuthMode(aVerifyPeerCertificate); +} + +#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +void otBleSecureSetCertificate(otInstance *aInstance, + const uint8_t *aX509Cert, + uint32_t aX509Length, + const uint8_t *aPrivateKey, + uint32_t aPrivateKeyLength) +{ + OT_ASSERT(aX509Cert != nullptr && aX509Length != 0 && aPrivateKey != nullptr && aPrivateKeyLength != 0); + + AsCoreType(aInstance).Get().SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength); +} + +void otBleSecureSetCaCertificateChain(otInstance *aInstance, + const uint8_t *aX509CaCertificateChain, + uint32_t aX509CaCertChainLength) +{ + OT_ASSERT(aX509CaCertificateChain != nullptr && aX509CaCertChainLength != 0); + + AsCoreType(aInstance).Get().SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength); +} +#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +otError otBleSecureConnect(otInstance *aInstance) { return AsCoreType(aInstance).Get().Connect(); } + +void otBleSecureDisconnect(otInstance *aInstance) { AsCoreType(aInstance).Get().Disconnect(); } + +bool otBleSecureIsConnectionActive(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().IsConnectionActive(); +} + +bool otBleSecureIsConnected(otInstance *aInstance) { return AsCoreType(aInstance).Get().IsConnected(); } + +bool otBleSecureIsTcatEnabled(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().IsTcatEnabled(); +} + +bool otBleSecureIsCommandClassAuthorized(otInstance *aInstance, otTcatCommandClass aCommandClass) +{ + return AsCoreType(aInstance).Get().IsCommandClassAuthorized( + static_cast(aCommandClass)); +} + +otError otBleSecureSendMessage(otInstance *aInstance, otMessage *aMessage) +{ + return AsCoreType(aInstance).Get().SendMessage(AsCoreType(aMessage)); +} + +otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength) +{ + return AsCoreType(aInstance).Get().Send(aBuf, aLength); +} + +otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength) +{ + return AsCoreType(aInstance).Get().SendApplicationTlv(aBuf, aLength); +} + +otError otBleSecureFlush(otInstance *aInstance) { return AsCoreType(aInstance).Get().Flush(); } + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE diff --git a/src/core/coap/coap_secure.cpp b/src/core/coap/coap_secure.cpp index 7d0fbe1b3f..1077cecc01 100644 --- a/src/core/coap/coap_secure.cpp +++ b/src/core/coap/coap_secure.cpp @@ -28,13 +28,14 @@ #include "coap_secure.hpp" -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE #include "common/locator_getters.hpp" #include "common/log.hpp" #include "common/new.hpp" #include "instance/instance.hpp" -#include "meshcop/dtls.hpp" +#include "meshcop/secure_transport.hpp" + #include "thread/thread_netif.hpp" /** @@ -67,7 +68,7 @@ Error CoapSecure::Start(uint16_t aPort) return error; } -Error CoapSecure::Start(MeshCoP::Dtls::TransportCallback aCallback, void *aContext) +Error CoapSecure::Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext) { Error error = kErrorNone; @@ -98,7 +99,7 @@ Error CoapSecure::Connect(const Ip6::SockAddr &aSockAddr, ConnectedCallback aCal void CoapSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd) { static_assert(static_cast(MeshCoP::JoinerPskd::kMaxLength) <= - static_cast(MeshCoP::Dtls::kPskMaxLength), + static_cast(MeshCoP::SecureTransport::kPskMaxLength), "The maximum length of DTLS PSK is smaller than joiner PSKd"); SuccessOrAssert(mDtls.SetPsk(reinterpret_cast(aPskd.GetAsCString()), aPskd.GetLength())); @@ -224,4 +225,4 @@ void CoapSecure::HandleTransmit(void) } // namespace Coap } // namespace ot -#endif // OPENTHREAD_CONFIG_DTLS_ENABLE +#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE diff --git a/src/core/coap/coap_secure.hpp b/src/core/coap/coap_secure.hpp index b24e7d0fb2..50a1d45216 100644 --- a/src/core/coap/coap_secure.hpp +++ b/src/core/coap/coap_secure.hpp @@ -31,12 +31,12 @@ #include "openthread-core-config.h" -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE #include "coap/coap.hpp" #include "common/callback.hpp" -#include "meshcop/dtls.hpp" #include "meshcop/meshcop.hpp" +#include "meshcop/secure_transport.hpp" #include @@ -91,7 +91,7 @@ class CoapSecure : public CoapBase * @retval kErrorAlready Already started. * */ - Error Start(MeshCoP::Dtls::TransportCallback aCallback, void *aContext); + Error Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext); /** * Sets connected callback of this secure CoAP agent. @@ -153,7 +153,7 @@ class CoapSecure : public CoapBase * @returns A reference to the DTLS object. * */ - MeshCoP::Dtls &GetDtls(void) { return mDtls; } + MeshCoP::SecureTransport &GetDtls(void) { return mDtls; } /** * Gets the UDP port of this agent. @@ -409,7 +409,7 @@ class CoapSecure : public CoapBase static void HandleTransmit(Tasklet &aTasklet); void HandleTransmit(void); - MeshCoP::Dtls mDtls; + MeshCoP::SecureTransport mDtls; Callback mConnectedCallback; ot::MessageQueue mTransmitQueue; TaskletContext mTransmitTask; @@ -418,6 +418,6 @@ class CoapSecure : public CoapBase } // namespace Coap } // namespace ot -#endif // OPENTHREAD_CONFIG_DTLS_ENABLE +#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE #endif // COAP_SECURE_HPP_ diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index 66153e240e..d48f719c2a 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -286,7 +286,8 @@ class Message : public otMessage, public Buffer, public GetProvider kTypeSupervision = 2, ///< A child supervision frame. kTypeMacEmptyData = 3, ///< An empty MAC data frame. kTypeIp4 = 4, ///< A full uncompressed IPv4 packet, for NAT64. - kTypeOther = 5, ///< Other (data) message. + kTypeBle = 5, ///< A BLE payload message. + kTypeOther = 6, ///< Other (data) message. }; /** diff --git a/src/core/config/ip6.h b/src/core/config/ip6.h index 75976e1a16..82dc45c954 100644 --- a/src/core/config/ip6.h +++ b/src/core/config/ip6.h @@ -178,7 +178,7 @@ * Define as 1 to enable support for TLS over TCP. * */ -#if OPENTHREAD_CONFIG_TCP_ENABLE && !defined(OPENTHREAD_CONFIG_TLS_ENABLE) +#if (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) && !defined(OPENTHREAD_CONFIG_TLS_ENABLE) #define OPENTHREAD_CONFIG_TLS_ENABLE 1 #endif diff --git a/src/core/config/openthread-core-config-check.h b/src/core/config/openthread-core-config-check.h index 5d26a6e0ff..de4fe15597 100644 --- a/src/core/config/openthread-core-config-check.h +++ b/src/core/config/openthread-core-config-check.h @@ -122,7 +122,7 @@ #endif #ifdef OPENTHREAD_ENABLE_DTLS -#error "OPENTHREAD_ENABLE_DTLS was replaced by OPENTHREAD_CONFIG_DTLS_ENABLE." +#error "OPENTHREAD_ENABLE_DTLS was replaced by OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE." #endif #ifdef OPENTHREAD_ENABLE_JAM_DETECTION diff --git a/src/core/config/dtls.h b/src/core/config/secure_transport.h similarity index 79% rename from src/core/config/dtls.h rename to src/core/config/secure_transport.h index 09e833788b..ea6799ff9a 100644 --- a/src/core/config/dtls.h +++ b/src/core/config/secure_transport.h @@ -28,12 +28,12 @@ /** * @file - * This file includes compile-time configurations for DTLS. + * This file includes compile-time configurations for TLS/DTLS. * */ -#ifndef CONFIG_DTLS_H_ -#define CONFIG_DTLS_H_ +#ifndef CONFIG_SECURE_TRANSPORT_H_ +#define CONFIG_SECURE_TRANSPORT_H_ #include "config/border_agent.h" #include "config/coap.h" @@ -51,15 +51,19 @@ #endif /** - * @def OPENTHREAD_CONFIG_DTLS_ENABLE + * @def OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE * - * Define to 1 to enable DTLS. + * Define to 1 to enable DTLS/TLS. * */ -#ifndef OPENTHREAD_CONFIG_DTLS_ENABLE -#define OPENTHREAD_CONFIG_DTLS_ENABLE \ +#ifndef OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE +#define OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE \ (OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || \ - OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE) + OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) #endif -#endif // CONFIG_DTLS_H_ +#if OPENTHREAD_CONFIG_DTLS_ENABLE +#error "OPENTHREAD_CONFIG_DTLS_ENABLE is deprecated please use OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE instead" +#endif + +#endif // CONFIG_SECURE_TRANSPORT_H_ diff --git a/src/core/instance/instance.cpp b/src/core/instance/instance.cpp index 6dcc3e8927..dd394fe79a 100644 --- a/src/core/instance/instance.cpp +++ b/src/core/instance/instance.cpp @@ -146,7 +146,7 @@ Instance::Instance(void) #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD , mCommissioner(*this) #endif -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE , mTmfSecureAgent(*this) #endif #if OPENTHREAD_CONFIG_JOINER_ENABLE @@ -201,6 +201,9 @@ Instance::Instance(void) #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE , mApplicationCoapSecure(*this, /* aLayerTwoSecurity */ true) #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + , mApplicationBleSecure(*this) +#endif #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE , mPingSender(*this) #endif @@ -423,7 +426,7 @@ void Instance::GetBufferInfo(BufferInfo &aInfo) Get().GetRequestMessages().GetInfo(aInfo.mCoapQueue); Get().GetCachedResponses().GetInfo(aInfo.mCoapQueue); -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE Get().GetRequestMessages().GetInfo(aInfo.mCoapSecureQueue); Get().GetCachedResponses().GetInfo(aInfo.mCoapSecureQueue); #endif diff --git a/src/core/instance/instance.hpp b/src/core/instance/instance.hpp index 6b26825abd..8b0d2914b4 100644 --- a/src/core/instance/instance.hpp +++ b/src/core/instance/instance.hpp @@ -97,6 +97,7 @@ #include "net/sntp_client.hpp" #include "net/srp_client.hpp" #include "net/srp_server.hpp" +#include "radio/ble_secure.hpp" #include "thread/address_resolver.hpp" #include "thread/announce_begin_server.hpp" #include "thread/announce_sender.hpp" @@ -520,7 +521,7 @@ class Instance : public otInstance, private NonCopyable MeshCoP::Commissioner mCommissioner; #endif -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE Tmf::SecureAgent mTmfSecureAgent; #endif @@ -591,6 +592,10 @@ class Instance : public otInstance, private NonCopyable Coap::CoapSecure mApplicationCoapSecure; #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + Ble::BleSecure mApplicationBleSecure; +#endif + #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE Utils::PingSender mPingSender; #endif @@ -801,7 +806,7 @@ template <> inline Ip6::Mpl &Instance::Get(void) { return mIp6.mMpl; } template <> inline Tmf::Agent &Instance::Get(void) { return mTmfAgent; } -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE template <> inline Tmf::SecureAgent &Instance::Get(void) { return mTmfSecureAgent; } #endif @@ -988,6 +993,10 @@ template <> inline Nat64::Translator &Instance::Get(void) { return mNat64Transla template <> inline Srp::Server &Instance::Get(void) { return mSrpServer; } #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +template <> inline Ble::BleSecure &Instance::Get(void) { return mApplicationBleSecure; } +#endif + #endif // OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 74c910c9d5..b971c7f2fe 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -50,9 +50,9 @@ #include "common/timer.hpp" #include "mac/mac_types.hpp" #include "meshcop/announce_begin_client.hpp" -#include "meshcop/dtls.hpp" #include "meshcop/energy_scan_client.hpp" #include "meshcop/panid_query_client.hpp" +#include "meshcop/secure_transport.hpp" #include "net/ip6_address.hpp" #include "net/udp6.hpp" #include "thread/key_manager.hpp" diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp index 1b42c6ad34..ce430a7374 100644 --- a/src/core/meshcop/joiner.hpp +++ b/src/core/meshcop/joiner.hpp @@ -49,9 +49,9 @@ #include "common/message.hpp" #include "common/non_copyable.hpp" #include "mac/mac_types.hpp" -#include "meshcop/dtls.hpp" #include "meshcop/meshcop.hpp" #include "meshcop/meshcop_tlvs.hpp" +#include "meshcop/secure_transport.hpp" #include "thread/discover_scanner.hpp" #include "thread/tmf.hpp" diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/secure_transport.cpp similarity index 59% rename from src/core/meshcop/dtls.cpp rename to src/core/meshcop/secure_transport.cpp index e3c2275f16..945f701c6b 100644 --- a/src/core/meshcop/dtls.cpp +++ b/src/core/meshcop/secure_transport.cpp @@ -31,7 +31,7 @@ * This file implements the necessary hooks for mbedTLS. */ -#include "dtls.hpp" +#include "secure_transport.hpp" #include #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED @@ -52,42 +52,43 @@ #include "instance/instance.hpp" #include "thread/thread_netif.hpp" -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE namespace ot { namespace MeshCoP { -RegisterLogModule("Dtls"); +RegisterLogModule("SecTransport"); #if (MBEDTLS_VERSION_NUMBER >= 0x03010000) -const uint16_t Dtls::sGroups[] = {MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, MBEDTLS_SSL_IANA_TLS_GROUP_NONE}; +const uint16_t SecureTransport::sGroups[] = {MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, MBEDTLS_SSL_IANA_TLS_GROUP_NONE}; #else -const mbedtls_ecp_group_id Dtls::sCurves[] = {MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_ECP_DP_NONE}; +const mbedtls_ecp_group_id SecureTransport::sCurves[] = {MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_ECP_DP_NONE}; #endif #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) #if (MBEDTLS_VERSION_NUMBER >= 0x03020000) -const uint16_t Dtls::sSignatures[] = {MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256, MBEDTLS_TLS1_3_SIG_NONE}; +const uint16_t SecureTransport::sSignatures[] = {MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256, MBEDTLS_TLS1_3_SIG_NONE}; #else -const int Dtls::sHashes[] = {MBEDTLS_MD_SHA256, MBEDTLS_MD_NONE}; +const int SecureTransport::sHashes[] = {MBEDTLS_MD_SHA256, MBEDTLS_MD_NONE}; #endif #endif -Dtls::Dtls(Instance &aInstance, bool aLayerTwoSecurity) +SecureTransport::SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bool aDatagramTransport) : InstanceLocator(aInstance) , mState(kStateClosed) , mPskLength(0) , mVerifyPeerCertificate(true) - , mTimer(aInstance, Dtls::HandleTimer, this) + , mTimer(aInstance, SecureTransport::HandleTimer, this) , mTimerIntermediate(0) , mTimerSet(false) , mLayerTwoSecurity(aLayerTwoSecurity) + , mDatagramTransport(aDatagramTransport) , mReceiveMessage(nullptr) , mSocket(aInstance) , mMessageSubType(Message::kSubTypeNone) , mMessageDefaultSubType(Message::kSubTypeNone) { -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED mPreSharedKey = nullptr; mPreSharedKeyIdentity = nullptr; @@ -118,12 +119,15 @@ Dtls::Dtls(Instance &aInstance, bool aLayerTwoSecurity) #endif } -void Dtls::FreeMbedtls(void) +void SecureTransport::FreeMbedtls(void) { #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C) - mbedtls_ssl_cookie_free(&mCookieCtx); + if (mDatagramTransport) + { + mbedtls_ssl_cookie_free(&mCookieCtx); + } #endif -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED mbedtls_x509_crt_free(&mCaChain); mbedtls_x509_crt_free(&mOwnCert); @@ -134,13 +138,13 @@ void Dtls::FreeMbedtls(void) mbedtls_ssl_free(&mSsl); } -Error Dtls::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext) +Error SecureTransport::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext) { Error error; VerifyOrExit(mState == kStateClosed, error = kErrorAlready); - SuccessOrExit(error = mSocket.Open(&Dtls::HandleUdpReceive, this)); + SuccessOrExit(error = mSocket.Open(&SecureTransport::HandleUdpReceive, this)); mConnectedCallback.Set(aConnectedHandler, aContext); mReceiveCallback.Set(aReceiveHandler, aContext); @@ -150,7 +154,7 @@ Error Dtls::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHand return error; } -Error Dtls::Connect(const Ip6::SockAddr &aSockAddr) +Error SecureTransport::Connect(const Ip6::SockAddr &aSockAddr) { Error error; @@ -165,24 +169,30 @@ Error Dtls::Connect(const Ip6::SockAddr &aSockAddr) return error; } -void Dtls::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) +void SecureTransport::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo) { - static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); + static_cast(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo)); } -void Dtls::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +void SecureTransport::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { switch (mState) { - case Dtls::kStateClosed: + case SecureTransport::kStateClosed: ExitNow(); - case Dtls::kStateOpen: + case SecureTransport::kStateOpen: + IgnoreError(mSocket.Connect(Ip6::SockAddr(aMessageInfo.GetPeerAddr(), aMessageInfo.GetPeerPort()))); + mMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr()); mMessageInfo.SetPeerPort(aMessageInfo.GetPeerPort()); mMessageInfo.SetIsHostInterface(aMessageInfo.IsHostInterface()); - mMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr()); + if (Get().HasUnicastAddress(aMessageInfo.GetSockAddr())) + { + mMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr()); + } + mMessageInfo.SetSockPort(aMessageInfo.GetSockPort()); SuccessOrExit(Setup(false)); @@ -196,7 +206,7 @@ void Dtls::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageI } #ifdef MBEDTLS_SSL_SRV_C - if (mState == Dtls::kStateConnecting) + if (mState == SecureTransport::kStateConnecting) { IgnoreError(SetClientId(mMessageInfo.GetPeerAddr().mFields.m8, sizeof(mMessageInfo.GetPeerAddr().mFields))); } @@ -208,9 +218,9 @@ void Dtls::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageI return; } -uint16_t Dtls::GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); } +uint16_t SecureTransport::GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); } -Error Dtls::Bind(uint16_t aPort) +Error SecureTransport::Bind(uint16_t aPort) { Error error; @@ -223,7 +233,7 @@ Error Dtls::Bind(uint16_t aPort) return error; } -Error Dtls::Bind(TransportCallback aCallback, void *aContext) +Error SecureTransport::Bind(TransportCallback aCallback, void *aContext) { Error error = kErrorNone; @@ -237,7 +247,7 @@ Error Dtls::Bind(TransportCallback aCallback, void *aContext) return error; } -Error Dtls::Setup(bool aClient) +Error SecureTransport::Setup(bool aClient) { int rval; @@ -248,7 +258,7 @@ Error Dtls::Setup(bool aClient) mbedtls_ssl_init(&mSsl); mbedtls_ssl_config_init(&mConf); -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED mbedtls_x509_crt_init(&mCaChain); mbedtls_x509_crt_init(&mOwnCert); @@ -256,15 +266,20 @@ Error Dtls::Setup(bool aClient) #endif #endif #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C) - mbedtls_ssl_cookie_init(&mCookieCtx); + if (mDatagramTransport) + { + mbedtls_ssl_cookie_init(&mCookieCtx); + } #endif - rval = mbedtls_ssl_config_defaults(&mConf, aClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); + rval = mbedtls_ssl_config_defaults( + &mConf, aClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER, + mDatagramTransport ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); VerifyOrExit(rval == 0); -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE - if (mVerifyPeerCertificate && mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) +#if OPENTHREAD_CONFIG_TLS_API_ENABLE + if (mVerifyPeerCertificate && (mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || + mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)) { mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_REQUIRED); } @@ -313,7 +328,7 @@ Error Dtls::Setup(bool aClient) mbedtls_ssl_conf_dbg(&mConf, HandleMbedtlsDebug, this); #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C) - if (!aClient) + if (!aClient && mDatagramTransport) { rval = mbedtls_ssl_cookie_setup(&mCookieCtx, Crypto::MbedTls::CryptoSecurePrng, nullptr); VerifyOrExit(rval == 0); @@ -325,17 +340,21 @@ Error Dtls::Setup(bool aClient) rval = mbedtls_ssl_setup(&mSsl, &mConf); VerifyOrExit(rval == 0); - mbedtls_ssl_set_bio(&mSsl, this, &Dtls::HandleMbedtlsTransmit, HandleMbedtlsReceive, nullptr); - mbedtls_ssl_set_timer_cb(&mSsl, this, &Dtls::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer); + mbedtls_ssl_set_bio(&mSsl, this, &SecureTransport::HandleMbedtlsTransmit, HandleMbedtlsReceive, nullptr); + + if (mDatagramTransport) + { + mbedtls_ssl_set_timer_cb(&mSsl, this, &SecureTransport::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer); + } if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - rval = SetApplicationCoapSecureKeys(); + rval = SetApplicationSecureKeys(); } #endif VerifyOrExit(rval == 0); @@ -348,10 +367,10 @@ Error Dtls::Setup(bool aClient) { LogInfo("DTLS started"); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - LogInfo("Application Coap Secure DTLS started"); + LogInfo("Application Secure (D)TLS started"); } #endif @@ -369,14 +388,16 @@ Error Dtls::Setup(bool aClient) return Crypto::MbedTls::MapError(rval); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE -int Dtls::SetApplicationCoapSecureKeys(void) +#if OPENTHREAD_CONFIG_TLS_API_ENABLE +int SecureTransport::SetApplicationSecureKeys(void) { int rval = 0; switch (mCipherSuites[0]) { case MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED if (mCaChainSrc != nullptr) { @@ -426,9 +447,9 @@ int Dtls::SetApplicationCoapSecureKeys(void) return rval; } -#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE -void Dtls::Close(void) +void SecureTransport::Close(void) { Disconnect(); @@ -440,7 +461,7 @@ void Dtls::Close(void) mTimer.Stop(); } -void Dtls::Disconnect(void) +void SecureTransport::Disconnect(void) { VerifyOrExit(mState == kStateConnecting || mState == kStateConnected); @@ -457,7 +478,7 @@ void Dtls::Disconnect(void) return; } -Error Dtls::SetPsk(const uint8_t *aPsk, uint8_t aPskLength) +Error SecureTransport::SetPsk(const uint8_t *aPsk, uint8_t aPskLength) { Error error = kErrorNone; @@ -472,13 +493,13 @@ Error Dtls::SetPsk(const uint8_t *aPsk, uint8_t aPskLength) return error; } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED -void Dtls::SetCertificate(const uint8_t *aX509Certificate, - uint32_t aX509CertLength, - const uint8_t *aPrivateKey, - uint32_t aPrivateKeyLength) +void SecureTransport::SetCertificate(const uint8_t *aX509Certificate, + uint32_t aX509CertLength, + const uint8_t *aPrivateKey, + uint32_t aPrivateKeyLength) { OT_ASSERT(aX509CertLength > 0); OT_ASSERT(aX509Certificate != nullptr); @@ -491,11 +512,19 @@ void Dtls::SetCertificate(const uint8_t *aX509Certificate, mPrivateKeySrc = aPrivateKey; mPrivateKeyLength = aPrivateKeyLength; - mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + if (mDatagramTransport) + { + mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + } + else + { + mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + } + mCipherSuites[1] = 0; } -void Dtls::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength) +void SecureTransport::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength) { OT_ASSERT(aX509CaCertChainLength > 0); OT_ASSERT(aX509CaCertificateChain != nullptr); @@ -507,7 +536,10 @@ void Dtls::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_ #endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED -void Dtls::SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength) +void SecureTransport::SetPreSharedKey(const uint8_t *aPsk, + uint16_t aPskLength, + const uint8_t *aPskIdentity, + uint16_t aPskIdLength) { OT_ASSERT(aPsk != nullptr); OT_ASSERT(aPskIdentity != nullptr); @@ -525,7 +557,7 @@ void Dtls::SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8 #endif #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) -Error Dtls::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize) +Error SecureTransport::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize) { Error error = kErrorNone; @@ -550,17 +582,153 @@ Error Dtls::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLeng } #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) -#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +Error SecureTransport::GetPeerSubjectAttributeByOid(const char *aOid, + size_t aOidLength, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength, + int *aAsn1Type) +{ + Error error = kErrorNone; + const mbedtls_asn1_named_data *data; + size_t length; + size_t attributeBufferSize; + mbedtls_x509_crt *peerCert = const_cast(mbedtls_ssl_get_peer_cert(&mSsl)); + + VerifyOrExit(aAttributeLength != nullptr, error = kErrorInvalidArgs); + attributeBufferSize = *aAttributeLength; + *aAttributeLength = 0; + + VerifyOrExit(aAttributeBuffer != nullptr, error = kErrorNoBufs); + VerifyOrExit(peerCert != nullptr, error = kErrorInvalidState); + data = mbedtls_asn1_find_named_data(&peerCert->subject, aOid, aOidLength); + VerifyOrExit(data != nullptr, error = kErrorNotFound); + length = data->val.len; + VerifyOrExit(length <= attributeBufferSize, error = kErrorNoBufs); + + if (aAttributeLength != nullptr) + { + *aAttributeLength = length; + } + + if (aAsn1Type != nullptr) + { + *aAsn1Type = data->val.tag; + } + + memcpy(aAttributeBuffer, data->val.p, length); + +exit: + return error; +} + +Error SecureTransport::GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) +{ + const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&mSsl); + + return GetThreadAttributeFromCertificate(cert, aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); +} + +#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + +Error SecureTransport::GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) +{ + const mbedtls_x509_crt *cert = &mOwnCert; + + return GetThreadAttributeFromCertificate(cert, aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); +} + +Error SecureTransport::GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) +{ + Error error = kErrorNotFound; + char oid[9] = {0x2B, 0x06, 0x01, 0x04, 0x01, static_cast(0x82), static_cast(0xDF), + 0x2A, 0x00}; // 1.3.6.1.4.1.44970.0 + mbedtls_x509_buf v3_ext; + unsigned char *p, *end, *endExtData; + size_t len; + size_t attributeBufferSize; + mbedtls_x509_buf extnOid; + int ret, isCritical; + + VerifyOrExit(aAttributeLength != nullptr, error = kErrorInvalidArgs); + attributeBufferSize = *aAttributeLength; + *aAttributeLength = 0; + + VerifyOrExit(aCert != nullptr, error = kErrorInvalidState); + v3_ext = aCert->v3_ext; + p = v3_ext.p; + VerifyOrExit(p != nullptr, error = kErrorInvalidState); + end = p + v3_ext.len; + VerifyOrExit(mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0, + error = kErrorParse); + VerifyOrExit(end == p + len, error = kErrorParse); + + VerifyOrExit(aThreadOidDescriptor < 128, error = kErrorNotImplemented); + oid[sizeof(oid) - 1] = static_cast(aThreadOidDescriptor); + + while (p < end) + { + isCritical = 0; + VerifyOrExit(mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0, + error = kErrorParse); + endExtData = p + len; + + // Get extension ID + VerifyOrExit(mbedtls_asn1_get_tag(&p, endExtData, &extnOid.len, MBEDTLS_ASN1_OID) == 0, error = kErrorParse); + extnOid.tag = MBEDTLS_ASN1_OID; + extnOid.p = p; + p += extnOid.len; + + // Get optional critical + ret = mbedtls_asn1_get_bool(&p, endExtData, &isCritical); + VerifyOrExit(ret == 0 || ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = kErrorParse); + + // Data should be octet string type + VerifyOrExit(mbedtls_asn1_get_tag(&p, endExtData, &len, MBEDTLS_ASN1_OCTET_STRING) == 0, error = kErrorParse); + VerifyOrExit(endExtData == p + len, error = kErrorParse); + + if (isCritical || extnOid.len != sizeof(oid)) + { + continue; + } + + if (memcmp(extnOid.p, oid, sizeof(oid)) == 0) + { + *aAttributeLength = len; + + if (aAttributeBuffer != nullptr) + { + VerifyOrExit(len <= attributeBufferSize, error = kErrorNoBufs); + memcpy(aAttributeBuffer, p, len); + } + + error = kErrorNone; + break; + } + } + +exit: + return error; +} + +#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_SSL_SRV_C -Error Dtls::SetClientId(const uint8_t *aClientId, uint8_t aLength) +Error SecureTransport::SetClientId(const uint8_t *aClientId, uint8_t aLength) { int rval = mbedtls_ssl_set_client_transport_id(&mSsl, aClientId, aLength); return Crypto::MbedTls::MapError(rval); } #endif -Error Dtls::Send(Message &aMessage, uint16_t aLength) +Error SecureTransport::Send(Message &aMessage, uint16_t aLength) { Error error = kErrorNone; uint8_t buffer[kApplicationDataMaxLength]; @@ -583,7 +751,7 @@ Error Dtls::Send(Message &aMessage, uint16_t aLength) return error; } -void Dtls::Receive(Message &aMessage) +void SecureTransport::Receive(Message &aMessage) { mReceiveMessage = &aMessage; @@ -592,28 +760,28 @@ void Dtls::Receive(Message &aMessage) mReceiveMessage = nullptr; } -int Dtls::HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength) +int SecureTransport::HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength) { - return static_cast(aContext)->HandleMbedtlsTransmit(aBuf, aLength); + return static_cast(aContext)->HandleMbedtlsTransmit(aBuf, aLength); } -int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength) +int SecureTransport::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength) { Error error; int rval = 0; if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { - LogDebg("HandleMbedtlsTransmit"); + LogDebg("HandleMbedtlsTransmit DTLS"); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - LogDebg("ApplicationCoapSecure HandleMbedtlsTransmit"); + LogDebg("HandleMbedtlsTransmit TLS"); } #endif - error = HandleDtlsSend(aBuf, static_cast(aLength), mMessageSubType); + error = HandleSecureTransportSend(aBuf, static_cast(aLength), mMessageSubType); // Restore default sub type. mMessageSubType = mMessageDefaultSubType; @@ -637,23 +805,23 @@ int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength) return rval; } -int Dtls::HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength) +int SecureTransport::HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength) { - return static_cast(aContext)->HandleMbedtlsReceive(aBuf, aLength); + return static_cast(aContext)->HandleMbedtlsReceive(aBuf, aLength); } -int Dtls::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength) +int SecureTransport::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength) { int rval; if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { - LogDebg("HandleMbedtlsReceive"); + LogDebg("HandleMbedtlsReceive DTLS"); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - LogDebg("ApplicationCoapSecure HandleMbedtlsReceive"); + LogDebg("HandleMbedtlsReceive TLS"); } #endif @@ -672,9 +840,12 @@ int Dtls::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength) return rval; } -int Dtls::HandleMbedtlsGetTimer(void *aContext) { return static_cast(aContext)->HandleMbedtlsGetTimer(); } +int SecureTransport::HandleMbedtlsGetTimer(void *aContext) +{ + return static_cast(aContext)->HandleMbedtlsGetTimer(); +} -int Dtls::HandleMbedtlsGetTimer(void) +int SecureTransport::HandleMbedtlsGetTimer(void) { int rval; @@ -682,10 +853,10 @@ int Dtls::HandleMbedtlsGetTimer(void) { LogDebg("HandleMbedtlsGetTimer"); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - LogDebg("ApplicationCoapSecure HandleMbedtlsGetTimer"); + LogDebg("HandleMbedtlsGetTimer"); } #endif @@ -709,21 +880,21 @@ int Dtls::HandleMbedtlsGetTimer(void) return rval; } -void Dtls::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish) +void SecureTransport::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish) { - static_cast(aContext)->HandleMbedtlsSetTimer(aIntermediate, aFinish); + static_cast(aContext)->HandleMbedtlsSetTimer(aIntermediate, aFinish); } -void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish) +void SecureTransport::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish) { if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8) { - LogDebg("SetTimer"); + LogDebg("SetTimer DTLS"); } -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE else { - LogDebg("ApplicationCoapSecure SetTimer"); + LogDebg("SetTimer TLS"); } #endif @@ -742,42 +913,42 @@ void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish) #if (MBEDTLS_VERSION_NUMBER >= 0x03000000) -void Dtls::HandleMbedtlsExportKeys(void *aContext, - mbedtls_ssl_key_export_type aType, - const unsigned char *aMasterSecret, - size_t aMasterSecretLen, - const unsigned char aClientRandom[32], - const unsigned char aServerRandom[32], - mbedtls_tls_prf_types aTlsPrfType) +void SecureTransport::HandleMbedtlsExportKeys(void *aContext, + mbedtls_ssl_key_export_type aType, + const unsigned char *aMasterSecret, + size_t aMasterSecretLen, + const unsigned char aClientRandom[32], + const unsigned char aServerRandom[32], + mbedtls_tls_prf_types aTlsPrfType) { - static_cast(aContext)->HandleMbedtlsExportKeys(aType, aMasterSecret, aMasterSecretLen, aClientRandom, - aServerRandom, aTlsPrfType); + static_cast(aContext)->HandleMbedtlsExportKeys(aType, aMasterSecret, aMasterSecretLen, + aClientRandom, aServerRandom, aTlsPrfType); } -void Dtls::HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType, - const unsigned char *aMasterSecret, - size_t aMasterSecretLen, - const unsigned char aClientRandom[32], - const unsigned char aServerRandom[32], - mbedtls_tls_prf_types aTlsPrfType) +void SecureTransport::HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType, + const unsigned char *aMasterSecret, + size_t aMasterSecretLen, + const unsigned char aClientRandom[32], + const unsigned char aServerRandom[32], + mbedtls_tls_prf_types aTlsPrfType) { Crypto::Sha256::Hash kek; Crypto::Sha256 sha256; - unsigned char keyBlock[kDtlsKeyBlockSize]; - unsigned char randBytes[2 * kDtlsRandomBufferSize]; + unsigned char keyBlock[kSecureTransportKeyBlockSize]; + unsigned char randBytes[2 * kSecureTransportRandomBufferSize]; VerifyOrExit(mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8); VerifyOrExit(aType == MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET); - memcpy(randBytes, aServerRandom, kDtlsRandomBufferSize); - memcpy(randBytes + kDtlsRandomBufferSize, aClientRandom, kDtlsRandomBufferSize); + memcpy(randBytes, aServerRandom, kSecureTransportRandomBufferSize); + memcpy(randBytes + kSecureTransportRandomBufferSize, aClientRandom, kSecureTransportRandomBufferSize); // Retrieve the Key block from Master secret mbedtls_ssl_tls_prf(aTlsPrfType, aMasterSecret, aMasterSecretLen, "key expansion", randBytes, sizeof(randBytes), keyBlock, sizeof(keyBlock)); sha256.Start(); - sha256.Update(keyBlock, kDtlsKeyBlockSize); + sha256.Update(keyBlock, kSecureTransportKeyBlockSize); sha256.Finish(kek); LogDebg("Generated KEK"); @@ -789,22 +960,22 @@ void Dtls::HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType, #else -int Dtls::HandleMbedtlsExportKeys(void *aContext, - const unsigned char *aMasterSecret, - const unsigned char *aKeyBlock, - size_t aMacLength, - size_t aKeyLength, - size_t aIvLength) +int SecureTransport::HandleMbedtlsExportKeys(void *aContext, + const unsigned char *aMasterSecret, + const unsigned char *aKeyBlock, + size_t aMacLength, + size_t aKeyLength, + size_t aIvLength) { - return static_cast(aContext)->HandleMbedtlsExportKeys(aMasterSecret, aKeyBlock, aMacLength, aKeyLength, - aIvLength); + return static_cast(aContext)->HandleMbedtlsExportKeys(aMasterSecret, aKeyBlock, aMacLength, + aKeyLength, aIvLength); } -int Dtls::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, - const unsigned char *aKeyBlock, - size_t aMacLength, - size_t aKeyLength, - size_t aIvLength) +int SecureTransport::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, + const unsigned char *aKeyBlock, + size_t aMacLength, + size_t aKeyLength, + size_t aIvLength) { OT_UNUSED_VARIABLE(aMasterSecret); @@ -826,12 +997,12 @@ int Dtls::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, #endif // (MBEDTLS_VERSION_NUMBER >= 0x03000000) -void Dtls::HandleTimer(Timer &aTimer) +void SecureTransport::HandleTimer(Timer &aTimer) { - static_cast(static_cast(aTimer).GetContext())->HandleTimer(); + static_cast(static_cast(aTimer).GetContext())->HandleTimer(); } -void Dtls::HandleTimer(void) +void SecureTransport::HandleTimer(void) { switch (mState) { @@ -852,7 +1023,7 @@ void Dtls::HandleTimer(void) } } -void Dtls::Process(void) +void SecureTransport::Process(void) { uint8_t buf[OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN]; bool shouldDisconnect = false; @@ -938,12 +1109,12 @@ void Dtls::Process(void) } } -void Dtls::HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr) +void SecureTransport::HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr) { - static_cast(aContext)->HandleMbedtlsDebug(aLevel, aFile, aLine, aStr); + static_cast(aContext)->HandleMbedtlsDebug(aLevel, aFile, aLine, aStr); } -void Dtls::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr) +void SecureTransport::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr) { OT_UNUSED_VARIABLE(aStr); OT_UNUSED_VARIABLE(aFile); @@ -970,7 +1141,9 @@ void Dtls::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const ch } } -Error Dtls::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType) +Error SecureTransport::HandleSecureTransportSend(const uint8_t *aBuf, + uint16_t aLength, + Message::SubType aMessageSubType) { Error error = kErrorNone; ot::Message *message = nullptr; @@ -1004,4 +1177,4 @@ Error Dtls::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, Message::SubTy } // namespace MeshCoP } // namespace ot -#endif // OPENTHREAD_CONFIG_DTLS_ENABLE +#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/secure_transport.hpp similarity index 65% rename from src/core/meshcop/dtls.hpp rename to src/core/meshcop/secure_transport.hpp index 2a4df728d2..ef51f5e28c 100644 --- a/src/core/meshcop/dtls.hpp +++ b/src/core/meshcop/secure_transport.hpp @@ -31,17 +31,33 @@ * This file includes definitions for using mbedTLS. */ -#ifndef DTLS_HPP_ -#define DTLS_HPP_ +#ifndef SECURE_TRANSPORT_HPP_ +#define SECURE_TRANSPORT_HPP_ #include "openthread-core-config.h" +#ifdef OPENTHREAD_CONFIG_TLS_API_ENABLE +#error `OPENTHREAD_CONFIG_TLS_API_ENABLE` must not be defined directly, it is determined from `COAP_SECURE_API_ENABLE` and `BLE_TCAT_ENABLE` +#endif + +#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define OPENTHREAD_CONFIG_TLS_API_ENABLE 1 +#else +#define OPENTHREAD_CONFIG_TLS_API_ENABLE 0 +#endif + #include #include #include #include -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#ifndef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#error OPENTHREAD_CONFIG_BLE_TCAT_ENABLE requires MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#endif +#endif + +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) #include #endif @@ -67,19 +83,20 @@ namespace ot { namespace MeshCoP { -class Dtls : public InstanceLocator +class SecureTransport : public InstanceLocator { public: static constexpr uint8_t kPskMaxLength = 32; ///< Maximum PSK length. /** - * Initializes the DTLS object. + * Initializes the SecureTransport object. * * @param[in] aInstance A reference to the OpenThread instance. * @param[in] aLayerTwoSecurity Specifies whether to use layer two security or not. + * @param[in] aDatagramTransport Specifies if dtls of tls connection should be used. * */ - explicit Dtls(Instance &aInstance, bool aLayerTwoSecurity); + explicit SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bool aDatagramTransport = true); /** * Pointer is called when a connection is established or torn down. @@ -91,7 +108,7 @@ class Dtls : public InstanceLocator typedef void (*ConnectedHandler)(void *aContext, bool aConnected); /** - * Pointer is called when data is received from the DTLS session. + * Pointer is called when data is received from the session. * * @param[in] aContext A pointer to application-specific context. * @param[in] aBuf A pointer to the received data buffer. @@ -111,14 +128,14 @@ class Dtls : public InstanceLocator typedef Error (*TransportCallback)(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); /** - * Opens the DTLS socket. + * Opens the socket. * - * @param[in] aReceiveHandler A pointer to a function that is called to receive DTLS payload. + * @param[in] aReceiveHandler A pointer to a function that is called to receive payload. * @param[in] aConnectedHandler A pointer to a function that is called when connected or disconnected. * @param[in] aContext A pointer to arbitrary context information. * * @retval kErrorNone Successfully opened the socket. - * @retval kErrorAlready The DTLS is already open. + * @retval kErrorAlready The connection is already open. * */ Error Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext); @@ -128,8 +145,8 @@ class Dtls : public InstanceLocator * * @param[in] aPort The port to bind. * - * @retval kErrorNone Successfully bound the DTLS socket. - * @retval kErrorInvalidState The DTLS socket is not open. + * @retval kErrorNone Successfully bound the socket. + * @retval kErrorInvalidState The socket is not open. * @retval kErrorAlready Already bound. * */ @@ -144,20 +161,20 @@ class Dtls : public InstanceLocator uint16_t GetUdpPort(void) const; /** - * Binds this DTLS with a transport callback. + * Binds with a transport callback. * * @param[in] aCallback A pointer to a function for sending messages. * @param[in] aContext A pointer to arbitrary context information. * - * @retval kErrorNone Successfully bound the DTLS socket. - * @retval kErrorInvalidState The DTLS socket is not open. + * @retval kErrorNone Successfully bound the socket. + * @retval kErrorInvalidState The socket is not open. * @retval kErrorAlready Already bound. * */ Error Bind(TransportCallback aCallback, void *aContext); /** - * Establishes a DTLS session. + * Establishes a secure session. * * For CoAP Secure API do first: * Set X509 Pk and Cert for use DTLS mode ECDHE ECDSA with AES 128 CCM 8 or @@ -165,38 +182,38 @@ class Dtls : public InstanceLocator * * @param[in] aSockAddr A reference to the remote sockaddr. * - * @retval kErrorNone Successfully started DTLS handshake. - * @retval kErrorInvalidState The DTLS socket is not open. + * @retval kErrorNone Successfully started handshake. + * @retval kErrorInvalidState The socket is not open. * */ Error Connect(const Ip6::SockAddr &aSockAddr); /** - * Indicates whether or not the DTLS session is active. + * Indicates whether or not the session is active. * - * @retval TRUE If DTLS session is active. - * @retval FALSE If DTLS session is not active. + * @retval TRUE If session is active. + * @retval FALSE If session is not active. * */ bool IsConnectionActive(void) const { return mState >= kStateConnecting; } /** - * Indicates whether or not the DTLS session is connected. + * Indicates whether or not the session is connected. * - * @retval TRUE The DTLS session is connected. - * @retval FALSE The DTLS session is not connected. + * @retval TRUE The session is connected. + * @retval FALSE The session is not connected. * */ bool IsConnected(void) const { return mState == kStateConnected; } /** - * Disconnects the DTLS session. + * Disconnects the session. * */ void Disconnect(void); /** - * Closes the DTLS socket. + * Closes the socket. * */ void Close(void); @@ -212,10 +229,10 @@ class Dtls : public InstanceLocator */ Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength); -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED /** - * Sets the Pre-Shared Key (PSK) for DTLS sessions- + * Sets the Pre-Shared Key (PSK) for sessions- * identified by a PSK. * * DTLS mode "PSK with AES 128 CCM 8" for Application CoAPS. @@ -280,8 +297,84 @@ class Dtls : public InstanceLocator Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize); #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) /** - * Set the authentication mode for a dtls connection. + * Returns an attribute value identified by its OID from the subject + * of the peer x509 certificate. The peer OID is provided in binary format. + * The attribute length is set if the attribute was successfully read or zero + * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard + * if the attribute was successfully read. + * + * @param[in] aOid A pointer to the OID to be found. + * @param[in] aOidLength The length of the OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer. + * + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorInvalidArgs Invalid attribute length. + * @retval kErrorNone Successfully read attribute. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * + */ + Error GetPeerSubjectAttributeByOid(const char *aOid, + size_t aOidLength, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength, + int *aAsn1Type); + + /** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval kErrorNone Successfully read attribute. + * @retval kErrorInvalidArgs Invalid attribute length. + * @retval kErrorNotFound The requested attribute was not found. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. + * @retval kErrorParse The certificate extensions could not be parsed. + * + */ + Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength); +#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + + /** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval kErrorNone Successfully read attribute. + * @retval kErrorInvalidArgs Invalid attribute length. + * @retval kErrorNotFound The requested attribute was not found. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. + * @retval kErrorParse The certificate extensions could not be parsed. + * + */ + Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength); + + /** + * Set the authentication mode for a connection. * * Disable or enable the verification of peer certificate. * Must called before start. @@ -290,7 +383,7 @@ class Dtls : public InstanceLocator * */ void SetSslAuthMode(bool aVerifyPeerCertificate) { mVerifyPeerCertificate = aVerifyPeerCertificate; } -#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_SSL_SRV_C /** @@ -306,19 +399,19 @@ class Dtls : public InstanceLocator #endif /** - * Sends data within the DTLS session. + * Sends data within the session. * - * @param[in] aMessage A message to send via DTLS. + * @param[in] aMessage A message to send via connection. * @param[in] aLength Number of bytes in the data buffer. * - * @retval kErrorNone Successfully sent the data via the DTLS session. + * @retval kErrorNone Successfully sent the data via the session. * @retval kErrorNoBufs A message is too long. * */ Error Send(Message &aMessage, uint16_t aLength); /** - * Provides a received DTLS message to the DTLS object. + * Provides a received message to the SecureTransport object. * * @param[in] aMessage A reference to the message. * @@ -335,9 +428,9 @@ class Dtls : public InstanceLocator void SetDefaultMessageSubType(Message::SubType aMessageSubType) { mMessageDefaultSubType = aMessageSubType; } /** - * Returns the DTLS session's peer address. + * Returns the session's peer address. * - * @return DTLS session's message info. + * @return session's message info. * */ const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; } @@ -349,34 +442,39 @@ class Dtls : public InstanceLocator { kStateClosed, // UDP socket is closed. kStateOpen, // UDP socket is open. - kStateInitializing, // The DTLS service is initializing. - kStateConnecting, // The DTLS service is establishing a connection. - kStateConnected, // The DTLS service has a connection established. - kStateCloseNotify, // The DTLS service is closing a connection. + kStateInitializing, // The service is initializing. + kStateConnecting, // The service is establishing a connection. + kStateConnected, // The service has a connection established. + kStateCloseNotify, // The service is closing a connection. }; static constexpr uint32_t kGuardTimeNewConnectionMilli = 2000; -#if !OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if !OPENTHREAD_CONFIG_TLS_API_ENABLE static constexpr uint16_t kApplicationDataMaxLength = 1152; #else static constexpr uint16_t kApplicationDataMaxLength = OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH; #endif - static constexpr size_t kDtlsKeyBlockSize = 40; - static constexpr size_t kDtlsRandomBufferSize = 32; + static constexpr size_t kSecureTransportKeyBlockSize = 40; + static constexpr size_t kSecureTransportRandomBufferSize = 32; void FreeMbedtls(void); Error Setup(bool aClient); -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE /** * Set keys and/or certificates for dtls session dependent of used cipher suite. * * @retval mbedtls error, 0 if successfully. * */ - int SetApplicationCoapSecureKeys(void); + int SetApplicationSecureKeys(void); + + Error GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert, + int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength); #endif static void HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr); @@ -434,8 +532,8 @@ class Dtls : public InstanceLocator static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); - void HandleDtlsReceive(const uint8_t *aBuf, uint16_t aLength); - Error HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType); + void HandleSecureTransportReceive(const uint8_t *aBuf, uint16_t aLength); + Error HandleSecureTransportSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType); void Process(void); @@ -459,7 +557,7 @@ class Dtls : public InstanceLocator #endif #endif -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE +#if OPENTHREAD_CONFIG_TLS_API_ENABLE #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED const uint8_t *mCaChainSrc; uint32_t mCaChainLength; @@ -494,16 +592,19 @@ class Dtls : public InstanceLocator bool mTimerSet : 1; bool mLayerTwoSecurity : 1; + bool mDatagramTransport : 1; Message *mReceiveMessage; Callback mConnectedCallback; Callback mReceiveCallback; + void *mContext; Ip6::MessageInfo mMessageInfo; Ip6::Udp::Socket mSocket; Callback mTransportCallback; + void *mTransportContext; Message::SubType mMessageSubType; Message::SubType mMessageDefaultSubType; @@ -512,4 +613,4 @@ class Dtls : public InstanceLocator } // namespace MeshCoP } // namespace ot -#endif // DTLS_HPP_ +#endif // SECURE_TRANSPORT_HPP_ diff --git a/src/core/meshcop/tcat_agent.cpp b/src/core/meshcop/tcat_agent.cpp new file mode 100644 index 0000000000..f8df7737ee --- /dev/null +++ b/src/core/meshcop/tcat_agent.cpp @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the TCAT Agent service. + */ + +#include "tcat_agent.hpp" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#include + +#include "common/array.hpp" +#include "common/code_utils.hpp" +#include "common/debug.hpp" +#include "common/encoding.hpp" +#include "common/locator_getters.hpp" +#include "common/string.hpp" +#include "instance/instance.hpp" +#include "radio/radio.hpp" +#include "thread/thread_netif.hpp" +#include "thread/uri_paths.hpp" +#include "utils/otns.hpp" + +namespace ot { +namespace MeshCoP { + +RegisterLogModule("TcatAgent"); + +bool TcatAgent::VendorInfo::IsValid(void) const +{ + return mProvisioningUrl == nullptr || IsValidUtf8String(mProvisioningUrl) || mPskdString != nullptr; +} + +TcatAgent::TcatAgent(Instance &aInstance) + : InstanceLocator(aInstance) + , mVendorInfo(nullptr) + , mCurrentApplicationProtocol(kApplicationProtocolNone) + , mState(kStateDisabled) + , mAlreadyCommissioned(false) + , mCommissionerHasNetworkName(false) + , mCommissionerHasDomainName(false) + , mCommissionerHasExtendedPanId(false) +{ + mJoinerPskd.Clear(); + mCurrentServiceName[0] = 0; +} + +Error TcatAgent::Start(const TcatAgent::VendorInfo &aVendorInfo, + AppDataReceiveCallback aAppDataReceiveCallback, + JoinCallback aHandler, + void *aContext) +{ + Error error = kErrorNone; + + LogInfo("Starting"); + + VerifyOrExit(aVendorInfo.IsValid(), error = kErrorInvalidArgs); + SuccessOrExit(error = mJoinerPskd.SetFrom(aVendorInfo.mPskdString)); + + mAppDataReceiveCallback.Set(aAppDataReceiveCallback, aContext); + mJoinCallback.Set(aHandler, aContext); + + mVendorInfo = &aVendorInfo; + mCurrentApplicationProtocol = kApplicationProtocolNone; + mState = kStateEnabled; + mAlreadyCommissioned = false; + +exit: + LogError("start TCAT agent", error); + return error; +} + +void TcatAgent::Stop(void) +{ + mCurrentApplicationProtocol = kApplicationProtocolNone; + mState = kStateDisabled; + mAlreadyCommissioned = false; + mAppDataReceiveCallback.Clear(); + mJoinCallback.Clear(); + LogInfo("TCAT agent stopped"); +} + +Error TcatAgent::Connected(MeshCoP::SecureTransport &aTlsContext) +{ + size_t len; + Error error; + + VerifyOrExit(IsEnabled(), error = kErrorInvalidState); + len = sizeof(mCommissionerAuthorizationField); + SuccessOrExit( + error = aTlsContext.GetThreadAttributeFromPeerCertificate( + kCertificateAuthorizationField, reinterpret_cast(&mCommissionerAuthorizationField), &len)); + VerifyOrExit(len == sizeof(mCommissionerAuthorizationField), error = kErrorParse); + VerifyOrExit((mCommissionerAuthorizationField.mHeader & kCommissionerFlag) == 1, error = kErrorParse); + + len = sizeof(mDeviceAuthorizationField); + SuccessOrExit(error = aTlsContext.GetThreadAttributeFromOwnCertificate( + kCertificateAuthorizationField, reinterpret_cast(&mDeviceAuthorizationField), &len)); + VerifyOrExit(len == sizeof(mDeviceAuthorizationField), error = kErrorParse); + VerifyOrExit((mDeviceAuthorizationField.mHeader & kCommissionerFlag) == 0, error = kErrorParse); + + mCommissionerHasDomainName = false; + mCommissionerHasNetworkName = false; + mCommissionerHasExtendedPanId = false; + + len = sizeof(mCommissionerDomainName) - 1; + if (aTlsContext.GetThreadAttributeFromPeerCertificate( + kCertificateDomainName, reinterpret_cast(&mCommissionerDomainName), &len) == kErrorNone) + { + mCommissionerDomainName.m8[len] = '\0'; + mCommissionerHasDomainName = true; + } + + len = sizeof(mCommissionerNetworkName) - 1; + if (aTlsContext.GetThreadAttributeFromPeerCertificate( + kCertificateNetworkName, reinterpret_cast(&mCommissionerNetworkName), &len) == kErrorNone) + { + mCommissionerNetworkName.m8[len] = '\0'; + mCommissionerHasNetworkName = true; + } + + len = sizeof(mCommissionerExtendedPanId); + if (aTlsContext.GetThreadAttributeFromPeerCertificate( + kCertificateExtendedPanId, reinterpret_cast(&mCommissionerExtendedPanId), &len) == kErrorNone) + { + if (len == sizeof(mCommissionerExtendedPanId)) + { + mCommissionerHasExtendedPanId = true; + } + } + + mCurrentApplicationProtocol = kApplicationProtocolNone; + mCurrentServiceName[0] = 0; + mState = kStateConnected; + mAlreadyCommissioned = Get().IsCommissioned(); + LogInfo("TCAT agent connected"); + +exit: + return error; +} + +void TcatAgent::Disconnected(void) +{ + mCurrentApplicationProtocol = kApplicationProtocolNone; + mAlreadyCommissioned = false; + + if (mState != kStateDisabled) + { + mState = kStateEnabled; + } + + LogInfo("TCAT agent disconnected"); +} + +bool TcatAgent::CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags, + CommandClassFlags aDeviceCommandClassFlags, + Dataset *aDataset) const +{ + bool authorized = false; + bool additionalDeviceRequirementMet = false; + bool domainNamesMatch = false; + bool networkNamesMatch = false; + bool extendedPanIdsMatch = false; + + VerifyOrExit(IsConnected()); + VerifyOrExit(aCommissionerCommandClassFlags & kAccessFlag); + + if (aDeviceCommandClassFlags & kAccessFlag) + { + additionalDeviceRequirementMet = true; + } + + if (aDeviceCommandClassFlags & kPskdFlag) + { + additionalDeviceRequirementMet = true; + } + + if (aDeviceCommandClassFlags & kPskcFlag) + { + additionalDeviceRequirementMet = true; + } + + if (mCommissionerHasNetworkName || mCommissionerHasExtendedPanId) + { + Dataset::Info datasetInfo; + Error datasetError = kErrorNone; + + if (aDataset == nullptr) + { + datasetError = Get().Read(datasetInfo); + } + else + { + aDataset->ConvertTo(datasetInfo); + } + + if (datasetError == kErrorNone) + { + if (datasetInfo.IsNetworkNamePresent() && mCommissionerHasNetworkName && + (datasetInfo.GetNetworkName() == mCommissionerNetworkName)) + { + networkNamesMatch = true; + } + + if (datasetInfo.IsExtendedPanIdPresent() && mCommissionerHasExtendedPanId && + (datasetInfo.GetExtendedPanId() == mCommissionerExtendedPanId)) + { + extendedPanIdsMatch = true; + } + } + } + + if (!networkNamesMatch) + { + VerifyOrExit((aCommissionerCommandClassFlags & kNetworkNameFlag) == 0); + } + else if (aDeviceCommandClassFlags & kNetworkNameFlag) + { + additionalDeviceRequirementMet = true; + } + + if (!extendedPanIdsMatch) + { + VerifyOrExit((aCommissionerCommandClassFlags & kExtendedPanIdFlag) == 0); + } + else if (aDeviceCommandClassFlags & kExtendedPanIdFlag) + { + additionalDeviceRequirementMet = true; + } + +#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) + VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0); +#endif + + if (!domainNamesMatch) + { + VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0); + } + else if (aDeviceCommandClassFlags & kThreadDomainFlag) + { + additionalDeviceRequirementMet = true; + } + + if (additionalDeviceRequirementMet) + { + authorized = true; + } + +exit: + return authorized; +} + +bool TcatAgent::IsCommandClassAuthorized(CommandClass aCommandClass) const +{ + bool authorized = false; + + switch (aCommandClass) + { + case kGeneral: + authorized = true; + break; + + case kCommissioning: + authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mCommissioningFlags, + mDeviceAuthorizationField.mCommissioningFlags, nullptr); + break; + + case kExtraction: + authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mExtractionFlags, + mDeviceAuthorizationField.mExtractionFlags, nullptr); + break; + + case kTlvDecommissioning: + authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mDecommissioningFlags, + mDeviceAuthorizationField.mDecommissioningFlags, nullptr); + break; + + case kApplication: + authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags, + mDeviceAuthorizationField.mApplicationFlags, nullptr); + break; + + case kInvalid: + authorized = false; + break; + } + + return authorized; +} + +TcatAgent::CommandClass TcatAgent::GetCommandClass(uint8_t aTlvType) const +{ + static constexpr int kGeneralTlvs = 0x1F; + static constexpr int kCommissioningTlvs = 0x3F; + static constexpr int kExtractionTlvs = 0x5F; + static constexpr int kTlvDecommissioningTlvs = 0x7F; + static constexpr int kApplicationTlvs = 0x9F; + + if (aTlvType <= kGeneralTlvs) + { + return kGeneral; + } + else if (aTlvType <= kCommissioningTlvs) + { + return kCommissioning; + } + else if (aTlvType <= kExtractionTlvs) + { + return kExtraction; + } + else if (aTlvType <= kTlvDecommissioningTlvs) + { + return kTlvDecommissioning; + } + else if (aTlvType <= kApplicationTlvs) + { + return kApplication; + } + else + { + return kInvalid; + } +} + +bool TcatAgent::CanProcessTlv(uint8_t aTlvType) const +{ + CommandClass tlvCommandClass = GetCommandClass(aTlvType); + return IsCommandClassAuthorized(tlvCommandClass); +} + +Error TcatAgent::HandleSingleTlv(const Message &aIncommingMessage, Message &aOutgoingMessage) +{ + Error error = kErrorParse; + ot::Tlv tlv; + uint16_t offset = aIncommingMessage.GetOffset(); + uint16_t length; + bool response = false; + + VerifyOrExit(IsConnected(), error = kErrorInvalidState); + SuccessOrExit(error = aIncommingMessage.Read(offset, tlv)); + + if (tlv.IsExtended()) + { + ot::ExtendedTlv extTlv; + SuccessOrExit(error = aIncommingMessage.Read(offset, extTlv)); + length = extTlv.GetLength(); + offset += sizeof(ot::ExtendedTlv); + } + else + { + length = tlv.GetLength(); + offset += sizeof(ot::Tlv); + } + + if (!CanProcessTlv(tlv.GetType())) + { + error = kErrorRejected; + } + else + { + switch (tlv.GetType()) + { + case kTlvDisconnect: + error = kErrorAbort; + break; + + case kTlvSetActiveOperationalDataset: + error = HandleSetActiveOperationalDataset(aIncommingMessage, offset, length); + break; + + case kTlvStartThreadInterface: + error = HandleStartThreadInterface(); + break; + + case kTlvStopThreadInterface: + error = otThreadSetEnabled(&GetInstance(), false); + break; + + case kTlvSendApplicationData: + LogInfo("Application data len:%d, offset:%d", length, offset); + mAppDataReceiveCallback.InvokeIfSet(&GetInstance(), &aIncommingMessage, offset, + MapEnum(mCurrentApplicationProtocol), mCurrentServiceName); + response = true; + error = kErrorNone; + break; + + default: + error = kErrorInvalidCommand; + } + } + + if (!response) + { + StatusCode statusCode; + + switch (error) + { + case kErrorNone: + statusCode = kStatusSuccess; + break; + + case kErrorInvalidState: + statusCode = kStatusUndefined; + break; + + case kErrorParse: + statusCode = kStatusParseError; + break; + + case kErrorInvalidCommand: + statusCode = kStatusUnsupported; + break; + + case kErrorRejected: + statusCode = kStatusUnauthorized; + break; + + case kErrorNotImplemented: + statusCode = kStatusUnsupported; + break; + + default: + statusCode = kStatusGeneralError; + break; + } + + SuccessOrExit(error = ot::Tlv::Append(aOutgoingMessage, statusCode)); + } + +exit: + return error; +} + +Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength) +{ + Dataset dataset; + otOperationalDatasetTlvs datasetTlvs; + Error error; + + SuccessOrExit(error = dataset.ReadFromMessage(aIncommingMessage, aOffset, aLength)); + + if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags, + mDeviceAuthorizationField.mApplicationFlags, &dataset)) + { + error = kErrorRejected; + ExitNow(); + } + + dataset.ConvertTo(datasetTlvs); + error = Get().Save(datasetTlvs); + +exit: + return error; +} + +Error TcatAgent::HandleStartThreadInterface(void) +{ + Error error; + Dataset::Info datasetInfo; + + VerifyOrExit(Get().Read(datasetInfo) == kErrorNone, error = kErrorInvalidState); + VerifyOrExit(datasetInfo.IsNetworkKeyPresent(), error = kErrorInvalidState); + +#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE + VerifyOrExit(!Get().IsEnabled(), error = kErrorInvalidState); +#endif + + Get().Up(); + error = Get().Start(); + +exit: + return error; +} + +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) +void TcatAgent::LogError(const char *aActionText, Error aError) +{ + if (aError != kErrorNone) + { + LogWarn("Failed to %s: %s", aActionText, ErrorToString(aError)); + } +} +#endif + +} // namespace MeshCoP +} // namespace ot + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE diff --git a/src/core/meshcop/tcat_agent.hpp b/src/core/meshcop/tcat_agent.hpp new file mode 100644 index 0000000000..d2dd9f340c --- /dev/null +++ b/src/core/meshcop/tcat_agent.hpp @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * Implements the TCAT Agent service. + */ + +#ifndef TCAT_AGENT_HPP_ +#define TCAT_AGENT_HPP_ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#include +#include + +#include "common/as_core_type.hpp" +#include "common/callback.hpp" +#include "common/locator.hpp" +#include "common/log.hpp" +#include "common/message.hpp" +#include "common/non_copyable.hpp" +#include "mac/mac_types.hpp" +#include "meshcop/dataset.hpp" +#include "meshcop/meshcop.hpp" +#include "meshcop/meshcop_tlvs.hpp" +#include "meshcop/secure_transport.hpp" + +namespace ot { + +namespace Ble { +class BleSecure; +} + +namespace MeshCoP { + +class TcatAgent : public InstanceLocator, private NonCopyable +{ +public: + /** + * Pointer to call when application data was received over the TLS connection. + * + * Please see otHandleTcatApplicationDataReceive for details. + * + */ + typedef otHandleTcatApplicationDataReceive AppDataReceiveCallback; + + /** + * Pointer to call to notify the completion of a join operation. + * + * Please see otHandleTcatJoin for details. + * + */ + typedef otHandleTcatJoin JoinCallback; + + /** + * Represents a TCAT command class. + * + */ + enum CommandClass + { + kGeneral = OT_TCAT_COMMAND_CLASS_GENERAL, ///< TCAT commands related to general operations + kCommissioning = OT_TCAT_COMMAND_CLASS_COMMISSIONING, ///< TCAT commands related to commissioning + kExtraction = OT_TCAT_COMMAND_CLASS_EXTRACTION, ///< TCAT commands related to key extraction + kTlvDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to de-commissioning + kApplication = OT_TCAT_COMMAND_CLASS_APPLICATION, ///< TCAT commands related to application layer + kInvalid ///< TCAT command belongs to reserved pool or is invalid + }; + + /** + * The certificate authorization field header type to indicate the type and version of the certificate. + * + */ + enum CertificateAuthorizationFieldHeader : uint8_t + { + kCommissionerFlag = 1 << 0, ///< TCAT commissioner ('1') or device ('0') + kHeaderVersion = 0xD0, ///< Header version (3 bits) + }; + + /** + * The command class flag type to indicate which requirements apply for a given command class. + * + */ + enum CommandClassFlags : uint8_t + { + kAccessFlag = 1 << 0, ///< Access to the command class (device: without without additional requirements). + kPskdFlag = 1 << 1, ///< Access requires proof-of-possession of the device's PSKd + kNetworkNameFlag = 1 << 2, ///< Access requires matching network name + kExtendedPanIdFlag = 1 << 3, ///< Access requires matching XPANID + kThreadDomainFlag = 1 << 4, ///< Access requires matching XPANID + kPskcFlag = 1 << 5, ///< Access requires proof-of-possession of the device's PSKc + }; + + /** + * + * Represents a data structure for storing TCAT Commissioner authorization information in the + * certificate ASN.1 field 1.3.6.1.4.1.44970.3. + * + */ + OT_TOOL_PACKED_BEGIN + struct CertificateAuthorizationField + { + CertificateAuthorizationFieldHeader mHeader; ///< Typ and version + CommandClassFlags mCommissioningFlags; ///< Command class flags + CommandClassFlags mExtractionFlags; ///< Command class flags + CommandClassFlags mDecommissioningFlags; ///< Command class flags + CommandClassFlags mApplicationFlags; ///< Command class flags + + } OT_TOOL_PACKED_END; + + typedef CertificateAuthorizationField CertificateAuthorizationField; + + /** + * Represents the TCAT vendor information. + * + */ + class VendorInfo : public otTcatVendorInfo + { + public: + /** + * Validates whether the TCAT vendor information is valid. + * + * @returns Whether the parameters are valid. + * + */ + bool IsValid(void) const; + }; + + /** + * TCAT TLV Types. + * + */ + enum TlvType : uint8_t + { + // Command Class General + kTlvResponseWithStatus = 1, ///< TCAT response with status value TLV + kTlvResponseWithPayload = 2, ///< TCAT response with payload TLV + kTlvResponseEvent = 3, ///< TCAT response event TLV (reserved) + kTlvGetNetworkName = 8, ///< TCAT network name query TLV + kTlvDisconnect = 9, ///< TCAT disconnect request TLV + kTlvPing = 10, ///< TCAT ping request TLV + kTlvGetDeviceId = 11, ///< TCAT device ID query TLV + kTlvGetExtendedPanID = 12, ///< TCAT extended PAN ID query TLV + kTlvPresentPskdHash = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash + kTlvPresentPskcHash = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash + kTlvPresentInstallCodeHash = 18, ///< TCAT commissioner rights elevation request TLV using install code + kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV + kTlvRequestPskdHash = 20, ///< TCAT PSKd hash request TLV + + // Command Class Commissioning + kTlvSetActiveOperationalDataset = 32, ///< TCAT active operational dataset TLV + kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV + kTlvGetProvisioningTlvs = 36, ///< TCAT provisioning TLVs query TLV + kTlvGetCommissionerCertificate = 37, ///< TCAT commissioner certificate query TLV + kTlvGetDiagnosticTlvs = 38, ///< TCAT diagnostics TLVs query TLV + kTlvStartThreadInterface = 39, ///< TCAT start thread interface request TLV + kTlvStopThreadInterface = 40, ///< TCAT stop thread interface request TLV + + // Command Class Extraction + kTlvGetActiveOperationalDataset = 64, ///< TCAT active oerational dataset query TLV + kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV + + // Command Class Decommissioning + kTlvDecommission = 96, ///< TCAT decommission request TLV + + // Command Class Application + kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV + kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV + kTlvSendApplicationData = 130, ///< TCAT send application data TLV + kTlvSendVendorSpecificData = 159, ///< TCAT send vendor specific command or data TLV + + // Command Class CCM + kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV + kTlvSetLDevIdPrivateKey = 161, ///< TCAT LDevID operational certificate pricate key TLV + kTlvSetDomainCaCert = 162, ///< TCAT domain CA certificate TLV + }; + + /** + * TCAT Response Types. + * + */ + enum StatusCode : uint8_t + { + kStatusSuccess = OT_TCAT_STATUS_SUCCESS, ///< Command or request was successfully processed + kStatusUnsupported = OT_TCAT_STATUS_UNSUPPORTED, ///< Requested command or received TLV is not supported + kStatusParseError = OT_TCAT_STATUS_PARSE_ERROR, ///< Request / command could not be parsed correctly + kStatusValueError = OT_TCAT_STATUS_VALUE_ERROR, ///< The value of the transmitted TLV has an error + kStatusGeneralError = OT_TCAT_STATUS_GENERAL_ERROR, ///< An error not matching any other category occurred + kStatusBusy = OT_TCAT_STATUS_BUSY, ///< Command cannot be executed because the resource is busy + kStatusUndefined = OT_TCAT_STATUS_UNDEFINED, ///< The requested value, data or service is not defined + ///< (currently) or not present + kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect + kStatusUnauthorized = + OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command + }; + + /** + * Represents TCAT application protocol. + * + */ + enum TcatApplicationProtocol : uint8_t + { + kApplicationProtocolNone = + OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent + kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service + kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP, ///< Message directed to a TCP service + }; + + /** + * Represents a TCAT certificate V3 extension attribute (OID 1.3.6.1.4.1.44970.x). + * + */ + enum TcatCertificateAttribute + { + kCertificateDomainName = 1, + kCertificateAuthorizationField = 3, + kCertificateNetworkName = 4, + kCertificateExtendedPanId = 5, + }; + + /** + * Represents TCAT status. + * + */ + enum State : uint8_t + { + kStateDisabled, + kStateEnabled, + kStateConnected, + }; + + /** + * Initializes the Joiner object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit TcatAgent(Instance &aInstance); + + /** + * Enables the TCAT protocol. + * + * @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method + * call, may be NULL). + * @param[in] aAppDataReceiveCallback A pointer to a function that is called when the user data is received. + * @param[in] aHandler A pointer to a function that is called when the join operation completes. + * @param[in] aContext A context pointer. + * + * @retval kErrorNone Successfully started the TCAT agent. + * @retval kErrorInvalidArgs The aVendorInfo is invalid. + * + */ + Error Start(const VendorInfo &aVendorInfo, + AppDataReceiveCallback aAppDataReceiveCallback, + JoinCallback aHandler, + void *aContext); + + /** + * Stops the TCAT protocol. + * + */ + void Stop(void); + + /** + * Indicates whether or not the TCAT agent is enabled. + * + * @retval TRUE The TCAT agent is enabled. + * @retval FALSE The TCAT agent is not enabled. + * + */ + bool IsEnabled(void) const { return mState != kStateDisabled; } + + /** + * Indicates whether or not the TCAT agent is connected. + * + * @retval TRUE The TCAT agent is connected. + * @retval FALSE The TCAT agent is not connected. + * + */ + bool IsConnected(void) const { return mState == kStateConnected; } + + /** + * Indicates whether or not a command class is authorized. + * + * @param[in] aCommandClass Command class to subject for authorization check. + * + * @retval TRUE The command class is authorized. + * @retval FALSE The command class is not authorized. + * + */ + bool IsCommandClassAuthorized(CommandClass aCommandClass) const; + +private: + Error Connected(MeshCoP::SecureTransport &aTlsContext); + void Disconnected(void); + + Error HandleSingleTlv(const Message &aIncommingMessage, Message &aOutgoingMessage); + Error HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength); + Error HandleStartThreadInterface(void); + +#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN) + void LogError(const char *aActionText, Error aError); +#else + void LogError(const char *, Error) {} +#endif + + bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags, + CommandClassFlags aDeviceCommandClassFlags, + Dataset *aDataset) const; + bool CanProcessTlv(uint8_t aTlvType) const; + CommandClass GetCommandClass(uint8_t aTlvType) const; + + static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; + + JoinerPskd mJoinerPskd; + const VendorInfo *mVendorInfo; + Callback mJoinCallback; + Callback mAppDataReceiveCallback; + CertificateAuthorizationField mCommissionerAuthorizationField; + CertificateAuthorizationField mDeviceAuthorizationField; + TcatApplicationProtocol mCurrentApplicationProtocol; + NetworkName mCommissionerNetworkName; + NetworkName mCommissionerDomainName; + ExtendedPanId mCommissionerExtendedPanId; + char mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1]; + State mState; + bool mAlreadyCommissioned : 1; + bool mCommissionerHasNetworkName : 1; + bool mCommissionerHasDomainName : 1; + bool mCommissionerHasExtendedPanId : 1; + + friend class Ble::BleSecure; +}; + +} // namespace MeshCoP + +DefineCoreType(otTcatVendorInfo, MeshCoP::TcatAgent::VendorInfo); + +DefineMapEnum(otTcatApplicationProtocol, MeshCoP::TcatAgent::TcatApplicationProtocol); + +typedef UintTlvInfo ResponseWithStatusTlv; + +} // namespace ot + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#endif // TCAT_AGENT_HPP_ diff --git a/src/core/openthread-core-config.h b/src/core/openthread-core-config.h index ea238fb1f8..79640a84fb 100644 --- a/src/core/openthread-core-config.h +++ b/src/core/openthread-core-config.h @@ -88,7 +88,6 @@ #include "config/dns_client.h" #include "config/dns_dso.h" #include "config/dnssd_server.h" -#include "config/dtls.h" #include "config/history_tracker.h" #include "config/ip6.h" #include "config/joiner.h" @@ -109,6 +108,7 @@ #include "config/platform.h" #include "config/power_calibration.h" #include "config/radio_link.h" +#include "config/secure_transport.h" #include "config/sntp_client.h" #include "config/srp_client.h" #include "config/srp_server.h" diff --git a/src/core/radio/ble_secure.cpp b/src/core/radio/ble_secure.cpp new file mode 100644 index 0000000000..fe0a6f5c3c --- /dev/null +++ b/src/core/radio/ble_secure.cpp @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ble_secure.hpp" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#include +#include "common/locator_getters.hpp" +#include "common/log.hpp" +#include "common/tlvs.hpp" +#include "instance/instance.hpp" +#include "meshcop/secure_transport.hpp" + +using namespace ot; + +/** + * @file + * This file implements the secure Ble agent. + */ + +namespace ot { +namespace Ble { + +RegisterLogModule("BleSecure"); + +BleSecure::BleSecure(Instance &aInstance) + : InstanceLocator(aInstance) + , mTls(aInstance, false, false) + , mTcatAgent(aInstance) + , mTlvMode(false) + , mReceivedMessage(nullptr) + , mSendMessage(nullptr) + , mTransmitTask(aInstance) + , mBleState(kStopped) + , mMtuSize(kInitialMtuSize) +{ +} + +Error BleSecure::Start(ConnectCallback aConnectHandler, ReceiveCallback aReceiveHandler, bool aTlvMode, void *aContext) +{ + Error error = kErrorNone; + + VerifyOrExit(mBleState == kStopped, error = kErrorAlready); + + mConnectCallback.Set(aConnectHandler, aContext); + mReceiveCallback.Set(aReceiveHandler, aContext); + mTlvMode = aTlvMode; + mMtuSize = kInitialMtuSize; + + SuccessOrExit(error = otPlatBleEnable(&GetInstance())); + SuccessOrExit(error = otPlatBleGapAdvStart(&GetInstance(), OT_BLE_ADV_INTERVAL_DEFAULT)); + SuccessOrExit(error = mTls.Open(&BleSecure::HandleTlsReceive, &BleSecure::HandleTlsConnected, this)); + SuccessOrExit(error = mTls.Bind(HandleTransport, this)); + +exit: + if (error == kErrorNone) + { + mBleState = kAdvertising; + } + return error; +} + +Error BleSecure::TcatStart(const MeshCoP::TcatAgent::VendorInfo &aVendorInfo, + MeshCoP::TcatAgent::JoinCallback aJoinHandler) +{ + return mTcatAgent.Start(aVendorInfo, mReceiveCallback.GetHandler(), aJoinHandler, mReceiveCallback.GetContext()); +} + +void BleSecure::Stop(void) +{ + VerifyOrExit(mBleState != kStopped); + SuccessOrExit(otPlatBleGapAdvStop(&GetInstance())); + SuccessOrExit(otPlatBleDisable(&GetInstance())); + mBleState = kStopped; + mMtuSize = kInitialMtuSize; + + if (mTcatAgent.IsEnabled()) + { + mTcatAgent.Stop(); + } + + mTls.Close(); + + mTransmitQueue.DequeueAndFreeAll(); + + mConnectCallback.Clear(); + mReceiveCallback.Clear(); + + FreeMessage(mReceivedMessage); + mReceivedMessage = nullptr; + FreeMessage(mSendMessage); + mSendMessage = nullptr; + +exit: + return; +} + +Error BleSecure::Connect(void) +{ + Ip6::SockAddr sockaddr; + + return mTls.Connect(sockaddr); +} + +void BleSecure::Disconnect(void) +{ + if (mTls.IsConnected()) + { + mTls.Disconnect(); + } + + if (mBleState == kConnected) + { + IgnoreReturnValue(otPlatBleGapDisconnect(&GetInstance())); + } +} + +void BleSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd) +{ + static_assert(static_cast(MeshCoP::JoinerPskd::kMaxLength) <= + static_cast(MeshCoP::SecureTransport::kPskMaxLength), + "The maximum length of TLS PSK is smaller than joiner PSKd"); + + SuccessOrAssert(mTls.SetPsk(reinterpret_cast(aPskd.GetAsCString()), aPskd.GetLength())); +} + +#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +Error BleSecure::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength) +{ + Error error; + + VerifyOrExit(aCertLength != nullptr, error = kErrorInvalidArgs); + + error = mTls.GetPeerCertificateBase64(aPeerCert, aCertLength, *aCertLength); + +exit: + return error; +} +#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + +Error BleSecure::SendMessage(ot::Message &aMessage) +{ + Error error = kErrorNone; + + VerifyOrExit(IsConnected(), error = kErrorInvalidState); + if (mSendMessage == nullptr) + { + mSendMessage = Get().Allocate(Message::kTypeBle); + VerifyOrExit(mSendMessage != nullptr, error = kErrorNoBufs); + } + SuccessOrExit(error = mSendMessage->AppendBytesFromMessage(aMessage, 0, aMessage.GetLength())); + SuccessOrExit(error = Flush()); + +exit: + aMessage.Free(); + return error; +} + +Error BleSecure::Send(uint8_t *aBuf, uint16_t aLength) +{ + Error error = kErrorNone; + + VerifyOrExit(IsConnected(), error = kErrorInvalidState); + if (mSendMessage == nullptr) + { + mSendMessage = Get().Allocate(Message::kTypeBle); + VerifyOrExit(mSendMessage != nullptr, error = kErrorNoBufs); + } + SuccessOrExit(error = mSendMessage->AppendBytes(aBuf, aLength)); + +exit: + return error; +} + +Error BleSecure::SendApplicationTlv(uint8_t *aBuf, uint16_t aLength) +{ + Error error = kErrorNone; + if (aLength > Tlv::kBaseTlvMaxLength) + { + ot::ExtendedTlv tlv; + + tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData); + tlv.SetLength(aLength); + SuccessOrExit(error = Send(reinterpret_cast(&tlv), sizeof(tlv))); + } + else + { + ot::Tlv tlv; + + tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData); + tlv.SetLength((uint8_t)aLength); + SuccessOrExit(error = Send(reinterpret_cast(&tlv), sizeof(tlv))); + } + + error = Send(aBuf, aLength); +exit: + return error; +} + +Error BleSecure::Flush(void) +{ + Error error = kErrorNone; + + VerifyOrExit(IsConnected(), error = kErrorInvalidState); + VerifyOrExit(mSendMessage->GetLength() != 0, error = kErrorNone); + + mTransmitQueue.Enqueue(*mSendMessage); + mTransmitTask.Post(); + + mSendMessage = nullptr; + +exit: + return error; +} + +Error BleSecure::HandleBleReceive(uint8_t *aBuf, uint16_t aLength) +{ + ot::Message *message = nullptr; + Ip6::MessageInfo messageInfo; + Error error = kErrorNone; + + if ((message = Get().Allocate(Message::kTypeBle, 0)) == nullptr) + { + error = kErrorNoBufs; + ExitNow(); + } + SuccessOrExit(error = message->AppendBytes(aBuf, aLength)); + + // Cannot call Receive(..) directly because Setup(..) and mState are private + mTls.HandleUdpReceive(*message, messageInfo); + +exit: + FreeMessage(message); + return error; +} + +void BleSecure::HandleBleConnected(uint16_t aConnectionId) +{ + OT_UNUSED_VARIABLE(aConnectionId); + + mBleState = kConnected; + + IgnoreReturnValue(otPlatBleGattMtuGet(&GetInstance(), &mMtuSize)); + + mConnectCallback.InvokeIfSet(&GetInstance(), IsConnected(), true); +} + +void BleSecure::HandleBleDisconnected(uint16_t aConnectionId) +{ + OT_UNUSED_VARIABLE(aConnectionId); + + mBleState = kAdvertising; + mMtuSize = kInitialMtuSize; + + if (IsConnected()) + { + Disconnect(); // Stop TLS connection + } + + mConnectCallback.InvokeIfSet(&GetInstance(), false, false); +} + +Error BleSecure::HandleBleMtuUpdate(uint16_t aMtu) +{ + Error error = kErrorNone; + + if (aMtu <= OT_BLE_ATT_MTU_MAX) + { + mMtuSize = aMtu; + } + else + { + mMtuSize = OT_BLE_ATT_MTU_MAX; + error = kErrorInvalidArgs; + } + + return error; +} + +void BleSecure::HandleTlsConnected(void *aContext, bool aConnected) +{ + return static_cast(aContext)->HandleTlsConnected(aConnected); +} + +void BleSecure::HandleTlsConnected(bool aConnected) +{ + if (aConnected) + { + if (mReceivedMessage == nullptr) + { + mReceivedMessage = Get().Allocate(Message::kTypeBle); + } + + if (mTcatAgent.IsEnabled()) + { + IgnoreReturnValue(mTcatAgent.Connected(mTls)); + } + } + else + { + FreeMessage(mReceivedMessage); + mReceivedMessage = nullptr; + + if (mTcatAgent.IsEnabled()) + { + mTcatAgent.Disconnected(); + } + } + + mConnectCallback.InvokeIfSet(&GetInstance(), aConnected, true); +} + +void BleSecure::HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) +{ + return static_cast(aContext)->HandleTlsReceive(aBuf, aLength); +} + +void BleSecure::HandleTlsReceive(uint8_t *aBuf, uint16_t aLength) +{ + VerifyOrExit(mReceivedMessage != nullptr); + + if (!mTlvMode) + { + SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, aLength)); + mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, 0, OT_TCAT_APPLICATION_PROTOCOL_NONE, ""); + IgnoreReturnValue(mReceivedMessage->SetLength(0)); + } + else + { + ot::Tlv tlv; + uint32_t requiredBytes = sizeof(Tlv); + uint32_t offset; + + while (aLength > 0) + { + if (mReceivedMessage->GetLength() < requiredBytes) + { + uint32_t missingBytes = requiredBytes - mReceivedMessage->GetLength(); + + if (missingBytes > aLength) + { + SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, aLength)); + break; + } + else + { + SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, (uint16_t)missingBytes)); + aLength -= missingBytes; + aBuf += missingBytes; + } + } + + IgnoreReturnValue(mReceivedMessage->Read(0, tlv)); + + if (tlv.IsExtended()) + { + ot::ExtendedTlv extTlv; + requiredBytes = sizeof(extTlv); + + if (mReceivedMessage->GetLength() < requiredBytes) + { + continue; + } + + IgnoreReturnValue(mReceivedMessage->Read(0, extTlv)); + requiredBytes = extTlv.GetSize(); + offset = sizeof(extTlv); + } + else + { + requiredBytes = tlv.GetSize(); + offset = sizeof(tlv); + } + + if (mReceivedMessage->GetLength() < requiredBytes) + { + continue; + } + + // TLV fully loaded + + if (mTcatAgent.IsEnabled()) + { + ot::Message *message; + Error error = kErrorNone; + + message = Get().Allocate(Message::kTypeBle); + VerifyOrExit(message != nullptr, error = kErrorNoBufs); + + error = mTcatAgent.HandleSingleTlv(*mReceivedMessage, *message); + if (message->GetLength() != 0) + { + IgnoreReturnValue(SendMessage(*message)); + } + + if (error == kErrorAbort) + { + Disconnect(); + Stop(); + ExitNow(); + } + } + else + { + mReceivedMessage->SetOffset((uint16_t)offset); + mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, (int32_t)offset, + OT_TCAT_APPLICATION_PROTOCOL_NONE, ""); + } + + SuccessOrExit(mReceivedMessage->SetLength(0)); // also sets the offset to 0 + requiredBytes = sizeof(Tlv); + } + } + +exit: + return; +} + +void BleSecure::HandleTransmit(void) +{ + Error error = kErrorNone; + ot::Message *message = mTransmitQueue.GetHead(); + + VerifyOrExit(message != nullptr); + mTransmitQueue.Dequeue(*message); + + if (mTransmitQueue.GetHead() != nullptr) + { + mTransmitTask.Post(); + } + + SuccessOrExit(error = mTls.Send(*message, message->GetLength())); + +exit: + if (error != kErrorNone) + { + LogNote("Transmit: %s", ErrorToString(error)); + message->Free(); + } + else + { + LogDebg("Transmit: %s", ErrorToString(error)); + } +} + +Error BleSecure::HandleTransport(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + OT_UNUSED_VARIABLE(aMessageInfo); + return static_cast(aContext)->HandleTransport(aMessage); +} + +Error BleSecure::HandleTransport(ot::Message &aMessage) +{ + otBleRadioPacket packet; + uint16_t len = aMessage.GetLength(); + uint16_t offset = 0; + Error error = kErrorNone; + + while (len > 0) + { + if (len <= mMtuSize - kGattOverhead) + { + packet.mLength = len; + } + else + { + packet.mLength = mMtuSize - kGattOverhead; + } + + if (packet.mLength > kPacketBufferSize) + { + packet.mLength = kPacketBufferSize; + } + + IgnoreReturnValue(aMessage.Read(offset, mPacketBuffer, packet.mLength)); + packet.mValue = mPacketBuffer; + packet.mPower = OT_BLE_DEFAULT_POWER; + + SuccessOrExit(error = otPlatBleGattServerIndicate(&GetInstance(), kTxBleHandle, &packet)); + + len -= packet.mLength; + offset += packet.mLength; + } + + aMessage.Free(); +exit: + return error; +} + +} // namespace Ble +} // namespace ot + +void otPlatBleGattServerOnWriteRequest(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket) +{ + OT_UNUSED_VARIABLE(aHandle); // Only a single handle is expected for RX + + VerifyOrExit(aPacket != nullptr); + IgnoreReturnValue(AsCoreType(aInstance).Get().HandleBleReceive(aPacket->mValue, aPacket->mLength)); +exit: + return; +} + +void otPlatBleGapOnConnected(otInstance *aInstance, uint16_t aConnectionId) +{ + AsCoreType(aInstance).Get().HandleBleConnected(aConnectionId); +} + +void otPlatBleGapOnDisconnected(otInstance *aInstance, uint16_t aConnectionId) +{ + AsCoreType(aInstance).Get().HandleBleDisconnected(aConnectionId); +} + +void otPlatBleGattOnMtuUpdate(otInstance *aInstance, uint16_t aMtu) +{ + IgnoreReturnValue(AsCoreType(aInstance).Get().HandleBleMtuUpdate(aMtu)); +} + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE diff --git a/src/core/radio/ble_secure.hpp b/src/core/radio/ble_secure.hpp new file mode 100644 index 0000000000..63a86aacdc --- /dev/null +++ b/src/core/radio/ble_secure.hpp @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BLE_SECURE_HPP_ +#define BLE_SECURE_HPP_ + +#include "openthread-core-config.h" + +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#include + +#include "meshcop/meshcop.hpp" +#include "meshcop/secure_transport.hpp" +#include "meshcop/tcat_agent.hpp" + +/** + * @file + * Includes definitions for the secure BLE agent. + */ + +namespace ot { + +namespace Ble { + +class BleSecure : public InstanceLocator, private NonCopyable +{ +public: + /** + * Pointer to call when the secure BLE connection state changes. + * + * Please see otHandleBleSecureConnect for details. + * + */ + typedef otHandleBleSecureConnect ConnectCallback; + + /** + * Pointer to call when data was received over the TLS connection. + * If line mode is activated the function is called only after EOL has been received. + * + * Please see otHandleBleSecureReceive for details. + * + */ + typedef otHandleBleSecureReceive ReceiveCallback; + + /** + * Represents a TCAT command class. + * + */ + typedef MeshCoP::TcatAgent::CommandClass CommandClass; + + /** + * Constructor initializes the object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit BleSecure(Instance &aInstance); + + /** + * Starts the secure BLE agent. + * + * @param[in] aConnectHandler A pointer to a function that will be called when the connection + * state changes. + * @param[in] aReceiveHandler A pointer to a function that will be called once data has been received + * over the TLS connection. + * @param[in] aTlvMode A boolean value indicating if line mode shall be activated. + * @param[in] aContext A pointer to arbitrary context information. May be NULL if not used. + * + * @retval kErrorNone Successfully started the BLE agent. + * @retval kErrorAlready Already started. + * + */ + Error Start(ConnectCallback aConnectHandler, ReceiveCallback aReceiveHandler, bool aTlvMode, void *aContext); + + /** + * Enables the TCAT protocol over BLE Secure. + * + * @param[in] aVendorInfo A reference to the Vendor Information (must remain valid after the method call) + * @param[in] aHandler Callback to a function that is called when the join operation completes. + * + * @retval kErrorNone Successfully started the BLE Secure Joiner role. + * @retval kErrorInvalidArgs The aVendorInfo is invalid. + * @retval kErrorInvaidState The BLE function has not been started or line mode is not selected. + * + */ + Error TcatStart(const MeshCoP::TcatAgent::VendorInfo &aVendorInfo, MeshCoP::TcatAgent::JoinCallback aHandler); + + /** + * Stops the secure BLE agent. + * + */ + void Stop(void); + + /** + * Initializes TLS session with a peer using an already open BLE connection. + * + * @retval kErrorNone Successfully started TLS connection. + * + */ + Error Connect(void); + + /** + * Stops the BLE and TLS connection. + * + */ + void Disconnect(void); + + /** + * Indicates whether or not the TLS session is active (connected or conneting). + * + * @retval TRUE If TLS session is active. + * @retval FALSE If TLS session is not active. + * + */ + bool IsConnectionActive(void) const { return mTls.IsConnectionActive(); } + + /** + * Indicates whether or not the TLS session is connected. + * + * @retval TRUE The TLS session is connected. + * @retval FALSE The TLS session is not connected. + * + */ + bool IsConnected(void) const { return mTls.IsConnected(); } + + /** + * Indicates whether or not the TCAT agent is enabled. + * + * @retval TRUE The TCAT agent is enabled. + * @retval FALSE The TCAT agent is not enabled. + * + */ + bool IsTcatEnabled(void) const { return mTcatAgent.IsEnabled(); } + + /** + * Indicates whether or not a TCAT command class is authorized. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aCommandClass A command class to check. + * + * @retval TRUE The command class is authorized. + * @retval FALSE The command class is not authorized. + * + */ + bool IsCommandClassAuthorized(CommandClass aCommandClass) const + { + return mTcatAgent.IsCommandClassAuthorized(aCommandClass); + } + + /** + * Sets the PSK. + * + * @param[in] aPsk A pointer to the PSK. + * @param[in] aPskLength The PSK length. + * + * @retval kErrorNone Successfully set the PSK. + * @retval kErrorInvalidArgs The PSK is invalid. + * + */ + Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength) { return mTls.SetPsk(aPsk, aPskLength); } + + /** + * Sets the PSK. + * + * @param[in] aPskd A Joiner PSKd. + * + */ + void SetPsk(const MeshCoP::JoinerPskd &aPskd); + +#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + /** + * Sets the Pre-Shared Key (PSK) for TLS sessions identified by a PSK. + * + * TLS mode "TLS with AES 128 CCM 8" for secure BLE. + * + * @param[in] aPsk A pointer to the PSK. + * @param[in] aPskLength The PSK char length. + * @param[in] aPskIdentity The Identity Name for the PSK. + * @param[in] aPskIdLength The PSK Identity Length. + * + */ + void SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength) + { + mTls.SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength); + } +#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + /** + * Sets a X509 certificate with corresponding private key for TLS session. + * + * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. + * + * @param[in] aX509Cert A pointer to the PEM formatted X509 PEM certificate. + * @param[in] aX509Length The length of certificate. + * @param[in] aPrivateKey A pointer to the PEM formatted private key. + * @param[in] aPrivateKeyLength The length of the private key. + * + */ + void SetCertificate(const uint8_t *aX509Cert, + uint32_t aX509Length, + const uint8_t *aPrivateKey, + uint32_t aPrivateKeyLength) + { + mTls.SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength); + } + + /** + * Sets the trusted top level CAs. It is needed for validate the certificate of the peer. + * + * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. + * + * @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain. + * @param[in] aX509CaCertChainLength The length of chain. + * + */ + void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength) + { + mTls.SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength); + } +#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /** + * Returns the peer x509 certificate base64 encoded. + * + * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. + * + * @param[out] aPeerCert A pointer to the base64 encoded certificate buffer. + * @param[out] aCertLength On input, the size the max size of @p aPeerCert. + * On output, the length of the base64 encoded peer certificate. + * + * @retval kErrorNone Successfully get the peer certificate. + * @retval kErrorInvalidArgs @p aInstance or @p aCertLength is invalid. + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNoBufs Can't allocate memory for certificate. + * + */ + Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength); +#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /** + * Returns an attribute value identified by its OID from the subject + * of the peer x509 certificate. The peer OID is provided in binary format. + * The attribute length is set if the attribute was successfully read or zero + * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard + * if the attribute was successfully read. + * + * @param[in] aOid A pointer to the OID to be found. + * @param[in] aOidLength The length of the OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer. + * + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNone Successfully read attribute. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * + */ + Error GetPeerSubjectAttributeByOid(const char *aOid, + size_t aOidLength, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength, + int *aAsn1Type) + { + return mTls.GetPeerSubjectAttributeByOid(aOid, aOidLength, aAttributeBuffer, aAttributeLength, aAsn1Type); + } + + /** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval kErrorNone Successfully read attribute. + * @retval kErrorNotFound The requested attribute was not found. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. + * @retval kErrorParse The certificate extensions could not be parsed. + * + */ + Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) + { + return mTls.GetThreadAttributeFromPeerCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); + } +#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + + /** + * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of + * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor. + * The attribute length is set if the attribute was successfully read or zero if unsuccessful. + * Requires a connection to be active. + * + * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. + * @param[out] aAttributeBuffer A pointer to the attribute buffer. + * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. + * On output, the length of the attribute written to the buffer. + * + * @retval kErrorNone Successfully read attribute. + * @retval kErrorNotFound The requested attribute was not found. + * @retval kErrorNoBufs Insufficient memory for storing the attribute value. + * @retval kErrorInvalidState Not connected yet. + * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. + * @retval kErrorParse The certificate extensions could not be parsed. + * + */ + Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor, + uint8_t *aAttributeBuffer, + size_t *aAttributeLength) + { + return mTls.GetThreadAttributeFromOwnCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); + } + + /** + * Sets the authentication mode for the BLE secure connection. It disables or enables the verification + * of peer certificate. + * + * @param[in] aVerifyPeerCertificate true, if the peer certificate should be verified + * + */ + void SetSslAuthMode(bool aVerifyPeerCertificate) { mTls.SetSslAuthMode(aVerifyPeerCertificate); } + + /** + * Sends a secure BLE message. + * + * @param[in] aMessage A pointer to the message to send. + * + * If the return value is kErrorNone, OpenThread takes ownership of @p aMessage, and the caller should no longer + * reference @p aMessage. If the return value is not kErrorNone, the caller retains ownership of @p aMessage, + * including freeing @p aMessage if the message buffer is no longer needed. + * + * @retval kErrorNone Successfully sent message. + * @retval kErrorNoBufs Failed to allocate buffer memory. + * @retval kErrorInvalidState TLS connection was not initialized. + * + */ + Error SendMessage(Message &aMessage); + + /** + * Sends a secure BLE data packet. + * + * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. + * @param[in] aLength A number indicating the length of the data buffer. + * + * @retval kErrorNone Successfully sent data. + * @retval kErrorNoBufs Failed to allocate buffer memory. + * @retval kErrorInvalidState TLS connection was not initialized. + * + */ + Error Send(uint8_t *aBuf, uint16_t aLength); + + /** + * Sends a secure BLE data packet containing a TCAT Send Application Data TLV. + * + * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. + * @param[in] aLength A number indicating the length of the data buffer. + * + * @retval kErrorNone Successfully sent data. + * @retval kErrorNoBufs Failed to allocate buffer memory. + * @retval kErrorInvalidState TLS connection was not initialized. + * + */ + Error SendApplicationTlv(uint8_t *aBuf, uint16_t aLength); + + /** + * Sends all remaining bytes in the send buffer. + * + * @retval kErrorNone Successfully enqueued data into the output interface. + * @retval kErrorNoBufs Failed to allocate buffer memory. + * @retval kErrorInvalidState TLS connection was not initialized. + * + */ + Error Flush(void); + + /** + * Used to pass data received over a BLE link to the secure BLE server. + * + * @param[in] aBuf A pointer to the data received. + * @param[in] aLength A number indicating the length of the data buffer. + * + */ + Error HandleBleReceive(uint8_t *aBuf, uint16_t aLength); + + /** + * Used to notify the secure BLE server that a BLE Device has been connected. + * + * @param[in] aConnectionId The identifier of the open connection. + * + */ + void HandleBleConnected(uint16_t aConnectionId); + + /** + * Used to notify the secure BLE server that the BLE Device has been disconnected. + * + * @param[in] aConnectionId The identifier of the open connection. + * + */ + void HandleBleDisconnected(uint16_t aConnectionId); + + /** + * Used to notify the secure BLE server that the BLE Device has updated ATT_MTU size. + * + * @param[in] aMtu The updated ATT_MTU value. + * + */ + Error HandleBleMtuUpdate(uint16_t aMtu); + +private: + enum BleState : uint8_t + { + kStopped = 0, // Ble secure not started. + kAdvertising = 1, // Ble secure not advertising. + kConnected = 2, // Ble secure not connected. + }; + + static constexpr uint8_t kInitialMtuSize = 23; // ATT_MTU + static constexpr uint8_t kGattOverhead = 3; // BLE GATT payload fits MTU size - 3 bytes + static constexpr uint8_t kPacketBufferSize = OT_BLE_ATT_MTU_MAX - kGattOverhead; + static constexpr uint16_t kTxBleHandle = 0; // Characteristics Handle for TX (not used) + + static void HandleTlsConnected(void *aContext, bool aConnected); + void HandleTlsConnected(bool aConnected); + + static void HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); + void HandleTlsReceive(uint8_t *aBuf, uint16_t aLength); + + void HandleTransmit(void); + + static Error HandleTransport(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + Error HandleTransport(ot::Message &aMessage); + + using TxTask = TaskletIn; + + MeshCoP::SecureTransport mTls; + MeshCoP::TcatAgent mTcatAgent; + Callback mConnectCallback; + Callback mReceiveCallback; + bool mTlvMode; + ot::Message *mReceivedMessage; + ot::Message *mSendMessage; + ot::MessageQueue mTransmitQueue; + TxTask mTransmitTask; + uint8_t mPacketBuffer[kPacketBufferSize]; + BleState mBleState; + uint16_t mMtuSize; +}; + +} // namespace Ble +} // namespace ot + +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +#endif // BLE_SECURE_HPP_ diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index bba16dec63..8e6848832f 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -97,7 +97,7 @@ void ThreadNetif::Down(void) #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE Get().Stop(); #endif -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE Get().Stop(); #endif IgnoreError(Get().Stop()); diff --git a/src/core/thread/tmf.cpp b/src/core/thread/tmf.cpp index 583f6e29d7..477e4d1edf 100644 --- a/src/core/thread/tmf.cpp +++ b/src/core/thread/tmf.cpp @@ -271,7 +271,7 @@ Message::Priority Agent::DscpToPriority(uint8_t aDscp) return priority; } -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE SecureAgent::SecureAgent(Instance &aInstance) : Coap::CoapSecure(aInstance) @@ -329,7 +329,7 @@ bool SecureAgent::HandleResource(const char *aUriPath, Message &aMessage, const return didHandle; } -#endif // OPENTHREAD_CONFIG_DTLS_ENABLE +#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE } // namespace Tmf } // namespace ot diff --git a/src/core/thread/tmf.hpp b/src/core/thread/tmf.hpp index 3b38544442..c90e24257c 100644 --- a/src/core/thread/tmf.hpp +++ b/src/core/thread/tmf.hpp @@ -214,7 +214,7 @@ class Agent : public Coap::Coap static Error Filter(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext); }; -#if OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE /** * Implements functionality of the secure TMF agent. diff --git a/src/core/utils/heap.hpp b/src/core/utils/heap.hpp index c4125b14b1..22868449c4 100644 --- a/src/core/utils/heap.hpp +++ b/src/core/utils/heap.hpp @@ -227,7 +227,7 @@ class Heap : private NonCopyable size_t GetFreeSize(void) const { return mMemory.mFreeSize; } private: -#if OPENTHREAD_CONFIG_TLS_ENABLE || OPENTHREAD_CONFIG_DTLS_ENABLE +#if OPENTHREAD_CONFIG_TLS_ENABLE || OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE static constexpr uint16_t kMemorySize = OPENTHREAD_CONFIG_HEAP_INTERNAL_SIZE; #else static constexpr uint16_t kMemorySize = OPENTHREAD_CONFIG_HEAP_INTERNAL_SIZE_NO_DTLS; diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index b367d8758d..d52ff48fc6 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -119,6 +119,7 @@ add_library(openthread-posix alarm.cpp backbone.cpp backtrace.cpp + ble.cpp configuration.cpp config_file.cpp daemon.cpp diff --git a/src/posix/platform/ble.cpp b/src/posix/platform/ble.cpp new file mode 100644 index 0000000000..2fe3c64535 --- /dev/null +++ b/src/posix/platform/ble.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +otError otPlatBleEnable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleDisable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aInterval); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStop(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapDisconnect(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aMtu); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aHandle); + OT_UNUSED_VARIABLE(aPacket); + return OT_ERROR_NOT_IMPLEMENTED; +} diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 5487643140..923895a047 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -35,6 +35,9 @@ #include #include +#ifdef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#include +#endif enum { @@ -623,4 +626,88 @@ void otPlatDnsCancelUpstreamQuery(otInstance *aInstance, otPlatDnsUpstreamQuery } #endif +<<<<<<< HEAD +======= +OT_TOOL_WEAK otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *, int8_t *) { return OT_ERROR_NONE; } + +OT_TOOL_WEAK otError otPlatRadioGetCoexMetrics(otInstance *, otRadioCoexMetrics *) { return OT_ERROR_NONE; } + +OT_TOOL_WEAK otError otPlatRadioGetTransmitPower(otInstance *, int8_t *) { return OT_ERROR_NONE; } + +OT_TOOL_WEAK bool otPlatRadioIsCoexEnabled(otInstance *) { return true; } + +OT_TOOL_WEAK otError otPlatRadioSetCoexEnabled(otInstance *, bool) { return OT_ERROR_NOT_IMPLEMENTED; } + +#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE +OT_TOOL_WEAK otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower) +{ + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK otError otPlatRadioAddCalibratedPower(otInstance *aInstance, + uint8_t aChannel, + int16_t aActualPower, + const uint8_t *aRawPowerSetting, + uint16_t aRawPowerSettingLength) +{ + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK otError otPlatRadioClearCalibratedPowers(otInstance *aInstance) { return OT_ERROR_NONE; } +#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE + +#if OPENTHREAD_CONFIG_NCP_ENABLE_MCU_POWER_STATE_CONTROL +OT_TOOL_WEAK otPlatMcuPowerState otPlatGetMcuPowerState(otInstance *aInstance) { return OT_PLAT_MCU_POWER_STATE_ON; } + +OT_TOOL_WEAK otError otPlatSetMcuPowerState(otInstance *aInstance, otPlatMcuPowerState aState) { return OT_ERROR_NONE; } +#endif // OPENTHREAD_CONFIG_NCP_ENABLE_MCU_POWER_STATE_CONTROL +#ifdef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +otError otPlatBleEnable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleDisable(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aInterval); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapAdvStop(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGapDisconnect(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aMtu); + return OT_ERROR_NOT_IMPLEMENTED; +} + +otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aHandle); + OT_UNUSED_VARIABLE(aPacket); + return OT_ERROR_NOT_IMPLEMENTED; +} +#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + +>>>>>>> 5cab15840d... [tcat] initial commit of bluetooth-based commissioning (#9210) } // extern "C" diff --git a/third_party/mbedtls/mbedtls-config.h b/third_party/mbedtls/mbedtls-config.h index fcb1739e13..a3e06ac63e 100644 --- a/third_party/mbedtls/mbedtls-config.h +++ b/third_party/mbedtls/mbedtls-config.h @@ -92,6 +92,10 @@ #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #endif +#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#endif + #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #define MBEDTLS_BASE64_C #define MBEDTLS_ECDH_C From 655756dbdb10e28ee7259e1f9dcec52780b650ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Baczma=C5=84ski?= Date: Fri, 16 Feb 2024 20:12:57 +0100 Subject: [PATCH 4/9] [tools] add missing tcat ble client files (#9857) Some files were missing during repo migration, this commit adds them. Signed-off-by: Maciej Baczmanski Co-authored-by: Piotr Jasinski Co-authored-by: Przemyslaw Bida --- tools/tcat_ble_client/tlv/tlv.py | 71 +++++++++++++++++++++++++ tools/tcat_ble_client/utils/__init__.py | 63 ++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 tools/tcat_ble_client/tlv/tlv.py create mode 100644 tools/tcat_ble_client/utils/__init__.py diff --git a/tools/tcat_ble_client/tlv/tlv.py b/tools/tcat_ble_client/tlv/tlv.py new file mode 100644 index 0000000000..75657c41a9 --- /dev/null +++ b/tools/tcat_ble_client/tlv/tlv.py @@ -0,0 +1,71 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from __future__ import annotations +from typing import List + + +class TLV(): + + def __init__(self, type: int = None, value: bytes = None): + self.type: int = type + self.value: bytes = value + + def __str__(self): + return f'TLV\n\tTYPE:\t0x{self.type:02x}\n\tVALUE:\t{self.value}' + + @staticmethod + def parse_tlvs(data: bytes) -> List[TLV]: + res: List[TLV] = [] + while data: + next_tlv = TLV.from_bytes(data) + next_tlv_size = len(next_tlv.to_bytes()) + data = data[next_tlv_size:] + res.append(next_tlv) + return res + + @staticmethod + def from_bytes(data: bytes) -> TLV: + res = TLV() + res.set_from_bytes(data) + return res + + def set_from_bytes(self, data: bytes): + self.type = data[0] + header_len = 2 + if data[1] == 0xFF: + header_len = 4 + length = int.from_bytes(data[1:header_len], byteorder='big') + self.value = data[header_len:header_len + length] + + def to_bytes(self) -> bytes: + has_long_header = len(self.value) >= 255 + header_len = 4 if has_long_header else 2 + len_bytes = len(self.value).to_bytes(header_len - 1, byteorder='big') + header = bytes([self.type]) + len_bytes + return header + self.value diff --git a/tools/tcat_ble_client/utils/__init__.py b/tools/tcat_ble_client/utils/__init__.py new file mode 100644 index 0000000000..d6d40bae9f --- /dev/null +++ b/tools/tcat_ble_client/utils/__init__.py @@ -0,0 +1,63 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + + +def get_int_in_range(min_value, max_value): + while True: + try: + user_input = int(input('> ')) + if min_value <= user_input <= max_value: + return user_input + else: + print('The value is out of range. Try again.') + except ValueError: + print('The value is not an integer. Try again.') + except KeyboardInterrupt: + quit_with_reason('Program interrupted by user. Quitting.') + + +def quit_with_reason(reason): + print(reason) + exit(1) + + +def select_device_by_user_input(tcat_devices): + if tcat_devices: + print('Found devices:\n') + for i, device in enumerate(tcat_devices): + print(f'{i + 1}: {device.name} - {device.address}') + else: + print('\nNo devices found.') + return None + + print('\nSelect the target number to connect to it.') + selected = get_int_in_range(1, len(tcat_devices)) + device = tcat_devices[selected - 1] + print('Selected ', device) + + return device From 75cd0688324c231224b8d818f223cdea824d7619 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 12 Jan 2024 10:55:41 -0800 Subject: [PATCH 5/9] [tcat] define config defaults (#9768) --- src/cli/cli_config.h | 10 ++++++++++ src/core/config/ip6.h | 5 +++-- src/core/config/misc.h | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/cli/cli_config.h b/src/cli/cli_config.h index ac9b5e1cc3..0eb9b2d088 100644 --- a/src/cli/cli_config.h +++ b/src/cli/cli_config.h @@ -196,4 +196,14 @@ #define OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK 0 #endif +/** + * @def OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE + * + * Define to 1 to enable BLE secure support. + * + */ +#ifndef OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE +#define OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 0 +#endif + #endif // CONFIG_CLI_H_ diff --git a/src/core/config/ip6.h b/src/core/config/ip6.h index 82dc45c954..3c143390a9 100644 --- a/src/core/config/ip6.h +++ b/src/core/config/ip6.h @@ -36,6 +36,7 @@ #define CONFIG_IP6_H_ #include "config/border_routing.h" +#include "config/misc.h" /** * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS @@ -178,8 +179,8 @@ * Define as 1 to enable support for TLS over TCP. * */ -#if (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) && !defined(OPENTHREAD_CONFIG_TLS_ENABLE) -#define OPENTHREAD_CONFIG_TLS_ENABLE 1 +#ifndef OPENTHREAD_CONFIG_TLS_ENABLE +#define OPENTHREAD_CONFIG_TLS_ENABLE (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) #endif /** diff --git a/src/core/config/misc.h b/src/core/config/misc.h index df9fd28fa4..227fb969fe 100644 --- a/src/core/config/misc.h +++ b/src/core/config/misc.h @@ -542,4 +542,19 @@ #define OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT 0 #endif +/** + * @def OPENTHREAD_CONFIG_BLE_TCAT_ENABLE + * + * Define to 1 to enable TCAT over BLE support. + * + */ +#ifndef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE +#define OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 0 +#endif + +/** + * @} + * + */ + #endif // CONFIG_MISC_H_ From ccdfc3d90565b12aac8e2b8522d22a622516cca7 Mon Sep 17 00:00:00 2001 From: Piotr Jasinski Date: Wed, 7 Feb 2024 22:13:12 +0100 Subject: [PATCH 6/9] [tools] add tcat ble client (#9739) Adds TCAT client implementation for BLE transport. Signed-off-by: Piotr Jasinski Co-authored-by: Przemyslaw Bida --- .../GENERATING_CERTIFICATES.md | 91 ++++ tools/tcat_ble_client/README.md | 56 ++ tools/tcat_ble_client/auth/ca_cert.pem | 13 + tools/tcat_ble_client/auth/ca_key.pem | 5 + .../auth/commissioner_cert.pem | 11 + .../tcat_ble_client/auth/commissioner_key.pem | 8 + tools/tcat_ble_client/bbtc.py | 112 ++++ .../ble/ble_connection_constants.py | 32 ++ tools/tcat_ble_client/ble/ble_scanner.py | 52 ++ tools/tcat_ble_client/ble/ble_stream.py | 93 ++++ .../tcat_ble_client/ble/ble_stream_secure.py | 121 +++++ tools/tcat_ble_client/cli/base_commands.py | 165 ++++++ tools/tcat_ble_client/cli/cli.py | 97 ++++ tools/tcat_ble_client/cli/command.py | 101 ++++ tools/tcat_ble_client/cli/dataset_commands.py | 221 ++++++++ tools/tcat_ble_client/dataset/dataset.py | 64 +++ .../dataset/dataset_entries.py | 502 ++++++++++++++++++ tools/tcat_ble_client/poetry.lock | 318 +++++++++++ tools/tcat_ble_client/pyproject.toml | 16 + tools/tcat_ble_client/tlv/dataset_tlv.py | 79 +++ tools/tcat_ble_client/tlv/tcat_tlv.py | 45 ++ 21 files changed, 2202 insertions(+) create mode 100644 tools/tcat_ble_client/GENERATING_CERTIFICATES.md create mode 100644 tools/tcat_ble_client/README.md create mode 100644 tools/tcat_ble_client/auth/ca_cert.pem create mode 100644 tools/tcat_ble_client/auth/ca_key.pem create mode 100644 tools/tcat_ble_client/auth/commissioner_cert.pem create mode 100644 tools/tcat_ble_client/auth/commissioner_key.pem create mode 100644 tools/tcat_ble_client/bbtc.py create mode 100644 tools/tcat_ble_client/ble/ble_connection_constants.py create mode 100644 tools/tcat_ble_client/ble/ble_scanner.py create mode 100644 tools/tcat_ble_client/ble/ble_stream.py create mode 100644 tools/tcat_ble_client/ble/ble_stream_secure.py create mode 100644 tools/tcat_ble_client/cli/base_commands.py create mode 100644 tools/tcat_ble_client/cli/cli.py create mode 100644 tools/tcat_ble_client/cli/command.py create mode 100644 tools/tcat_ble_client/cli/dataset_commands.py create mode 100644 tools/tcat_ble_client/dataset/dataset.py create mode 100644 tools/tcat_ble_client/dataset/dataset_entries.py create mode 100644 tools/tcat_ble_client/poetry.lock create mode 100644 tools/tcat_ble_client/pyproject.toml create mode 100644 tools/tcat_ble_client/tlv/dataset_tlv.py create mode 100644 tools/tcat_ble_client/tlv/tcat_tlv.py diff --git a/tools/tcat_ble_client/GENERATING_CERTIFICATES.md b/tools/tcat_ble_client/GENERATING_CERTIFICATES.md new file mode 100644 index 0000000000..1eb1b79768 --- /dev/null +++ b/tools/tcat_ble_client/GENERATING_CERTIFICATES.md @@ -0,0 +1,91 @@ +# BBTC X.509 certificates generation + +--- + +TCAT uses X.509 Certificate Extensions to provide permissions with certificates. + +## Extensions + +Extensions were introduced in version 3 of the X.509 standard for certificates. They allow certificates to be customised to applications by supporting the addition of arbitrary fields in the certificate. Each extension, identified by its OID (Object Identifier), is marked as "Critical" or "Non-Critical", and includes the extension-specific data. + +## Certificates generation + +Thread uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl` argument to generate the keys. + +### Root certificate + +1. Generate the private key: + +``` +openssl ecparam -genkey -name prime256v1 -out ca_key.pem +``` + +1. We can then generate the **.csr** (certificate signing request) file, which will contain all the parameters of our final certificate: + +``` +openssl req -new -sha256 -key ca_key.pem -out ca.csr +``` + +1. Finally, we can generate the certificate itself: + +``` +openssl req -x509 -sha256 -days 365 -key ca_key.pem -in ca.csr -out ca_cert.pem +``` + +1. See the generated certificate using + +``` +openssl x509 -in ca_cert.pem -text -noout +``` + +### Commissioner (client) certificate + +1. Generate the key: + +``` +openssl ecparam -genkey -name prime256v1 -out commissioner_key.pem +``` + +1. Specify additional extensions when generating the .csr (see [sample configuration](#Configurations)): + +``` +openssl req -new -sha256 -key commissioner_key.pem -out commissioner.csr -config commissioner.cnf +``` + +1. Generate the certificate: + +``` +openssl x509 -req -in commissioner.csr -CA ca_cert.pem -CAkey ca_key.pem -out commissioner_cert.pem -days 365 -sha256 -copy_extensions copy +``` + +1. View the generated certificate using: + +``` +openssl x509 -in commissioner_cert.pem -text -noout +``` + +1. View parsed certificate extensions using: + +``` +openssl asn1parse -inform PEM -in commissioner_cert.pem +``` + +## Configurations + +file: `commissioner.cnf` (line `1.3.6.1.4.1.44970.3 = DER:21:01:01:01:01` specifies permissions (all)) + +``` +[ req ] +default_bits = 2048 +distinguished_name = req_distinguished_name +prompt = no +req_extensions = v3_req + +[ req_distinguished_name ] +CN = Commissioner + +[v3_req] +1.3.6.1.4.1.44970.3 = DER:21:01:01:01:01 +authorityKeyIdentifier = none +subjectKeyIdentifier = none +``` diff --git a/tools/tcat_ble_client/README.md b/tools/tcat_ble_client/README.md new file mode 100644 index 0000000000..3af2fead02 --- /dev/null +++ b/tools/tcat_ble_client/README.md @@ -0,0 +1,56 @@ +# BBTC Client + +## Overview + +This is a Python implementation of Bluetooth-Based Thread Commissioning client, based on Thread's TCAT (Thread Commissioning over Authenticated TLS) functionality. + +## Installation + +If you don't have the poetry module installed (check with `poetry --version`), install it first using: + +```bash +python3 -m pip install poetry +``` + +Thread uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl` argument to generate the keys. + +``` +poetry install +``` + +This will install all the required modules to a virtual environment, which can be used by calling `poetry run ` from the project directory. + +## Usage + +In order to connect to a TCAT device, enter the project directory and run: + +```bash +poetry run python3 bbtc.py { | --scan} +``` + +where `` can be: + +- `--name ` - name advertised by the device +- `--mac
` - physical address of the device's Bluetooth interface + +Using the `--scan` option will scan for every TCAT device and display them in a list, to allow selection of the target. + +For example: + +``` +poetry run python3 bbtc.py --name 'Thread BLE' +``` + +The application will connect to the first matching device discovered and set up a secure TLS channel. The user is then presented with the CLI. + +## Commands + +The application supports the following interactive CLI commands: + +- `help` - Display available commands. +- `commission` - Commission the device with current dataset. +- `thread start` - Enable Thread interface. +- `thread stop` - Disable Thread interface. +- `hello` - Send "hello world" application data and read the response. +- `exit` - Close the connection and exit. +- `dataset` - View and manipulate current dataset. See `dataset help` for more information. diff --git a/tools/tcat_ble_client/auth/ca_cert.pem b/tools/tcat_ble_client/auth/ca_cert.pem new file mode 100644 index 0000000000..e9994c122d --- /dev/null +++ b/tools/tcat_ble_client/auth/ca_cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCDCCAa2gAwIBAgIJAIKxygBXoH+5MAoGCCqGSM49BAMCMG8xCzAJBgNVBAYT +AlhYMRAwDgYDVQQIEwdNeVN0YXRlMQ8wDQYDVQQHEwZNeUNpdHkxDzANBgNVBAsT +Bk15VW5pdDERMA8GA1UEChMITXlWZW5kb3IxGTAXBgNVBAMTEHd3dy5teXZlbmRv +ci5jb20wHhcNMjMxMDE2MTAzMzE1WhcNMjYxMDE2MTAzMzE1WjBvMQswCQYDVQQG +EwJYWDEQMA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQL +EwZNeVVuaXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5k +b3IuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdyzPAXGKeZY94OhHAWX +HzJfQIjGSyaOzlgL9OEFw2SoUDncLKPGwfPAUSfuMyEkzszNDM0HHkBsDLqu4n25 +/6MyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4EynoSw9eDKZEVPkums2 +IWLAJCowCgYIKoZIzj0EAwIDSQAwRgIhAMYGGL9xShyE6P9wEU+MAYF6W3CzdrwV +kuerX1encIH2AiEA5rq490NUobM1Au43roxJq1T6Z43LscPVbGZfULD1Jq0= +-----END CERTIFICATE----- diff --git a/tools/tcat_ble_client/auth/ca_key.pem b/tools/tcat_ble_client/auth/ca_key.pem new file mode 100644 index 0000000000..f75c9173f4 --- /dev/null +++ b/tools/tcat_ble_client/auth/ca_key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEII/jxkoUczPvlYM3ayhneif63B64lan3SubrXiVEbhoVoAoGCCqGSM49 +AwEHoUQDQgAEWdyzPAXGKeZY94OhHAWXHzJfQIjGSyaOzlgL9OEFw2SoUDncLKPG +wfPAUSfuMyEkzszNDM0HHkBsDLqu4n25/w== +-----END EC PRIVATE KEY----- diff --git a/tools/tcat_ble_client/auth/commissioner_cert.pem b/tools/tcat_ble_client/auth/commissioner_cert.pem new file mode 100644 index 0000000000..3f40dc8d4d --- /dev/null +++ b/tools/tcat_ble_client/auth/commissioner_cert.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBnzCCAUSgAwIBAgIUQ5RUJMc95ssHQybR6pcx7LXSBzcwCgYIKoZIzj0EAwIw +bzELMAkGA1UEBhMCWFgxEDAOBgNVBAgTB015U3RhdGUxDzANBgNVBAcTBk15Q2l0 +eTEPMA0GA1UECxMGTXlVbml0MREwDwYDVQQKEwhNeVZlbmRvcjEZMBcGA1UEAxMQ +d3d3Lm15dmVuZG9yLmNvbTAeFw0yMzEwMTgxNTIyMTZaFw0zMzEwMTUxNTIyMTZa +MBcxFTATBgNVBAMMDENvbW1pc3Npb25lcjBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABDU90Qpae5c+5Diou072S6MMHNv9+Ah9Kmo+mZTT6gQUyRScFey3+6wE08o7 +wl6/8EKRgS8TFSihK4mYGxYoN06jFjAUMBIGCSsGAQQBgt8qAwQFIQEBAQEwCgYI +KoZIzj0EAwIDSQAwRgIhAOgQH8wFSe3JtGSmEFLy4fbMhOg+5Mfhqoq95vu2ML/u +AiEAt4BjuFo7GTxQxXl1e8TvMGESPGBKnR7cIT/BCnn2fto= +-----END CERTIFICATE----- diff --git a/tools/tcat_ble_client/auth/commissioner_key.pem b/tools/tcat_ble_client/auth/commissioner_key.pem new file mode 100644 index 0000000000..57b6839202 --- /dev/null +++ b/tools/tcat_ble_client/auth/commissioner_key.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIFOGszqvbs62fRwd3Rnd79wf6fpWxkXLO5YzhEuJ9EV1oAoGCCqGSM49 +AwEHoUQDQgAENT3RClp7lz7kOKi7TvZLowwc2/34CH0qaj6ZlNPqBBTJFJwV7Lf7 +rATTyjvCXr/wQpGBLxMVKKEriZgbFig3Tg== +-----END EC PRIVATE KEY----- diff --git a/tools/tcat_ble_client/bbtc.py b/tools/tcat_ble_client/bbtc.py new file mode 100644 index 0000000000..fa2ebbb249 --- /dev/null +++ b/tools/tcat_ble_client/bbtc.py @@ -0,0 +1,112 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +import asyncio +import argparse +from os import path +import logging + +from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \ + BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME +from ble.ble_stream import BleStream +from ble.ble_stream_secure import BleStreamSecure +from ble import ble_scanner +from cli.cli import CLI +from dataset.dataset import ThreadDataset +from cli.command import CommandResult +from utils import select_device_by_user_input + + +async def main(): + logging.basicConfig(level=logging.WARNING) + + parser = argparse.ArgumentParser(description='Device parameters') + parser.add_argument('--debug', help='Enable debug logs', action='store_true') + group = parser.add_mutually_exclusive_group() + group.add_argument('--mac', type=str, help='Device MAC address', action='store') + group.add_argument('--name', type=str, help='Device name', action='store') + group.add_argument('--scan', help='Scan all available devices', action='store_true') + args = parser.parse_args() + + if args.debug: + logging.getLogger('ble_stream').setLevel(logging.DEBUG) + logging.getLogger('ble_stream_secure').setLevel(logging.DEBUG) + + device = await get_device_by_args(args) + + ble_sstream = None + + if not (device is None): + print(f'Connecting to {device}') + ble_stream = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID) + ble_sstream = BleStreamSecure(ble_stream) + ble_sstream.load_cert( + certfile=path.join('auth', 'commissioner_cert.pem'), + keyfile=path.join('auth', 'commissioner_key.pem'), + cafile=path.join('auth', 'ca_cert.pem'), + ) + + print('Setting up secure channel...') + await ble_sstream.do_handshake(hostname=SERVER_COMMON_NAME) + print('Done') + + ds = ThreadDataset() + cli = CLI(ds, ble_sstream) + loop = asyncio.get_running_loop() + print('Enter \'help\' to see available commands' ' or \'exit\' to exit the application.') + while True: + user_input = await loop.run_in_executor(None, lambda: input('> ')) + if user_input.lower() == 'exit': + print('Disconnecting...') + break + try: + result: CommandResult = await cli.evaluate_input(user_input) + if result: + result.pretty_print() + except Exception as e: + print(e) + + +async def get_device_by_args(args): + device = None + if args.mac: + device = await ble_scanner.find_first_by_mac(args.mac) + elif args.name: + device = await ble_scanner.find_first_by_name(args.name) + elif args.scan: + tcat_devices = await ble_scanner.scan_tcat_devices() + device = select_device_by_user_input(tcat_devices) + + return device + + +if __name__ == '__main__': + try: + asyncio.run(main()) + except asyncio.CancelledError: + pass # device disconnected diff --git a/tools/tcat_ble_client/ble/ble_connection_constants.py b/tools/tcat_ble_client/ble/ble_connection_constants.py new file mode 100644 index 0000000000..f1064c635a --- /dev/null +++ b/tools/tcat_ble_client/ble/ble_connection_constants.py @@ -0,0 +1,32 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +BBTC_SERVICE_UUID = 'FFFB' +BBTC_RX_CHAR_UUID = '6BD10D8B-85A7-4E5A-BA2D-C83558A5F220' +BBTC_TX_CHAR_UUID = '7FDDF61F-280A-4773-B448-BA1B8FE0DD69' +SERVER_COMMON_NAME = 'myvendor.com/tcat/mydev' diff --git a/tools/tcat_ble_client/ble/ble_scanner.py b/tools/tcat_ble_client/ble/ble_scanner.py new file mode 100644 index 0000000000..f8dc55e736 --- /dev/null +++ b/tools/tcat_ble_client/ble/ble_scanner.py @@ -0,0 +1,52 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from bleak import BleakScanner +from bbtc import BBTC_SERVICE_UUID + + +async def find_first_by_name(name): + match_name = lambda dev, adv_data: name == dev.name + device = await BleakScanner.find_device_by_filter(match_name) + return device + + +async def find_first_by_mac(mac): + match_mac = lambda dev, adv_data: mac.upper() == dev.address + device = await BleakScanner.find_device_by_filter(match_mac) + return device + + +async def scan_tcat_devices(): + scanner = BleakScanner() + tcat_devices = [] + devices_dict = await scanner.discover(return_adv=True, service_uuids=[BBTC_SERVICE_UUID.lower()]) + for _, (device, _) in devices_dict.items(): + tcat_devices.append(device) + + return tcat_devices diff --git a/tools/tcat_ble_client/ble/ble_stream.py b/tools/tcat_ble_client/ble/ble_stream.py new file mode 100644 index 0000000000..3e22da8f49 --- /dev/null +++ b/tools/tcat_ble_client/ble/ble_stream.py @@ -0,0 +1,93 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from itertools import count, takewhile +from typing import Iterator +import logging +import time +from asyncio import sleep + +from bleak import BleakClient +from bleak.backends.characteristic import BleakGATTCharacteristic + +logger = logging.getLogger(__name__) + + +class BleStream: + + def __init__(self, client, service_uuid, tx_char_uuid, rx_char_uuid): + self.__receive_buffer = b'' + self.__last_recv_time = None + self.client = client + self.service_uuid = service_uuid + self.tx_char_uuid = tx_char_uuid + self.rx_char_uuid = rx_char_uuid + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + if self.client.is_connected: + await self.client.disconnect() + + def __handle_rx(self, _: BleakGATTCharacteristic, data: bytearray): + logger.debug(f'received {len(data)} bytes') + self.__receive_buffer += data + self.__last_recv_time = time.time() + + @staticmethod + def __sliced(data: bytes, n: int) -> Iterator[bytes]: + return takewhile(len, (data[i:i + n] for i in count(0, n))) + + @classmethod + async def create(cls, address, service_uuid, tx_char_uuid, rx_char_uuid): + client = BleakClient(address) + await client.connect() + self = cls(client, service_uuid, tx_char_uuid, rx_char_uuid) + await client.start_notify(self.tx_char_uuid, self.__handle_rx) + return self + + async def send(self, data): + logger.debug(f'sending {data}') + services = self.client.services.get_service(self.service_uuid) + rx_char = services.get_characteristic(self.rx_char_uuid) + for s in BleStream.__sliced(data, rx_char.max_write_without_response_size): + await self.client.write_gatt_char(rx_char, s) + return len(data) + + async def recv(self, bufsize, recv_timeout=0.2): + if not self.__receive_buffer: + return b'' + + while time.time() - self.__last_recv_time <= recv_timeout: + await sleep(0.1) + + message = self.__receive_buffer[:bufsize] + self.__receive_buffer = self.__receive_buffer[bufsize:] + logger.debug(f'retrieved {message}') + return message diff --git a/tools/tcat_ble_client/ble/ble_stream_secure.py b/tools/tcat_ble_client/ble/ble_stream_secure.py new file mode 100644 index 0000000000..9d15b79453 --- /dev/null +++ b/tools/tcat_ble_client/ble/ble_stream_secure.py @@ -0,0 +1,121 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +import asyncio +import ssl +import logging + +from .ble_stream import BleStream + +logger = logging.getLogger(__name__) + + +class BleStreamSecure: + + def __init__(self, ble_stream: BleStream): + self.ble_stream = ble_stream + self.ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + self.incoming = ssl.MemoryBIO() + self.outgoing = ssl.MemoryBIO() + self.ssl_object = None + + def load_cert(self, certfile='', keyfile='', cafile=''): + if certfile and keyfile: + self.ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile) + elif certfile: + self.ssl_context.load_cert_chain(certfile=certfile) + + if cafile: + self.ssl_context.load_verify_locations(cafile=cafile) + + async def do_handshake(self, hostname): + self.ssl_object = self.ssl_context.wrap_bio( + incoming=self.incoming, + outgoing=self.outgoing, + server_side=False, + server_hostname=hostname, + ) + while True: + try: + self.ssl_object.do_handshake() + break + # SSLWantWrite means ssl wants to send data over the link, + # but might need a receive first + except ssl.SSLWantWriteError: + output = await self.ble_stream.recv(4096) + if output: + self.incoming.write(output) + data = self.outgoing.read() + if data: + await self.ble_stream.send(data) + await asyncio.sleep(0.1) + + # SSLWantRead means ssl wants to receive data from the link, + # but might need to send first + except ssl.SSLWantReadError: + data = self.outgoing.read() + if data: + await self.ble_stream.send(data) + output = await self.ble_stream.recv(4096) + if output: + self.incoming.write(output) + await asyncio.sleep(0.1) + + async def send(self, bytes): + self.ssl_object.write(bytes) + encode = self.outgoing.read(4096) + await self.ble_stream.send(encode) + + async def recv(self, buffersize, timeout=1): + end_time = asyncio.get_event_loop().time() + timeout + data = await self.ble_stream.recv(buffersize) + while not data and asyncio.get_event_loop().time() < end_time: + await asyncio.sleep(0.1) + data = await self.ble_stream.recv(buffersize) + if not data: + logger.warning('No response when response expected.') + return b'' + + self.incoming.write(data) + while True: + try: + decode = self.ssl_object.read(4096) + break + # if recv called before entire message was received from the link + except ssl.SSLWantReadError: + more = await self.ble_stream.recv(buffersize) + while not more: + await asyncio.sleep(0.1) + more = await self.ble_stream.recv(buffersize) + self.incoming.write(more) + return decode + + async def send_with_resp(self, bytes): + await self.send(bytes) + res = await self.recv(buffersize=4096, timeout=5) + return res diff --git a/tools/tcat_ble_client/cli/base_commands.py b/tools/tcat_ble_client/cli/base_commands.py new file mode 100644 index 0000000000..bd4c1dbea8 --- /dev/null +++ b/tools/tcat_ble_client/cli/base_commands.py @@ -0,0 +1,165 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \ + BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME +from ble.ble_stream import BleStream +from ble.ble_stream_secure import BleStreamSecure +from ble import ble_scanner +from tlv.tlv import TLV +from tlv.tcat_tlv import TcatTLVType +from cli.command import Command, CommandResultNone, CommandResultTLV +from dataset.dataset import ThreadDataset +from utils import select_device_by_user_input +from os import path + + +class HelpCommand(Command): + + def get_help_string(self) -> str: + return 'Display help and return.' + + async def execute_default(self, args, context): + commands = context['commands'] + for name, command in commands.items(): + print(f'{name}') + command.print_help(indent=1) + return CommandResultNone() + + +class HelloCommand(Command): + + def get_help_string(self) -> str: + return 'Send round trip "Hello world!" message.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + print('Sending hello world...') + data = TLV(TcatTLVType.APPLICATION.value, bytes('Hello world!', 'ascii')).to_bytes() + response = await bless.send_with_resp(data) + if not response: + return + tlv_response = TLV.from_bytes(response) + return CommandResultTLV(tlv_response) + + +class CommissionCommand(Command): + + def get_help_string(self) -> str: + return 'Update the connected device with current dataset.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + dataset: ThreadDataset = context['dataset'] + + print('Commissioning...') + dataset_bytes = dataset.to_bytes() + data = TLV(TcatTLVType.ACTIVE_DATASET.value, dataset_bytes).to_bytes() + response = await bless.send_with_resp(data) + if not response: + return + tlv_response = TLV.from_bytes(response) + return CommandResultTLV(tlv_response) + + +class ThreadStartCommand(Command): + + def get_help_string(self) -> str: + return 'Enable thread interface.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + + print('Enabling Thread...') + data = TLV(TcatTLVType.THREAD_START.value, bytes()).to_bytes() + response = await bless.send_with_resp(data) + if not response: + return + tlv_response = TLV.from_bytes(response) + return CommandResultTLV(tlv_response) + + +class ThreadStopCommand(Command): + + def get_help_string(self) -> str: + return 'Disable thread interface.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + print('Disabling Thread...') + data = TLV(TcatTLVType.THREAD_STOP.value, bytes()).to_bytes() + response = await bless.send_with_resp(data) + if not response: + return + tlv_response = TLV.from_bytes(response) + return CommandResultTLV(tlv_response) + + +class ThreadStateCommand(Command): + + def __init__(self): + self._subcommands = {'start': ThreadStartCommand(), 'stop': ThreadStopCommand()} + + def get_help_string(self) -> str: + return 'Manipulate state of the Thread interface of the connected device.' + + async def execute_default(self, args, context): + print('Invalid usage. Provide a subcommand.') + return CommandResultNone() + + +class ScanCommand(Command): + + def get_help_string(self) -> str: + return 'Perform scan for TCAT devices.' + + async def execute_default(self, args, context): + if not (context['ble_sstream'] is None): + del context['ble_sstream'] + + tcat_devices = await ble_scanner.scan_tcat_devices() + device = select_device_by_user_input(tcat_devices) + + if device is None: + return CommandResultNone() + + ble_sstream = None + + print(f'Connecting to {device}') + ble_stream = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID) + ble_sstream = BleStreamSecure(ble_stream) + ble_sstream.load_cert( + certfile=path.join('auth', 'commissioner_cert.pem'), + keyfile=path.join('auth', 'commissioner_key.pem'), + cafile=path.join('auth', 'ca_cert.pem'), + ) + + print('Setting up secure channel...') + await ble_sstream.do_handshake(hostname=SERVER_COMMON_NAME) + print('Done') + context['ble_sstream'] = ble_sstream diff --git a/tools/tcat_ble_client/cli/cli.py b/tools/tcat_ble_client/cli/cli.py new file mode 100644 index 0000000000..bfe6cd3d1f --- /dev/null +++ b/tools/tcat_ble_client/cli/cli.py @@ -0,0 +1,97 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +import readline +import shlex +from ble.ble_stream_secure import BleStreamSecure +from cli.base_commands import (HelpCommand, HelloCommand, CommissionCommand, ThreadStateCommand, ScanCommand) +from cli.dataset_commands import (DatasetCommand) +from dataset.dataset import ThreadDataset +from typing import Optional + + +class CLI: + + def __init__(self, dataset: ThreadDataset, ble_sstream: Optional[BleStreamSecure] = None): + self._commands = { + 'help': HelpCommand(), + 'hello': HelloCommand(), + 'commission': CommissionCommand(), + 'dataset': DatasetCommand(), + 'thread': ThreadStateCommand(), + 'scan': ScanCommand(), + } + self._context = {'ble_sstream': ble_sstream, 'dataset': dataset, 'commands': self._commands} + readline.set_completer(self.completer) + readline.parse_and_bind('tab: complete') + + def completer(self, text, state): + command_pool = self._commands.keys() + full_line = readline.get_line_buffer().lstrip() + words = full_line.split() + + should_suggest_subcommands = len(words) > 1 or (len(words) == 1 and full_line[-1].isspace()) + if should_suggest_subcommands: + if words[0] not in self._commands.keys(): + return None + + current_command = self._commands[words[0]] + if full_line[-1].isspace(): + subcommands = words[1:] + else: + subcommands = words[1:-1] + for nextarg in subcommands: + if nextarg in current_command._subcommands.keys(): + current_command = current_command._subcommands[nextarg] + else: + return None + + if len(current_command._subcommands) == 0: + return None + + command_pool = current_command._subcommands.keys() + + options = [c for c in command_pool if c.startswith(text)] + if state < len(options): + return options[state] + else: + return None + + async def evaluate_input(self, user_input): + # do not parse empty commands + if not user_input.strip(): + return + + command_parts = shlex.split(user_input) + command = command_parts[0] + args = command_parts[1:] + + if command not in self._commands.keys(): + raise Exception('Invalid command: {}'.format(command)) + + return await self._commands[command].execute(args, self._context) diff --git a/tools/tcat_ble_client/cli/command.py b/tools/tcat_ble_client/cli/command.py new file mode 100644 index 0000000000..f494a3e7d6 --- /dev/null +++ b/tools/tcat_ble_client/cli/command.py @@ -0,0 +1,101 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from tlv.tlv import TLV +from tlv.tcat_tlv import TcatTLVType + +from abc import ABC, abstractmethod + + +class CommandResult(ABC): + + def __init__(self, value=None): + self.value = value + + @abstractmethod + def pretty_print(self): + pass + + +class Command(ABC): + + def __init__(self): + self._subcommands = {} + + async def execute(self, args, context) -> CommandResult: + if len(args) > 0 and args[0] in self._subcommands.keys(): + return await self.execute_subcommand(args, context) + + return await self.execute_default(args, context) + + async def execute_subcommand(self, args, context) -> CommandResult: + return await self._subcommands[args[0]].execute(args[1:], context) + + @abstractmethod + async def execute_default(self, args, context) -> CommandResult: + pass + + @abstractmethod + def get_help_string(self) -> str: + pass + + def print_help(self, indent=0): + indent_width = 4 + indentation = ' ' * indent_width * indent + print(f'{indentation}{self.get_help_string()}') + + if 'help' in self._subcommands.keys(): + print(f'{indentation}"help" command available.') + elif len(self._subcommands) != 0: + print(f'{indentation}Subcommands:') + for name, sc in self._subcommands.items(): + print(f'{indentation}{" " * indent_width}{name}\t- ', end='') + sc.print_help() + + +class CommandResultTLV(CommandResult): + + def pretty_print(self): + tlv: TLV = self.value + tlv_type = TcatTLVType.from_value(tlv.type) + print('Result: TLV:') + if tlv_type is not None: + print(f'\tTYPE:\t{TcatTLVType.from_value(tlv.type).name}') + else: + print(f'\tTYPE:\tunknown: {hex(tlv.type)} ({tlv.type})') + print(f'\tLEN:\t{len(tlv.value)}') + if tlv_type == TcatTLVType.APPLICATION: + print(f'\tVALUE:\t{tlv.value.decode("ascii")}') + else: + print(f'\tVALUE:\t0x{tlv.value.hex()}') + + +class CommandResultNone(CommandResult): + + def pretty_print(self): + pass diff --git a/tools/tcat_ble_client/cli/dataset_commands.py b/tools/tcat_ble_client/cli/dataset_commands.py new file mode 100644 index 0000000000..aa54c82d74 --- /dev/null +++ b/tools/tcat_ble_client/cli/dataset_commands.py @@ -0,0 +1,221 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from cli.command import Command, CommandResultNone +from dataset.dataset import ThreadDataset, initial_dataset +from tlv.dataset_tlv import MeshcopTlvType + + +def handle_dataset_entry_command(type: MeshcopTlvType, args, context): + ds: ThreadDataset = context['dataset'] + if len(args) == 0: + ds.get_entry(type).print_content() + return CommandResultNone() + + ds.set_entry(type, args) + print('Done.') + return CommandResultNone() + + +class DatasetHelpCommand(Command): + + def get_help_string(self) -> str: + return 'Display help message and return.' + + async def execute_default(self, args, context): + indent_width = 4 + indentation = ' ' * indent_width + commands: ThreadDataset = context['commands'] + ds_command: Command = commands['dataset'] + print(ds_command.get_help_string()) + print('Subcommands:') + for name, subcommand in ds_command._subcommands.items(): + print(f'{indentation}{name}') + print(f'{indentation}{" " * indent_width}{subcommand.get_help_string()}') + return CommandResultNone() + + +class PrintDatasetHexCommand(Command): + + def get_help_string(self) -> str: + return 'Print current dataset as a hexadecimal string.' + + async def execute_default(self, args, context): + ds: ThreadDataset = context['dataset'] + print(ds.to_bytes().hex()) + return CommandResultNone() + + +class ReloadDatasetCommand(Command): + + def get_help_string(self) -> str: + return 'Reset dataset to the initial value.' + + async def execute_default(self, args, context): + context['dataset'].set_from_bytes(initial_dataset) + return CommandResultNone() + + +class ActiveTimestampCommand(Command): + + def get_help_string(self) -> str: + return 'View and set ActiveTimestamp seconds. Arguments: [seconds (int)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.ACTIVETIMESTAMP, args, context) + + +class PendingTimestampCommand(Command): + + def get_help_string(self) -> str: + return 'View and set PendingTimestamp seconds. Arguments: [seconds (int)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.PENDINGTIMESTAMP, args, context) + + +class NetworkKeyCommand(Command): + + def get_help_string(self) -> str: + return 'View and set NetworkKey. Arguments: [nk (hexstring, len=32)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.NETWORKKEY, args, context) + + +class NetworkNameCommand(Command): + + def get_help_string(self) -> str: + return 'View and set NetworkName. Arguments: [nn (string, maxlen=16)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.NETWORKNAME, args, context) + + +class ExtPanIDCommand(Command): + + def get_help_string(self) -> str: + return 'View and set ExtPanID. Arguments: [extpanid (hexstring, len=16)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.EXTPANID, args, context) + + +class MeshLocalPrefixCommand(Command): + + def get_help_string(self) -> str: + return 'View and set MeshLocalPrefix. Arguments: [mlp (hexstring, len=16)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.MESHLOCALPREFIX, args, context) + + +class DelayTimerCommand(Command): + + def get_help_string(self) -> str: + return 'View and set DelayTimer delay. Arguments: [delay (int)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.DELAYTIMER, args, context) + + +class PanIDCommand(Command): + + def get_help_string(self) -> str: + return 'View and set PanID. Arguments: [panid (hexstring, len=4)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.PANID, args, context) + + +class ChannelCommand(Command): + + def get_help_string(self) -> str: + return 'View and set Channel. Arguments: [channel (int)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.CHANNEL, args, context) + + +class ChannelMaskCommand(Command): + + def get_help_string(self) -> str: + return 'View and set ChannelMask. Arguments: [mask (hexstring)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.CHANNELMASK, args, context) + + +class PskcCommand(Command): + + def get_help_string(self) -> str: + return 'View and set Pskc. Arguments: [pskc (hexstring, maxlen=32)]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.PSKC, args, context) + + +class SecurityPolicyCommand(Command): + + def get_help_string(self) -> str: + return 'View and set SecurityPolicy. Arguments: '\ + '[ [flags (string)] [version_threshold (int)]]' + + async def execute_default(self, args, context): + return handle_dataset_entry_command(MeshcopTlvType.SECURITYPOLICY, args, context) + + +class DatasetCommand(Command): + + def __init__(self): + self._subcommands = { + 'help': DatasetHelpCommand(), + 'hex': PrintDatasetHexCommand(), + 'reload': ReloadDatasetCommand(), + 'activetimestamp': ActiveTimestampCommand(), + 'pendingtimestamp': PendingTimestampCommand(), + 'networkkey': NetworkKeyCommand(), + 'networkname': NetworkNameCommand(), + 'extpanid': ExtPanIDCommand(), + 'meshlocalprefix': MeshLocalPrefixCommand(), + 'delay': DelayTimerCommand(), + 'panid': PanIDCommand(), + 'channel': ChannelCommand(), + 'channelmask': ChannelMaskCommand(), + 'pskc': PskcCommand(), + 'securitypolicy': SecurityPolicyCommand() + } + + def get_help_string(self) -> str: + return 'View and manipulate current dataset. ' \ + 'Call without parameters to show current dataset.' + + async def execute_default(self, args, context): + ds: ThreadDataset = context['dataset'] + ds.print_content() + return CommandResultNone() diff --git a/tools/tcat_ble_client/dataset/dataset.py b/tools/tcat_ble_client/dataset/dataset.py new file mode 100644 index 0000000000..2ec4cdda8c --- /dev/null +++ b/tools/tcat_ble_client/dataset/dataset.py @@ -0,0 +1,64 @@ +""" + Copyright (c) 2023 Nordic Semiconductor ASA + + 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. +""" + +from typing import Dict, List + +from tlv.tlv import TLV +from tlv.dataset_tlv import MeshcopTlvType +from dataset.dataset_entries import DatasetEntry, create_dataset_entry + +initial_dataset = bytes([ + 0x0E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x12, 0x35, 0x06, 0x00, 0x04, + 0x00, 0x1F, 0xFF, 0xE0, 0x02, 0x08, 0xEF, 0x13, 0x98, 0xC2, 0xFD, 0x50, 0x4B, 0x67, 0x07, 0x08, 0xFD, 0x35, 0x34, + 0x41, 0x33, 0xD1, 0xD7, 0x3E, 0x05, 0x10, 0xFD, 0xA7, 0xC7, 0x71, 0xA2, 0x72, 0x02, 0xE2, 0x32, 0xEC, 0xD0, 0x4C, + 0xF9, 0x34, 0xF4, 0x76, 0x03, 0x0F, 0x4F, 0x70, 0x65, 0x6E, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x2D, 0x63, 0x36, + 0x34, 0x65, 0x01, 0x02, 0xC6, 0x4E, 0x04, 0x10, 0x5E, 0x9B, 0x9B, 0x36, 0x0F, 0x80, 0xB8, 0x8B, 0xE2, 0x60, 0x3F, + 0xB0, 0x13, 0x5C, 0x8D, 0x65, 0x0C, 0x04, 0x02, 0xA0, 0xF7, 0xF8 +]) + + +class ThreadDataset: + + def __init__(self): + self.entries: Dict[MeshcopTlvType, DatasetEntry] = {} + self.set_from_bytes(initial_dataset) + + def print_content(self): + for type, entry in self.entries.items(): + print(f'{type.name}:') + entry.print_content(indent=1) + print() + + def set_from_bytes(self, bytes): + for tlv in TLV.parse_tlvs(bytes): + type = MeshcopTlvType.from_value(tlv.type) + self.entries[type] = create_dataset_entry(type) + self.entries[type].set_from_tlv(tlv) + + def to_bytes(self): + res = bytes() + for entry in self.entries.values(): + res += entry.to_tlv().to_bytes() + return res + + def get_entry(self, type: MeshcopTlvType): + return self.entries[type] + + def set_entry(self, type: MeshcopTlvType, args: List[str]): + if type in self.entries: + self.entries[type].set(args) + return + raise KeyError(f'Key {type} not available in the dataset.') diff --git a/tools/tcat_ble_client/dataset/dataset_entries.py b/tools/tcat_ble_client/dataset/dataset_entries.py new file mode 100644 index 0000000000..20d470e36d --- /dev/null +++ b/tools/tcat_ble_client/dataset/dataset_entries.py @@ -0,0 +1,502 @@ +""" + Copyright (c) 2023 Nordic Semiconductor ASA + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import struct +import inspect +from typing import List +from abc import ABC, abstractmethod + +from tlv.dataset_tlv import MeshcopTlvType +from tlv.tlv import TLV + + +class DatasetEntry(ABC): + + def __init__(self, type: MeshcopTlvType): + self.type = type + self.length = None + self.maxlen = None + + def print_content(self, indent: int = 0, excluded_fields: List[str] = []): + excluded_fields += ['length', 'maxlen', 'type'] + indentation = " " * 4 * indent + for attr_name in dir(self): + if not attr_name.startswith('_') and attr_name not in excluded_fields: + value = getattr(self, attr_name) + if not inspect.ismethod(value): + if isinstance(value, bytes): + value = value.hex() + print(f'{indentation}{attr_name}: {value}') + + @abstractmethod + def to_tlv(self) -> TLV: + pass + + @abstractmethod + def set_from_tlv(self, tlv: TLV): + pass + + @abstractmethod + def set(self, args: List[str]): + pass + + +class ActiveTimestamp(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.ACTIVETIMESTAMP) + self.length = 8 # spec defined + self.seconds = 0 + self.ubit = 0 + self.ticks = 0 + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for ActiveTimestamp') + self._seconds = int(args[0]) + + def set_from_tlv(self, tlv: TLV): + (value,) = struct.unpack('>Q', tlv.value) + self.ubit = value & 0x1 + self.ticks = (value >> 1) & 0x7FFF + self.seconds = (value >> 16) & 0xFFFF + + def to_tlv(self): + value = (self.seconds << 16) | (self.ticks << 1) | self.ubit + tlv = struct.pack('>BBQ', self.type.value, self.length, value) + return TLV.from_bytes(tlv) + + +class PendingTimestamp(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.PENDINGTIMESTAMP) + self.length = 8 # spec defined + self.seconds = 0 + self.ubit = 0 + self.ticks = 0 + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for PendingTimestamp') + self._seconds = int(args[0]) + + def set_from_tlv(self, tlv: TLV): + (value,) = struct.unpack('>Q', tlv.value) + self.ubit = value & 0x1 + self.ticks = (value >> 1) & 0x7FFF + self.seconds = (value >> 16) & 0xFFFF + + def to_tlv(self): + value = (self.seconds << 16) | (self.ticks << 1) | self.ubit + tlv = struct.pack('>BBQ', self.type.value, self.length, value) + return TLV.from_bytes(tlv) + + +class NetworkKey(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.NETWORKKEY) + self.length = 16 # spec defined + self.data: str = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for NetworkKey') + if args[0].startswith('0x'): + args[0] = args[0][2:] + nk = args[0] + if len(nk) != self.length * 2: # need length * 2 hex characters + raise ValueError('Invalid length of NetworkKey') + self.data = nk + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.hex() + + def to_tlv(self): + if len(self.data) != self.length * 2: # need length * 2 hex characters + raise ValueError('Invalid length of NetworkKey') + value = bytes.fromhex(self.data) + tlv = struct.pack('>BB', self.type.value, self.length) + value + return TLV.from_bytes(tlv) + + +class NetworkName(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.NETWORKNAME) + self.maxlen = 16 + self.data: str = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for NetworkName') + nn = args[0] + if len(nn) > self.maxlen: + raise ValueError('Invalid length of NetworkName') + self.data = nn + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.decode('utf-8') + + def to_tlv(self): + length_value = len(self.data) + value = self.data.encode('utf-8') + tlv = struct.pack('>BB', self.type.value, length_value) + value + return TLV.from_bytes(tlv) + + +class ExtPanID(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.EXTPANID) + self.length = 8 # spec defined + self.data: str = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for ExtPanID') + if args[0].startswith('0x'): + args[0] = args[0][2:] + epid = args[0] + if len(epid) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of ExtPanID') + self.data = epid + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.hex() + + def to_tlv(self): + if len(self.data) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of ExtPanID') + + value = bytes.fromhex(self.data) + tlv = struct.pack('>BB', self.type.value, self.length) + value + return TLV.from_bytes(tlv) + + +class MeshLocalPrefix(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.MESHLOCALPREFIX) + self.length = 8 # spec defined + self.data = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for MeshLocalPrefix') + if args[0].startswith('0x'): + args[0] = args[0][2:] + mlp = args[0] + if len(mlp) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of MeshLocalPrefix') + self.data = mlp + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.hex() + + def to_tlv(self): + if len(self.data) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of MeshLocalPrefix') + + value = bytes.fromhex(self.data) + tlv = struct.pack('>BB', self.type.value, self.length) + value + return TLV.from_bytes(tlv) + + +class DelayTimer(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.DELAYTIMER) + self.length = 4 # spec defined + self.time_remaining = 0 + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for DelayTimer') + dt = int(args[0]) + self.time_remaining = dt + + def set_from_tlv(self, tlv: TLV): + self.time_remaining = tlv.value + + def to_tlv(self): + value = self.time_remaining + tlv = struct.pack('>BBI', self.type.value, self.length, value) + return TLV.from_bytes(tlv) + + +class PanID(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.PANID) + self.length = 2 # spec defined + self.data: str = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for PanID') + if args[0].startswith('0x'): + args[0] = args[0][2:] + pid = args[0] + if len(pid) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of PanID') + self.data = pid + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.hex() + + def to_tlv(self): + if len(self.data) != self.length * 2: # need length*2 hex characters + raise ValueError('Invalid length of PanID') + + value = bytes.fromhex(self.data) + tlv = struct.pack('>BB', self.type.value, self.length) + value + return TLV.from_bytes(tlv) + + +class Channel(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.CHANNEL) + self.length = 3 # spec defined + self.channel_page = 0 + self.channel = 0 + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for Channel') + channel = int(args[0]) + self.channel = channel + + def set_from_tlv(self, tlv: TLV): + self.channel = int.from_bytes(tlv.value[1:3], byteorder='big') + self.channel_page = tlv.value[0] + + def to_tlv(self): + tlv = struct.pack('>BBB', self.type.value, self.length, self.channel_page) + tlv += struct.pack('>H', self.channel) + return TLV.from_bytes(tlv) + + +class Pskc(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.PSKC) + self.maxlen = 16 + self.data = '' + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for Pskc') + if args[0].startswith('0x'): + args[0] = args[0][2:] + pskc = args[0] + if (len(pskc) > self.maxlen * 2): + raise ValueError('Invalid length of Pskc. Can be max ' f'{self.length * 2} hex characters.') + self.data = pskc + + def set_from_tlv(self, tlv: TLV): + self.data = tlv.value.hex() + + def to_tlv(self): + # should not exceed max length*2 hex characters + if (len(self.data) > self.maxlen * 2): + raise ValueError('Invalid length of Pskc') + + length_value = len(self.data) // 2 + value = bytes.fromhex(self.data) + tlv = struct.pack('>BB', self.type.value, length_value) + value + return TLV.from_bytes(tlv) + + +class SecurityPolicy(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.SECURITYPOLICY) + self.length = 4 # spec defined + self.rotation_time = 0 + self.out_of_band = 0 # o + self.native = 0 # n + self.routers_1_2 = 0 # r + self.external_commissioners = 0 # c + self.reserved = 0 + self.commercial_commissioning_off = 0 # C + self.autonomous_enrollment_off = 0 # e + self.networkkey_provisioning_off = 0 # p + self.thread_over_ble = 0 + self.non_ccm_routers_off = 0 # R + self.rsv = 0b111 + self.version_threshold = 0 + + def set(self, args: List[str]): + if len(args) == 0: + raise ValueError('No argument for SecurityPolicy') + rotation_time, flags, version_threshold = args + [None] * (3 - len(args)) + self.rotation_time = int(rotation_time) & 0xffff + + if flags: + self.out_of_band = 1 if 'o' in flags else 0 + self.native = 1 if 'n' in flags else 0 + self.routers_1_2 = 1 if 'r' in flags else 0 + self.external_commissioners = 1 if 'c' in flags else 0 + self.commercial_commissioning_off = 0 if 'C' in flags else 1 + self.autonomous_enrollment_off = 0 if 'e' in flags else 1 + self.networkkey_provisioning_off = 0 if 'p' in flags else 1 + self.non_ccm_routers_off = 0 if 'R' in flags else 1 + + if version_threshold: + self.version_threshold = int(version_threshold) & 0b111 + + def set_from_tlv(self, tlv: TLV): + value = int.from_bytes(tlv.value, byteorder='big') + + self.rotation_time = (value >> 16) & 0xFFFF + self.out_of_band = (value >> 15) & 0x1 + self.native = (value >> 14) & 0x1 + self.routers_1_2 = (value >> 13) & 0x1 + self.external_commissioners = (value >> 12) & 0x1 + self.reserved = (value >> 11) & 0x1 + self.commercial_commissioning_off = (value >> 10) & 0x1 + self.autonomous_enrollment_off = (value >> 9) & 0x1 + self.networkkey_provisioning_off = (value >> 8) & 0x1 + self.thread_over_ble = (value >> 7) & 0x1 + self.non_ccm_routers_off = (value >> 6) & 0x1 + self.rsv = (value >> 3) & 0x7 + self.version_threshold = value & 0x7 + + def to_tlv(self): + value = self.rotation_time << 16 + value |= self.out_of_band << 15 + value |= self.native << 14 + value |= self.routers_1_2 << 13 + value |= self.external_commissioners << 12 + value |= self.reserved << 11 + value |= self.commercial_commissioning_off << 10 + value |= self.autonomous_enrollment_off << 9 + value |= self.networkkey_provisioning_off << 8 + value |= self.thread_over_ble << 7 + value |= self.non_ccm_routers_off << 6 + value |= self.rsv << 3 + value |= self.version_threshold + tlv = struct.pack('>BBI', self.type.value, self.length, value) + return TLV.from_bytes(tlv) + + def print_content(self, indent: int = 0): + flags = '' + if self.out_of_band: + flags += 'o' + if self.native: + flags += 'n' + if self.routers_1_2: + flags += 'r' + if self.external_commissioners: + flags += 'c' + if not self.commercial_commissioning_off: + flags += 'C' + if not self.autonomous_enrollment_off: + flags += 'e' + if not self.networkkey_provisioning_off: + flags += 'p' + if not self.non_ccm_routers_off: + flags += 'R' + indentation = " " * 4 * indent + print(f'{indentation}rotation_time: {self.rotation_time}') + print(f'{indentation}flags: {flags}') + print(f'{indentation}version_threshold: {self.version_threshold}') + + +class ChannelMask(DatasetEntry): + + def __init__(self): + super().__init__(MeshcopTlvType.CHANNELMASK) + self.entries: List[ChannelMaskEntry] = [] + + def set(self, args: List[str]): + # to remain consistent with the OpenThread CLI API, + # provided hex string is value of the first channel mask entry + if len(args) == 0: + raise ValueError('No argument for ChannelMask') + if args[0].startswith('0x'): + args[0] = args[0][2:] + channelmsk = bytes.fromhex(args[0]) + self.entries = [ChannelMaskEntry()] + self.entries[0].channel_mask = channelmsk + + def print_content(self, indent: int = 0): + super().print_content(indent=indent, excluded_fields=['entries']) + indentation = " " * 4 * indent + for i, entry in enumerate(self.entries): + print(f'{indentation}ChannelMaskEntry {i}') + entry.print_content(indent=indent + 1) + + def set_from_tlv(self, tlv: TLV): + self.entries = [] + for mask_entry_tlv in TLV.parse_tlvs(tlv.value): + new_entry = ChannelMaskEntry() + new_entry.set_from_tlv(mask_entry_tlv) + self.entries.append(new_entry) + + def to_tlv(self): + tlv_value = b''.join(mask_entry.to_tlv().to_bytes() for mask_entry in self.entries) + tlv = struct.pack('>BB', self.type.value, len(tlv_value)) + tlv_value + return TLV.from_bytes(tlv) + + +class ChannelMaskEntry(DatasetEntry): + + def __init__(self): + self.channel_page = 0 + self.channel_mask: bytes = None + + def set(self, args: List[str]): + pass + + def set_from_tlv(self, tlv: TLV): + self.channel_page = tlv.type + self.mask_length = len(tlv.value) + self.channel_mask = tlv.value + + def to_tlv(self): + mask_len = len(self.channel_mask) + tlv = struct.pack('>BB', self.channel_page, mask_len) + self.channel_mask + return TLV.from_bytes(tlv) + + +def create_dataset_entry(type: MeshcopTlvType, args=None): + entry_classes = { + MeshcopTlvType.ACTIVETIMESTAMP: ActiveTimestamp, + MeshcopTlvType.PENDINGTIMESTAMP: PendingTimestamp, + MeshcopTlvType.NETWORKKEY: NetworkKey, + MeshcopTlvType.NETWORKNAME: NetworkName, + MeshcopTlvType.EXTPANID: ExtPanID, + MeshcopTlvType.MESHLOCALPREFIX: MeshLocalPrefix, + MeshcopTlvType.DELAYTIMER: DelayTimer, + MeshcopTlvType.PANID: PanID, + MeshcopTlvType.CHANNEL: Channel, + MeshcopTlvType.PSKC: Pskc, + MeshcopTlvType.SECURITYPOLICY: SecurityPolicy, + MeshcopTlvType.CHANNELMASK: ChannelMask + } + + entry_class = entry_classes.get(type) + if not entry_class: + raise ValueError(f"Invalid configuration type: {type}") + + res = entry_class() + if args: + res.set(args) + return res diff --git a/tools/tcat_ble_client/poetry.lock b/tools/tcat_ble_client/poetry.lock new file mode 100644 index 0000000000..72a06109ff --- /dev/null +++ b/tools/tcat_ble_client/poetry.lock @@ -0,0 +1,318 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] + +[package.dependencies] +typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} + +[[package]] +name = "bleak" +version = "0.20.2" +description = "Bluetooth Low Energy platform Agnostic Klient" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "bleak-0.20.2-py3-none-any.whl", hash = "sha256:ce3106b7258212d92bb77be06f9301774f51f5bbc9f7cd50976ad794e9514dba"}, + {file = "bleak-0.20.2.tar.gz", hash = "sha256:6c92a47abe34e6dea8ffc5cea9457cbff6e1be966854839dbc25cddb36b79ee4"}, +] + +[package.dependencies] +async-timeout = {version = ">=3.0.0,<5", markers = "python_version < \"3.11\""} +bleak-winrt = {version = ">=1.2.0,<2.0.0", markers = "platform_system == \"Windows\""} +dbus-fast = {version = ">=1.83.0,<2.0.0", markers = "platform_system == \"Linux\""} +pyobjc-core = {version = ">=9.0.1,<10.0.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-CoreBluetooth = {version = ">=9.0.1,<10.0.0", markers = "platform_system == \"Darwin\""} +pyobjc-framework-libdispatch = {version = ">=9.0.1,<10.0.0", markers = "platform_system == \"Darwin\""} +typing-extensions = {version = ">=4.2.0,<5.0.0", markers = "python_version < \"3.8\""} + +[[package]] +name = "bleak-winrt" +version = "1.2.0" +description = "Python WinRT bindings for Bleak" +optional = false +python-versions = "*" +files = [ + {file = "bleak-winrt-1.2.0.tar.gz", hash = "sha256:0577d070251b9354fc6c45ffac57e39341ebb08ead014b1bdbd43e211d2ce1d6"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win32.whl", hash = "sha256:a2ae3054d6843ae0cfd3b94c83293a1dfd5804393977dd69bde91cb5099fc47c"}, + {file = "bleak_winrt-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:677df51dc825c6657b3ae94f00bd09b8ab88422b40d6a7bdbf7972a63bc44e9a"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9449cdb942f22c9892bc1ada99e2ccce9bea8a8af1493e81fefb6de2cb3a7b80"}, + {file = "bleak_winrt-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:98c1b5a6a6c431ac7f76aa4285b752fe14a1c626bd8a1dfa56f66173ff120bee"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:623ac511696e1f58d83cb9c431e32f613395f2199b3db7f125a3d872cab968a4"}, + {file = "bleak_winrt-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:13ab06dec55469cf51a2c187be7b630a7a2922e1ea9ac1998135974a7239b1e3"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win32.whl", hash = "sha256:5a36ff8cd53068c01a795a75d2c13054ddc5f99ce6de62c1a97cd343fc4d0727"}, + {file = "bleak_winrt-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:810c00726653a962256b7acd8edf81ab9e4a3c66e936a342ce4aec7dbd3a7263"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win32.whl", hash = "sha256:dd740047a08925bde54bec357391fcee595d7b8ca0c74c87170a5cbc3f97aa0a"}, + {file = "bleak_winrt-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:63130c11acfe75c504a79c01f9919e87f009f5e742bfc7b7a5c2a9c72bf591a7"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dbus-fast" +version = "1.90.1" +description = "A faster version of dbus-next" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:657f9f292f770b50c755bc9cc3607ec0901a607d6d6e31c67aa953b73b31d66a"}, + {file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:229cb2dc0942dfe36ce4f5a49cacb7f39ae05527c6ccec66b9a670ca7a02129a"}, + {file = "dbus_fast-1.90.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:4978d6dca49b778c426f279f014554e29ece6bfc7530fa8ab9d258f068e5954e"}, + {file = "dbus_fast-1.90.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2161851a1f90a1c2fe064d1870b04bdca0033b42fdc97cc7d5132637227ac915"}, + {file = "dbus_fast-1.90.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0012799b154fb6b066ff6948f5edd0c6bf8655fca6f3578fc78598334f9f978b"}, + {file = "dbus_fast-1.90.1-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:0b97748928e3e56bc98f292be894d1d3c2a4acc58555795a3aa3b74769b96542"}, + {file = "dbus_fast-1.90.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2baa2e1053ded0a5ccdefc651ee8fcd09d6f4f864b9f301363dbf0545f95a89"}, + {file = "dbus_fast-1.90.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0262ab1d3d07ac892645d4cec54daabd3ba4a096ca4c4b2e9f09abd1819ca663"}, + {file = "dbus_fast-1.90.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c39a352a893923d255031d15fa005ac5f5df2d1195729f206fc79a95b219daed"}, + {file = "dbus_fast-1.90.1-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bd012a0ed7e6479bcc5b0efe91a45c3abb3e0e4e371a28c0f3c347cb9baffe8a"}, + {file = "dbus_fast-1.90.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3e895adfa89a6c08d23fd22707bd5ea8a301579f3a6ff8bd33df1e94ea16e8a"}, + {file = "dbus_fast-1.90.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a94806e9990b6a7fd4896ee2a979c20af4e5ba76bfddda55a7a79f4da268b51f"}, + {file = "dbus_fast-1.90.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae0b95a08db0a7e38452926c8d5964d41e5f20d8c89fd00b8913ec4f1908f7bd"}, + {file = "dbus_fast-1.90.1-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:3ce5153accbbb7fc2aeab055f46d5611c4c57978d43feba9257fba53c338ebbe"}, + {file = "dbus_fast-1.90.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3b05b68a7be76df3e4833c72d9fadf1b934359ed3fabd69ed205eaa18d132a6"}, + {file = "dbus_fast-1.90.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d407eb9a3581ee5cc047a664d3d15e9846e5a1c0b3565922c72ffe15fea590f2"}, + {file = "dbus_fast-1.90.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f06e4cbf560e682930f0d23ea93b1887c40db00b98ee4d6a207aa2a616851e"}, + {file = "dbus_fast-1.90.1-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:28a4ee863b4a42351afb38ce9432850922dc2f0d9d9863f98fcb47e23b710572"}, + {file = "dbus_fast-1.90.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd6090c794ca3404702b59cb4dc92f674e26a15bb79a9d5ae0236658c10cac5"}, + {file = "dbus_fast-1.90.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9e7be16e96bcad521f2c045561799fc486047b6e1ce071c35a5cea36a9ed19f4"}, + {file = "dbus_fast-1.90.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:01f582d9c3f24e1721f3dd9a62c7a558c7c8406752eb042738623b9d89f454e9"}, + {file = "dbus_fast-1.90.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:085fd80c7ea3e41a2ac32e419611036a042593778fecb4d92526a22fd2be2c0b"}, + {file = "dbus_fast-1.90.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e0dbffd42875d31d0c7e2407eff685d5cb2dfa7c0448079c96ef2cec0afe8be"}, + {file = "dbus_fast-1.90.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:04eaaea336059909b5cb51c897fc343e038e80f698a049b1bf3002d162d4fec7"}, + {file = "dbus_fast-1.90.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc215dbccb798df07ee6104b984ae09c159ed3a633df915c3c6dd9df97af753"}, + {file = "dbus_fast-1.90.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:74f7afaf780fbbc7f39cc8167ec585f8e7ce140d214768f5c296c2b03d23e571"}, + {file = "dbus_fast-1.90.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f12c7bcec416e28ba1f741e43ad2eef7eb3c677838208cf6a801ced711b508c"}, + {file = "dbus_fast-1.90.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c0811b7bdfdce40072fd7c29f0c7e0145982b981bb068efd79a5e43ef14150e5"}, + {file = "dbus_fast-1.90.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f00197e08c7c5837861624fd1afb8e1d8331d4e28e8d2ff01dc17ac2305ae2"}, + {file = "dbus_fast-1.90.1.tar.gz", hash = "sha256:eff98b45443681bd8876bbb1444b35112d62e8d12157f004d88ebe5f0481d5b7"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, + {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "importlib-metadata" +version = "6.7.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, +] + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pluggy" +version = "1.2.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pyobjc-core" +version = "9.2" +description = "Python<->ObjC Interoperability Module" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyobjc-core-9.2.tar.gz", hash = "sha256:d734b9291fec91ff4e3ae38b9c6839debf02b79c07314476e87da8e90b2c68c3"}, + {file = "pyobjc_core-9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fa674a39949f5cde8e5c7bbcd24496446bfc67592b028aedbec7f81dc5fc4daa"}, + {file = "pyobjc_core-9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc8de304ee322a1ee530b4d2daca135a49b4a49aa3cedc6b2c26c43885f4842"}, + {file = "pyobjc_core-9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0fa950f092673883b8bd28bc18397415cabb457bf410920762109b411789ade9"}, + {file = "pyobjc_core-9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:586e4cae966282eaa61b21cae66ccdcee9d69c036979def26eebdc08ddebe20f"}, + {file = "pyobjc_core-9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:41189c2c680931c0395a55691763c481fc681f454f21bb4f1644f98c24a45954"}, + {file = "pyobjc_core-9.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2d23ee539f2ba5e9f5653d75a13f575c7e36586fc0086792739e69e4c2617eda"}, + {file = "pyobjc_core-9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b9809cf96678797acb72a758f34932fe8e2602d5ab7abec15c5ac68ddb481720"}, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "9.2" +description = "Wrappers for the Cocoa frameworks on macOS" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyobjc-framework-Cocoa-9.2.tar.gz", hash = "sha256:efd78080872d8c8de6c2b97e0e4eac99d6203a5d1637aa135d071d464eb2db53"}, + {file = "pyobjc_framework_Cocoa-9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9e02d8a7cc4eb7685377c50ba4f17345701acf4c05b1e7480d421bff9e2f62a4"}, + {file = "pyobjc_framework_Cocoa-9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3b1e6287b3149e4c6679cdbccd8e9ef6557a4e492a892e80a77df143f40026d2"}, + {file = "pyobjc_framework_Cocoa-9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:312977ce2e3989073c6b324c69ba24283de206fe7acd6dbbbaf3e29238a22537"}, + {file = "pyobjc_framework_Cocoa-9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:aae7841cf40c26dd915f4dd828f91c6616e6b7998630b72e704750c09e00f334"}, + {file = "pyobjc_framework_Cocoa-9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:739a421e14382a46cbeb9a883f192dceff368ad28ec34d895c48c0ad34cf2c1d"}, + {file = "pyobjc_framework_Cocoa-9.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:32d9ac1033fac1b821ddee8c68f972a7074ad8c50bec0bea9a719034c1c2fb94"}, + {file = "pyobjc_framework_Cocoa-9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b236bb965e41aeb2e215d4e98a5a230d4b63252c6d26e00924ea2e69540a59d6"}, +] + +[package.dependencies] +pyobjc-core = ">=9.2" + +[[package]] +name = "pyobjc-framework-corebluetooth" +version = "9.2" +description = "Wrappers for the framework CoreBluetooth on macOS" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyobjc-framework-CoreBluetooth-9.2.tar.gz", hash = "sha256:cb2481b1dfe211ae9ce55f36537dc8155dbf0dc8ff26e0bc2e13f7afb0a291d1"}, + {file = "pyobjc_framework_CoreBluetooth-9.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:53d888742119d0f0c725d0b0c2389f68e8f21f0cba6d6aec288c53260a0196b6"}, + {file = "pyobjc_framework_CoreBluetooth-9.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:179532882126526e38fe716a50fb0ee8f440e0b838d290252c515e622b5d0e49"}, + {file = "pyobjc_framework_CoreBluetooth-9.2-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:256a5031ea9d8a7406541fa1b0dfac549b1de93deae8284605f9355b13fb58be"}, +] + +[package.dependencies] +pyobjc-core = ">=9.2" +pyobjc-framework-Cocoa = ">=9.2" + +[[package]] +name = "pyobjc-framework-libdispatch" +version = "9.2" +description = "Wrappers for libdispatch on macOS" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyobjc-framework-libdispatch-9.2.tar.gz", hash = "sha256:542e7f7c2b041939db5ed6f3119c1d67d73ec14a996278b92485f8513039c168"}, + {file = "pyobjc_framework_libdispatch-9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88d4091d4bcb5702783d6e86b4107db973425a17d1de491543f56bd348909b60"}, + {file = "pyobjc_framework_libdispatch-9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1a67b007113328538b57893cc7829a722270764cdbeae6d5e1460a1d911314df"}, + {file = "pyobjc_framework_libdispatch-9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6fccea1a57436cf1ac50d9ebc6e3e725bcf77f829ba6b118e62e6ed7866d359d"}, + {file = "pyobjc_framework_libdispatch-9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6eba747b7ad91b0463265a7aee59235bb051fb97687f35ca2233690369b5e4e4"}, + {file = "pyobjc_framework_libdispatch-9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2e835495860d04f63c2d2f73ae3dd79da4222864c107096dc0f99e8382700026"}, + {file = "pyobjc_framework_libdispatch-9.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1b107e5c3580b09553030961ea6b17abad4a5132101eab1af3ad2cb36d0f08bb"}, + {file = "pyobjc_framework_libdispatch-9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:83cdb672acf722717b5ecf004768f215f02ac02d7f7f2a9703da6e921ab02222"}, +] + +[package.dependencies] +pyobjc-core = ">=9.2" + +[[package]] +name = "pytest" +version = "7.4.0" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.7" +content-hash = "488001f322904181b097ee8c0dd489ad81af39c4378d76f5945de9832077a315" diff --git a/tools/tcat_ble_client/pyproject.toml b/tools/tcat_ble_client/pyproject.toml new file mode 100644 index 0000000000..c28ac724db --- /dev/null +++ b/tools/tcat_ble_client/pyproject.toml @@ -0,0 +1,16 @@ +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "bbtc client" +version = "0.1.0" +description = "BBTC client for TCAT devices" +authors = ["Piotr Jasinski "] + +[tool.poetry.dependencies] +python = "^3.7" +bleak = "^0.20.2" +pytest ="^7.1.2" + +[tool.poetry.dev-dependencies] diff --git a/tools/tcat_ble_client/tlv/dataset_tlv.py b/tools/tcat_ble_client/tlv/dataset_tlv.py new file mode 100644 index 0000000000..4bd020c8db --- /dev/null +++ b/tools/tcat_ble_client/tlv/dataset_tlv.py @@ -0,0 +1,79 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" + +from enum import Enum + + +class MeshcopTlvType(Enum): + CHANNEL = 0 + PANID = 1 + EXTPANID = 2 + NETWORKNAME = 3 + PSKC = 4 + NETWORKKEY = 5 + NETWORK_KEY_SEQUENCE = 6 + MESHLOCALPREFIX = 7 + STEERING_DATA = 8 + BORDER_AGENT_RLOC = 9 + COMMISSIONER_ID = 10 + COMM_SESSION_ID = 11 + SECURITYPOLICY = 12 + GET = 13 + ACTIVETIMESTAMP = 14 + COMMISSIONER_UDP_PORT = 15 + STATE = 16 + JOINER_DTLS = 17 + JOINER_UDP_PORT = 18 + JOINER_IID = 19 + JOINER_RLOC = 20 + JOINER_ROUTER_KEK = 21 + PROVISIONING_URL = 32 + VENDOR_NAME_TLV = 33 + VENDOR_MODEL_TLV = 34 + VENDOR_SW_VERSION_TLV = 35 + VENDOR_DATA_TLV = 36 + VENDOR_STACK_VERSION_TLV = 37 + UDP_ENCAPSULATION_TLV = 48 + IPV6_ADDRESS_TLV = 49 + PENDINGTIMESTAMP = 51 + DELAYTIMER = 52 + CHANNELMASK = 53 + COUNT = 54 + PERIOD = 55 + SCAN_DURATION = 56 + ENERGY_LIST = 57 + DISCOVERYREQUEST = 128 + DISCOVERYRESPONSE = 129 + JOINERADVERTISEMENT = 241 + + @classmethod + def from_value(cls, value: int): + return cls._value2member_map_.get(value) + + def to_bytes(self): + return bytes([self.value]) diff --git a/tools/tcat_ble_client/tlv/tcat_tlv.py b/tools/tcat_ble_client/tlv/tcat_tlv.py new file mode 100644 index 0000000000..cb5b49e0c7 --- /dev/null +++ b/tools/tcat_ble_client/tlv/tcat_tlv.py @@ -0,0 +1,45 @@ +""" + Copyright (c) 2024, The OpenThread Authors. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +""" +from enum import Enum + + +class TcatTLVType(Enum): + RESPONSE_W_STATUS = 0x01 + RESPONSE_W_PAYLOAD = 0x02 + ACTIVE_DATASET = 0x20 + DECOMMISSION = 0x60 + APPLICATION = 0x82 + THREAD_START = 0x27 + THREAD_STOP = 0x28 + + @classmethod + def from_value(cls, value: int): + return cls._value2member_map_.get(value) + + def to_bytes(self): + return bytes([self.value]) From 05539103bef65c519d7144e2ee754284abda78af Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 22 Feb 2024 11:30:23 -0800 Subject: [PATCH 7/9] [cli-tcat] define `VendorInfo` as a member variable (#9869) Changes `mVendorInfo` to be a member variable of `Tcat` class instead of a static variable. --- src/cli/cli_tcat.cpp | 12 ++++++------ src/cli/cli_tcat.hpp | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/cli/cli_tcat.cpp b/src/cli/cli_tcat.cpp index e754bca93a..545c255f4b 100644 --- a/src/cli/cli_tcat.cpp +++ b/src/cli/cli_tcat.cpp @@ -79,9 +79,8 @@ namespace ot { namespace Cli { -otTcatVendorInfo sVendorInfo; -const char kPskdVendor[] = "J01NM3"; -const char kUrl[] = "dummy_url"; +const char kPskdVendor[] = "J01NM3"; +const char kUrl[] = "dummy_url"; static void HandleBleSecureReceive(otInstance *aInstance, const otMessage *aMessage, @@ -114,8 +113,9 @@ template <> otError Tcat::Process(Arg aArgs[]) otError error = OT_ERROR_NONE; - sVendorInfo.mPskdString = kPskdVendor; - sVendorInfo.mProvisioningUrl = kUrl; + ClearAllBytes(mVendorInfo); + mVendorInfo.mPskdString = kPskdVendor; + mVendorInfo.mProvisioningUrl = kUrl; otBleSecureSetCertificate(GetInstancePtr(), reinterpret_cast(OT_CLI_TCAT_X509_CERT), sizeof(OT_CLI_TCAT_X509_CERT), reinterpret_cast(OT_CLI_TCAT_PRIV_KEY), @@ -128,7 +128,7 @@ template <> otError Tcat::Process(Arg aArgs[]) otBleSecureSetSslAuthMode(GetInstancePtr(), true); SuccessOrExit(error = otBleSecureStart(GetInstancePtr(), nullptr, HandleBleSecureReceive, true, nullptr)); - SuccessOrExit(error = otBleSecureTcatStart(GetInstancePtr(), &sVendorInfo, nullptr)); + SuccessOrExit(error = otBleSecureTcatStart(GetInstancePtr(), &mVendorInfo, nullptr)); exit: return error; diff --git a/src/cli/cli_tcat.hpp b/src/cli/cli_tcat.hpp index 3f1d0be6e6..91b36cc4b6 100644 --- a/src/cli/cli_tcat.hpp +++ b/src/cli/cli_tcat.hpp @@ -31,6 +31,8 @@ #include "openthread-core-config.h" +#include + #include "cli/cli_output.hpp" #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE @@ -78,6 +80,8 @@ class Tcat : private Output using Command = CommandEntry; template otError Process(Arg aArgs[]); + + otTcatVendorInfo mVendorInfo; }; } // namespace Cli From 47894d419b32be4174b0c7ef1dbad31400c83c51 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 1 Feb 2024 11:58:47 -0800 Subject: [PATCH 8/9] [common] add `ClearAllBytes()` template function (#9818) This commit introduces the `ClearAllBytes()` template function to zero out all bytes within an object. This replaces `memset(0)` calls in OT core modules, simplifying code and improving safety by automatically using the correct object size. --- src/cli/cli.cpp | 10 +- src/cli/cli_coap.cpp | 26 +-- src/cli/cli_coap_secure.cpp | 10 +- src/cli/cli_commissioner.cpp | 4 +- src/cli/cli_dataset.cpp | 10 +- src/cli/cli_dns.cpp | 2 +- src/cli/cli_joiner.cpp | 2 +- src/cli/cli_link_metrics.cpp | 6 +- src/cli/cli_output.hpp | 16 ++ src/cli/cli_ping.cpp | 256 +++++++++++++++++++++++++ src/cli/cli_tcp.cpp | 4 +- src/cli/cli_udp.cpp | 4 +- src/core/common/clearable.hpp | 19 +- src/core/common/message.cpp | 2 +- src/core/common/settings.hpp | 4 +- src/core/diags/factory_diags.hpp | 5 +- src/core/mac/mac.cpp | 4 +- src/core/mac/mac.hpp | 3 +- src/core/mac/mac_frame.cpp | 4 +- src/core/meshcop/commissioner.cpp | 4 +- src/core/meshcop/dataset.cpp | 2 +- src/core/meshcop/dataset_local.cpp | 2 +- src/core/meshcop/joiner.cpp | 2 +- src/core/meshcop/meshcop.cpp | 5 +- src/core/meshcop/secure_transport.cpp | 17 +- src/core/net/dhcp6_client.cpp | 2 +- src/core/net/dhcp6_server.cpp | 2 +- src/core/net/dns_client.cpp | 4 +- src/core/net/ip6.hpp | 2 +- src/core/net/ip6_mpl.cpp | 2 +- src/core/net/tcp6.cpp | 14 +- src/core/radio/trel_link.cpp | 6 +- src/core/thread/child.cpp | 4 +- src/core/thread/discover_scanner.cpp | 2 +- src/core/thread/mesh_forwarder.hpp | 2 +- src/core/thread/mle.cpp | 4 +- src/core/thread/mle_tlvs.cpp | 3 +- src/core/thread/mle_types.hpp | 8 +- src/core/thread/network_diagnostic.cpp | 2 +- src/core/thread/radio_selector.cpp | 2 +- src/core/thread/router.cpp | 4 +- src/core/thread/router_table.hpp | 3 +- src/core/utils/channel_monitor.cpp | 4 +- src/core/utils/history_tracker.cpp | 2 +- src/core/utils/slaac_address.cpp | 2 +- 45 files changed, 391 insertions(+), 106 deletions(-) create mode 100644 src/cli/cli_ping.cpp diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index c02555276a..2a3b612792 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -158,7 +158,7 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi #if (OPENTHREAD_FTD || OPENTHREAD_MTD) && OPENTHREAD_CONFIG_CLI_REGISTER_IP6_RECV_CALLBACK otIp6SetReceiveCallback(GetInstancePtr(), &Interpreter::HandleIp6Receive, this); #endif - memset(&mUserCommands, 0, sizeof(mUserCommands)); + ClearAllBytes(mUserCommands); OutputPrompt(); } @@ -2675,7 +2675,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) otCacheEntryIterator iterator; otCacheEntryInfo entry; - memset(&iterator, 0, sizeof(iterator)); + ClearAllBytes(iterator); while (true) { @@ -4085,7 +4085,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) otError error = OT_ERROR_NONE; otLinkModeConfig linkMode; - memset(&linkMode, 0, sizeof(otLinkModeConfig)); + ClearAllBytes(linkMode); if (aArgs[0].IsEmpty()) { @@ -5876,7 +5876,7 @@ otError Interpreter::ParsePrefix(Arg aArgs[], otBorderRouterConfig &aConfig) { otError error = OT_ERROR_NONE; - memset(&aConfig, 0, sizeof(otBorderRouterConfig)); + ClearAllBytes(aConfig); SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); aArgs++; @@ -6303,7 +6303,7 @@ otError Interpreter::ParseRoute(Arg aArgs[], otExternalRouteConfig &aConfig) { otError error = OT_ERROR_NONE; - memset(&aConfig, 0, sizeof(otExternalRouteConfig)); + ClearAllBytes(aConfig); SuccessOrExit(error = aArgs[0].ParseAsIp6Prefix(aConfig.mPrefix)); aArgs++; diff --git a/src/cli/cli_coap.cpp b/src/cli/cli_coap.cpp index 7f71781510..f69800b8ef 100644 --- a/src/cli/cli_coap.cpp +++ b/src/cli/cli_coap.cpp @@ -58,15 +58,15 @@ Coap::Coap(otInstance *aInstance, OutputImplementer &aOutputImplementer) , mBlockCount(1) #endif { - memset(&mResource, 0, sizeof(mResource)); + ClearAllBytes(mResource); #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE - memset(&mRequestAddr, 0, sizeof(mRequestAddr)); - memset(&mSubscriberSock, 0, sizeof(mSubscriberSock)); - memset(&mRequestToken, 0, sizeof(mRequestToken)); - memset(&mSubscriberToken, 0, sizeof(mSubscriberToken)); - memset(&mRequestUri, 0, sizeof(mRequestUri)); + ClearAllBytes(mRequestAddr); + ClearAllBytes(mSubscriberSock); + ClearAllBytes(mRequestToken); + ClearAllBytes(mSubscriberToken); + ClearAllBytes(mRequestUri); #endif - memset(&mUriPath, 0, sizeof(mUriPath)); + ClearAllBytes(mUriPath); strncpy(mResourceContent, "0", sizeof(mResourceContent)); mResourceContent[sizeof(mResourceContent) - 1] = '\0'; } @@ -78,7 +78,7 @@ otError Coap::CancelResourceSubscription(void) otMessage *message = nullptr; otMessageInfo messageInfo; - memset(&messageInfo, 0, sizeof(messageInfo)); + ClearAllBytes(messageInfo); messageInfo.mPeerAddr = mRequestAddr; messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT; @@ -94,8 +94,8 @@ otError Coap::CancelResourceSubscription(void) SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, mRequestUri)); SuccessOrExit(error = otCoapSendRequest(GetInstancePtr(), message, &messageInfo, &Coap::HandleResponse, this)); - memset(&mRequestAddr, 0, sizeof(mRequestAddr)); - memset(&mRequestUri, 0, sizeof(mRequestUri)); + ClearAllBytes(mRequestAddr); + ClearAllBytes(mRequestUri); mRequestTokenLength = 0; exit: @@ -110,7 +110,7 @@ otError Coap::CancelResourceSubscription(void) void Coap::CancelSubscriber(void) { - memset(&mSubscriberSock, 0, sizeof(mSubscriberSock)); + ClearAllBytes(mSubscriberSock); mSubscriberTokenLength = 0; } #endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE @@ -207,7 +207,7 @@ template <> otError Coap::Process(Arg aArgs[]) if (mSubscriberTokenLength > 0) { // Notify the subscriber - memset(&messageInfo, 0, sizeof(messageInfo)); + ClearAllBytes(messageInfo); messageInfo.mPeerAddr = mSubscriberSock.mAddress; messageInfo.mPeerPort = mSubscriberSock.mPort; @@ -494,7 +494,7 @@ otError Coap::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode) SuccessOrExit(error = otMessageAppend(message, aArgs[3].GetCString(), payloadLength)); } - memset(&messageInfo, 0, sizeof(messageInfo)); + ClearAllBytes(messageInfo); messageInfo.mPeerAddr = coapDestinationIp; messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT; diff --git a/src/cli/cli_coap_secure.cpp b/src/cli/cli_coap_secure.cpp index 518e9075d5..fbd7a3fe30 100644 --- a/src/cli/cli_coap_secure.cpp +++ b/src/cli/cli_coap_secure.cpp @@ -56,10 +56,10 @@ CoapSecure::CoapSecure(otInstance *aInstance, OutputImplementer &aOutputImplemen , mBlockCount(1) #endif { - memset(&mResource, 0, sizeof(mResource)); - memset(&mPsk, 0, sizeof(mPsk)); - memset(&mPskId, 0, sizeof(mPskId)); - memset(&mUriPath, 0, sizeof(mUriPath)); + ClearAllBytes(mResource); + ClearAllBytes(mPsk); + ClearAllBytes(mPskId); + ClearAllBytes(mUriPath); strncpy(mResourceContent, "0", sizeof(mResourceContent)); mResourceContent[sizeof(mResourceContent) - 1] = '\0'; } @@ -366,7 +366,7 @@ template <> otError CoapSecure::Process(Arg aArgs[]) otError error; otSockAddr sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); + ClearAllBytes(sockaddr); SuccessOrExit(error = aArgs[0].ParseAsIp6Address(sockaddr.mAddress)); sockaddr.mPort = OT_DEFAULT_COAP_SECURE_PORT; diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp index d8fa14a099..68337c942c 100644 --- a/src/cli/cli_commissioner.cpp +++ b/src/cli/cli_commissioner.cpp @@ -133,7 +133,7 @@ template <> otError Commissioner::Process(Arg aArgs[]) VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - memset(&discerner, 0, sizeof(discerner)); + ClearAllBytes(discerner); if (aArgs[1] == "*") { @@ -248,7 +248,7 @@ template <> otError Commissioner::Process(Arg aArgs[]) VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); - memset(&dataset, 0, sizeof(dataset)); + ClearAllBytes(dataset); for (; !aArgs->IsEmpty(); aArgs++) { diff --git a/src/cli/cli_dataset.cpp b/src/cli/cli_dataset.cpp index 32a4372ecf..cfd47a18c6 100644 --- a/src/cli/cli_dataset.cpp +++ b/src/cli/cli_dataset.cpp @@ -526,7 +526,7 @@ otError Dataset::ProcessCommand(const ComponentMapper &aMapper, Arg aArgs[]) } else { - memset(&dataset, 0, sizeof(dataset)); + ClearAllBytes(dataset); SuccessOrExit(error = (this->*aMapper.mParse)(aArgs, dataset)); dataset.mComponents.*aMapper.mIsPresentPtr = true; SuccessOrExit(error = otDatasetUpdateTlvs(&dataset, &sDatasetTlvs)); @@ -716,7 +716,7 @@ template <> otError Dataset::Process(Arg aArgs[]) { OT_UNUSED_VARIABLE(aArgs); - memset(&sDatasetTlvs, 0, sizeof(sDatasetTlvs)); + ClearAllBytes(sDatasetTlvs); return OT_ERROR_NONE; } @@ -765,7 +765,7 @@ template <> otError Dataset::Process(Arg aArgs[]) uint8_t tlvs[128]; uint8_t tlvsLength = 0; - memset(&dataset, 0, sizeof(dataset)); + ClearAllBytes(dataset); for (Arg *arg = &aArgs[1]; !arg->IsEmpty();) { @@ -853,7 +853,7 @@ template <> otError Dataset::Process(Arg aArgs[]) bool destAddrSpecified = false; otIp6Address address; - memset(&datasetComponents, 0, sizeof(datasetComponents)); + ClearAllBytes(datasetComponents); for (Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++) { @@ -1003,7 +1003,7 @@ otError Dataset::ParseSecurityPolicy(otSecurityPolicy &aSecurityPolicy, Arg *&aA otSecurityPolicy policy; uint8_t versionThreshold; - memset(&policy, 0, sizeof(policy)); + ClearAllBytes(policy); SuccessOrExit(error = aArgs->ParseAsUint16(policy.mRotationTime)); aArgs++; diff --git a/src/cli/cli_dns.cpp b/src/cli/cli_dns.cpp index c532a0f6f0..7aef47976c 100644 --- a/src/cli/cli_dns.cpp +++ b/src/cli/cli_dns.cpp @@ -418,7 +418,7 @@ otError Dns::GetDnsConfig(Arg aArgs[], otDnsQueryConfig *&aConfig) bool recursionDesired; bool nat64SynthesizedAddress; - memset(aConfig, 0, sizeof(otDnsQueryConfig)); + ClearAllBytes(*aConfig); VerifyOrExit(!aArgs[0].IsEmpty(), aConfig = nullptr); diff --git a/src/cli/cli_joiner.cpp b/src/cli/cli_joiner.cpp index cf84968eda..805087989f 100644 --- a/src/cli/cli_joiner.cpp +++ b/src/cli/cli_joiner.cpp @@ -78,7 +78,7 @@ template <> otError Joiner::Process(Arg aArgs[]) { otJoinerDiscerner discerner; - memset(&discerner, 0, sizeof(discerner)); + ClearAllBytes(discerner); /** * @cli joiner discerner clear diff --git a/src/cli/cli_link_metrics.cpp b/src/cli/cli_link_metrics.cpp index b8c284611d..93cc8c575a 100644 --- a/src/cli/cli_link_metrics.cpp +++ b/src/cli/cli_link_metrics.cpp @@ -138,7 +138,7 @@ template <> otError LinkMetrics::Process(Arg aArgs[]) SuccessOrExit(error = aArgs[0].ParseAsIp6Address(address)); - memset(&seriesFlags, 0, sizeof(otLinkMetricsSeriesFlags)); + ClearAllBytes(seriesFlags); /** * @cli linkmetrics mgmt forward @@ -171,7 +171,7 @@ template <> otError LinkMetrics::Process(Arg aArgs[]) uint8_t seriesId; otLinkMetrics linkMetrics; - memset(&linkMetrics, 0, sizeof(otLinkMetrics)); + ClearAllBytes(linkMetrics); SuccessOrExit(error = aArgs[2].ParseAsUint8(seriesId)); VerifyOrExit(!aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); @@ -368,7 +368,7 @@ otError LinkMetrics::ParseLinkMetricsFlags(otLinkMetrics &aLinkMetrics, const Ar VerifyOrExit(!aFlags.IsEmpty(), error = OT_ERROR_INVALID_ARGS); - memset(&aLinkMetrics, 0, sizeof(aLinkMetrics)); + ClearAllBytes(aLinkMetrics); for (const char *arg = aFlags.GetCString(); *arg != '\0'; arg++) { diff --git a/src/cli/cli_output.hpp b/src/cli/cli_output.hpp index 8941f7e575..3029108cfa 100644 --- a/src/cli/cli_output.hpp +++ b/src/cli/cli_output.hpp @@ -45,6 +45,7 @@ #include "common/binary_search.hpp" #include "common/num_utils.hpp" #include "common/string.hpp" +#include "common/type_traits.hpp" #include "utils/parse_cmdline.hpp" namespace ot { @@ -527,6 +528,21 @@ class Output } } + /** + * Clears (sets to zero) all bytes of a given object. + * + * @tparam ObjectType The object type. + * + * @param[in] aObject A reference to the object of type `ObjectType` to clear all its bytes. + * + */ + template static void ClearAllBytes(ObjectType &aObject) + { + static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); + + memset(reinterpret_cast(&aObject), 0, sizeof(ObjectType)); + } + protected: void OutputFormatV(const char *aFormat, va_list aArguments); diff --git a/src/cli/cli_ping.cpp b/src/cli/cli_ping.cpp new file mode 100644 index 0000000000..e8e7621578 --- /dev/null +++ b/src/cli/cli_ping.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the CLI interpreter for Ping Sender function. + */ + +#include "cli_ping.hpp" + +#include + +#include "cli/cli.hpp" +#include "cli/cli_output.hpp" +#include "common/code_utils.hpp" + +#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE + +namespace ot { +namespace Cli { + +PingSender::PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer) + : Output(aInstance, aOutputImplementer) + , mPingIsAsync(false) +{ +} + +otError PingSender::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + otPingSenderConfig config; + bool async = false; + bool nat64SynthesizedAddress; + + /** + * @cli ping stop + * @code + * ping stop + * Done + * @endcode + * @par + * Stop sending ICMPv6 Echo Requests. + * @sa otPingSenderStop + */ + if (aArgs[0] == "stop") + { + otPingSenderStop(GetInstancePtr()); + ExitNow(); + } + else if (aArgs[0] == "async") + { + async = true; + aArgs++; + } + + ClearAllBytes(config); + + if (aArgs[0] == "-I") + { + SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource)); + +#if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS); +#endif + aArgs += 2; + } + + if (aArgs[0] == "-m") + { + config.mMulticastLoop = true; + aArgs++; + } + + SuccessOrExit(error = Interpreter::GetInterpreter().ParseToIp6Address( + GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress)); + if (nat64SynthesizedAddress) + { + OutputFormat("Pinging synthesized IPv6 address: "); + OutputIp6AddressLine(config.mDestination); + } + + if (!aArgs[1].IsEmpty()) + { + SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize)); + } + + if (!aArgs[2].IsEmpty()) + { + SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount)); + } + + if (!aArgs[3].IsEmpty()) + { + SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval)); + } + + if (!aArgs[4].IsEmpty()) + { + SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit)); + config.mAllowZeroHopLimit = (config.mHopLimit == 0); + } + + if (!aArgs[5].IsEmpty()) + { + uint32_t timeout; + + SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout)); + VerifyOrExit(timeout <= NumericLimits::kMax, error = OT_ERROR_INVALID_ARGS); + config.mTimeout = static_cast(timeout); + } + + VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + config.mReplyCallback = PingSender::HandlePingReply; + config.mStatisticsCallback = PingSender::HandlePingStatistics; + config.mCallbackContext = this; + + SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config)); + + mPingIsAsync = async; + + if (!async) + { + error = OT_ERROR_PENDING; + } + +exit: + return error; +} + +otError PingSender::ParsePingInterval(const Arg &aArg, uint32_t &aInterval) +{ + otError error = OT_ERROR_NONE; + const char *string = aArg.GetCString(); + const uint32_t msFactor = 1000; + uint32_t factor = msFactor; + + aInterval = 0; + + while (*string) + { + if ('0' <= *string && *string <= '9') + { + // In the case of seconds, change the base of already calculated value. + if (factor == msFactor) + { + aInterval *= 10; + } + + aInterval += static_cast(*string - '0') * factor; + + // In the case of milliseconds, change the multiplier factor. + if (factor != msFactor) + { + factor /= 10; + } + } + else if (*string == '.') + { + // Accept only one dot character. + VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS); + + // Start analyzing hundreds of milliseconds. + factor /= 10; + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + + string++; + } + +exit: + return error; +} + +void PingSender::HandlePingReply(const otPingSenderReply *aReply, void *aContext) +{ + static_cast(aContext)->HandlePingReply(aReply); +} + +void PingSender::HandlePingReply(const otPingSenderReply *aReply) +{ + OutputFormat("%u bytes from ", static_cast(aReply->mSize + sizeof(otIcmp6Header))); + OutputIp6Address(aReply->mSenderAddress); + OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime); +} + +void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext) +{ + static_cast(aContext)->HandlePingStatistics(aStatistics); +} + +void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics) +{ + OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount); + + if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast && + aStatistics->mReceivedCount <= aStatistics->mSentCount) + { + uint32_t packetLossRate = + 1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount; + + OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10), + static_cast(packetLossRate % 10)); + } + + if (aStatistics->mReceivedCount != 0) + { + uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount; + + OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime, + static_cast(avgRoundTripTime / 1000), static_cast(avgRoundTripTime % 1000), + aStatistics->mMaxRoundTripTime); + } + + OutputNewLine(); + + if (!mPingIsAsync) + { + OutputResult(OT_ERROR_NONE); + } +} + +void PingSender::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); } + +} // namespace Cli +} // namespace ot + +#endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE diff --git a/src/cli/cli_tcp.cpp b/src/cli/cli_tcp.cpp index 67534f0b9c..a3ea000e33 100644 --- a/src/cli/cli_tcp.cpp +++ b/src/cli/cli_tcp.cpp @@ -193,7 +193,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) { otTcpEndpointInitializeArgs endpointArgs; - memset(&endpointArgs, 0x00, sizeof(endpointArgs)); + ClearAllBytes(endpointArgs); endpointArgs.mEstablishedCallback = HandleTcpEstablishedCallback; if (mUseCircularSendBuffer) { @@ -215,7 +215,7 @@ template <> otError TcpExample::Process(Arg aArgs[]) { otTcpListenerInitializeArgs listenerArgs; - memset(&listenerArgs, 0x00, sizeof(listenerArgs)); + ClearAllBytes(listenerArgs); listenerArgs.mAcceptReadyCallback = HandleTcpAcceptReadyCallback; listenerArgs.mAcceptDoneCallback = HandleTcpAcceptDoneCallback; listenerArgs.mContext = this; diff --git a/src/cli/cli_udp.cpp b/src/cli/cli_udp.cpp index d5f3792885..56f7db843a 100644 --- a/src/cli/cli_udp.cpp +++ b/src/cli/cli_udp.cpp @@ -47,7 +47,7 @@ UdpExample::UdpExample(otInstance *aInstance, OutputImplementer &aOutputImplemen : Output(aInstance, aOutputImplementer) , mLinkSecurityEnabled(true) { - memset(&mSocket, 0, sizeof(mSocket)); + ClearAllBytes(mSocket); } template <> otError UdpExample::Process(Arg aArgs[]) @@ -127,7 +127,7 @@ template <> otError UdpExample::Process(Arg aArgs[]) otMessageInfo messageInfo; otMessageSettings messageSettings = {mLinkSecurityEnabled, OT_MESSAGE_PRIORITY_NORMAL}; - memset(&messageInfo, 0, sizeof(messageInfo)); + ClearAllBytes(messageInfo); // Possible argument formats: // diff --git a/src/core/common/clearable.hpp b/src/core/common/clearable.hpp index f91c15f41f..bc1b1f6371 100644 --- a/src/core/common/clearable.hpp +++ b/src/core/common/clearable.hpp @@ -38,8 +38,25 @@ #include +#include "common/type_traits.hpp" + namespace ot { +/** + * Clears (sets to zero) all bytes of a given object. + * + * @tparam ObjectType The object type. + * + * @param[in] aObject A reference to the object of type `ObjectType` to clear all its bytes. + * + */ +template void ClearAllBytes(ObjectType &aObject) +{ + static_assert(!TypeTraits::IsPointer::kValue, "ObjectType must not be a pointer"); + + memset(reinterpret_cast(&aObject), 0, sizeof(ObjectType)); +} + /** * Defines a `Clearable` object which provides `Clear()` method. * @@ -52,7 +69,7 @@ namespace ot { template class Clearable { public: - void Clear(void) { memset(reinterpret_cast(static_cast(this)), 0, sizeof(Type)); } + void Clear(void) { ClearAllBytes(*static_cast(this)); } }; } // namespace ot diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 1c7028d0fa..50e1fcc459 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -75,7 +75,7 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, con VerifyOrExit((message = static_cast(NewBuffer(aSettings.GetPriority()))) != nullptr); - memset(message, 0, sizeof(*message)); + ClearAllBytes(*message); message->SetMessagePool(this); message->SetType(aType); message->SetReserved(aReserveHeader); diff --git a/src/core/common/settings.hpp b/src/core/common/settings.hpp index f7f538136e..fdf148e9aa 100644 --- a/src/core/common/settings.hpp +++ b/src/core/common/settings.hpp @@ -417,7 +417,7 @@ class SettingsBase : public InstanceLocator */ void Init(void) { - memset(this, 0, sizeof(*this)); + ClearAllBytes(*this); SetVersion(kThreadVersion1p1); } @@ -784,7 +784,7 @@ class SettingsBase : public InstanceLocator * Initializes the `BorderAgentId` object. * */ - void Init(void) { mId = {}; } + void Init(void) { ClearAllBytes(mId); } /** * Returns the Border Agent ID. diff --git a/src/core/diags/factory_diags.hpp b/src/core/diags/factory_diags.hpp index 5d015d278f..1b72a15639 100644 --- a/src/core/diags/factory_diags.hpp +++ b/src/core/diags/factory_diags.hpp @@ -42,6 +42,7 @@ #include +#include "common/clearable.hpp" #include "common/error.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" @@ -131,10 +132,8 @@ class Diags : public InstanceLocator, private NonCopyable Error (Diags::*mCommand)(uint8_t aArgsLength, char *aArgs[], char *aOutput, size_t aOutputMaxLen); }; - struct Stats + struct Stats : public Clearable { - void Clear(void) { memset(this, 0, sizeof(*this)); } - uint32_t mReceivedPackets; uint32_t mSentPackets; int8_t mFirstRssi; diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 3432ce0ae6..93002e1f4a 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -234,7 +234,7 @@ Error Mac::ConvertBeaconToActiveScanResult(const RxFrame *aBeaconFrame, ActiveSc uint16_t payloadLength; #endif - memset(&aResult, 0, sizeof(ActiveScanResult)); + ClearAllBytes(aResult); VerifyOrExit(aBeaconFrame != nullptr, error = kErrorInvalidArgs); @@ -2136,7 +2136,7 @@ const uint32_t *Mac::GetIndirectRetrySuccessHistogram(uint8_t &aNumberOfEntries) } #endif -void Mac::ResetRetrySuccessHistogram() { memset(&mRetryHistogram, 0, sizeof(mRetryHistogram)); } +void Mac::ResetRetrySuccessHistogram() { ClearAllBytes(mRetryHistogram); } #endif // OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE uint8_t Mac::ComputeLinkMargin(int8_t aRss) const { return ot::ComputeLinkMargin(GetNoiseFloor(), aRss); } diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index e14d436c84..6205d0b638 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -39,6 +39,7 @@ #include #include +#include "common/clearable.hpp" #include "common/locator.hpp" #include "common/log.hpp" #include "common/non_copyable.hpp" @@ -496,7 +497,7 @@ class Mac : public InstanceLocator, private NonCopyable * Resets mac counters * */ - void ResetCounters(void) { memset(&mCounters, 0, sizeof(mCounters)); } + void ResetCounters(void) { ClearAllBytes(mCounters); } /** * Returns the MAC counter. diff --git a/src/core/mac/mac_frame.cpp b/src/core/mac/mac_frame.cpp index 3e26a6ba8a..d7355ea6a5 100644 --- a/src/core/mac/mac_frame.cpp +++ b/src/core/mac/mac_frame.cpp @@ -1390,7 +1390,7 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending) uint16_t fcf = static_cast(kTypeAck) | aFrame.GetVersion(); mChannel = aFrame.mChannel; - memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo)); + ClearAllBytes(mInfo.mTxInfo); if (aIsFramePending) { @@ -1454,7 +1454,7 @@ Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, con // Prepare the ack frame mChannel = aRxFrame.mChannel; - memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo)); + ClearAllBytes(mInfo.mTxInfo); InitMacHeader(kTypeAck, kVersion2015, addrs, panIds, static_cast(securityLevel), static_cast(keyIdMode)); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 1e0223cfa1..36aeeca069 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -72,7 +72,7 @@ Commissioner::Commissioner(Instance &aInstance) , mPanIdQuery(aInstance) , mState(kStateDisabled) { - memset(reinterpret_cast(mJoiners), 0, sizeof(mJoiners)); + ClearAllBytes(mJoiners); mCommissionerAloc.Clear(); mCommissionerAloc.mPrefixLength = 64; @@ -491,7 +491,7 @@ Error Commissioner::AddJoiner(const Mac::ExtAddress *aEui64, void Commissioner::Joiner::CopyToJoinerInfo(otJoinerInfo &aJoiner) const { - memset(&aJoiner, 0, sizeof(aJoiner)); + ClearAllBytes(aJoiner); switch (mType) { diff --git a/src/core/meshcop/dataset.cpp b/src/core/meshcop/dataset.cpp index 9bab49d33f..6c1bb50515 100644 --- a/src/core/meshcop/dataset.cpp +++ b/src/core/meshcop/dataset.cpp @@ -159,7 +159,7 @@ Dataset::Dataset(void) : mUpdateTime(0) , mLength(0) { - memset(mTlvs, 0, sizeof(mTlvs)); + ClearAllBytes(mTlvs); } void Dataset::Clear(void) { mLength = 0; } diff --git a/src/core/meshcop/dataset_local.cpp b/src/core/meshcop/dataset_local.cpp index ac1095732c..4506c7ec89 100644 --- a/src/core/meshcop/dataset_local.cpp +++ b/src/core/meshcop/dataset_local.cpp @@ -148,7 +148,7 @@ Error DatasetLocal::Read(otOperationalDatasetTlvs &aDataset) const Dataset dataset; Error error; - memset(&aDataset, 0, sizeof(aDataset)); + ClearAllBytes(aDataset); SuccessOrExit(error = Read(dataset)); dataset.ConvertTo(aDataset); diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 50b02e9239..fb0f3e61cb 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -68,7 +68,7 @@ Joiner::Joiner(Instance &aInstance) { SetIdFromIeeeEui64(); mDiscerner.Clear(); - memset(mJoinerRouters, 0, sizeof(mJoinerRouters)); + ClearAllBytes(mJoinerRouters); } void Joiner::SetIdFromIeeeEui64(void) diff --git a/src/core/meshcop/meshcop.cpp b/src/core/meshcop/meshcop.cpp index 9dd65663c7..c4ac924b21 100644 --- a/src/core/meshcop/meshcop.cpp +++ b/src/core/meshcop/meshcop.cpp @@ -33,6 +33,7 @@ #include "meshcop.hpp" +#include "common/clearable.hpp" #include "common/crc16.hpp" #include "common/debug.hpp" #include "common/locator_getters.hpp" @@ -190,7 +191,7 @@ void SteeringData::Init(uint8_t aLength) { OT_ASSERT(aLength <= kMaxLength); mLength = aLength; - memset(m8, 0, sizeof(m8)); + ClearAllBytes(m8); } void SteeringData::SetToPermitAllJoiners(void) @@ -338,7 +339,7 @@ Error GeneratePskc(const char *aPassPhrase, (networkNameLen <= OT_NETWORK_NAME_MAX_SIZE), error = kErrorInvalidArgs); - memset(salt, 0, sizeof(salt)); + ClearAllBytes(salt); memcpy(salt, saltPrefix, sizeof(saltPrefix) - 1); saltLen += static_cast(sizeof(saltPrefix) - 1); diff --git a/src/core/meshcop/secure_transport.cpp b/src/core/meshcop/secure_transport.cpp index 945f701c6b..6648130334 100644 --- a/src/core/meshcop/secure_transport.cpp +++ b/src/core/meshcop/secure_transport.cpp @@ -41,6 +41,7 @@ #include #include "common/as_core_type.hpp" +#include "common/clearable.hpp" #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/encoding.hpp" @@ -103,19 +104,19 @@ SecureTransport::SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bo mOwnCertLength = 0; mPrivateKeySrc = nullptr; mPrivateKeyLength = 0; - memset(&mCaChain, 0, sizeof(mCaChain)); - memset(&mOwnCert, 0, sizeof(mOwnCert)); - memset(&mPrivateKey, 0, sizeof(mPrivateKey)); + ClearAllBytes(mCaChain); + ClearAllBytes(mOwnCert); + ClearAllBytes(mPrivateKey); #endif #endif - memset(mCipherSuites, 0, sizeof(mCipherSuites)); - memset(mPsk, 0, sizeof(mPsk)); - memset(&mSsl, 0, sizeof(mSsl)); - memset(&mConf, 0, sizeof(mConf)); + ClearAllBytes(mCipherSuites); + ClearAllBytes(mPsk); + ClearAllBytes(mSsl); + ClearAllBytes(mConf); #ifdef MBEDTLS_SSL_COOKIE_C - memset(&mCookieCtx, 0, sizeof(mCookieCtx)); + ClearAllBytes(mCookieCtx); #endif } diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp index 680ea049e1..e206ff6648 100644 --- a/src/core/net/dhcp6_client.cpp +++ b/src/core/net/dhcp6_client.cpp @@ -57,7 +57,7 @@ Client::Client(Instance &aInstance) , mStartTime(0) , mIdentityAssociationCurrent(nullptr) { - memset(mIdentityAssociations, 0, sizeof(mIdentityAssociations)); + ClearAllBytes(mIdentityAssociations); } bool Client::MatchNetifAddressWithPrefix(const Ip6::Netif::UnicastAddress &aNetifAddress, const Ip6::Prefix &aIp6Prefix) diff --git a/src/core/net/dhcp6_server.cpp b/src/core/net/dhcp6_server.cpp index dc9ced5d3d..c5f6dcb0d8 100644 --- a/src/core/net/dhcp6_server.cpp +++ b/src/core/net/dhcp6_server.cpp @@ -56,7 +56,7 @@ Server::Server(Instance &aInstance) , mPrefixAgentsCount(0) , mPrefixAgentsMask(0) { - memset(mPrefixAgents, 0, sizeof(mPrefixAgents)); + ClearAllBytes(mPrefixAgents); } Error Server::UpdateService(void) diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index df7c737a18..f7809c0d30 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -804,7 +804,7 @@ Error Client::InitTcpSocket(void) Error error; otTcpEndpointInitializeArgs endpointArgs; - memset(&endpointArgs, 0x00, sizeof(endpointArgs)); + ClearAllBytes(endpointArgs); endpointArgs.mSendDoneCallback = HandleTcpSendDoneCallback; endpointArgs.mEstablishedCallback = HandleTcpEstablishedCallback; endpointArgs.mReceiveAvailableCallback = HandleTcpReceiveAvailableCallback; @@ -1639,7 +1639,7 @@ void Client::ResolveHostAddressIfNeeded(Query &aQuery, const Message &aResponseM PopulateResponse(response, aQuery, aResponseMessage); - memset(&serviceInfo, 0, sizeof(serviceInfo)); + ClearAllBytes(serviceInfo); serviceInfo.mHostNameBuffer = hostName; serviceInfo.mHostNameBufferSize = sizeof(hostName); SuccessOrExit(response.ReadServiceInfo(Response::kAnswerSection, Name(aQuery, kNameOffsetInQuery), serviceInfo)); diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 46e0b05f7c..9bf0db1681 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -353,7 +353,7 @@ class Ip6 : public InstanceLocator, private NonCopyable * Resets the Border Routing counters. * */ - void ResetBorderRoutingCounters(void) { memset(&mBorderRoutingCounters, 0, sizeof(mBorderRoutingCounters)); } + void ResetBorderRoutingCounters(void) { ClearAllBytes(mBorderRoutingCounters); } #endif private: diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 78922ef6f2..61be9ea112 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -52,7 +52,7 @@ Mpl::Mpl(Instance &aInstance) , mRetransmissionTimer(aInstance) #endif { - memset(mSeedSet, 0, sizeof(mSeedSet)); + ClearAllBytes(mSeedSet); } void MplOption::Init(SeedIdLength aSeedIdLength) diff --git a/src/core/net/tcp6.cpp b/src/core/net/tcp6.cpp index dccb41bb2e..0bfbed4649 100644 --- a/src/core/net/tcp6.cpp +++ b/src/core/net/tcp6.cpp @@ -84,7 +84,7 @@ Error Tcp::Endpoint::Initialize(Instance &aInstance, const otTcpEndpointInitiali Error error; struct tcpcb &tp = GetTcb(); - memset(&tp, 0x00, sizeof(tp)); + ClearAllBytes(tp); SuccessOrExit(error = aInstance.Get().mEndpoints.Add(*this)); @@ -95,8 +95,8 @@ Error Tcp::Endpoint::Initialize(Instance &aInstance, const otTcpEndpointInitiali mReceiveAvailableCallback = aArgs.mReceiveAvailableCallback; mDisconnectedCallback = aArgs.mDisconnectedCallback; - memset(mTimers, 0x00, sizeof(mTimers)); - memset(&mSockAddr, 0x00, sizeof(mSockAddr)); + ClearAllBytes(mTimers); + ClearAllBytes(mSockAddr); mPendingCallbacks = 0; /* @@ -552,7 +552,7 @@ Error Tcp::Listener::Initialize(Instance &aInstance, const otTcpListenerInitiali mAcceptReadyCallback = aArgs.mAcceptReadyCallback; mAcceptDoneCallback = aArgs.mAcceptDoneCallback; - memset(tpl, 0x00, sizeof(struct tcpcb_listen)); + ClearAllBytes(*tpl); tpl->instance = &aInstance; exit: @@ -582,7 +582,7 @@ Error Tcp::Listener::StopListening(void) { struct tcpcb_listen *tpl = &GetTcbListen(); - memset(&tpl->laddr, 0x00, sizeof(tpl->laddr)); + ClearAllBytes(tpl->laddr); tpl->lport = 0; tpl->t_state = TCP6S_CLOSED; return kErrorNone; @@ -673,7 +673,7 @@ Error Tcp::HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, Message otLinkedBuffer *priorHead = lbuf_head(&tp->sendbuf); size_t priorBacklog = endpoint->GetSendBufferBytes() - endpoint->GetInFlightBytes(); - memset(&sig, 0x00, sizeof(sig)); + ClearAllBytes(sig); nextAction = tcp_input(ip6Header, tcpHeader, &aMessage, tp, nullptr, &sig); if (nextAction != RELOOKUP_REQUIRED) { @@ -688,7 +688,7 @@ Error Tcp::HandleMessage(ot::Ip6::Header &aIp6Header, Message &aMessage, Message { struct tcpcb_listen *tpl = &listener->GetTcbListen(); - memset(&sig, 0x00, sizeof(sig)); + ClearAllBytes(sig); nextAction = tcp_input(ip6Header, tcpHeader, &aMessage, nullptr, tpl, &sig); OT_ASSERT(nextAction != RELOOKUP_REQUIRED); if (sig.accepted_connection != nullptr) diff --git a/src/core/radio/trel_link.cpp b/src/core/radio/trel_link.cpp index 4735f379e3..ab6e733a3f 100644 --- a/src/core/radio/trel_link.cpp +++ b/src/core/radio/trel_link.cpp @@ -55,9 +55,9 @@ Link::Link(Instance &aInstance) , mTimer(aInstance) , mInterface(aInstance) { - memset(&mTxFrame, 0, sizeof(mTxFrame)); - memset(&mRxFrame, 0, sizeof(mRxFrame)); - memset(mAckFrameBuffer, 0, sizeof(mAckFrameBuffer)); + ClearAllBytes(mTxFrame); + ClearAllBytes(mRxFrame); + ClearAllBytes(mAckFrameBuffer); mTxFrame.mPsdu = &mTxPacketBuffer[kMaxHeaderSize]; mTxFrame.SetLength(0); diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index 008173b6d9..92a0b0566d 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -112,14 +112,14 @@ void Child::Clear(void) { Instance &instance = GetInstance(); - memset(reinterpret_cast(this), 0, sizeof(Child)); + ClearAllBytes(*this); Init(instance); } void Child::ClearIp6Addresses(void) { mMeshLocalIid.Clear(); - memset(mIp6Address, 0, sizeof(mIp6Address)); + ClearAllBytes(mIp6Address); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE mMlrToRegisterMask.Clear(); mMlrRegisteredMask.Clear(); diff --git a/src/core/thread/discover_scanner.cpp b/src/core/thread/discover_scanner.cpp index 2425e1e3af..62987fd690 100644 --- a/src/core/thread/discover_scanner.cpp +++ b/src/core/thread/discover_scanner.cpp @@ -312,7 +312,7 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const // Find MLE Discovery TLV SuccessOrExit(error = Tlv::FindTlvValueStartEndOffsets(aRxInfo.mMessage, Tlv::kDiscovery, offset, end)); - memset(&result, 0, sizeof(result)); + ClearAllBytes(result); result.mDiscover = true; result.mPanId = linkInfo->mPanId; result.mChannel = linkInfo->mChannel; diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index dfdc749fd3..14355364cd 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -309,7 +309,7 @@ class MeshForwarder : public InstanceLocator, private NonCopyable * Resets the IP level counters. * */ - void ResetCounters(void) { memset(&mIpCounters, 0, sizeof(mIpCounters)); } + void ResetCounters(void) { ClearAllBytes(mIpCounters); } #if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE /** diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index cc8936c842..021dc61382 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -263,7 +263,7 @@ void Mle::Stop(StopMode aMode) void Mle::ResetCounters(void) { - memset(&mCounters, 0, sizeof(mCounters)); + ClearAllBytes(mCounters); #if OPENTHREAD_CONFIG_UPTIME_ENABLE mLastUpdatedTimestamp = Get().GetUptime(); #endif @@ -5122,7 +5122,7 @@ void Mle::ParentCandidate::Clear(void) { Instance &instance = GetInstance(); - memset(reinterpret_cast(this), 0, sizeof(ParentCandidate)); + ClearAllBytes(*this); Init(instance); } diff --git a/src/core/thread/mle_tlvs.cpp b/src/core/thread/mle_tlvs.cpp index 1908d61d48..7ae333166b 100644 --- a/src/core/thread/mle_tlvs.cpp +++ b/src/core/thread/mle_tlvs.cpp @@ -33,6 +33,7 @@ #include "mle_tlvs.hpp" +#include "common/clearable.hpp" #include "common/code_utils.hpp" namespace ot { @@ -45,7 +46,7 @@ void RouteTlv::Init(void) SetType(kRoute); SetLength(sizeof(*this) - sizeof(Tlv)); mRouterIdMask.Clear(); - memset(mRouteData, 0, sizeof(mRouteData)); + ClearAllBytes(mRouteData); } bool RouteTlv::IsValid(void) const diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index ae4dfdfa31..f8b9e6bc93 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -434,15 +434,9 @@ class LeaderData : public otLeaderData, public Clearable }; OT_TOOL_PACKED_BEGIN -class RouterIdSet : public Equatable +class RouterIdSet : public Equatable, public Clearable { public: - /** - * Clears the Router Id Set. - * - */ - void Clear(void) { memset(mRouterIdSet, 0, sizeof(mRouterIdSet)); } - /** * Indicates whether or not a Router ID bit is set. * diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index ae1f15499c..9035f85f20 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -230,7 +230,7 @@ Error Server::AppendMacCounters(Message &aMessage) MacCountersTlv tlv; const otMacCounters &counters = Get().GetCounters(); - memset(&tlv, 0, sizeof(tlv)); + ClearAllBytes(tlv); tlv.Init(); tlv.SetIfInUnknownProtos(counters.mRxOther); diff --git a/src/core/thread/radio_selector.cpp b/src/core/thread/radio_selector.cpp index ea7ea74de3..4268bb0925 100644 --- a/src/core/thread/radio_selector.cpp +++ b/src/core/thread/radio_selector.cpp @@ -63,7 +63,7 @@ RadioSelector::RadioSelector(Instance &aInstance) void RadioSelector::NeighborInfo::PopulateMultiRadioInfo(MultiRadioInfo &aInfo) { - memset(&aInfo, 0, sizeof(MultiRadioInfo)); + ClearAllBytes(aInfo); #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE if (GetSupportedRadioTypes().Contains(Mac::kRadioTypeIeee802154)) diff --git a/src/core/thread/router.cpp b/src/core/thread/router.cpp index d16d635e54..e130b69ab3 100644 --- a/src/core/thread/router.cpp +++ b/src/core/thread/router.cpp @@ -71,7 +71,7 @@ void Router::Clear(void) { Instance &instance = GetInstance(); - memset(reinterpret_cast(this), 0, sizeof(Router)); + ClearAllBytes(*this); Init(instance); } @@ -92,7 +92,7 @@ void Parent::Clear(void) { Instance &instance = GetInstance(); - memset(reinterpret_cast(this), 0, sizeof(Parent)); + ClearAllBytes(*this); Init(instance); } diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index bf11573a2e..8f2b8f207b 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -465,7 +465,7 @@ class RouterTable : public InstanceLocator, private NonCopyable void HandleTableChanged(void); void LogRouteTable(void) const; - class RouterIdMap + class RouterIdMap : public Clearable { public: // The `RouterIdMap` tracks which Router IDs are allocated. @@ -474,7 +474,6 @@ class RouterTable : public InstanceLocator, private NonCopyable // remaining reuse delay time (in seconds). RouterIdMap(void) { Clear(); } - void Clear(void) { memset(mIndexes, 0, sizeof(mIndexes)); } bool IsAllocated(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kAllocatedFlag); } uint8_t GetIndex(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kIndexMask); } void SetIndex(uint8_t aRouterId, uint8_t aIndex) { mIndexes[aRouterId] = kAllocatedFlag | aIndex; } diff --git a/src/core/utils/channel_monitor.cpp b/src/core/utils/channel_monitor.cpp index b707a79b63..f10dd93c29 100644 --- a/src/core/utils/channel_monitor.cpp +++ b/src/core/utils/channel_monitor.cpp @@ -66,7 +66,7 @@ ChannelMonitor::ChannelMonitor(Instance &aInstance) , mSampleCount(0) , mTimer(aInstance) { - memset(mChannelOccupancy, 0, sizeof(mChannelOccupancy)); + ClearAllBytes(mChannelOccupancy); } Error ChannelMonitor::Start(void) @@ -98,7 +98,7 @@ void ChannelMonitor::Clear(void) { mChannelMaskIndex = 0; mSampleCount = 0; - memset(mChannelOccupancy, 0, sizeof(mChannelOccupancy)); + ClearAllBytes(mChannelOccupancy); LogDebg("Clearing data"); } diff --git a/src/core/utils/history_tracker.cpp b/src/core/utils/history_tracker.cpp index 74d8cfb855..1b2a4fd277 100644 --- a/src/core/utils/history_tracker.cpp +++ b/src/core/utils/history_tracker.cpp @@ -61,7 +61,7 @@ HistoryTracker::HistoryTracker(Instance &aInstance) mTimer.Start(kAgeCheckPeriod); #if OPENTHREAD_FTD && (OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE > 0) - memset(mRouterEntries, 0, sizeof(mRouterEntries)); + ClearAllBytes(mRouterEntries); #endif } diff --git a/src/core/utils/slaac_address.cpp b/src/core/utils/slaac_address.cpp index dacbbcd55f..32531ca7ab 100644 --- a/src/core/utils/slaac_address.cpp +++ b/src/core/utils/slaac_address.cpp @@ -55,7 +55,7 @@ Slaac::Slaac(Instance &aInstance) , mEnabled(true) , mFilter(nullptr) { - memset(mAddresses, 0, sizeof(mAddresses)); + ClearAllBytes(mAddresses); } void Slaac::Enable(void) From 811add6ac0c2af228d3801712970413db37ef142 Mon Sep 17 00:00:00 2001 From: Marcin Gasiorek Date: Thu, 21 Mar 2024 12:02:20 +0100 Subject: [PATCH 9/9] [tools] tcat: extend TCAT command list. Add commands for: -WiFi connection management, -Perform reboot Signed-off-by: Marcin Gasiorek --- .../tcat_ble_client/ble/ble_stream_secure.py | 10 +- tools/tcat_ble_client/cli/base_commands.py | 195 +++++++++++++++++- tools/tcat_ble_client/cli/cli.py | 4 +- 3 files changed, 206 insertions(+), 3 deletions(-) diff --git a/tools/tcat_ble_client/ble/ble_stream_secure.py b/tools/tcat_ble_client/ble/ble_stream_secure.py index 9d15b79453..af39ed77c0 100644 --- a/tools/tcat_ble_client/ble/ble_stream_secure.py +++ b/tools/tcat_ble_client/ble/ble_stream_secure.py @@ -103,8 +103,14 @@ async def recv(self, buffersize, timeout=1): self.incoming.write(data) while True: + decode = [] try: - decode = self.ssl_object.read(4096) + # try decode all available data + while True: + decode.append(self.ssl_object.read(4096)) + + if self.incoming.pending <= 0: + break break # if recv called before entire message was received from the link except ssl.SSLWantReadError: @@ -113,6 +119,8 @@ async def recv(self, buffersize, timeout=1): await asyncio.sleep(0.1) more = await self.ble_stream.recv(buffersize) self.incoming.write(more) + if len(decode) == 1: + return decode[0] return decode async def send_with_resp(self, bytes): diff --git a/tools/tcat_ble_client/cli/base_commands.py b/tools/tcat_ble_client/cli/base_commands.py index bd4c1dbea8..b4cb4b065f 100644 --- a/tools/tcat_ble_client/cli/base_commands.py +++ b/tools/tcat_ble_client/cli/base_commands.py @@ -35,7 +35,7 @@ from tlv.tcat_tlv import TcatTLVType from cli.command import Command, CommandResultNone, CommandResultTLV from dataset.dataset import ThreadDataset -from utils import select_device_by_user_input +from utils import select_device_by_user_input, get_int_in_range from os import path @@ -163,3 +163,196 @@ async def execute_default(self, args, context): await ble_sstream.do_handshake(hostname=SERVER_COMMON_NAME) print('Done') context['ble_sstream'] = ble_sstream + + +class TbrWiFiScanSubCmd(Command): + + def get_help_string(self) -> str: + return 'Find available Wi-Fi access points and connect to one of them.' + + def user_confirmation(self): + while True: + try: + userAnswer = str(input('Do you want to continue? [Y]es/[n]o\n> ')) + if userAnswer.lower() == 'y' or userAnswer.lower() == 'yes': + return True + elif userAnswer.lower() == 'n' or userAnswer.lower() == 'no': + return False + else: + print('\nTry again.') + except KeyboardInterrupt: + print('\nInterrupted by user.') + return None + + def get_password(self, networkName): + while True: + try: + password = str(input(f'\nPassword for \"{networkName}\"\n> ')) + if len(password) > 0: + return password + else: + print('\nThe password is too short. Try again.') + except KeyboardInterrupt: + print('\nInterrupted by user.') + return None + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + + print('Wi-Fi scanning...\n') + cmd = TLV(TcatTLVType.APPLICATION.value, bytes('wifi_scan', 'ascii')).to_bytes() + + response = await bless.send_with_resp(cmd) + if not response: + return + + tlv_response = TLV.from_bytes(response) + if tlv_response.value.decode("ascii").find("RESP_NOT_SUPP") != -1: + print('Command not supported\n') + return + elif tlv_response.value.decode("ascii").find("RESP_FAIL") != -1: + print('Wi-Fi status get fail\n') + return + + wifiNetworks = [] + wifiNetworksDictKeys = ["id", "ssid", "chan", "band", "rssi", "security"] + + while True: + response = await bless.recv(buffersize=4096, timeout=15) + if not response: + return + for _resp in response: + tlv_response = TLV.from_bytes(_resp) + if tlv_response.value.decode("ascii").find("RESP_FAIL") != -1: + print('Wi-Fi status get fail\n') + break + elif tlv_response.value.decode("ascii").find("RESP_OK") != -1: + break + wifiNetworks.append(dict(zip(wifiNetworksDictKeys, tlv_response.value.decode("ascii").split('|')))) + break + + if len(wifiNetworks) > 0: + print('Found Wi-Fi networks:\n') + print(f"{'Num' :<4}| {'SSID' :<30}| {'Chan' :<5}| {'Band' :<7}| {'RSSI' :<5}") + for _net in wifiNetworks: + print(f"{_net['id'] :<4}| {_net['ssid'] :<30}| {_net['chan'] :<5}| {_net['band'] :<7}| {_net['rssi'] :<5}") + else: + print('\nNo Wi-Fi networks found.') + return None + + print("""\nConnect to Wi-Fi network?\n""" + """After you continue, the network is saved as default """ + """and TBR automatically connects to this network.""") + conf = self.user_confirmation() + if not conf: + return + + print('\nSelect Wi-Fi network number to connect to it') + selected = get_int_in_range(1, len(wifiNetworks)) + ssid = wifiNetworks[selected - 1]['ssid'] + sec = wifiNetworks[selected - 1]['security'] + + pwd = self.get_password(ssid) + if pwd is None: + return + + print('Store Wi-Fi network...\n') + cmd = TLV(TcatTLVType.APPLICATION.value, bytes('wifi_add ' + ssid + ' ' + pwd + ' ' + sec, 'ascii')).to_bytes() + response = await bless.send_with_resp(cmd) + + if not response: + return + + tlv_response = TLV.from_bytes(response) + if tlv_response.value.decode("ascii").find("RESP_FAIL") != -1: + print('\nConnection fail\n') + print('Wi-Fi network is saved') + return + + +class TbrWiFiStatusSubCmd(Command): + + def get_help_string(self) -> str: + return 'Get Wi-Fi connection status for TBR.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + + print('Wi-Fi status get...\n') + command = TLV(TcatTLVType.APPLICATION.value, bytes('wifi_status', 'ascii')).to_bytes() + await bless.send(command) + + wifiStatus = {} + wifiStatusDictKeys = ['state', 'ssid', 'rssi'] + + while True: + response = await bless.recv(buffersize=4096, timeout=15) + if not response: + return + for _resp in response: + tlv_response = TLV.from_bytes(_resp) + if tlv_response.value.decode("ascii").find("RESP_NOT_SUPP") != -1: + print('Command not supported\n') + break + elif tlv_response.value.decode("ascii").find("RESP_FAIL") != -1: + print('Wi-Fi status get fail\n') + break + elif tlv_response.value.decode("ascii").find("RESP_OK") != -1: + break + wifiStatus = dict(zip(wifiStatusDictKeys, tlv_response.value.decode("ascii").split('|'))) + break + + if 'state' in wifiStatus: + if wifiStatus['state'] == 'COMPLETED': + print(f'\tWi-Fi connected to: \"{wifiStatus["ssid"]}\" [RSSI: {wifiStatus["rssi"]}]') + else: + print(f'\tWi-Fi {wifiStatus["state"].lower()}') + + return + + +class TbrWiFiCommand(Command): + + def __init__(self): + self._subcommands = {'scan': TbrWiFiScanSubCmd(), 'status': TbrWiFiStatusSubCmd()} + + def get_help_string(self) -> str: + return 'Manage Wi-Fi network connection for TBR.' + + async def execute_default(self, args, context): + print('Invalid usage. Provide a subcommand.') + return CommandResultNone() + + +class TbrRebootSubCmd(Command): + + def get_help_string(self) -> str: + return 'Reboot the TBR.' + + async def execute_default(self, args, context): + bless: BleStreamSecure = context['ble_sstream'] + + cmd = TLV(TcatTLVType.APPLICATION.value, bytes('reboot', 'ascii')).to_bytes() + + response = await bless.send_with_resp(cmd) + if not response: + return + + tlv_response = TLV.from_bytes(response) + if tlv_response.value.decode("ascii").find("RESP_FAIL") != -1: + print('Command execution fail\n') + + return CommandResultTLV(tlv_response) + + +class TbrCommand(Command): + + def __init__(self): + self._subcommands = {'reboot': TbrRebootSubCmd()} + + def get_help_string(self) -> str: + return 'Manage TBR.' + + async def execute_default(self, args, context): + print('Invalid usage. Provide a subcommand.') + return CommandResultNone() diff --git a/tools/tcat_ble_client/cli/cli.py b/tools/tcat_ble_client/cli/cli.py index bfe6cd3d1f..dfc4bdd0c8 100644 --- a/tools/tcat_ble_client/cli/cli.py +++ b/tools/tcat_ble_client/cli/cli.py @@ -29,7 +29,7 @@ import readline import shlex from ble.ble_stream_secure import BleStreamSecure -from cli.base_commands import (HelpCommand, HelloCommand, CommissionCommand, ThreadStateCommand, ScanCommand) +from cli.base_commands import (HelpCommand, HelloCommand, CommissionCommand, ThreadStateCommand, ScanCommand, TbrWiFiCommand, TbrCommand) from cli.dataset_commands import (DatasetCommand) from dataset.dataset import ThreadDataset from typing import Optional @@ -45,6 +45,8 @@ def __init__(self, dataset: ThreadDataset, ble_sstream: Optional[BleStreamSecure 'dataset': DatasetCommand(), 'thread': ThreadStateCommand(), 'scan': ScanCommand(), + 'wifi': TbrWiFiCommand(), + 'tbr' : TbrCommand(), } self._context = {'ble_sstream': ble_sstream, 'dataset': dataset, 'commands': self._commands} readline.set_completer(self.completer)