From 32174171687dbd8398061cfe5a35405868a94a2b Mon Sep 17 00:00:00 2001 From: Dohyun Pyun Date: Wed, 23 Feb 2022 13:30:36 +0900 Subject: [PATCH 2/9] Initial commit for thread CAPI Change-Id: I139bbbc03acc77127d04f82f8081adf0ffd90a85 Signed-off-by: Dohyun Pyun --- AUTHORS | 1 + CMakeLists.txt | 112 ++++ LICENSE | 202 +++++++ NOTICE | 3 + README.md | 1 + capi-network-thread.pc.in | 14 + include/thread-dbus-handler.h | 104 ++++ include/thread-log.h | 60 ++ include/thread-private.h | 385 +++++++++++++ include/thread-socket-handler.h | 63 ++ include/thread-type.h | 219 +++++++ include/thread.h | 830 +++++++++++++++++++++++++++ packaging/capi-network-thread-devel.manifest | 5 + packaging/capi-network-thread.manifest | 5 + packaging/capi-network-thread.spec | 91 +++ src/thread-br.c | 527 +++++++++++++++++ src/thread-commissioner.c | 92 +++ src/thread-core.c | 572 ++++++++++++++++++ src/thread-dbus-handler.c | 559 ++++++++++++++++++ src/thread-joiner.c | 127 ++++ src/thread-network.c | 414 +++++++++++++ src/thread-socket-handler.c | 286 +++++++++ src/thread-srp.c | 237 ++++++++ src/thread-util.c | 251 ++++++++ tests/CMakeLists.txt | 31 + tests/thread-br.c | 520 +++++++++++++++++ tests/thread-commissioner.c | 86 +++ tests/thread-core.c | 394 +++++++++++++ tests/thread-init.c | 48 ++ tests/thread-joiner.c | 129 +++++ tests/thread-main.c | 128 +++++ tests/thread-menu.c | 333 +++++++++++ tests/thread-menu.h | 177 ++++++ tests/thread-network.c | 244 ++++++++ tests/thread-srp.c | 245 ++++++++ tests/thread-util.c | 124 ++++ tests/thread-util.h | 63 ++ 37 files changed, 7682 insertions(+) create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100755 LICENSE create mode 100755 NOTICE create mode 100644 README.md create mode 100755 capi-network-thread.pc.in create mode 100644 include/thread-dbus-handler.h create mode 100755 include/thread-log.h create mode 100755 include/thread-private.h create mode 100644 include/thread-socket-handler.h create mode 100755 include/thread-type.h create mode 100644 include/thread.h create mode 100755 packaging/capi-network-thread-devel.manifest create mode 100755 packaging/capi-network-thread.manifest create mode 100644 packaging/capi-network-thread.spec create mode 100644 src/thread-br.c create mode 100644 src/thread-commissioner.c create mode 100644 src/thread-core.c create mode 100644 src/thread-dbus-handler.c create mode 100644 src/thread-joiner.c create mode 100644 src/thread-network.c create mode 100644 src/thread-socket-handler.c create mode 100644 src/thread-srp.c create mode 100755 src/thread-util.c create mode 100755 tests/CMakeLists.txt create mode 100644 tests/thread-br.c create mode 100644 tests/thread-commissioner.c create mode 100755 tests/thread-core.c create mode 100755 tests/thread-init.c create mode 100644 tests/thread-joiner.c create mode 100755 tests/thread-main.c create mode 100755 tests/thread-menu.c create mode 100755 tests/thread-menu.h create mode 100644 tests/thread-network.c create mode 100644 tests/thread-srp.c create mode 100644 tests/thread-util.c create mode 100644 tests/thread-util.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..f949861 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Anupam Roy diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a9da0bc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,112 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "capi-network-thread") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +SET(dependents "dlog glib-2.0 gio-2.0 gio-unix-2.0 gobject-2.0 gmodule-2.0 capi-base-common capi-system-info") +SET(pc_dependents "capi-base-common glib-2.0") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") + + +SET(SOURCES +src/thread-core.c +src/thread-br.c +src/thread-joiner.c +src/thread-network.c +src/thread-commissioner.c +src/thread-srp.c +src/thread-util.c +src/thread-dbus-handler.c +src/thread-socket-handler.c +) + +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) + +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/network + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) + +CONFIGURE_FILE( + capi-network-thread.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + +#ADD_SUBDIRECTORY(tests/test) +#ADD_SUBDIRECTORY(tests/unittest) + +ADD_SUBDIRECTORY(tests) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) + diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/NOTICE b/NOTICE new file mode 100755 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a20725a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +This is Thread CAPI library for Tizen diff --git a/capi-network-thread.pc.in b/capi-network-thread.pc.in new file mode 100755 index 0000000..85a129a --- /dev/null +++ b/capi-network-thread.pc.in @@ -0,0 +1,14 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@/network + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} + diff --git a/include/thread-dbus-handler.h b/include/thread-dbus-handler.h new file mode 100644 index 0000000..28b6a25 --- /dev/null +++ b/include/thread-dbus-handler.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __TIZEN_CAPI_NETWORK_THREAD_DBUS_HANDLER_H__ +#define __TIZEN_CAPI_NETWORK_THREAD_DBUS_HANDLER_H__ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define THREAD_EVENT_NAME "PropertiesChanged" +#define THREAD_EVENT_INTERFACE "org.freedesktop.DBus.Properties" +#define THREAD_EVENT_PATH "/io/openthread/BorderRouter/wpan0" + +#define THREAD_DBUS_SCAN_METHOD "Scan" +#define THREAD_DBUS_ATTACH_METHOD "Attach" +#define THREAD_DBUS_DETACH_METHOD "Detach" +#define THREAD_DBUS_FACTORY_RESET_METHOD "FactoryReset" +#define THREAD_DBUS_RESET_METHOD "Reset" +#define THREAD_DBUS_ADD_ON_MESH_PREFIX_METHOD "AddOnMeshPrefix" +#define THREAD_DBUS_REMOVE_ON_MESH_PREFIX_METHOD "RemoveOnMeshPrefix" +#define THREAD_DBUS_PERMIT_UNSECURE_JOIN_METHOD "PermitUnsecureJoin" +#define THREAD_DBUS_JOINER_START_METHOD "JoinerStart" +#define THREAD_DBUS_JOINER_STOP_METHOD "JoinerStop" +#define THREAD_DBUS_ADD_EXTERNAL_ROUTE_METHOD "AddExternalRoute" +#define THREAD_DBUS_REMOVE_EXTERNAL_ROUTE_METHOD "RemoveExternalRoute" + +#define THREAD_DBUS_PROPERTY_MESH_LOCAL_PREFIX "MeshLocalPrefix" +#define THREAD_DBUS_PROPERTY_LEGACY_ULA_PREFIX "LegacyULAPrefix" +#define THREAD_DBUS_PROPERTY_LINK_MODE "LinkMode" +#define THREAD_DBUS_PROPERTY_DEVICE_ROLE "DeviceRole" +#define THREAD_DBUS_PROPERTY_NETWORK_NAME "NetworkName" +#define THREAD_DBUS_PROPERTY_PANID "PanId" +#define THREAD_DBUS_PROPERTY_EXTPANID "ExtPanId" +#define THREAD_DBUS_PROPERTY_CHANNEL "Channel" +#define THREAD_DBUS_PROPERTY_NETWORK_KEY "NetworkKey" +#define THREAD_DBUS_PROPERTY_CCA_FAILURE_RATE "CcaFailureRate" +#define THREAD_DBUS_PROPERTY_LINK_COUNTERS "LinkCounters" +#define THREAD_DBUS_PROPERTY_IP6_COUNTERS "Ip6Counters" +#define THREAD_DBUS_PROPERTY_SUPPORTED_CHANNEL_MASK "LinkSupportedChannelMask" +#define THREAD_DBUS_PROPERTY_RLOC16 "Rloc16" +#define THREAD_DBUS_PROPERTY_EXTENDED_ADDRESS "ExtendedAddress" +#define THREAD_DBUS_PROPERTY_ROUTER_ID "RouterID" +#define THREAD_DBUS_PROPERTY_LEADER_DATA "LeaderData" +#define THREAD_DBUS_PROPERTY_NETWORK_DATA_PRPOERTY "NetworkData" +#define THREAD_DBUS_PROPERTY_STABLE_NETWORK_DATA_PRPOERTY "StableNetworkData" +#define THREAD_DBUS_PROPERTY_LOCAL_LEADER_WEIGHT "LocalLeaderWeight" +#define THREAD_DBUS_PROPERTY_CHANNEL_MONITOR_SAMPLE_COUNT "ChannelMonitorSampleCount" +#define THREAD_DBUS_PROPERTY_CHANNEL_MONITOR_ALL_CHANNEL_QUALITIES "ChannelMonitorAllChannelQualities" +#define THREAD_DBUS_PROPERTY_CHILD_TABLE "ChildTable" +#define THREAD_DBUS_PROPERTY_NEIGHBOR_TABLE_PROEPRTY "NeighborTable" +#define THREAD_DBUS_PROPERTY_PARTITION_ID_PROEPRTY "PartitionID" +#define THREAD_DBUS_PROPERTY_INSTANT_RSSI "InstantRssi" +#define THREAD_DBUS_PROPERTY_RADIO_TX_POWER "RadioTxPower" +#define THREAD_DBUS_PROPERTY_EXTERNAL_ROUTES "ExternalRoutes" +#define THREAD_DBUS_PROPERTY_ACTIVE_DATASET_TLVS "ActiveDatasetTlvs" +#define THREAD_DBUS_PROPERTY_RADIO_REGION "RadioRegion" + + +typedef void (*thread_async_request_cb)(gboolean res, const char *method, GVariant *val, void *user_data); + +int _thread_dbus_init(void); + +int _thread_dbus_deinit(void); + +int _thread_dbus_register_event(const char *event_name, const char *interface, + const char *path, GDBusSignalCallback event_callback, void *user_data); + +int _thread_dbus_register_event_helper(); + +int _thread_dbus_unregister_event(const char *event_name); + +int _thread_dbus_sync_method_call(const char *method_name, GVariant *parameters); + +int _thread_dbus_async_method_call(const char *method_name, GVariant *parameters, + thread_async_request_cb method_cb, void *user_data); + +int _thread_dbus_set_property(const char *property_name, GVariant *parameter); + +int _thread_dbus_get_property(const char *property_name, GVariant **outparam); + +#ifdef __cplusplus +} +#endif +#endif /* __TIZEN_CAPI_NETWORK_THREAD_DBUS_HANDLER_H__ */ diff --git a/include/thread-log.h b/include/thread-log.h new file mode 100755 index 0000000..bba55b1 --- /dev/null +++ b/include/thread-log.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __TIZEN_CAPI_NETWORK_THREAD_LOG_H__ +#define __TIZEN_CAPI_NETWORK_THREAD_LOG_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "CAPI_NETWORK_THREAD" + +#define LOG_COLOR_RESET "\033[0m" +#define LOG_COLOR_RED "\033[31m" +#define LOG_COLOR_YELLOW "\033[33m" +#define LOG_COLOR_GREEN "\033[32m" +#define LOG_COLOR_BLUE "\033[36m" +#define LOG_COLOR_PURPLE "\033[35m" + +#define THREAD_DBG(fmt, args...) \ + SLOGD(fmt, ##args) +#define THREAD_INFO(fmt, args...) \ + SLOGI(fmt, ##args) +#define THREAD_INFO_C(fmt, arg...) \ + SLOGI_IF(TRUE, LOG_COLOR_GREEN" "fmt" "LOG_COLOR_RESET, ##arg) +#define THREAD_WARN(fmt, arg...) \ + SLOGI_IF(TRUE, LOG_COLOR_YELLOW" "fmt" "LOG_COLOR_RESET, ##arg) +#define THREAD_ERR(fmt, arg...) \ + SLOGI_IF(TRUE, LOG_COLOR_RED" "fmt" "LOG_COLOR_RESET, ##arg) + +#define THREAD_DEPRECATED_LOG(origin, substitution) \ + SLOGI("DEPRECATION WARNING: %s() is deprecated and will be removed " \ + "from next release. Use %s() instead.", origin, substitution) + +#define FUNC_ENTRY THREAD_DBG("+") +#define FUNC_EXIT THREAD_DBG("-") + +#ifdef __cplusplus +} +#endif +#endif /* __TIZEN_CAPI_NETWORK_THREAD_LOG_H__ */ diff --git a/include/thread-private.h b/include/thread-private.h new file mode 100755 index 0000000..c6ae2e1 --- /dev/null +++ b/include/thread-private.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __TIZEN_CAPI_NETWORK_THREAD_PRIVATE_H__ +#define __TIZEN_CAPI_NETWORK_THREAD_PRIVATE_H__ + + +#include +#include +#include + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define THREAD_MAX_BUFFER_SIZE 1024 +#define THREAD_DAEMON_MAX_LOG_LEVEL 5 + +/** + * @brief Returns if expr is true. + * @since_tizen 7.0 + */ +#define ret_if(expr) \ + do { \ + if (expr) { \ + THREAD_DBG("(%s) return", #expr); \ + return; \ + } \ + } while (0) + +/** + * @brief Returns val if expr is true. + * @since_tizen 7.0 + */ +#define retv_if(expr, val) \ + do { \ + if (expr) { \ + THREAD_DBG("(%s) return", #expr); \ + return (val); \ + } \ + } while (0) + +/** + * @brief Returns error code If not initialized. + * @since_tizen 7.0 + */ +#define THREAD_CHECK_INIT_STATUS() \ + retv_if(TRUE != _thread_is_initialized(), THREAD_ERROR_NOT_INITIALIZED); + +/** + * @brief Returns error code if expr is NULL. + * @since_tizen 7.0 + */ +#define THREAD_VALIDATE_INPUT_PARAMETER(arg) \ + if (arg == NULL) { \ + THREAD_ERR("INVALID_PARAMETER(%s is NULL)", #arg); \ + return THREAD_ERROR_INVALID_PARAMETER; \ + } + +/** + * @brief Returns error code if expr is NULL. + * @since_tizen 7.0 + */ +#define THREAD_IS_EXIST(arg) \ + if (arg == NULL) { \ + THREAD_ERR("THREAD_ERROR_NOT_FOUND(%s is NULL)", #arg); \ + return THREAD_ERROR_NOT_FOUND; \ + } + +/** + * @brief Checks if h1 is not in the list. + * @since_tizen 7.0 + */ +#define THREAD_VALIDATE_HANDLE(h1, list) \ + { \ + GSList *l; \ + bool valid = FALSE; \ + for (l = list; l; l = g_slist_next(l)) { \ + void *h2 = (void *)l->data; \ + if (h1 == h2) { \ + THREAD_INFO("Handle matched [%p]", h2); \ + valid = TRUE; break; \ + } \ + } \ + if (valid == FALSE) { \ + THREAD_ERR("Handle [%p] did not match with any stored handles!!", h1); \ + return THREAD_ERROR_INVALID_PARAMETER; \ + } \ + } \ + +/** + * @brief Returns true if h1 is in the list, else return false. + * @since_tizen 7.0 + */ +#define THREAD_EXIST_HANDLE(h1, list) \ + { \ + GSList *l; \ + bool valid = FALSE; \ + for (l = list; l; l = g_slist_next(l)) { \ + void *h2 = (void *)l->data; \ + if (h1 == h2) { \ + THREAD_INFO("Handle matched [%p]", h2); \ + valid = TRUE; break; \ + } \ + } \ + if (valid == TRUE) { \ + THREAD_ERR("Handle [%p] match with any stored handles!!", h1); \ + return THREAD_ERROR_ALREADY_DONE; \ + } \ + } \ + +/** + * @brief Feature structure info + * @since_tizen 7.0 + */ +typedef enum { + THREAD_FEATURE_BASE = 0, + THREAD_FEATURE_COMMON = THREAD_FEATURE_BASE, + THREAD_FEATURE_MAX +} thread_feature_t; + +/** + * @brief Thread Feature table structure info. + * @since_tizen 7.0 + */ +typedef struct { + const char *name; + gboolean is_check; + gboolean value; +} thread_feature_table_t; + +/** + * @brief Checks if OT feature is supported in platform + * @since_tizen 7.0 + */ +int _thread_check_supported_feature(thread_feature_t feature, bool *supported); + +#define THREAD_CHECK_SUPPORTED_FEATURE(feature) \ +do { \ + bool is_supported = false; \ + if (!_thread_check_supported_feature(feature, &is_supported)) { \ + if (is_supported == false) { \ + THREAD_ERR("[%s] NOT_SUPPORTED", __FUNCTION__); \ + return THREAD_ERROR_NOT_SUPPORTED; \ + } \ + } else { \ + THREAD_ERR("[%s] Fail to get the system feature: [%d]", __FUNCTION__, feature); \ + } \ +} while (0) + + +/** + * @brief Checks whether thread is initialized or not. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +bool _thread_is_initialized(void); + +/** + * @brief Thread Instance structure info. + * @since_tizen 7.0 + */ +typedef struct { + bool is_thread_started; + bool is_br_enabled; + thread_network_h network; + GSList *route_list; + GSList *onmesh_prefix_list; +} thread_instance_s; + +/** + * @brief Thread Network structure info. + * @since_tizen 7.0 + */ +typedef struct { + bool is_network_active; + char name[THREAD_NETWORK_NAME_MAX + 1]; + char key[THREAD_NETWORK_KEY_STRING_MAX + 1]; + char pskc[THREAD_NETWORK_PSKC_STRING_MAX + 1]; + uint32_t channel; + uint64_t extended_panid; + uint16_t panid; +} thread_network_s; + +/** + * @brief Thread Scan param structure info. + * @since_tizen 7.0 + */ +typedef struct { + uint16_t duration; /*< Duration in millisecond >*/ +} thread_scan_param_info_s; + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Enumerations of thread device type + * @since_tizen 7.0 + */ +typedef struct { + union { + uint8_t m8[THREAD_IPV6_ADDRESS_SIZE]; /*< 8-bit fields */ + uint16_t m16[THREAD_IPV6_ADDRESS_SIZE / sizeof(uint16_t)]; /*< 16-bit fields */ + uint32_t m32[THREAD_IPV6_ADDRESS_SIZE / sizeof(uint32_t)]; /*< *32-bit fields */ + } fields; +} thread_ipv6_address_s; + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @since_tizen 7.0 + * + */ +typedef struct { + union { + uint8_t m8[THREAD_EUI_64_SIZE]; /*< 8-bit fields */ + uint16_t m16[THREAD_EUI_64_SIZE / sizeof(uint16_t)]; /*< 16-bit fields */ + uint32_t m32[THREAD_EUI_64_SIZE / sizeof(uint32_t)]; /*< *32-bit fields */ + } fields; +} thread_eui64_data_s; + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Structure of thread IPV6 prefix information + * @since_tizen 7.0 + */ +typedef struct { + thread_ipv6_address_s ipv6; + uint8_t length; +} thread_ipv6_prefix_s; + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Structure of thread External route information + * @since_tizen 7.0 + */ +typedef struct { + thread_ipv6_prefix_s prefix; + uint16_t rloc16; + int8_t preference; + bool is_stable; + bool is_nexthop_this_device; +} thread_route_info_s; + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Structure of thread On-Mesh Prefix information + * @since_tizen 7.0 + */ +typedef struct { + thread_ipv6_prefix_s prefix; + uint8_t preference; + bool preferred; + bool slaac; + bool dhcp; + bool configure; + bool default_route; + bool on_mesh; + bool stable; +} thread_onmesh_prefix_info_s; + +/** + * @brief Thread callback structure info. + * @since_tizen 7.0 + */ +typedef struct { + const void *callback; /** Callback function pointer */ + void *user_data; /**< user data */ +} thread_callback_s; + +/** + * @brief method type for thread callback. + * @since_tizen 7.0 + */ +typedef enum { + THREAD_METHOD_SCAN = 0, /** scan method */ + THREAD_METHOD_JOIN = 1, /** join method */ + THREAD_DEVICE_ROLE = 2, /** Device role Method */ + THREAD_METHOD_MAX /** Method Max */ +} thread_method_e; + +/** + * @brief Thread dbus method callback. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +void _thread_dbus_method_cb(gboolean res, const char* method, + GVariant *val, gpointer user_data); + +/** + * @brief Saves callback pointer for a method. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +void _thread_add_callback(thread_method_e method, + void *callback, void *user_data); +/** + * @brief Get callback pointer for a method. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +thread_callback_s *_thread_get_callback(thread_method_e method); + +/** + * @brief Convert thread device role from string to enum. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +thread_device_role_e _thread_get_device_role(const char* dev_role); + +/** + * @brief Get current thread socket interface fd. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +int _thread_get_socket_fd(void); + +/** + * @brief Free Thread network. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ + +void _thread_network_free(thread_network_h network); + +/** + * @brief Free Route + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +void _thread_route_free(gpointer data); + +/** + * @brief Free Onmesh prefix + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +void _thread_onmesh_prefix_free(gpointer data); + +#ifdef __cplusplus +} +#endif +#endif /* __TIZEN_CAPI_NETWORK_THREAD_PRIVATE_H__ */ diff --git a/include/thread-socket-handler.h b/include/thread-socket-handler.h new file mode 100644 index 0000000..9c8cdad --- /dev/null +++ b/include/thread-socket-handler.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __TIZEN_CAPI_NETWORK_THREAD_SOCKET_HANDLER_H__ +#define __TIZEN_CAPI_NETWORK_THREAD_SOCKET_HANDLER_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define THREAD_SOCKET_INTERFACE "wpan0" + +#define THREAD_SOCKET_LOG_CMD "log level %d" +#define THREAD_SOCKET_START_CMD "thread start" +#define THREAD_SOCKET_STOP_CMD "thread stop" +#define THREAD_IFCONFIG_UP_CMD "ifconfig up" +#define THREAD_COMMISSIONER_START_CMD "commissioner start" +#define THREAD_BR_ENABLE_CMD "br enable" +#define THREAD_BR_DISABLE_CMD "br disable" +#define THREAD_NETDATA_REGISTER_CMD "netdata register" +#define THREAD_SRP_SERVER_START_CMD "srp server enable" +#define THREAD_SRP_SERVER_STOP_CMD "srp server disable" +#define THREAD_SRP_CLIENT_REGISTER_SERVICE_CMD "srp client service add" +#define THREAD_SRP_CLIENT_SET_HOST_ADDRESS_CMD "srp client host address" +#define THREAD_SRP_CLIENT_SET_HOST_NAME_CMD "srp client host name" +#define THREAD_SRP_CLIENT_REMOVE_HOST_CMD "srp client host remove" +#define THREAD_SRP_CLIENT_STOP_CMD "srp client stop" +#define THREAD_SRP_CLIENT_START_CMD "srp client autostart enable" + +int _thread_socket_client_init(int *session_fd, const char *if_name); + +int _thread_socket_client_deinit(int session_fd); + +int _thread_socket_client_connect(void); + +int _thread_socket_client_execute(int session_fd, const char *cmd_buffer, size_t buf_size); + +int _thread_socket_client_read(int session_fd, char *response_buffer); + +int _thread_socket_client_write(int session_fd, const char *request_buffer, size_t buf_size); + +#ifdef __cplusplus +} +#endif +#endif /* __TIZEN_CAPI_NETWORK_THREAD_SOCKET_HANDLER_H__ */ diff --git a/include/thread-type.h b/include/thread-type.h new file mode 100755 index 0000000..bb0bbe8 --- /dev/null +++ b/include/thread-type.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __TIZEN_CAPI_NETWORK_THREAD_TYPE_H__ +#define __TIZEN_CAPI_NETWORK_THREAD_TYPE_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file thread-type.h + */ + +#ifndef TIZEN_ERROR_THREAD +#define TIZEN_ERROR_THREAD 0x11FF0000 +#endif + +#define THREAD_IPV6_ADDRESS_SIZE 16 /*< Size of an IPv6 address (bytes) */ +#define THREAD_IPV6_ADDRESS_LEN 128 /*< Size of an IPv6 address length (uint8) */ +#define THREAD_IPV6_PREFIX_SIZE 8 /*< Size of an IPv6 prefix size (uint8) */ +#define THREAD_IPV6_PREFIX_LEN 64 /*< Size of an IPv6 prefix length (uint8) */ +#define THREAD_STEERING_DATA_MAX 256 /*< Max length of OT Steering Data`(bytes) */ +#define THREAD_NETWORK_NAME_MAX 256 /*< Max length of OT Network name (bytes) */ +#define THREAD_NETWORK_KEY_STRING_MAX 256 /**< Max length of OT Network key (bytes)*/ +#define THREAD_NETWORK_PSKC_STRING_MAX 256 /**< Max length of OT PSKC (bytes)*/ +#define THREAD_COMMISSIONER_JOINER_BUFFER_MAX 1024 /** +#include +#include +#include +#include + +#include + +#ifndef TIZEN_DEPRECATED_API +#define TIZEN_DEPRECATED_API __attribute__((__visibility__("default"), deprecated)) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** + * @file thread.h + * @brief API to control the Thread adapter and devices and communications. + * @ingroup CAPI_NETWORK_THREAD_MODULE + */ + + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Initializes the thread API. + * @since_tizen 7.0 + * + * @remarks This function must be called before thread API starts. \n + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @see thread_deinitialize() + */ +int thread_initialize(void); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Releases all resources of the thread API. + * @since_tizen 7.0 + * + * @remarks This function must be called if thread API is no longer needed. + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_initialize() + */ +int thread_deinitialize(void); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Enable thread Module + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_initialize() + */ +int thread_enable(thread_instance_h *instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Disable thread Module + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_enable() + */ +int thread_disable(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Start Thread + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_stop() + */ +int thread_start(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Stop Thread + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_start() + */ +int thread_stop(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Perform reset of OT hardware, tries to resume the network after reset + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_enable() + */ +int thread_reset(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Perform Factory reset of OT hardware, wipes all Thread persistent data + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_enable() + */ +int thread_factoryreset(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Get Thread Device Role + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_get_device_role(thread_instance_h instance, thread_device_role_e *device_role); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Set Thread Device Role changed callback + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_set_device_role_changed_cb(thread_instance_h instance, + thread_device_role_cb callback, void *user_data); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Set Thread Device Type + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_set_device_type(thread_instance_h instance, thread_device_type_e device_type); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Get Thread Device Type + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_get_device_type(thread_instance_h instance, thread_device_type_e *device_type); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Create Thread Network Scan param + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_network_scan_result_cb() + */ +int thread_scan_param_create(thread_instance_h instance, + uint16_t duration, thread_scan_param_h *param_handle); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Destroys Thread Network Scan param + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_network_scan_result_cb() + */ +int thread_scan_param_destroy(thread_instance_h instance, + thread_scan_param_h param_handle); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Scan Thread Network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_network_scan_result_cb() + */ +int thread_scan(thread_instance_h instance, thread_scan_param_h handle, + thread_network_scan_result_cb callback, void *user_data); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Gets the extended address + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_get_extended_address(thread_instance_h instance, uint64_t *extended_address); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Gets the extended uuid(EUI-64) of the Thread Device + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_get_extended_uuid(thread_instance_h instance, const char **uuid); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Set Active operational Network dataset + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_active_dataset_tlvs_s + */ +int thread_network_set_active_dataset_tlvs(thread_instance_h instance, + const uint8_t *tlvs_buffer, int length); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Get Active operational Network dataset + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @remarks copy the data returned by buffer. It will go out of scope after API returns + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_active_dataset_tlvs_s + * @see thread_set_active_dataset_tlvs() + */ +int thread_network_get_active_dataset_tlvs(thread_instance_h instance, + uint8_t **tlvs_buffer, int *buf_len); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Attach the OT hardware to the active Operational Network, which is pre-set + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @pre Active Operational Dataset must be set using thread_set_active_dataset_tlvs(). + * + * @see thread_set_active_dataset_tlvs() + */ +int thread_network_attach(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Detach the OT hardware from the active Operational Network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @pre Active Operational Dataset must be attached. + * + * @see thread_network_attach() + */ +int thread_network_detach(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Enable OT Border Routing + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_br_disable() + */ +int thread_br_enable(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Disable OT Border Routing + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_br_enable() + */ +int thread_br_disable(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Get All External Route informations + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_external_route_foreach_cb() + */ +int thread_br_get_external_routes(thread_instance_h instance, + thread_external_route_foreach_cb callback, void *user_data); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Get Route informations + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_external_route_foreach_cb() + */ +int thread_br_get_route_info(thread_route_info_h route, uint8_t *ipv6_prefix, + uint8_t *ipv6_prefix_len, uint16_t *rloc16, int8_t *preference, + bool *is_stable, bool *is_device_nexthop); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Add an external border routing rule to the network. + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_remove_external_route() + */ +int thread_br_add_external_route(thread_instance_h instance, + const uint8_t *ipv6_prefix, uint8_t ipv6_prefix_len, + uint16_t rloc16, int8_t preference, + bool is_stable, bool is_device_nexthop, + thread_route_info_h *route_handle); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Remove an external border routing rule from the network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_add_external_route() + */ +int thread_br_remove_external_route(thread_instance_h instance, thread_route_info_h route_handle); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Add an on-mesh prefix to the network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_remove_onmesh_prefix() + */ +int thread_br_add_onmesh_prefix(thread_instance_h instance, + const uint8_t *ipv6_prefix, int ipv6_prefix_len, int8_t preference, + bool preferred, bool slaac, bool dhcp, bool configure, bool default_route, + bool on_mesh, bool stable, thread_onmesh_prefix_info_h *onmesh_prefix); + +/** + * @ingroup CAPI_NETWORK_THREAD_BORDERROUTER_MODULE + * @brief Remove on-mesh prefix from the network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * + * @see thread_add_onmesh_prefix() + */ +int thread_br_remove_onmesh_prefix(thread_instance_h instance, thread_onmesh_prefix_info_h prefix_info); + +/** + * @ingroup CAPI_NETWORK_THREAD_NETWORK_MODULE + * @brief Form an operational Thread Network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_network_create_operational_network(thread_instance_h instance, + const char *name, const char *key, const char *pskc, uint32_t channel, + uint64_t extended_panid, uint16_t panid, thread_network_h *network); + +/** + * @ingroup CAPI_NETWORK_THREAD_NETWORK_MODULE + * @brief Destroy an operational Thread Network + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_network_create_operational_network() + */ +int thread_network_destroy_operational_network(thread_instance_h instance, thread_network_h network); + +/** + * @ingroup CAPI_NETWORK_THREAD_JOINER_MODULE + * @brief Start Thread joining with detailed informations + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_joiner_stop() + */ +int thread_joiner_start(thread_instance_h instance, + const char *pskd, const char *prov_url, + const char *vendor_name, const char *vendor_model, + const char *vendor_sw_ver, const char *vendor_data, + thread_joiner_result_cb callback, void *user_data); + +/** + * @ingroup CAPI_NETWORK_THREAD_JOINER_MODULE + * @brief Stop Thread Joining + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_joiner_start() + */ +int thread_joiner_stop(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_JOINER_MODULE + * @brief Join Thread Network by Network key (Out-Of-Band Commisioning) + * network key must be obtained by the commissioner via any trusted Out-Of-Band method + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_joiner_join_by_network_key(thread_instance_h instance, const char *network_key, const char *panid); + +/** + * @ingroup CAPI_NETWORK_THREAD_COMMISSIONER_MODULE + * @brief Start thread commissioner (In-Band Commissioning) + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_commissioner_start(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_COMMISSIONER_MODULE + * @brief Set commissioning Data (In-Band Commissioning) + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + */ +int thread_commissioner_set_commisioning_data(thread_instance_h instance, const char *joiner_uuid, + const char *joiner_passphrase); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Start SRP Client + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_stop() + */ +int thread_srp_client_start(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Stop SRP Client + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + */ +int thread_srp_client_stop(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Remove already registered SRP host service + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + */ +int thread_srp_client_remove_host(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Set Host name + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + */ +int thread_srp_client_set_host_name(thread_instance_h instance, const char *host_name); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Set Host address + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + */ +int thread_srp_client_set_host_address(thread_instance_h instance, const char *ipv6_address); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Register Service to SRP server + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + * @see thread_srp_client_set_host_address() + */ +int thread_srp_client_register_service(thread_instance_h instance, + const char *service_name, const char *service_type, uint64_t port); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Start SRP Server + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_server_stop() + */ +int thread_srp_server_start(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Stop SRP Server + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_server_start() + */ +int thread_srp_server_stop(thread_instance_h instance); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Get registered service detail from the SRP server + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_server_start() + */ +int thread_srp_server_get_registered_service(thread_instance_h instance, const char **service_name, + const char **address, uint64_t *port, bool *is_deleted); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Get registered service detail from the SRP server + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_server_start() + */ +int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callback, + thread_ipaddr_type_e ipaddr_type, void *user_data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_NETWORK_THREAD_H__ */ diff --git a/packaging/capi-network-thread-devel.manifest b/packaging/capi-network-thread-devel.manifest new file mode 100755 index 0000000..c00c25b --- /dev/null +++ b/packaging/capi-network-thread-devel.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/capi-network-thread.manifest b/packaging/capi-network-thread.manifest new file mode 100755 index 0000000..c00c25b --- /dev/null +++ b/packaging/capi-network-thread.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/capi-network-thread.spec b/packaging/capi-network-thread.spec new file mode 100644 index 0000000..1309292 --- /dev/null +++ b/packaging/capi-network-thread.spec @@ -0,0 +1,91 @@ +Name: capi-network-thread +Summary: Network Thread Framework +Version: 0.1.0 +Release: 1 +Group: Connectivity/API +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1001: %{name}.manifest +Source1002: %{name}-devel.manifest +#Requires(post): /sbin/ldconfig +#Requires(postun): /sbin/ldconfig + +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(capi-appfw-app-control) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: cmake + +%description +Network Thread Framework + +%package devel +Summary: Network Thread Framework (DEV) +Group: Development/Connectivit +Requires: %{name} = %{version}-%{release} + +%description devel +Network Thread Framework. + +%devel_desc + +%package test +Summary: Network Thread Framework test application +Group: TO_BE/FILLED +Requires: %{name} = %{version}-%{release} + +%description test +This package is for Network Thread Framework CAPI test application + +%prep +%setup -q +cp %{SOURCE1001} %{SOURCE1002} . + +%ifarch aarch64 +echo arch64 +export CFLAGS+=" -DARCH64" +export CXXFLAGS+=" -DARCH64" +export FFLAGS+=" -DARCH64" +%endif + +%ifarch x86_64 +echo x86_64 +export CFLAGS+=" -DARCH64" +export CXXFLAGS+=" -DARCH64" +export FFLAGS+=" -DARCH64" +%endif + +%cmake + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%manifest %{name}.manifest +%license LICENSE +%{_libdir}/libcapi-network-thread.so.* + +%files devel +%manifest %{name}-devel.manifest +%{_includedir}/network/* +%{_libdir}/pkgconfig/%{name}.pc + +%{_libdir}/pkgconfig/capi-network-thread.pc +%{_libdir}/libcapi-network-thread.so + +%files test +%manifest %{name}.manifest +%attr(777,network_fw,network_fw) %{_bindir}/thread-test + diff --git a/src/thread-br.c b/src/thread-br.c new file mode 100644 index 0000000..68010af --- /dev/null +++ b/src/thread-br.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" +#include "thread-type.h" + +extern int _thread_get_socket_fd(); + +void _thread_route_free(gpointer data) +{ + FUNC_ENTRY; + thread_route_info_s *route = data; + + ret_if(NULL == route); + g_free(route); + + FUNC_EXIT; +} + +void _thread_onmesh_prefix_free(gpointer data) +{ + FUNC_ENTRY; + thread_onmesh_prefix_info_s *onmesh_prefix = data; + + ret_if(NULL == onmesh_prefix); + g_free(onmesh_prefix); + + FUNC_EXIT; +} + +thread_route_info_s* _create_new_route(void) +{ + FUNC_ENTRY; + + thread_route_info_s *new_route = NULL; + new_route = g_malloc0(sizeof(thread_route_info_s)); + if (!new_route) { + THREAD_ERR("g_malloc0 failed while allocating new route"); + return NULL; + } + + FUNC_EXIT; + return new_route; +} + +thread_onmesh_prefix_info_s* _create_new_onmesh_prefix(void) +{ + FUNC_ENTRY; + + thread_onmesh_prefix_info_s *new_onmesh_prefix = NULL; + new_onmesh_prefix = g_malloc0(sizeof(thread_onmesh_prefix_info_s)); + if (!new_onmesh_prefix) { + THREAD_ERR("g_malloc0 failed while allocating new_onmesh_prefix"); + return NULL; + } + + FUNC_EXIT; + return new_onmesh_prefix; +} + +static int __thread_br_get_external_route_cb(GVariant *val, + thread_external_route_foreach_cb callback, + thread_instance_s* instance, void *user_data) +{ + FUNC_ENTRY; + THREAD_VALIDATE_INPUT_PARAMETER(callback); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + GVariantIter iter; + uint8_t *prefix_address = NULL; + uint8_t prefix_len = 0; + uint16_t rloc16 = 0; + uint8_t preference = 0; + bool stable = TRUE; + bool next_hop_is_self = TRUE; + int count = 0; + thread_instance_s *current_instance = instance; + + THREAD_DBG("Process callback for get external route"); + g_variant_iter_init(&iter, val); + + while (g_variant_iter_next(&iter, "((ayy)qybb)", + &prefix_address, &prefix_len, &rloc16, &preference, + &stable, &next_hop_is_self)) { + + thread_route_info_s *route_info = _create_new_route(); + + THREAD_DBG("Got the external route..."); + + THREAD_DBG("prefix_address: %02x%02x:%02x%02x:%02x%02x:%02x%02x", + prefix_address[0], prefix_address[1], prefix_address[2], + prefix_address[3], prefix_address[4], prefix_address[5], + prefix_address[6], prefix_address[7]); + + THREAD_DBG("prefix_len: %u", prefix_len); + THREAD_DBG("rloc16: %u", rloc16); + THREAD_DBG("preference: %u", preference); + THREAD_DBG("stable: %s", stable ? "TRUE" : "FALSE"); + THREAD_DBG("next_hop_is_self: %s", next_hop_is_self ? + "TRUE" : "FALSE"); + memcpy((route_info->prefix).ipv6.fields.m8, prefix_address, + THREAD_IPV6_PREFIX_SIZE*sizeof(uint8_t)); + (route_info->prefix).length = prefix_len; + route_info->preference = preference; + route_info->is_stable = stable; + route_info->rloc16 = rloc16; + route_info->is_nexthop_this_device = next_hop_is_self; + current_instance->route_list = g_slist_append( + current_instance->route_list, + route_info); + + if (callback) + (callback)(++count, (thread_route_info_h)route_info, + user_data); + } + THREAD_DBG("Exiting __thread_br_get_external_route_cb ..."); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +/* Thread Border Router functions */ +int thread_br_enable(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + thread_instance_s *current_instance = instance; + retv_if(current_instance->is_br_enabled, THREAD_ERROR_ALREADY_DONE); + + int ret = THREAD_ERROR_NONE; + + /*free and initialize the instance list*/ + g_slist_free_full(current_instance->route_list, _thread_route_free); + current_instance->route_list = NULL; + + g_slist_free_full(current_instance->onmesh_prefix_list, _thread_onmesh_prefix_free); + current_instance->onmesh_prefix_list = NULL; + + /* Enable border router */ + const char *msg = THREAD_BR_ENABLE_CMD; + + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + + current_instance->is_br_enabled = TRUE; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_disable(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + int ret = THREAD_ERROR_NONE; + + /* Disable border router */ + const char *msg = THREAD_BR_DISABLE_CMD; + + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + + /*free and initialize the instance list*/ + g_slist_free_full(current_instance->route_list, _thread_route_free); + current_instance->route_list = NULL; + + g_slist_free_full(current_instance->onmesh_prefix_list, _thread_onmesh_prefix_free); + current_instance->onmesh_prefix_list = NULL; + + current_instance->is_br_enabled = FALSE; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_get_external_routes(thread_instance_h instance, + thread_external_route_foreach_cb callback, void *user_data) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(callback); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + int ret = THREAD_ERROR_NONE; + GVariant *out = NULL; + + ret = _thread_dbus_get_property( + THREAD_DBUS_PROPERTY_EXTERNAL_ROUTES, &out); + retv_if(ret != THREAD_ERROR_NONE, ret); + + g_slist_free_full(current_instance->route_list, _thread_route_free); + current_instance->route_list = NULL; + + __thread_br_get_external_route_cb(out, callback, + current_instance, user_data); + + g_variant_unref(out); + THREAD_DBG("Freed out..."); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_get_route_info(thread_route_info_h route, + uint8_t *ipv6_prefix, uint8_t *ipv6_prefix_len, + uint16_t *rloc16, int8_t *preference, bool *is_stable, + bool *is_device_nexthop) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(route); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_prefix); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_prefix_len); + THREAD_VALIDATE_INPUT_PARAMETER(rloc16); + THREAD_VALIDATE_INPUT_PARAMETER(preference); + THREAD_VALIDATE_INPUT_PARAMETER(is_stable); + THREAD_VALIDATE_INPUT_PARAMETER(is_device_nexthop); + + thread_route_info_s *route_info = (thread_route_info_s*)route; + memcpy(ipv6_prefix, (route_info->prefix).ipv6.fields.m8, + THREAD_IPV6_PREFIX_SIZE*sizeof(uint8_t)); + *ipv6_prefix_len = (route_info->prefix).length; + *rloc16 = route_info->rloc16; + *preference = route_info->preference; + *is_stable = route_info->is_stable; + *is_device_nexthop = route_info->is_nexthop_this_device; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_add_external_route(thread_instance_h instance, + const uint8_t *ipv6_prefix, uint8_t ipv6_prefix_len, + uint16_t rloc16, int8_t preference, + bool is_stable, bool is_device_nexthop, + thread_route_info_h *route_handle) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_prefix); + THREAD_VALIDATE_INPUT_PARAMETER(route_handle); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + retv_if(ipv6_prefix_len > THREAD_IPV6_PREFIX_LEN, + THREAD_ERROR_INVALID_PARAMETER); + + char msg[THREAD_BORDER_ROUTER_BUFFER_MAX]; + snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX, + "route add %02x%02x:%02x%02x:%02x%02x:%02x%02x::/%u", + ipv6_prefix[0], ipv6_prefix[1], ipv6_prefix[2], ipv6_prefix[3], + ipv6_prefix[4], ipv6_prefix[5], ipv6_prefix[6], ipv6_prefix[7], + ipv6_prefix_len); + + if (is_stable) + strcat(msg, " s"); + + if (preference == 0) + strcat(msg, " low"); + else if (preference == 1) + strcat(msg, " med"); + else if (preference == 2) + strcat(msg, " high"); + + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + int ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully added route"); + + const char *msg2 = THREAD_NETDATA_REGISTER_CMD; + THREAD_DBG("DEBUG: NETDATA MESSAGE -> [%s]", msg2); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg2, strlen(msg2)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully registered netdata"); + + thread_route_info_s* new_route = _create_new_route(); + memcpy((new_route->prefix).ipv6.fields.m8, ipv6_prefix, + THREAD_IPV6_PREFIX_SIZE*sizeof(uint8_t)); + (new_route->prefix).length = ipv6_prefix_len; + new_route->preference = preference; + new_route->is_stable = is_stable; + new_route->rloc16 = rloc16; + new_route->is_nexthop_this_device = is_device_nexthop; + + current_instance->route_list = g_slist_append( + current_instance->route_list, + new_route); + *route_handle = (thread_route_info_h)new_route; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_remove_external_route(thread_instance_h instance, + thread_route_info_h route_info) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(route_info); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + thread_route_info_s* route = (thread_route_info_s*)route_info; + uint8_t *ipv6_prefix = (route->prefix).ipv6.fields.m8; + uint8_t ipv6_prefix_len = (route->prefix).length; + + retv_if(ipv6_prefix_len > THREAD_IPV6_PREFIX_LEN, + THREAD_ERROR_INVALID_PARAMETER); + + char msg[THREAD_BORDER_ROUTER_BUFFER_MAX]; + snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX, + "route remove %02x%02x:%02x%02x:%02x%02x:%02x%02x::/%u", + ipv6_prefix[0], ipv6_prefix[1], ipv6_prefix[2], ipv6_prefix[3], + ipv6_prefix[4], ipv6_prefix[5], ipv6_prefix[6], ipv6_prefix[7], + ipv6_prefix_len); + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + int ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully removed route data"); + + const char *msg2 = THREAD_NETDATA_REGISTER_CMD; + THREAD_DBG("DEBUG: NETDATA MESSAGE -> [%s]", msg2); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg2, strlen(msg2)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully registered netdata"); + + current_instance->route_list = g_slist_remove( + current_instance->route_list, + route); + g_free(route); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_add_onmesh_prefix(thread_instance_h instance, + const uint8_t *ipv6_prefix, int ipv6_prefix_len, int8_t preference, + bool preferred, bool slaac, bool dhcp, bool configure, bool default_route, + bool on_mesh, bool stable, thread_onmesh_prefix_info_h *onmesh_prefix) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_prefix); + THREAD_VALIDATE_INPUT_PARAMETER(onmesh_prefix); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + retv_if(ipv6_prefix_len > THREAD_IPV6_PREFIX_LEN, + THREAD_ERROR_INVALID_PARAMETER); + + char msg[THREAD_BORDER_ROUTER_BUFFER_MAX]; + snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX, + "prefix add %02x%02x:%02x%02x:%02x%02x:%02x%02x::/%u", + ipv6_prefix[0], ipv6_prefix[1], ipv6_prefix[2], ipv6_prefix[3], + ipv6_prefix[4], ipv6_prefix[5], ipv6_prefix[6], ipv6_prefix[7], + ipv6_prefix_len); + + if (preference == 0) + strcat(msg, " low "); + else if (preference == 1) + strcat(msg, " med "); + else if (preference == 2) + strcat(msg, " high "); + + if (preferred) + strcat(msg, "p"); + if (slaac) + strcat(msg, "a"); + if (configure) + strcat(msg, "c"); + if (default_route) + strcat(msg, "r"); + if (on_mesh) + strcat(msg, "o"); + if (stable) + strcat(msg, "s"); + + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + int ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully added onmesh prefix"); + + const char *msg2 = THREAD_NETDATA_REGISTER_CMD; + THREAD_DBG("DEBUG: NETDATA MESSAGE -> [%s]", msg2); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg2, strlen(msg2)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully registered netdata"); + + thread_onmesh_prefix_info_s* new_onmesh_prefix = + _create_new_onmesh_prefix(); + memcpy((new_onmesh_prefix->prefix).ipv6.fields.m8, ipv6_prefix, + THREAD_IPV6_PREFIX_SIZE*sizeof(uint8_t)); + (new_onmesh_prefix->prefix).length = ipv6_prefix_len; + new_onmesh_prefix->preference = preference; + new_onmesh_prefix->preferred = preferred; + new_onmesh_prefix->slaac = slaac; + new_onmesh_prefix->dhcp = dhcp; + new_onmesh_prefix->configure = configure; + new_onmesh_prefix->default_route = default_route; + new_onmesh_prefix->on_mesh = on_mesh; + new_onmesh_prefix->stable = stable; + + current_instance->onmesh_prefix_list = g_slist_append( + current_instance->onmesh_prefix_list, + new_onmesh_prefix); + + *onmesh_prefix = (thread_onmesh_prefix_info_h)new_onmesh_prefix; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_br_remove_onmesh_prefix(thread_instance_h instance, + thread_onmesh_prefix_info_h prefix_info) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(prefix_info); + + thread_instance_s *current_instance = instance; + retv_if(!current_instance->is_br_enabled, THREAD_ERROR_NOT_ENABLED); + + thread_onmesh_prefix_info_s* onmesh_prefix = + (thread_onmesh_prefix_info_s*)prefix_info; + uint8_t *ipv6_prefix = (onmesh_prefix->prefix).ipv6.fields.m8; + uint8_t ipv6_prefix_len = (onmesh_prefix->prefix).length; + + retv_if(ipv6_prefix_len > THREAD_IPV6_PREFIX_LEN, + THREAD_ERROR_INVALID_PARAMETER); + + char msg[THREAD_BORDER_ROUTER_BUFFER_MAX]; + snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX, + "prefix remove %02x%02x:%02x%02x:%02x%02x:%02x%02x::/%u", + ipv6_prefix[0], ipv6_prefix[1], ipv6_prefix[2], ipv6_prefix[3], + ipv6_prefix[4], ipv6_prefix[5], ipv6_prefix[6], ipv6_prefix[7], + ipv6_prefix_len); + THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); + int ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + + if (ret == THREAD_ERROR_NONE) { + THREAD_DBG("Successfully added onmesh prefix"); + const char *msg2 = THREAD_NETDATA_REGISTER_CMD; + THREAD_DBG("DEBUG: NETDATA MESSAGE -> [%s]", msg2); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg2, strlen(msg2)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully registered netdata"); + } else { + THREAD_ERR("Failed to add onmesh prefix"); + return ret; + } + + current_instance->onmesh_prefix_list = g_slist_remove( + current_instance->onmesh_prefix_list, + onmesh_prefix); + g_free(onmesh_prefix); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} diff --git a/src/thread-commissioner.c b/src/thread-commissioner.c new file mode 100644 index 0000000..4ee4788 --- /dev/null +++ b/src/thread-commissioner.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" +#include "thread-type.h" + +extern int _thread_get_socket_fd(); + +/* LCOV_EXCL_START */ +int thread_commissioner_start(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + + /* Start Commissioner */ + const char *msg = THREAD_COMMISSIONER_START_CMD; + + THREAD_DBG("DEBUG: COMMISSIONER MESSAGE -> [%s]", msg); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_commissioner_set_commisioning_data(thread_instance_h instance, + const char *joiner_uuid, + const char *joiner_passphrase) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(joiner_passphrase); + + int joiner_passphrase_len = strlen(joiner_passphrase); + int joiner_uuid_len = strlen(joiner_uuid); + + retv_if(joiner_passphrase_len < 6 || joiner_passphrase_len > 32, THREAD_ERROR_INVALID_PARAMETER); + retv_if(joiner_uuid_len > 16, THREAD_ERROR_INVALID_PARAMETER); + + int ret = THREAD_ERROR_NONE; + + if (!joiner_uuid || !strcmp(joiner_uuid, "")) + joiner_uuid = "*"; + + char msg[THREAD_COMMISSIONER_JOINER_BUFFER_MAX]; + snprintf(msg, THREAD_COMMISSIONER_JOINER_BUFFER_MAX, + "commissioner joiner add %s %s", joiner_uuid, joiner_passphrase); + + THREAD_DBG("DEBUG: COMMISSIONER MESSAGE -> [%s]", msg); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + + FUNC_EXIT; + return THREAD_ERROR_NONE; + +} diff --git a/src/thread-core.c b/src/thread-core.c new file mode 100644 index 0000000..e3ebad6 --- /dev/null +++ b/src/thread-core.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" + +static GSList *instances; /* thread_instance_h */ +static gboolean is_initialized = FALSE; + +static void __thread_free_instance(thread_instance_h instance) +{ + FUNC_ENTRY; + ret_if(!instance); + + thread_instance_s *current_instance = instance; + _thread_network_free(current_instance->network); + + g_slist_free_full(current_instance->route_list, _thread_route_free); + g_slist_free_full(current_instance->onmesh_prefix_list, _thread_onmesh_prefix_free); + + g_free(instance); + + FUNC_EXIT; +} + +static void __thread_release_all_resources(void) +{ + FUNC_ENTRY; + + /* Free all instances */ + GSList *l; + for (l = instances; l; l = g_slist_next(l)) + __thread_free_instance(l->data); + + g_slist_free(instances); + instances = NULL; + + FUNC_EXIT; +} + +int thread_initialize(void) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + + THREAD_DBG("Initialize Thread capi"); + retv_if(TRUE == is_initialized, THREAD_ERROR_ALREADY_DONE); + int ret = THREAD_ERROR_NONE; + + /* Init Dbus interface */ + ret = _thread_dbus_init(); + retv_if(ret != THREAD_ERROR_NONE, ret); + + /* Register dbus event */ + ret = _thread_dbus_register_event_helper(); + retv_if(ret != THREAD_ERROR_NONE, ret); + + /* Init socket interface */ + ret = _thread_socket_client_connect(); + retv_if(ret != THREAD_ERROR_NONE, ret); + + is_initialized = TRUE; + THREAD_DBG("Thread capi initialized successfully !!"); + + /* Set log level for thread daemon */ + char msg[THREAD_MAX_BUFFER_SIZE] = {0}; + snprintf(msg, sizeof(msg), THREAD_SOCKET_LOG_CMD, + THREAD_DAEMON_MAX_LOG_LEVEL); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Failed to set thread daemon log level"); + return THREAD_ERROR_NONE; + } + + FUNC_EXIT; + return ret; +} + +int thread_deinitialize(void) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + int ret = THREAD_ERROR_NONE; + + THREAD_DBG("De-initialize Thread capi"); + is_initialized = FALSE; + + /* Release all resources */ + __thread_release_all_resources(); + + /* Unregister dbus event */ + ret = _thread_dbus_unregister_event(THREAD_EVENT_NAME); + if (ret != THREAD_ERROR_NONE) + THREAD_ERR("Unregister Thread Event failed"); + + /* De-init Dbus interface */ + ret = _thread_dbus_deinit(); + if (ret != THREAD_ERROR_NONE) + THREAD_ERR("Thread dbus de-init failed"); + + /* De-init socket interface */ + ret = _thread_socket_client_deinit(_thread_get_socket_fd()); + if (ret != THREAD_ERROR_NONE) + THREAD_ERR("Thread socket de-init failed"); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_enable(thread_instance_h *instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + + thread_instance_s *new_instance = NULL; + new_instance = g_malloc0(sizeof(thread_instance_s)); + if (!new_instance) { + /* LCOV_EXCL_START */ + THREAD_ERR("g_malloc0 failed"); + return THREAD_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + new_instance->is_thread_started = FALSE; + new_instance->network = NULL; + new_instance->route_list = NULL; + new_instance->onmesh_prefix_list = NULL; + new_instance->is_br_enabled = FALSE; + + *instance = (thread_instance_h)new_instance; + instances = g_slist_append(instances, + (thread_instance_h)new_instance); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_disable(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + /*update GSList of instances */ + instances = g_slist_remove(instances, instance); + + __thread_free_instance(instance); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +static int __thread_ifconfig_up(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* ifconfig up */ + const char *msg = THREAD_IFCONFIG_UP_CMD; + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + if (ret == THREAD_ERROR_NONE) + THREAD_DBG("Thread: ifconfig up successful"); + + FUNC_EXIT; + return ret; +} + +int thread_start(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + thread_instance_s *current_instance = instance; + retv_if(current_instance->is_thread_started, THREAD_ERROR_ALREADY_DONE); + + /* ifconfig up */ + ret = __thread_ifconfig_up(instance); + if (ret != THREAD_ERROR_NONE) + THREAD_DBG("Thread: ifconfig up failed"); + + /* Start Thread */ + const char *msg = THREAD_SOCKET_START_CMD; + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + current_instance->is_thread_started = TRUE; + + FUNC_EXIT; + return ret; +} + +int thread_stop(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + thread_instance_s *current_instance = instance; + retv_if(!(current_instance->is_thread_started), + THREAD_ERROR_NOT_IN_PROGRESS); + + /* Stop Thread */ + const char *msg = THREAD_SOCKET_STOP_CMD; + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + + current_instance->is_thread_started = FALSE; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_reset(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + ret = _thread_dbus_sync_method_call(THREAD_DBUS_RESET_METHOD, + g_variant_new("()")); + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Thread Reset failed"); + return ret; + } + THREAD_DBG("Thread Reset successful"); + + FUNC_EXIT; + return ret; +} + +int thread_factoryreset(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + ret = _thread_dbus_sync_method_call( + THREAD_DBUS_FACTORY_RESET_METHOD, g_variant_new("()")); + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Thread FactoryReset failed"); + return ret; + } + THREAD_DBG("Thread FactoryReset successful"); + + /* Update current active network */ + thread_instance_s *current_instance = instance; + thread_network_s *network = current_instance->network; + if (network && network->is_network_active) + network->is_network_active = FALSE; + + FUNC_EXIT; + return ret; +} + +int thread_get_device_role(thread_instance_h instance, + thread_device_role_e *device_role) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(device_role); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + GVariant *out = NULL; + + /* get "DeviceRole" dbus property */ + ret = _thread_dbus_get_property( + THREAD_DBUS_PROPERTY_DEVICE_ROLE, &out); + retv_if(ret != THREAD_ERROR_NONE, ret); + + /* update device role */ + const gchar *dev_role = g_variant_get_string(out, NULL); + *device_role = _thread_get_device_role(dev_role); + THREAD_DBG("Thread device role %d: %s", + *device_role, dev_role); + g_variant_unref(out); + + FUNC_EXIT; + return ret; +} + + +int thread_set_device_role_changed_cb(thread_instance_h instance, + thread_device_role_cb callback, void *user_data) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + THREAD_DBG("Save application callback pointer"); + _thread_add_callback(THREAD_DEVICE_ROLE, callback, user_data); + + FUNC_EXIT; + return ret; +} + +int thread_get_device_type(thread_instance_h instance, + thread_device_type_e *device_type) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(device_type); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + thread_device_role_e device_role; + *device_type = THREAD_DEVICE_TYPE_NOT_SUPPORTED; + + /* Get device role */ + ret = thread_get_device_role(instance, &device_role); + retv_if(ret != THREAD_ERROR_NONE, THREAD_ERROR_OPERATION_FAILED); + + switch (device_role) { + case THREAD_DEVICE_ROLE_DISABLED: + case THREAD_DEVICE_ROLE_DETACHED: + THREAD_DBG("Thread device type is not supported"); + *device_type = THREAD_DEVICE_TYPE_NOT_SUPPORTED; + break; + case THREAD_DEVICE_ROLE_LEADER: + case THREAD_DEVICE_ROLE_ROUTER: + THREAD_DBG("Thread device type is Router"); + *device_type = THREAD_DEVICE_TYPE_ROUTER; + break; + case THREAD_DEVICE_ROLE_CHILD: + THREAD_DBG("Thread device role: child, check device-type.."); + GVariant *out = NULL; + gboolean rx_on_when_idle = TRUE; + gboolean dev_type = TRUE; /*TRUE for FTD, FALSE otherwise*/ + gboolean network_data = TRUE; + + /* get "LinkMode" dbus property */ + ret = _thread_dbus_get_property(THREAD_DBUS_PROPERTY_LINK_MODE, &out); + retv_if(ret != THREAD_ERROR_NONE, ret); + + g_variant_get(out, "(bbb)", &rx_on_when_idle, + &dev_type, &network_data); + THREAD_DBG("Link Mode:: rx_on_when_idle: %d dev_type: %d" \ + " network_data: %d", rx_on_when_idle, + dev_type, network_data); + g_variant_unref(out); + + if (!rx_on_when_idle) { + *device_type = THREAD_DEVICE_TYPE_SLEEPY_END_DEVICE; + THREAD_DBG("thread device type:: sleepy end device"); + } else { + *device_type = dev_type ? THREAD_DEVICE_TYPE_FULL_END_DEVICE : + THREAD_DEVICE_TYPE_MINIMAL_END_DEVICE; + THREAD_DBG("thread device type:: [%s]", + dev_type ? "full end device" : "minimal end device"); + } + break; + default: + THREAD_ERR("Unknown thread device role"); + return THREAD_ERROR_OPERATION_FAILED; + } + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_set_device_type(thread_instance_h instance, + thread_device_type_e device_type) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + thread_device_role_e device_role; + + /* check device role */ + ret = thread_get_device_role(instance, &device_role); + retv_if(ret != THREAD_ERROR_NONE, THREAD_ERROR_OPERATION_FAILED); + + if (device_role == THREAD_DEVICE_ROLE_DISABLED || + device_role == THREAD_DEVICE_ROLE_DETACHED) { + THREAD_ERR("Thread device type:: not supported, can not be set"); + return THREAD_ERROR_OPERATION_FAILED; + } else if (device_role == THREAD_DEVICE_ROLE_LEADER || + device_role == THREAD_DEVICE_ROLE_ROUTER) { + THREAD_ERR("Thread device type:: router, can not be set"); + return THREAD_ERROR_OPERATION_FAILED; + } + + gboolean rx_on_when_idle = TRUE; + gboolean dev_type = TRUE; /*TRUE for FTD, FALSE otherwise*/ + gboolean network_data = TRUE; + + if (device_type == THREAD_DEVICE_TYPE_MINIMAL_END_DEVICE) { + dev_type = FALSE; + network_data = FALSE; + } else if (device_type == THREAD_DEVICE_TYPE_SLEEPY_END_DEVICE) { + rx_on_when_idle = FALSE; + dev_type = FALSE; + network_data = FALSE; + } + + /* set "LinkMode" dbus property */ + ret = _thread_dbus_set_property(THREAD_DBUS_PROPERTY_LINK_MODE, + g_variant_new("(bbb)", rx_on_when_idle, + dev_type, network_data)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Thread set device type successful"); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_scan_param_create(thread_instance_h instance, + uint16_t duration, thread_scan_param_h *param_handle) +{ + FUNC_ENTRY; + thread_scan_param_info_s *scan_param = NULL; + + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(param_handle); + + scan_param = g_malloc0(sizeof(thread_scan_param_info_s)); + if (!scan_param) { + /* LCOV_EXCL_START */ + THREAD_ERR("g_malloc0 failed"); + return THREAD_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + scan_param->duration = duration; + *param_handle = (thread_scan_param_h)scan_param; + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_scan_param_destroy(thread_instance_h instance, + thread_scan_param_h param_handle) +{ + FUNC_ENTRY; + thread_scan_param_info_s *scan_param = NULL; + + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(param_handle); + scan_param = (thread_scan_param_info_s*) param_handle; + g_free(scan_param); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_scan(thread_instance_h instance, + thread_scan_param_h param_handle, + thread_network_scan_result_cb callback, void *user_data) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(param_handle); + THREAD_VALIDATE_INPUT_PARAMETER(callback); + + int ret = THREAD_ERROR_NONE; + + ret = _thread_dbus_async_method_call(THREAD_DBUS_SCAN_METHOD, + g_variant_new("()"), _thread_dbus_method_cb, NULL); + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Thread Scan failed"); + return ret; + } + THREAD_DBG("Thread Scan started..."); + + THREAD_DBG("Save application callback pointer"); + _thread_add_callback(THREAD_METHOD_SCAN, callback, user_data); + + /* Send scanning started callback */ + (callback)(ret, THREAD_SCANNING_STARTED, 0, NULL, 0, NULL, + 0, 0, 0, 0, 0, 0, 0, 0, 0, user_data); + FUNC_EXIT; + return ret; +} + +int thread_get_extended_address(thread_instance_h instance, uint64_t *extended_address) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(extended_address); + + int ret = THREAD_ERROR_NONE; + GVariant *out = NULL; + + /* get "ExtendedAddress" dbus property */ + ret = _thread_dbus_get_property( + THREAD_DBUS_PROPERTY_EXTENDED_ADDRESS, &out); + retv_if(ret != THREAD_ERROR_NONE, ret); + + g_variant_get(out, "t", extended_address); + THREAD_DBG("Thread extended address: %llu", *extended_address); + g_variant_unref(out); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_get_extended_uuid(thread_instance_h instance, + const char **uuid) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_VALIDATE_INPUT_PARAMETER(uuid); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + FUNC_EXIT; + return THREAD_ERROR_NOT_SUPPORTED; +} + +bool _thread_is_initialized(void) +{ + return is_initialized; +} diff --git a/src/thread-dbus-handler.c b/src/thread-dbus-handler.c new file mode 100644 index 0000000..6796cf8 --- /dev/null +++ b/src/thread-dbus-handler.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "thread-type.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" + + +#define OPENTHREAD_DBUS_SERVICE "io.openthread.BorderRouter.wpan0" +#define OPENTHREAD_DBUS_SERVICE_PATH "/io/openthread/BorderRouter/wpan0" +#define OPENTHREAD_DBUS_SERVICE_INTERFACE "io.openthread.BorderRouter" +#define OPENTHREAD_DBUS_SERVICE_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" + +/* Global declarations */ +static GDBusConnection *g_system_connection = NULL; +static GDBusProxy *g_method_proxy = NULL; +static GDBusProxy *g_property_proxy = NULL; + +/* For cancelling async dbus requests */ +static GCancellable *register_cancel; + +/* For caching all registered events */ +static GSList *events = NULL; + +/* For caching all dbus async requests */ +static GSList *requests = NULL; + +typedef struct { + int event_id; + char *event_name; +} thread_event_data_t; + +typedef struct { + char *user_method; + thread_async_request_cb user_cb; + void *user_data; +} thread_dbus_async_data_t; + +static int __compare_string(gconstpointer a, gconstpointer b) +{ + const char *s1 = (const char *)((thread_event_data_t*)a)->event_name; + const char *s2 = b; + + return g_strcmp0(s1, s2); +} + +static void __thread_dbus_event_handler(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + FUNC_ENTRY; + GVariantIter valueIter; + GVariant *val = NULL; + GVariant *val1 = NULL; + char *property = NULL; + + THREAD_DBG("Received Thread dbus event..."); + THREAD_DBG("Sender name [%s]", sender_name); + THREAD_DBG("Object path [%s]", object_path); + THREAD_DBG("Interface name [%s]", interface_name); + THREAD_DBG("Signal name [%s]", signal_name); + + if (0 != strcasecmp(object_path, THREAD_EVENT_PATH)) + return; + + if (0 != strcasecmp(interface_name, THREAD_EVENT_INTERFACE)) + return; + + g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &val, NULL); + + thread_callback_s *cb_data = _thread_get_callback(THREAD_DEVICE_ROLE); + + g_variant_iter_init(&valueIter, val); + while ((g_variant_iter_loop(&valueIter, "{sv}", &property, &val1))) { + if (property == NULL || val1 == NULL) + continue; + THREAD_DBG("Property Name [%s]", property); + + if (strcasecmp(property, "DeviceRole") == 0) { + const gchar *devrole = NULL; + g_variant_get(val1, "s", &devrole); + thread_device_type_e dev_role = _thread_get_device_role(devrole); + THREAD_DBG("Device Role Changed to [%s]", devrole); + + if (cb_data && cb_data->callback) { + THREAD_DBG("Called device role callback funtion"); + ((thread_device_role_cb)(cb_data->callback))(dev_role, + user_data); + THREAD_DBG("Thread device role %d: %s", + dev_role, devrole); + return; + } + } + /* TODO : Handle more properties */ + } + + FUNC_EXIT; +} + +static GDBusProxy *__thread_dbus_get_method_proxy(void) +{ + GDBusProxy *proxy; + GError *err = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, + OPENTHREAD_DBUS_SERVICE, + OPENTHREAD_DBUS_SERVICE_PATH, + OPENTHREAD_DBUS_SERVICE_INTERFACE, + NULL, &err); + if (!proxy) { + if (err) { + THREAD_ERR("Unable to create proxy: %s", err->message); + g_clear_error(&err); + } + + return NULL; + } + + THREAD_INFO("Got OpenThread System Bus Proxy"); + return proxy; +} + +static GDBusProxy *__thread_dbus_get_thread_property_proxy(GDBusConnection *conn) +{ + GDBusProxy *proxy; + + retv_if(conn == NULL, NULL); + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, + OPENTHREAD_DBUS_SERVICE, + OPENTHREAD_DBUS_SERVICE_PATH, + OPENTHREAD_DBUS_SERVICE_PROPERTIES_INTERFACE, + NULL, NULL); + + if (!proxy) { + THREAD_ERR("Unable to create property proxy"); + return NULL; + } + + THREAD_INFO("Got OpenThread Property Interface Proxy"); + return proxy; +} + +int _thread_dbus_init(void) +{ + FUNC_ENTRY; + + if (g_system_connection != NULL && g_method_proxy != NULL && g_property_proxy != NULL) { + THREAD_INFO("Initialization already done!"); + FUNC_EXIT; + return THREAD_ERROR_NONE; + } + + /* Get System Bus Connection */ + if (g_system_connection == NULL) { + GError *error = NULL; + g_system_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if (error) { + THREAD_ERR("GDBus connection Error : %s \n", error->message); + g_clear_error(&error); + goto fail; + } + } + + /* Get OT Service Interface Proxy */ + if (g_method_proxy == NULL) { + g_method_proxy = __thread_dbus_get_method_proxy(); + if (!g_method_proxy) + goto fail; + } + /* Get OT Service Property Interface Proxy */ + if (g_property_proxy == NULL) { + g_property_proxy = __thread_dbus_get_thread_property_proxy(g_system_connection); + if (!g_property_proxy) + goto fail; + } + + FUNC_EXIT; + return THREAD_ERROR_NONE; + +fail: + /* Clear connection & aquired proxies */ + if (g_system_connection) { + g_object_unref(g_system_connection); + g_system_connection = NULL; + } + if (g_method_proxy) { + g_object_unref(g_method_proxy); + g_method_proxy = NULL; + } + if (g_property_proxy) { + g_object_unref(g_property_proxy); + g_property_proxy = NULL; + } + FUNC_EXIT; + return THREAD_ERROR_OPERATION_FAILED; +} + +int _thread_dbus_deinit(void) +{ + FUNC_ENTRY; + GSList *l; + + if (g_system_connection == NULL || + g_method_proxy == NULL || + g_property_proxy == NULL) { + THREAD_INFO("Initialization not yet done..."); + FUNC_EXIT; + return THREAD_ERROR_NONE; + } + + if (register_cancel) { + g_cancellable_cancel(register_cancel); + g_object_unref(register_cancel); + register_cancel = NULL; + } + + for (l = requests; l;) { + thread_dbus_async_data_t *req = l->data; + l = g_slist_next(l); + g_free(req->user_method); + g_free(req); + } + requests = NULL; + + for (l = events; l;) { + thread_event_data_t *event = l->data; + l = g_slist_next(l); + g_dbus_connection_signal_unsubscribe(g_system_connection, event->event_id); + g_free(event->event_name); + g_free(event); + } + events = NULL; + + /* Clear connection & aquired proxies */ + g_object_unref(g_system_connection); + g_system_connection = NULL; + g_object_unref(g_method_proxy); + g_method_proxy = NULL; + g_object_unref(g_property_proxy); + g_property_proxy = NULL; + + THREAD_INFO("Deinitialization Done!"); + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_dbus_register_event(const char *event_name, const char *interface, + const char *path, GDBusSignalCallback event_callback, void *user_data) +{ + FUNC_ENTRY; + thread_event_data_t *event_data = NULL; + GSList *l = NULL; + THREAD_INFO("Event Name [%s] Interface name [%s] Path [%s]", event_name, interface, path); + + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + l = g_slist_find_custom(events, event_name, + (GCompareFunc)__compare_string); + retv_if(l != NULL, THREAD_ERROR_NONE); /* Return success, when already Done */ + + event_data = g_malloc0(sizeof(thread_event_data_t)); + retv_if(event_data == NULL, THREAD_ERROR_OUT_OF_MEMORY); + + event_data->event_name = g_strdup(event_name); + retv_if(event_data->event_name == NULL, THREAD_ERROR_OUT_OF_MEMORY); + + /* Register event */ + event_data->event_id = g_dbus_connection_signal_subscribe(g_system_connection, + NULL, interface, NULL, + path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, + event_callback, user_data, NULL); + + events = g_slist_append(events, event_data); + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_dbus_register_event_helper() +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + + const char *event_name = THREAD_EVENT_NAME; + const char *interface = THREAD_EVENT_INTERFACE; + const char *path = THREAD_EVENT_PATH; + GDBusSignalCallback event_func = __thread_dbus_event_handler; + + ret = _thread_dbus_register_event(event_name, interface, + path, event_func, NULL); + retv_if(ret != THREAD_ERROR_NONE, ret); + + FUNC_EXIT; + return ret; +} + +int _thread_dbus_unregister_event(const char *event_name) +{ + FUNC_ENTRY; + thread_event_data_t *event_data = NULL; + GSList *l = NULL; + THREAD_INFO("Unregister Thread Event Name [%s]", event_name); + + retv_if(event_name == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + + l = g_slist_find_custom(events, event_name, + (GCompareFunc)__compare_string); + retv_if(l == NULL, THREAD_ERROR_INVALID_PARAMETER); + + event_data = (thread_event_data_t*)l->data; + g_dbus_connection_signal_unsubscribe(g_system_connection, event_data->event_id); + + events = g_slist_remove(events, event_data); + g_free(event_data->event_name); + g_free(event_data); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_dbus_sync_method_call(const char *method_name, GVariant *parameters) +{ + FUNC_ENTRY; + GError *err = NULL; + GVariant *ret; + + retv_if(method_name == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(parameters == NULL, THREAD_ERROR_INVALID_PARAMETER); + + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + retv_if(g_method_proxy == NULL, THREAD_ERROR_OPERATION_FAILED); + + THREAD_INFO("Invoke Sync Method [%s]", method_name); + + ret = g_dbus_proxy_call_sync(g_method_proxy, + method_name, + parameters, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err); + + if (err) { + THREAD_ERR("Sync DBUS call failed"); + g_dbus_error_strip_remote_error(err); + g_clear_error(&err); + return THREAD_ERROR_OPERATION_FAILED; + } else if (!ret) { + THREAD_ERR("Sync Method Call failed to get result!"); + return THREAD_ERROR_OPERATION_FAILED; + } + + g_variant_unref(ret); + THREAD_INFO("Sync call successful"); + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +static void __thread_async_dbus_cb(GObject *object, GAsyncResult *res, gpointer cb_data) +{ + FUNC_ENTRY; + GVariant *value; + GError *error = NULL; + thread_dbus_async_data_t *async_data = (thread_dbus_async_data_t*)cb_data; + THREAD_INFO("Got Async callback: Method [%s]", async_data->user_method); + + if (register_cancel) { + g_object_unref(register_cancel); + register_cancel = NULL; + } + + value = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), res, &error); + + if (value == NULL) { + THREAD_ERR("Dbus-RPC is failed"); + if (error != NULL) { + THREAD_ERR("D-Bus API failure: errCode[%x], message[%s]", + error->code, error->message); + g_clear_error(&error); + } + if (async_data->user_cb) + async_data->user_cb(false, async_data->user_method, value, async_data->user_data); + } else { + THREAD_INFO("Aysnc call successful"); + if (async_data->user_cb) + async_data->user_cb(true, async_data->user_method, value, async_data->user_data); + + /* value should be cloned by user */ + g_variant_unref(value); + } + requests = g_slist_remove(requests, async_data); + g_free(async_data->user_method); + g_free(async_data); + + FUNC_EXIT; +} + +int _thread_dbus_async_method_call(const char *method_name, GVariant *parameters, + thread_async_request_cb method_cb, void *user_data) +{ + thread_dbus_async_data_t *async_data = NULL; + GSList *l = NULL; + THREAD_INFO("Invoke Async Method [%s]", method_name); + + retv_if(method_name == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(parameters == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(method_cb == NULL, THREAD_ERROR_INVALID_PARAMETER); + + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + retv_if(g_method_proxy == NULL, THREAD_ERROR_OPERATION_FAILED); + + l = g_slist_find_custom(requests, method_name, + (GCompareFunc)__compare_string); + retv_if(l != NULL, THREAD_ERROR_NOW_IN_PROGRESS); + + THREAD_INFO("Invoke Async Method [%s]", method_name); + + async_data = g_malloc0(sizeof(thread_dbus_async_data_t)); + retv_if(async_data == NULL, THREAD_ERROR_OPERATION_FAILED); + + async_data->user_cb = method_cb; + async_data->user_data = user_data; + async_data->user_method = g_strdup(method_name); + + if (register_cancel) { + g_cancellable_cancel(register_cancel); + g_object_unref(register_cancel); + } + register_cancel = g_cancellable_new(); + g_dbus_proxy_call(g_method_proxy, + method_name, + parameters, + G_DBUS_CALL_FLAGS_NONE, + -1, + register_cancel, + (GAsyncReadyCallback)__thread_async_dbus_cb, + (gpointer)async_data); + + requests = g_slist_append(requests, async_data); + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_dbus_get_property(const char *property_name, GVariant **outparam) +{ + FUNC_ENTRY; + GError *err = NULL; + GVariant *result = NULL; + GVariant *value = NULL; + + retv_if(property_name == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(outparam == NULL, THREAD_ERROR_INVALID_PARAMETER); + + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + retv_if(g_property_proxy == NULL, THREAD_ERROR_OPERATION_FAILED); + + THREAD_INFO("Invoke [%s] Get property Handler...", property_name); + + result = g_dbus_proxy_call_sync(g_property_proxy, + "Get", + g_variant_new("(ss)", + OPENTHREAD_DBUS_SERVICE_INTERFACE, + property_name), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err); + + if (!result) { + THREAD_ERR("Error occured in Get PropertyGet Call"); + if (err != NULL) { + THREAD_ERR("Error (Error: %s)", err->message); + g_clear_error(&err); + } + return THREAD_ERROR_OPERATION_FAILED; + } else { + THREAD_INFO("Get property Successful"); + g_variant_get(result, "(v)", &value); + /* Application must unref the value */ + *outparam = value; + g_variant_unref(result); + } + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_dbus_set_property(const char *property_name, GVariant *parameter) +{ + FUNC_ENTRY; + GError *err = NULL; + GVariant *result = NULL; + + retv_if(property_name == NULL, THREAD_ERROR_INVALID_PARAMETER); + retv_if(parameter == NULL, THREAD_ERROR_INVALID_PARAMETER); + + retv_if(g_system_connection == NULL, THREAD_ERROR_OPERATION_FAILED); + retv_if(g_property_proxy == NULL, THREAD_ERROR_OPERATION_FAILED); + + THREAD_INFO("Invoke [%s] Set property Handler...", property_name); + + result = g_dbus_proxy_call_sync(g_property_proxy, + "Set", + g_variant_new("(ssv)", + OPENTHREAD_DBUS_SERVICE_INTERFACE, + property_name, + parameter), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err); + + if (!result) { + THREAD_ERR("Error occured in Set PropertyGet Call"); + if (err != NULL) { + THREAD_ERR("Error (Error: %s)", err->message); + g_clear_error(&err); + } + return THREAD_ERROR_OPERATION_FAILED; + } else { + THREAD_INFO("Set property Successful"); + g_variant_unref(result); + } + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} diff --git a/src/thread-joiner.c b/src/thread-joiner.c new file mode 100644 index 0000000..5ff4bc0 --- /dev/null +++ b/src/thread-joiner.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" +/* LCOV_EXCL_START */ + +/* Out-Band-Commissioning: Get Network key/operational dataset from out-of-band methods */ +int thread_joiner_join_by_network_key(thread_instance_h instance, + const char *network_key, const char* panid) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(network_key); + int ret = THREAD_ERROR_NONE; + char *set_network_key = "dataset networkkey"; + char *set_panid = "dataset panid"; + + char buf[THREAD_MAX_BUFFER_SIZE]; + snprintf(buf, sizeof(buf), "%s %s", set_network_key, network_key); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), buf, strlen(buf)); + retv_if(ret != THREAD_ERROR_NONE, ret); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("socket dataset networkkey execute failed"); + return ret; + } + THREAD_DBG("socket dataset networkkey execute successful"); + + ret = THREAD_ERROR_NONE; + buf[0] = '\0'; + snprintf(buf, sizeof(buf), "%s %s", set_panid, panid); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), buf, strlen(buf)); + retv_if(ret != THREAD_ERROR_NONE, ret); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("socket dataset panid execute failed"); + return ret; + } + THREAD_DBG("socket dataset panid execute successful"); + + FUNC_EXIT; + return ret; +} + + +int thread_joiner_start(thread_instance_h instance, + const char *pskd, const char *prov_url, + const char *vendor_name, const char *vendor_model, + const char *vendor_sw_ver, const char *vendor_data, + thread_joiner_result_cb callback, void *user_data) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(pskd); + THREAD_VALIDATE_INPUT_PARAMETER(prov_url); + THREAD_VALIDATE_INPUT_PARAMETER(vendor_name); + THREAD_VALIDATE_INPUT_PARAMETER(vendor_model); + THREAD_VALIDATE_INPUT_PARAMETER(vendor_sw_ver); + THREAD_VALIDATE_INPUT_PARAMETER(vendor_data); + + int ret = _thread_dbus_async_method_call(THREAD_DBUS_JOINER_START_METHOD, + g_variant_new("(ssssss)", pskd, prov_url, vendor_name, vendor_model, + vendor_sw_ver, vendor_data), _thread_dbus_method_cb, NULL); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("Thread JoinerStart failed"); + return ret; + } + THREAD_DBG("Thread JoinerStart successful"); + + THREAD_DBG("Save application callback pointer"); + _thread_add_callback(THREAD_METHOD_JOIN, callback, user_data); + FUNC_EXIT; + return ret; +} + + +int thread_joiner_stop(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + /* Joiner Stop */ + int ret = THREAD_ERROR_NONE; + ret = _thread_dbus_sync_method_call(THREAD_DBUS_JOINER_STOP_METHOD, + g_variant_new("()")); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("Thread Stop failed"); + return ret; + } + THREAD_DBG("Thread Stop successful"); + FUNC_EXIT; + return ret; +} diff --git a/src/thread-network.c b/src/thread-network.c new file mode 100644 index 0000000..5cec98c --- /dev/null +++ b/src/thread-network.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" + +/* LCOV_EXCL_START */ + +void _thread_network_free(thread_network_h network) +{ + FUNC_ENTRY; + if (!network) + return; + + g_free(network); + + FUNC_EXIT; +} + +/* Network leader/Creator */ +int thread_network_create_operational_network(thread_instance_h instance, + const char *name, const char *key, const char *pskc, uint32_t channel, + uint64_t extended_panid, uint16_t panid, thread_network_h *network) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(name); + THREAD_VALIDATE_INPUT_PARAMETER(key); + THREAD_VALIDATE_INPUT_PARAMETER(pskc); + THREAD_VALIDATE_INPUT_PARAMETER(network); + + retv_if(strlen(name) > THREAD_NETWORK_NAME_MAX, + THREAD_ERROR_INVALID_PARAMETER); + retv_if(strlen(key) > THREAD_NETWORK_KEY_STRING_MAX, + THREAD_ERROR_INVALID_PARAMETER); + retv_if(strlen(pskc) > THREAD_NETWORK_PSKC_STRING_MAX, + THREAD_ERROR_INVALID_PARAMETER); + + THREAD_DBG("Network Name: %s", name); + THREAD_DBG("Network key: %s", key); + THREAD_DBG("Network pskc: %s", pskc); + THREAD_DBG("Network channel: 0x%8.8x", channel); + THREAD_DBG("Network extended_panid: %llu", extended_panid); + THREAD_DBG("Network panid: %u", panid); + + /* Free existing current network */ + thread_instance_s *current_instance = instance; + _thread_network_free(current_instance->network); + current_instance->network = NULL; + + /* Create New Network */ + thread_network_s *new_network = NULL; + new_network = g_malloc0(sizeof(thread_network_s)); + if (!new_network) { + /* LCOV_EXCL_START */ + THREAD_ERR("g_malloc0 failed"); + return THREAD_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + new_network->is_network_active = FALSE; + g_strlcpy(new_network->name, name, THREAD_NETWORK_NAME_MAX + 1); + g_strlcpy(new_network->key, key, THREAD_NETWORK_KEY_STRING_MAX + 1); + g_strlcpy(new_network->pskc, pskc, THREAD_NETWORK_PSKC_STRING_MAX + 1); + new_network->channel = channel; + new_network->extended_panid = extended_panid; + new_network->panid = panid; + *network = (thread_network_h)new_network; + + current_instance->network = *network; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_network_destroy_operational_network(thread_instance_h instance, + thread_network_h network) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(network); + + thread_instance_s *current_instance = instance; + thread_network_s *current_network = network; + + if (current_network->is_network_active) { + THREAD_DBG("Thread network active, can't be destroyed:: \ + First Reset the Network"); + return THREAD_ERROR_OPERATION_FAILED; + } + + _thread_network_free(current_network); + current_network = NULL; + current_instance->network = NULL; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int thread_network_set_active_dataset_tlvs(thread_instance_h instance, + const uint8_t *tlvs_buffer, int buf_length) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer); + + int ret = THREAD_ERROR_NONE; + GBytes *bytes = NULL; + GVariant *value = NULL; + + /* Print input data */ + char buf[THREAD_MAX_BUFFER_SIZE]; + for (int i = 0; i < buf_length; i++) + sprintf(buf + i*2, "%2.2x", tlvs_buffer[i]); + THREAD_DBG("Active dataset tlvs size: %d :: %s", buf_length, buf); + + bytes = g_bytes_new(tlvs_buffer, buf_length); + if (bytes == NULL) { + ret = THREAD_ERROR_OPERATION_FAILED; + goto exit; + } + + value = g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, bytes, true); + if (value == NULL) { + ret = THREAD_ERROR_OPERATION_FAILED; + goto exit; + } + + /* set "ActiveDatasetTlvs" dbus property */ + ret = _thread_dbus_set_property( + THREAD_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, value); + if (ret != THREAD_ERROR_NONE) { + ret = THREAD_ERROR_OPERATION_FAILED; + goto exit; + } + THREAD_DBG("Thread set active dataset tlvs successful"); + +exit: + if (value) + g_variant_unref(value); + if (bytes) + g_bytes_unref(bytes); + + FUNC_EXIT; + return ret; +} + +int thread_network_get_active_dataset_tlvs(thread_instance_h instance, + uint8_t **tlvs_buffer, int *buf_len) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer); + THREAD_VALIDATE_INPUT_PARAMETER(buf_len); + + /* get "ActiveDatasetTlvs" */ + int ret = THREAD_ERROR_NONE; + char buffer[THREAD_MAX_BUFFER_SIZE]; + + int session_fd = _thread_get_socket_fd(); + char cmd_buffer[THREAD_NETWORK_BUFFER_MAX]; + int index; + + snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "dataset active -x"); + + THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer); + + ret = _thread_socket_client_write(session_fd, cmd_buffer, strlen(cmd_buffer)); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("Failed to execute command %s", cmd_buffer); + return ret; + } + THREAD_DBG("Executed command '%s' with size %d", cmd_buffer, strlen(cmd_buffer)); + + /* Check response */ + ret = _thread_socket_client_read(session_fd, buffer); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("Socket response failed.."); + return ret; + } + + *tlvs_buffer = g_malloc0(THREAD_MAX_BUFFER_SIZE*sizeof(uint8_t)); + index = 0; + while (index < THREAD_MAX_BUFFER_SIZE) { + if (buffer[index] == 'D') + break; + + (*tlvs_buffer)[index] = (uint8_t)buffer[index]; + index++; + } + *buf_len = index; + + FUNC_EXIT; + return ret; +} + +static int __thread_attach_active_network() +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + + THREAD_DBG("Attach current active network dataset"); + ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD, + g_variant_new("()")); + if (ret != THREAD_ERROR_NONE) + THREAD_ERR("Thread Attach failed"); + else + THREAD_DBG("Thread Attach successful"); + + return ret; + + FUNC_EXIT; +} + +int thread_network_attach(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + thread_instance_s *current_instance = instance; + thread_network_s *network = current_instance->network; + + if (!network) { + ret = __thread_attach_active_network(); + goto done; + } + + /* Network Info */ + THREAD_DBG("Network Name: %s", network->name); + THREAD_DBG("Network key: %s", network->key); + THREAD_DBG("Network pskc: %s", network->pskc); + THREAD_DBG("Network channel: 0x%8.8x", network->channel); + + THREAD_DBG("Network extended_panid: %llu", network->extended_panid); + if (network->extended_panid == UINT64_MAX) + THREAD_DBG("extended_panid is UINT64_MAX, "\ + "Random extended_panid will be used"); + + THREAD_DBG("Network panid: %u", network->panid); + if (network->panid == UINT16_MAX) + THREAD_DBG("panid is UINT16_MAX, Random panid will be used"); + + THREAD_DBG("Network is_active: %s", + network->is_network_active ? "Active" : "Not Active"); + + if (network->is_network_active) { + ret = __thread_attach_active_network(); + goto done; + } + + THREAD_DBG("Attach the current device to Thread Network"); + /* Network key builder */ + GVariantBuilder *key_builder; + key_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + THREAD_DBG("key str length: %d", strlen(network->key)); + for (int i = 0; i < strlen(network->key); i++) { + g_variant_builder_add(key_builder, "y", + (unsigned char)network->key[i]); + } + + /* pskc builder */ + GVariantBuilder *pskc_builder; + pskc_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + THREAD_DBG("pskc str length: %d", strlen(network->pskc)); + for (int i = 0; i < strlen(network->pskc); i++) { + g_variant_builder_add(pskc_builder, "y", + (unsigned char)network->pskc[i]); + } + + THREAD_DBG("Thread dbus sync call..."); + ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD, + g_variant_new("(ayqstayu)", key_builder, network->panid, + network->name, network->extended_panid, pskc_builder, network->channel)); + + g_variant_builder_unref(key_builder); + g_variant_builder_unref(pskc_builder); + + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Thread Attach failed"); + goto done; + } + network->is_network_active = TRUE; + + THREAD_DBG("Thread Attach successful"); + +done: + FUNC_EXIT; + return ret; +} + +int thread_network_detach(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NOT_SUPPORTED; + + + FUNC_EXIT; + return ret; +} + +int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callback, + thread_ipaddr_type_e ipaddr_type, void *user_data) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + char buffer[THREAD_MAX_BUFFER_SIZE]; + int index = 0; + int pos = 0; + int count = 0; + char ipaddr[THREAD_IPV6_ADDRESS_LEN]; + + int session_fd = _thread_get_socket_fd(); + char cmd_buffer[THREAD_NETWORK_BUFFER_MAX]; + + switch (ipaddr_type) { + case THREAD_IPADDR_TYPE_LINK_LOCAL: + snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr linklocal"); + break; + case THREAD_IPADDR_TYPE_RLOC: + snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr rloc"); + break; + case THREAD_IPADDR_TYPE_MLEID: + snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr mleid"); + break; + default: + snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr"); + } + + size_t buf_size = strlen(cmd_buffer); + + THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer); + + ret = _thread_socket_client_write(session_fd, cmd_buffer, buf_size); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("Failed to execute command %s", cmd_buffer); + return ret; + } + THREAD_DBG("Executed command '%s' with size %d", cmd_buffer, buf_size); + + /* Check response */ + ret = _thread_socket_client_read(session_fd, buffer); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("Socket response failed.."); + return ret; + } + + while (true) { + if ((buffer[index] >= 'a' && buffer[index] <= 'f') || buffer[index] == ':' + || (buffer[index] >= '0' && buffer[index] <= '9')) { + ipaddr[pos++] = buffer[index]; + } else if (buffer[index] == 'D') { + THREAD_DBG("Socket read response buffer: Done"); + break; + } else { + ipaddr[pos] = '\0'; + if (pos > 0) { + THREAD_DBG("IP address: %s, length: %d", ipaddr, + strlen(ipaddr)); + callback(++count, ipaddr, ipaddr_type, user_data); + } + pos = 0; + } + index++; + } + + FUNC_EXIT; + return ret; +} diff --git a/src/thread-socket-handler.c b/src/thread-socket-handler.c new file mode 100644 index 0000000..f198622 --- /dev/null +++ b/src/thread-socket-handler.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include "thread-type.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-socket-handler.h" + +#ifndef OPENTHREAD_POSIX_DAEMON_SOCKET_NAME +#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/run/openthread-%s" +#define OPENTHREAD_POSIX_DAEMON_SOCKET_NAME OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME ".sock" +#endif + +static int g_socket_fd = -1; + +int _thread_get_socket_fd(void) +{ + return g_socket_fd; +} + +int _thread_socket_client_init(int *socket_fd, const char *if_name) +{ + FUNC_ENTRY; + int ret; + struct sockaddr_un sockname; + int session_fd = -1; + + retv_if(!if_name, THREAD_ERROR_INVALID_PARAMETER); + + if (*socket_fd != -1) { + THREAD_DBG("Socket connection already exists"); + return THREAD_ERROR_ALREADY_DONE; + } + + session_fd = socket(AF_UNIX, SOCK_STREAM, 0); + retv_if(session_fd < 0, THREAD_ERROR_OPERATION_FAILED); + + memset(&sockname, 0, sizeof(struct sockaddr_un)); + sockname.sun_family = AF_UNIX; + ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), + OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, if_name); + + retv_if(!(ret >= 0 && (size_t)ret < sizeof(sockname.sun_path)), + THREAD_ERROR_OPERATION_FAILED); + + THREAD_DBG("Connect on socket fd %d path %s", + session_fd, sockname.sun_path); + ret = connect(session_fd, (struct sockaddr*)&sockname, + sizeof(struct sockaddr_un)); + if (ret == -1) { + THREAD_DBG("OpenThread daemon is not running."); + close(session_fd); + return THREAD_ERROR_OPERATION_FAILED; + } + THREAD_DBG("Socket Initialized successfully !"); + *socket_fd = session_fd; + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_socket_client_deinit(int session_fd) +{ + FUNC_ENTRY; + + if (session_fd != -1) + close(session_fd); + + g_socket_fd = -1; + THREAD_DBG("Socket connection closed"); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_socket_client_connect(void) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + + /* Init socket interface */ + ret = _thread_socket_client_init(&g_socket_fd, THREAD_SOCKET_INTERFACE); + retv_if(ret != THREAD_ERROR_NONE, ret); + + FUNC_EXIT; + return ret; +} + +int __thread_socket_client_reconnect(void) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + int delay = 0; + + /* close existing session, if any */ + if (g_socket_fd != -1) + _thread_socket_client_deinit(g_socket_fd); + + /* start with 0 delay, increase to 100ms + and then double every loop */ + for (int i = 0; i < 6; i++) { + usleep(delay); + delay = delay > 0 ? delay * 2 : 100000; + + ret = _thread_socket_client_connect(); + if (ret == THREAD_ERROR_NONE) + goto exit; + } + +exit: + FUNC_EXIT; + return ret; +} + +int _thread_socket_client_read(int session_fd, char *response_buffer) +{ + FUNC_ENTRY; + ssize_t count = 0; + int ret = THREAD_ERROR_NONE; + char buffer[THREAD_MAX_BUFFER_SIZE] = {0}; + size_t response_buffer_pos = 0; + bool is_begin_of_line = true; + + retv_if(!response_buffer, THREAD_ERROR_INVALID_PARAMETER); + + bool is_finished = FALSE; + + while (!is_finished) { + char line_buffer[THREAD_MAX_BUFFER_SIZE] = {0}; + size_t line_buffer_write_pos = 0; + + fd_set read_fd_set; + int max_fd = session_fd; + + FD_ZERO(&read_fd_set); + + FD_SET(session_fd, &read_fd_set); + + int select_ret = select(max_fd + 1, + &read_fd_set, NULL, NULL, NULL); + if (select_ret == -1) { + THREAD_ERR("socket select failed"); + return THREAD_ERROR_OPERATION_FAILED; + } else if (select_ret == 0) { + THREAD_DBG("socket select returned 0"); + return THREAD_ERROR_NONE; + } + + if (!FD_ISSET(session_fd, &read_fd_set)) { + THREAD_ERR("FD_ISSET failed"); + continue; + } + + count = read(session_fd, buffer, sizeof(buffer)); + if (count < 0) { + THREAD_ERR("socket read failed"); + return THREAD_ERROR_OPERATION_FAILED; + } + + if (count == 0) { + /* try socket reconnection */ + THREAD_DBG("Daemon closed session fd, reconnect..."); + ret = __thread_socket_client_reconnect(); + retv_if(ret != THREAD_ERROR_NONE, ret); + + if (ret == THREAD_ERROR_NONE) { + /* retry socket read */ + THREAD_DBG("socket reconnected..."); + continue; + } + } + for (int i = 0; i < count; i++) { + char c = buffer[i]; + line_buffer[line_buffer_write_pos++] = c; + response_buffer[response_buffer_pos++] = c; + + if (c != '\n' + && line_buffer_write_pos < sizeof(line_buffer) - 1) + continue; + + /* read one line successfully or line buffer is full */ + char * line = line_buffer; + size_t len = line_buffer_write_pos; + line[len] = '\0'; + + if (is_begin_of_line && strncmp("> ", line_buffer, 2) == 0) { + line += 2; + len -= 2; + } + + THREAD_DBG("Got buffer %s", line); + + if (is_begin_of_line && (NULL != g_strrstr_len(line_buffer, 5, "Done") + || NULL != g_strrstr(line_buffer, "Done"))) { + THREAD_DBG("Successful socket execution.."); + ret = THREAD_ERROR_NONE; + is_finished = true; + break; + } + if (is_begin_of_line + && NULL != g_strrstr_len(line_buffer, 18, "Error 24: Already")) { + + THREAD_DBG("Already Done"); + ret = THREAD_ERROR_ALREADY_DONE; + is_finished = true; + break; + } + if (is_begin_of_line + && NULL != g_strrstr_len(line_buffer, 6, "Error")) { + + THREAD_DBG("socket execution failed.."); + ret = THREAD_ERROR_OPERATION_FAILED; + is_finished = true; + break; + } + /* reset for next line */ + line_buffer_write_pos = 0; + is_begin_of_line = c == '\n'; + } + } + + FUNC_EXIT; + return ret; +} + +int _thread_socket_client_write(int session_fd, + const char* request_buffer, size_t buf_size) +{ + FUNC_ENTRY; + ssize_t rval; + + if (!request_buffer || buf_size <= 0) + return THREAD_ERROR_INVALID_PARAMETER; + + THREAD_DBG("Socket write command '%s' with size %d", + request_buffer, buf_size); + + rval = write(session_fd, request_buffer, buf_size); + if (rval < buf_size) { + THREAD_ERR("socket write failed"); + return THREAD_ERROR_OPERATION_FAILED; + } + THREAD_DBG("socket write successful"); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + +int _thread_socket_client_execute(int session_fd, + const char *cmd_buffer, size_t buf_size) +{ + FUNC_ENTRY; + char buffer[THREAD_MAX_BUFFER_SIZE]; + + int ret = _thread_socket_client_write(session_fd, + cmd_buffer, buf_size); + retv_if(ret != THREAD_ERROR_NONE, ret); + + /* Check response */ + ret = _thread_socket_client_read(session_fd, buffer); + retv_if(ret != THREAD_ERROR_NONE + && ret != THREAD_ERROR_ALREADY_DONE, ret); + + FUNC_EXIT; + return ret; +} diff --git a/src/thread-srp.c b/src/thread-srp.c new file mode 100644 index 0000000..edb5066 --- /dev/null +++ b/src/thread-srp.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" +/* LCOV_EXCL_START */ + +/* SRP Client & Server */ +int thread_srp_client_start(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + /* Start SRP client */ + const char *msg = THREAD_SRP_CLIENT_START_CMD; + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_start execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_start execute successful"); + FUNC_EXIT; + return ret; +} + +int thread_srp_client_stop(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + /* Stop SRP client */ + const char *msg = THREAD_SRP_CLIENT_STOP_CMD; + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_stop execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_stop execute successful"); + FUNC_EXIT; + return ret; +} + +int thread_srp_client_set_host_name(thread_instance_h instance, + const char *host_name) +{ + + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* Add SRP client host name */ + const char *msg = THREAD_SRP_CLIENT_SET_HOST_NAME_CMD; + char buffer[THREAD_MAX_BUFFER_SIZE]; + snprintf(buffer, sizeof(buffer), "%s %s", msg, host_name); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), buffer, strlen(buffer)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_set_host execute failed"); + return ret; + } + + THREAD_DBG("thread_srp_client_set_host successful"); + FUNC_EXIT; + return ret; +} + +int thread_srp_client_remove_host(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* Remove SRP client host name */ + const char *msg = THREAD_SRP_CLIENT_REMOVE_HOST_CMD; + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_remove_host execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_remove_host execute successdul"); + FUNC_EXIT; + return ret; +} + +int thread_srp_client_set_host_address(thread_instance_h instance, + const char *address) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + + int ret = THREAD_ERROR_NONE; + /* Set SRP client host address */ + const char *msg = THREAD_SRP_CLIENT_SET_HOST_ADDRESS_CMD; + + char buffer[THREAD_MAX_BUFFER_SIZE]; + snprintf(buffer, sizeof(buffer), "%s %s", msg, address); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), buffer, strlen(buffer)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_set_host_address execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_set_host_address execute successful"); + FUNC_EXIT; + return ret; +} + +int thread_srp_client_register_service(thread_instance_h instance, + const char *service_name, const char *service_type, uint64_t port) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_VALIDATE_INPUT_PARAMETER(service_name); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* Register SRP service */ + const char *msg = THREAD_SRP_CLIENT_REGISTER_SERVICE_CMD; + + char buffer[THREAD_MAX_BUFFER_SIZE] = {0}; + snprintf(buffer, sizeof(buffer), "%s %s %s %llu", msg, + service_name, service_type, port); + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + buffer, strlen(buffer)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_register_service execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_register_service execute successful"); + + FUNC_EXIT; + return ret; +} + +int thread_srp_server_start(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* SRP server start */ + const char *msg = THREAD_SRP_SERVER_START_CMD; + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_server_start failed"); + return ret; + } + THREAD_DBG("socket srp_server_start successful"); + + FUNC_EXIT; + return ret; +} + +int thread_srp_server_stop(thread_instance_h instance) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* SRP server stop */ + const char *msg = THREAD_SRP_SERVER_STOP_CMD; + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + msg, strlen(msg)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_server_stop falied"); + return ret; + } + THREAD_DBG("socket srp_server_stop successful"); + + FUNC_EXIT; + return ret; +} + +int thread_srp_server_get_registered_service(thread_instance_h instance, + const char **service_name, const char **address, + uint64_t *port, bool *is_deleted) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(service_name); + THREAD_VALIDATE_INPUT_PARAMETER(address); + THREAD_VALIDATE_INPUT_PARAMETER(port); + THREAD_VALIDATE_INPUT_PARAMETER(is_deleted); + + FUNC_EXIT; + return THREAD_ERROR_NOT_SUPPORTED; +} diff --git a/src/thread-util.c b/src/thread-util.c new file mode 100755 index 0000000..1225fa9 --- /dev/null +++ b/src/thread-util.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include "thread.h" +#include "thread-log.h" +#include "thread-private.h" +#include "thread-dbus-handler.h" +#include "thread-socket-handler.h" + +#define MAX_BUFFER_SIZE 1024 + +static thread_callback_s thread_callbacks[THREAD_METHOD_MAX] = {{NULL, NULL},}; + +static thread_feature_table_t feature_table[] = { + {"tizen.org/feature/network.thread", TRUE, TRUE}, /* THREAD_FEATURE_COMMON */ +}; + +int _thread_check_supported_feature(thread_feature_t feature, bool *supported) +{ + int ret; + + if (feature < THREAD_FEATURE_BASE || feature >= THREAD_FEATURE_MAX) { + THREAD_ERR("Invalid parameter. feature [%d]", feature); + return THREAD_ERROR_INVALID_PARAMETER; + } + + if (TRUE == feature_table[feature].is_check) { + *supported = feature_table[feature].value; + return THREAD_ERROR_NONE; + } + + ret = system_info_get_platform_bool(feature_table[feature].name, supported); + if (SYSTEM_INFO_ERROR_NONE != ret) { + THREAD_ERR("fail to get %s", feature_table[feature].name); + return THREAD_ERROR_OPERATION_FAILED; + } + + feature_table[feature].is_check = TRUE; + feature_table[feature].value = *supported; + + return THREAD_ERROR_NONE; +} + +thread_device_role_e _thread_get_device_role(const char* dev_role) +{ + if (!g_strcmp0(dev_role, "detached")) + return THREAD_DEVICE_ROLE_DETACHED; + else if (!g_strcmp0(dev_role, "child")) + return THREAD_DEVICE_ROLE_CHILD; + else if (!g_strcmp0(dev_role, "router")) + return THREAD_DEVICE_ROLE_ROUTER; + else if (!g_strcmp0(dev_role, "leader")) + return THREAD_DEVICE_ROLE_LEADER; + else + return THREAD_DEVICE_ROLE_DISABLED; +} + +void _thread_add_callback(thread_method_e method, void *callback, void *user_data) +{ + thread_callbacks[method].callback = callback; + thread_callbacks[method].user_data = user_data; +} + +thread_callback_s *_thread_get_callback(thread_method_e method) +{ + if (thread_callbacks[method].callback) { + THREAD_DBG("Thread scan in progress..."); + return &(thread_callbacks[method]); + } + return NULL; +} + +const void *_thread_reset_callback(thread_method_e method) +{ + if (thread_callbacks[method].callback) { + thread_callbacks[method].callback = NULL; + thread_callbacks[method].user_data = NULL; + } + return NULL; +} + + +/* dbus async callback handling */ + +int __thread_dbus_handle_joiner_start_cb(gboolean res, GVariant *val, gpointer user_data) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + GVariantIter *iter; + char *pskd = NULL; + char *prov_url = NULL; + char *vendor_name = NULL; + char *vendor_model = NULL; + char *vendor_sw_ver = NULL; + char *vendor_data = NULL; + + thread_callback_s *cb_data = _thread_get_callback(THREAD_METHOD_JOIN); + + if (!res) { + ret = THREAD_ERROR_OPERATION_FAILED; + THREAD_DBG("Thread scan callback received - join unsuccessful"); + goto end; + } + + g_variant_get(val, "(ssssss)", &iter); + + while (g_variant_iter_loop(iter, "(&s&s&s&s&s&s)", + &pskd, &prov_url, &vendor_name, &vendor_model, + &vendor_sw_ver, &vendor_data)) { + + THREAD_DBG("Got the thread beacon..."); + THREAD_DBG("pskd: %s", pskd); + + THREAD_DBG("pskd: %s", pskd); + THREAD_DBG("prov_url: %s", prov_url); + THREAD_DBG("vendor_name: %s", vendor_name); + THREAD_DBG("vendor_model: %s", vendor_model); + THREAD_DBG("vendor_sw_ver: %s", vendor_sw_ver); + THREAD_DBG("vendor_data: %s", vendor_data); + + if (cb_data && cb_data->callback) + ((thread_joiner_result_cb)(cb_data->callback))(res, user_data); + } + g_variant_iter_free(iter); + +end: + if (cb_data && cb_data->callback) + ((thread_joiner_result_cb)(cb_data->callback))(res, user_data); + + _thread_reset_callback(THREAD_METHOD_JOIN); + FUNC_EXIT; + return ret; + +} + +void __thread_dbus_handle_scan_cb(gboolean res, + GVariant *val, gpointer user_data) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + GVariantIter *iter; + uint64_t ext_address = 0; + char *network_name = NULL; + uint64_t ext_panid = 0; + uint8_t *steering_data = NULL; + int length = 0; + uint16_t panid = 0; + uint16_t joiner_udp_port = 0; + uint16_t channel = 0; + uint16_t rssi = 0; + uint8_t lqi = 0; + uint8_t version = 0; + bool is_native = 0; + bool is_joinable = 0; + thread_network_scanning_state_e state = THREAD_SCAN_DEVICE_FOUND; + + THREAD_DBG("Process callback for method: THREAD_DBUS_SCAN_METHOD"); + + thread_callback_s *cb_data = _thread_get_callback(THREAD_METHOD_SCAN); + + if (!res) { + ret = THREAD_ERROR_OPERATION_FAILED; + THREAD_DBG("Thread scan callback received - scan unsuccessful"); + goto scan_finished; + } + + g_variant_get(val, "(a(tstayqqyyyybb))", &iter); + + while (g_variant_iter_loop(iter, "(t&stayqqyyyybb)", + &ext_address, &network_name, &ext_panid, &steering_data, + &panid, &joiner_udp_port, &channel, &rssi, &lqi, + &version, &is_native, &is_native)) { + + THREAD_DBG("Got the thread beacon..."); + THREAD_DBG("ext_address: %llu", ext_address); + THREAD_DBG("network_name: %s", network_name); + THREAD_DBG("ext panid: %llu", ext_panid); + + int i = 0; + while (steering_data[i] != '\0') { + i++; + THREAD_DBG("steering_data[%d]: %d", i, steering_data[i]); + } + length = i; + + THREAD_DBG("panid: %u", panid); + THREAD_DBG("joner_udp_port: %u", joiner_udp_port); + THREAD_DBG("channel: %u", channel); + THREAD_DBG("rssi: %u", rssi); + THREAD_DBG("lqi: %u", lqi); + THREAD_DBG("version: %u", version); + THREAD_DBG("is_native: %s", is_native ? "TRUE" : "FALSE"); + THREAD_DBG("is_joinable: %s", is_joinable ? "TRUE" : "FALSE"); + + if (cb_data && cb_data->callback) { + ((thread_network_scan_result_cb)(cb_data->callback))(ret, + state, ext_address, network_name, ext_panid, steering_data, + length, panid, joiner_udp_port, channel, rssi, lqi, version, + is_native, is_joinable, cb_data->user_data); + } + } + g_variant_iter_free(iter); + +scan_finished: + state = THREAD_SCANNING_FINISHED; + if (cb_data && cb_data->callback) { + ((thread_network_scan_result_cb)(cb_data->callback))(ret, + state, ext_address, network_name, ext_panid, steering_data, + length, panid, joiner_udp_port, channel, rssi, lqi, version, + is_native, is_joinable, cb_data->user_data); + } + + _thread_reset_callback(THREAD_METHOD_SCAN); + FUNC_EXIT; +} + +void _thread_dbus_method_cb(gboolean res, const char* method, + GVariant *val, gpointer user_data) +{ + FUNC_ENTRY; + + if (!method) { + THREAD_DBG("Thread dbus callback received - No method found"); + return; + } + + THREAD_DBG("Thread dbus callback received for method %s ", method); + if (!g_strcmp0(method, THREAD_DBUS_SCAN_METHOD)) + __thread_dbus_handle_scan_cb(res, val, user_data); + else if (!g_strcmp0(method, THREAD_DBUS_JOINER_START_METHOD)) + __thread_dbus_handle_joiner_start_cb(res, val, user_data); + /* TODO: Handle more methods */ + + FUNC_EXIT; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100755 index 0000000..2ea7876 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,31 @@ +SET(test thread-test) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${test} REQUIRED + glib-2.0 +) + +FOREACH(flag ${${test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") + +SET(TEST_SRCS + thread-init.c + thread-menu.c + thread-main.c + thread-core.c + thread-util.c + thread-joiner.c + thread-commissioner.c + thread-network.c + thread-br.c + thread-srp.c +) + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") +ADD_EXECUTABLE(${test} ${TEST_SRCS}) +TARGET_LINK_LIBRARIES(${test} ${PROJECT_NAME} ${test_LDFLAGS}) +INSTALL(TARGETS ${test} DESTINATION bin) + diff --git a/tests/thread-br.c b/tests/thread-br.c new file mode 100644 index 0000000..8c40d19 --- /dev/null +++ b/tests/thread-br.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +/* External route related variables */ +char g_str_ext_ipv6_prefix[MENU_DATA_SIZE + 1]; +char g_str_ext_ipv6_prefix_len[MENU_DATA_SIZE + 1]; +char g_str_ext_rloc16[MENU_DATA_SIZE + 1]; +char g_str_ext_preference[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_ext_is_stable[MENU_DATA_SIZE + 1] = {"1"}; + +uint8_t g_ext_ipv6_prefix[THREAD_IPV6_ADDRESS_SIZE]; +uint8_t g_ext_ipv6_prefix_len; +uint16_t g_ext_rloc16; +int8_t g_ext_preference; +bool g_ext_is_stable; +bool g_ext_is_device_next_hop = THREAD_IS_DEVICE_NEXT_HOP_DEFAULT; + +/* Onmesh prefix related variables */ +char g_str_onmesh_ipv6_prefix[MENU_DATA_SIZE + 1]; +char g_str_onmesh_ipv6_prefix_len[MENU_DATA_SIZE + 1]; +char g_str_onmesh_preference[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_slaac[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_dhcp[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_configure[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_default_route[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_on_mesh[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_stable[MENU_DATA_SIZE + 1] = {"1"}; +char g_str_preferred[MENU_DATA_SIZE + 1] = {"1"}; + +int g_slaac; +int g_dhcp; +int g_configure; +int g_default_route; +int g_on_mesh; +int g_stable; +uint8_t g_onmesh_ipv6_prefix[THREAD_IPV6_ADDRESS_SIZE]; +uint8_t g_onmesh_ipv6_prefix_len; +int8_t g_onmesh_preference; +int g_preferred; + +GSList *route_list; +GSList *onmesh_prefix_list; + +void free_list(GSList *list) +{ + for (GSList *l = list; l; l = g_slist_next(l)) + if (l->data) + g_free(l->data); + + return; +} + +thread_route_info_a* _create_new_route(void) +{ + FUNC_ENTRY; + + thread_route_info_a *new_route = NULL; + new_route = g_malloc0(sizeof(thread_route_info_a)); + if (!new_route) { + THREAD_ERR("g_malloc0 failed while allocating new route"); + return NULL; + } + + FUNC_EXIT; + return new_route; +} + +thread_onmesh_prefix_info_a* _create_new_onmesh_prefix(void) +{ + FUNC_ENTRY; + + thread_onmesh_prefix_info_a *new_onmesh_prefix = NULL; + new_onmesh_prefix = g_malloc0(sizeof(thread_onmesh_prefix_info_a)); + if (!new_onmesh_prefix) { + THREAD_ERR("g_malloc0 failed while allocating new_onmesh_prefix"); + return NULL; + } + + FUNC_EXIT; + return new_onmesh_prefix; +} + +static bool __thread_br_get_external_routes_callback(int total, thread_route_info_h route_info, void *user_data) +{ + msg("__thread_br_get_external_routes_callback, result: %d", total); + + msg("Found the external route..."); + + int ret = thread_br_get_route_info(route_info, + g_ext_ipv6_prefix, &g_ext_ipv6_prefix_len, &g_ext_rloc16, + &g_ext_preference, &g_ext_is_stable, &g_ext_is_device_next_hop); + + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_get_route_info success"); + uint8_t *prefix_address = g_ext_ipv6_prefix; + + msg("prefix_address: %02x%02x:%02x%02x:%02x%02x:%02x%02x", + prefix_address[0], prefix_address[1], prefix_address[2], + prefix_address[3], prefix_address[4], prefix_address[5], + prefix_address[6], prefix_address[7]); + msg("prefix_len: %u", g_ext_ipv6_prefix_len); + msg("rloc16: %u", g_ext_rloc16); + msg("preference: %u", g_ext_preference); + msg("stable: %s", g_ext_is_stable ? "TRUE" : "FALSE"); + msg("next_hop_is_self: %s", g_ext_is_device_next_hop ? + "TRUE" : "FALSE"); + + /* Create a new route and add to route_list */ + thread_route_info_a *new_route = _create_new_route(); + if (!new_route) + goto OUT; + + new_route->handle = route_info; + memcpy(new_route->prefix_address, prefix_address, + THREAD_IPV6_PREFIX_SIZE); + new_route->prefix_length = g_ext_ipv6_prefix_len; + + route_list = g_slist_append(route_list, new_route); + + } else + msg("thread_br_get_route_info failed"); +OUT: + + msg("Callback exit"); + + return TRUE; +} + +static int run_thread_br_enable(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_br_enable(g_instance); + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_enable success"); + free_list(route_list); + route_list = NULL; + free_list(onmesh_prefix_list); + onmesh_prefix_list = NULL; + + /* Initialize the route_list */ + ret = thread_br_get_external_routes(g_instance, + __thread_br_get_external_routes_callback, NULL); + retv_if(ret != THREAD_ERROR_NONE, ret); + } else + msg("thread_br_enable failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_disable(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_br_disable(g_instance); + + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_disable success"); + free_list(route_list); + route_list = NULL; + free_list(onmesh_prefix_list); + onmesh_prefix_list = NULL; + + } else + msg("thread_br_disable failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_get_external_routes(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + free_list(route_list); + route_list = NULL; + int ret = thread_br_get_external_routes(g_instance, + __thread_br_get_external_routes_callback, NULL); + if (ret == THREAD_ERROR_NONE) + msg("thread_br_get_external_routes success"); + else + msg("thread_br_get_external_routes failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_add_external_route(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int is_stable; + int ret = _preprocess_ipv6_prefix(g_str_ext_ipv6_prefix, + g_ext_ipv6_prefix); + retv_if(ret != THREAD_ERROR_NONE, ret); + + sscanf(g_str_ext_ipv6_prefix_len, "%hhu", &g_ext_ipv6_prefix_len); + sscanf(g_str_ext_rloc16, "%hu", &g_ext_rloc16); + sscanf(g_str_ext_preference, "%hhd", &g_ext_preference); + sscanf(g_str_ext_is_stable, "%d", &is_stable); + g_ext_is_stable = (bool)is_stable; + + /* Printing parameters value */ + msg("Parameter value for add external route"); + + uint8_t *prefix_address = g_ext_ipv6_prefix; + msg("prefix_address: %02x%02x:%02x%02x:%02x%02x:%02x%02x::", + prefix_address[0], prefix_address[1], prefix_address[2], + prefix_address[3], prefix_address[4], prefix_address[5], + prefix_address[6], prefix_address[7]); + + msg("external__prefix_len: %hhu", g_ext_ipv6_prefix_len); + msg("external_preference: %hhd", g_ext_preference); + msg("external_rloc16: %hhd", g_ext_rloc16); + msg("external_is_stable: %s", g_ext_is_stable ? "TRUE" : "FALSE"); + + thread_route_info_a *new_route = _create_new_route(); + if (!new_route) + goto OUT; + + ret = thread_br_add_external_route(g_instance, g_ext_ipv6_prefix, + g_ext_ipv6_prefix_len, g_ext_rloc16, g_ext_preference, + g_ext_is_stable, g_ext_is_device_next_hop, + &(new_route->handle)); + + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_add_external_route success"); + memcpy(new_route->prefix_address, prefix_address, + THREAD_IPV6_PREFIX_SIZE); + new_route->prefix_length = g_ext_ipv6_prefix_len; + route_list = g_slist_append(route_list, new_route); + } else { + msg("thread_br_add_external_route failed"); + g_free(new_route); + } +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_remove_external_route(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + + if (g_instance == NULL) + goto OUT; + + int ret = _preprocess_ipv6_prefix(g_str_ext_ipv6_prefix, + g_ext_ipv6_prefix); + retv_if(ret != THREAD_ERROR_NONE, ret); + sscanf(g_str_ext_ipv6_prefix_len, "%hhu", &g_ext_ipv6_prefix_len); + + thread_route_info_a *req_route = NULL; + + for (GSList *l = route_list; l; l = g_slist_next(l)) { + thread_route_info_a *route_info = l->data; + if (memcmp(route_info->prefix_address, g_ext_ipv6_prefix, + THREAD_IPV6_PREFIX_SIZE*(sizeof(uint8_t))) == 0) { + + if (route_info->prefix_length == g_ext_ipv6_prefix_len) { + req_route = route_info; + break; + } + } + } + + if (!req_route) { + msg("No Route found"); + goto OUT; + } + + ret = thread_br_remove_external_route(g_instance, req_route->handle); + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_remove_external_route success"); + route_list = g_slist_remove(route_list, req_route); + } else + msg("thread_br_remove_external_route failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_add_onmesh_prefix(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = _preprocess_ipv6_prefix(g_str_onmesh_ipv6_prefix, + g_onmesh_ipv6_prefix); + retv_if(ret != THREAD_ERROR_NONE, ret); + + sscanf(g_str_onmesh_ipv6_prefix_len, "%hhu", &g_onmesh_ipv6_prefix_len); + sscanf(g_str_onmesh_preference, "%hhd", &g_onmesh_preference); + sscanf(g_str_slaac, "%d", &g_slaac); + sscanf(g_str_dhcp, "%d", &g_dhcp); + sscanf(g_str_configure, "%d", &g_configure); + sscanf(g_str_default_route, "%d", &g_default_route); + sscanf(g_str_on_mesh, "%d", &g_on_mesh); + sscanf(g_str_stable, "%d", &g_stable); + sscanf(g_str_preferred, "%d", &g_preferred); + + /* Printing parameters value */ + msg("Parameter value for add onmesh_prefix"); + + uint8_t *prefix_address = g_onmesh_ipv6_prefix; + msg("prefix_address: %02x%02x:%02x%02x:%02x%02x:%02x%02x", + prefix_address[0], prefix_address[1], prefix_address[2], + prefix_address[3], prefix_address[4], prefix_address[5], + prefix_address[6], prefix_address[7]); + + msg("g_onmesh_prefix_len: %hhu", g_onmesh_ipv6_prefix_len); + msg("g_onmesh_preference: %hhd", g_onmesh_preference); + msg("g_slaac: %s", g_slaac ? "TRUE" : "FALSE"); + msg("g_dhcp: %s", g_dhcp ? "TRUE" : "FALSE"); + msg("g_configure: %s", g_configure ? "TRUE" : "FALSE"); + msg("g_default_route: %s", g_default_route ? "TRUE" : "FALSE"); + msg("g_on_mesh: %s", g_on_mesh ? "TRUE" : "FALSE"); + msg("g_stable: %s", g_stable ? "TRUE" : "FALSE"); + msg("g_preferred: %s", g_preferred ? "TRUE" : "FALSE"); + + thread_onmesh_prefix_info_a *new_onmesh_prefix = _create_new_onmesh_prefix(); + if (!new_onmesh_prefix) + goto OUT; + + ret = thread_br_add_onmesh_prefix(g_instance, g_onmesh_ipv6_prefix, + g_onmesh_ipv6_prefix_len, g_onmesh_preference, + g_preferred, g_slaac, g_dhcp, g_configure, + g_default_route, g_on_mesh, g_stable, + &(new_onmesh_prefix->handle)); + + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_add_onmesh_prefix success"); + memcpy(new_onmesh_prefix->prefix_address, prefix_address, + THREAD_IPV6_PREFIX_SIZE); + new_onmesh_prefix->prefix_length = g_onmesh_ipv6_prefix_len; + onmesh_prefix_list = g_slist_append(onmesh_prefix_list, + new_onmesh_prefix); + } else { + msg("thread_br_add_onmesh_prefix failed"); + g_free(new_onmesh_prefix); + } +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_br_remove_onmesh_prefix(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = _preprocess_ipv6_prefix(g_str_onmesh_ipv6_prefix, + g_onmesh_ipv6_prefix); + retv_if(ret != THREAD_ERROR_NONE, ret); + sscanf(g_str_onmesh_ipv6_prefix_len, "%hhu", &g_onmesh_ipv6_prefix_len); + + thread_onmesh_prefix_info_a *req_onmesh_prefix = NULL; + + for (GSList *l = route_list; l; l = g_slist_next(l)) { + thread_onmesh_prefix_info_a *onmesh_prefix_info = l->data; + if (memcmp(onmesh_prefix_info->prefix_address, + g_onmesh_ipv6_prefix, + THREAD_IPV6_PREFIX_SIZE*(sizeof(uint8_t))) == 0) { + + if (onmesh_prefix_info->prefix_length == + g_onmesh_ipv6_prefix_len) { + req_onmesh_prefix = onmesh_prefix_info; + break; + } + } + } + + if (!req_onmesh_prefix) { + msg("No Onmesh Prefix found"); + goto OUT; + } + + ret = thread_br_remove_onmesh_prefix(g_instance, + req_onmesh_prefix->handle); + if (ret == THREAD_ERROR_NONE) { + msg("thread_br_remove_onmesh_prefix success"); + onmesh_prefix_list = g_slist_remove(onmesh_prefix_list, + req_onmesh_prefix); + } else + msg("thread_br_remove_onmesh_prefix failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_br_add_external_route[] = { + { "1", "ext_ipv6_prefix", + NULL, NULL, g_str_ext_ipv6_prefix }, + { "2", "ext_ipv6_prefix_len", + NULL, NULL, g_str_ext_ipv6_prefix_len }, + { "3", "ext_rloc16", + NULL, NULL, g_str_ext_rloc16 }, + { "4", "ext_preference", + NULL, NULL, g_str_ext_preference }, + { "5", "is_stable[ Type 0:false, 1:true]", + NULL, NULL, g_str_ext_is_stable }, + { "6", "run", NULL, + run_thread_br_add_external_route, NULL }, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_br_remove_external_route[] = { + { "1", "ext_ipv6_prefix", + NULL, NULL, g_str_ext_ipv6_prefix }, + { "2", "ext_ipv6_prefix_len", + NULL, NULL, g_str_ext_ipv6_prefix_len }, + { "3", "run", NULL, + run_thread_br_remove_external_route, NULL }, + { NULL, NULL, }, +}; + + +static struct menu_data menu_thread_br_add_onmesh_prefix[] = { + { "1", "onmesh_ipv6_prefix", + NULL, NULL, g_str_onmesh_ipv6_prefix }, + { "2", "onmesh_ipv6_prefix_len", + NULL, NULL, g_str_onmesh_ipv6_prefix_len }, + { "3", "onmesh_prefernce [Type 0:Low, 1:Med, 2:High]", + NULL, NULL, g_str_onmesh_preference }, + { "4", "slaac [Type 0:False, 1:True]", + NULL, NULL, g_str_slaac }, + { "5", "dhcp [Type 0:False, 1:True]", + NULL, NULL, g_str_dhcp }, + { "6", "configure [Type 0:False, 1:True]", + NULL, NULL, g_str_configure }, + { "7", "default_route [Type 0:False, 1:True]", + NULL, NULL, g_str_default_route }, + { "8", "on_mesh [Type 0:False, 1:True]", + NULL, NULL, g_str_on_mesh }, + { "9", "stable [Type 0:False, 1:True]", + NULL, NULL, g_str_stable }, + { "10", "preferred [Type 0:False, 1:True]", + NULL, NULL, g_str_preferred }, + { "11", "run", NULL, + run_thread_br_add_onmesh_prefix, NULL }, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_br_remove_onmesh_prefix[] = { + { "1", "onmesh_ipv6_prefix", + NULL, NULL, g_str_onmesh_ipv6_prefix }, + { "2", "onmesh_prefix_len", + NULL, NULL, g_str_onmesh_ipv6_prefix_len }, + { "3", "run", NULL, + run_thread_br_remove_onmesh_prefix, NULL }, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_br[] = { + { "1", "thread_br_enable", + NULL, run_thread_br_enable, NULL}, + { "2", "thread_br_disable", + NULL, run_thread_br_disable, NULL }, + { "3", "thread_br_get_external_routes", + NULL, run_thread_br_get_external_routes, NULL }, + { "4", "thread_br_add_external_route", + menu_thread_br_add_external_route, NULL, NULL }, + { "5", "thread_br_remove_external_route", + menu_thread_br_remove_external_route, NULL, NULL }, + { "6", "thread_br_add_onmesh_prefix", + menu_thread_br_add_onmesh_prefix, NULL, NULL }, + { "7", "thread_br_remove_onmesh_prefix", + menu_thread_br_remove_onmesh_prefix, NULL, NULL }, + { NULL, NULL, }, +}; diff --git a/tests/thread-commissioner.c b/tests/thread-commissioner.c new file mode 100644 index 0000000..e2baf2b --- /dev/null +++ b/tests/thread-commissioner.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +static char g_joiner_uuid[MENU_DATA_SIZE + 1]; +static char g_joiner_passphrase[MENU_DATA_SIZE + 1]; + +static int run_thread_commissioner_start(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_commissioner_start(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_commissioner_start success"); + else + msg("thread_commissioner_start failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_commissioner_set_commisioning_data(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_commissioner_set_commisioning_data(g_instance, g_joiner_uuid, + g_joiner_passphrase); + if (ret == THREAD_ERROR_NONE) + msg("thread_commissioner_set_commisioning_data success"); + else + msg("thread_commissioner_set_commisioning_data failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_commissioner_set_commisioning_data[] = { + { "1", "Joiner UUID", NULL, NULL, g_joiner_uuid}, + { "2", "Joiner Passphrase", NULL, NULL, g_joiner_passphrase}, + { "3", "run", NULL, run_thread_commissioner_set_commisioning_data, NULL}, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_commissioner[] = { + { "1", "thread_commissioner_start", + NULL, run_thread_commissioner_start, NULL}, + { "2", "thread_commissioner_set_commisioning_data", + menu_thread_commissioner_set_commisioning_data, NULL, NULL }, + { NULL, NULL, }, +}; diff --git a/tests/thread-core.c b/tests/thread-core.c new file mode 100755 index 0000000..79af951 --- /dev/null +++ b/tests/thread-core.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +thread_device_role_e g_device_role; +thread_device_type_e g_device_type; +char g_str_device_type[MENU_DATA_SIZE + 1]; + +char g_str_scan_duration[MENU_DATA_SIZE + 1]; +uint16_t g_scan_duration; + +uint64_t g_extended_address; +thread_scan_param_h g_param_handle; +const char* g_uuid; + +static void __thread_scan_callback(int result, thread_network_scanning_state_e state, + uint64_t ext_address, const char *network_name, uint64_t ext_panidi, + const uint8_t *steering_data, int length, uint16_t panid, uint16_t joiner_udp_port, uint16_t channel, + uint16_t rssi, uint8_t lqi, uint8_t version, bool is_native, bool is_joinable, void *user_data) { + + msg("Thread scan callback, result: %s", _thread_get_error_message(result)); + + if (state == THREAD_SCANNING_STARTED) + msg("The scanning state is: STARTED"); + else if (state == THREAD_SCANNING_FINISHED) + msg("The scanning state is: STOPPED"); + else { + msg("thread_network_scanning_state: [%d]", state); + msg("network_name: [%s]", network_name); + msg("ext_address: [%llu]", ext_address); + msg("ext_panidi: [%llu]", ext_panidi); + msg("steering_data: [%d]", (int)steering_data); + msg("length: [%d]", length); + msg("panid: [%hu]", panid); + msg("joiner_udp_port: [%hu]", joiner_udp_port); + msg("channel: [%hu]", channel); + msg("rssi: [%hu]", rssi); + msg("lqi: [%hu]", lqi); + msg("version: [%hu]", version); + msg("is_native: [%d]", is_native); + msg("is_joinable: [%d]", is_joinable); + } + + msg("Callback exit"); + + return; +} + +void thread_device_role_callback(thread_device_role_e device_role, void *user_data) +{ + FUNC_ENTRY; + THREAD_DBG("Device Role is [%d]", device_role); + FUNC_EXIT; +} + + +static int run_thread_enable(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h *g_instance = &(mm->t_instance); + + int ret = thread_enable(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("successfully enabled"); + else + msg("enabled failed"); + thread_set_device_role_changed_cb(g_instance, thread_device_role_callback, NULL); + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_disable(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_disable(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("successfully disabled"); + else + msg("disabled failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_start(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_start(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("successfully started"); + else + msg("start failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_stop(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_stop(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("successfully stopped"); + else + msg("stop failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_reset(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_reset(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("successfully reset"); + else + msg("reset failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_factory_reset(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_factoryreset(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("factoryreset success"); + else + msg("factoryreset failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_get_device_role(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_get_device_role(g_instance, &g_device_role); + if (ret == THREAD_ERROR_NONE) + msg("thread_get_device_role success"); + else + msg("thread_get_device_role failed"); + + msg("- thread_get_device_role() ret: Device role->[%s]", _thread_device_role_to_string(g_device_role)); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_get_device_type(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_get_device_type(g_instance, &g_device_type); + if (ret == THREAD_ERROR_NONE) + msg("thread_get_device_type success"); + else + msg("thread_get_device_type failed"); + + msg("-thread_get_device_type() ret: Device type->[%s]", _thread_device_type_to_string(g_device_type)); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_set_device_type(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + g_device_type = (thread_device_type_e)atoi(g_str_device_type); + + int ret = thread_set_device_type(g_instance, g_device_type); + if (ret == THREAD_ERROR_NONE) + msg("thread_get_device_type success"); + else + msg("thread_get_device_type failed"); + + msg("- thread_set_device_type() ret: Device type->[%s]", _thread_device_type_to_string(g_device_type)); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_scan_param_create(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + g_scan_duration = (uint16_t)atoi(g_str_scan_duration); + + int ret = thread_scan_param_create(g_instance, g_scan_duration, &g_param_handle); + if (ret == THREAD_ERROR_NONE) + msg("thread_scan_param_create success"); + else + msg("thread_scan_param_create failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_scan_param_destroy(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_scan_param_destroy(g_instance, g_param_handle); + if (ret == THREAD_ERROR_NONE) + msg("thread_scan_param_distroy success"); + else + msg("thread_scan_param_distroy failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_scan(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = THREAD_ERROR_NONE; + + if (!g_param_handle) { + ret = thread_scan_param_create(g_instance, THREAD_DEFAULT_SCAN_TIME, &g_param_handle); + if (ret == THREAD_ERROR_NONE) + msg("thread_scan_param_create success"); + else { + msg("thread_scan_param_create failed"); + goto OUT; + } + } + + ret = thread_scan(g_instance, g_param_handle, __thread_scan_callback, NULL); + if (ret == THREAD_ERROR_NONE) + msg("thread_scan success"); + else + msg("thread_scan failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_get_extended_address(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_get_extended_address(g_instance, &g_extended_address); + if (ret == THREAD_ERROR_NONE) { + msg("thread_get_extended_address success"); + msg("- thread_get_exenteded_address() ret: Device extended address->[%llu]", + g_extended_address); + } else + msg("thread_get_extended_address failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_get_extended_uuid(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_get_extended_uuid(g_instance, &g_uuid); + if (ret == THREAD_ERROR_NONE) { + msg("thread_get_extended_uuid success"); + msg("- thread_get_exenteded_uuid() ret: Device extended uuid->[%s]", g_uuid); + } else + msg("thread_get_extended_uuid failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_set_device_type[] = { + { "1", "type(1: Router 2: FED(full end device) 3: MED(minimal end device) 4: SED(sleepy end device)", + NULL, NULL, g_str_device_type }, + { "2", "run", NULL, + run_thread_set_device_type, NULL }, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_scan_param_create[] = { + { "1", "duration", + NULL, NULL, g_str_scan_duration }, + { "2", "run", NULL, + run_thread_scan_param_create, NULL }, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_core[] = { + { "1", "thread_enable", + NULL, run_thread_enable, NULL}, + { "2", "thread_disable", + NULL, run_thread_disable, NULL }, + { "3", "thread_start", + NULL, run_thread_start, NULL }, + { "4", "thread_stop", + NULL, run_thread_stop, NULL }, + { "5", "thread_reset", + NULL, run_thread_reset, NULL }, + { "6", "thread_factoryreset", + NULL, run_factory_reset, NULL }, + { "7", "thread_get_device_role", + NULL, run_thread_get_device_role, NULL }, + { "8", "thread_get_device_type", + NULL, run_thread_get_device_type, NULL }, + { "9", "thread_set_device_type", + menu_thread_set_device_type, NULL, NULL }, + { "10", "thread_scan_param_create", + menu_thread_scan_param_create, NULL, NULL }, + { "11", "thread_scan_param_destroy", + NULL, run_thread_scan_param_destroy, NULL }, + { "12", "thread_scan", + NULL, run_thread_scan, NULL }, + { "13", "thread_get_extended_address", + NULL, run_thread_get_extended_address, NULL }, + { "14", "thread_get_extended_uuid", + NULL, run_thread_get_extended_uuid, NULL }, + { NULL, NULL, }, +}; diff --git a/tests/thread-init.c b/tests/thread-init.c new file mode 100755 index 0000000..a8b2733 --- /dev/null +++ b/tests/thread-init.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" + +char g_selected_user_idx[MENU_DATA_SIZE + 1] = {0,}; + + +static int run_thread_init(MManager *mm, struct menu_data *menu) +{ + msg("thread_initialize started..."); + + int ret = thread_initialize(); + + if (ret == THREAD_ERROR_NOT_SUPPORTED) + msg("thread_initialize_completed"); + else + msg("thread_initalize_failed"); + + return RET_SUCCESS; +} + +struct menu_data menu_thread_init[] = { + { "1", "Run Init", NULL, run_thread_init, NULL}, + { NULL, NULL, }, +}; diff --git a/tests/thread-joiner.c b/tests/thread-joiner.c new file mode 100644 index 0000000..c71e0c3 --- /dev/null +++ b/tests/thread-joiner.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +static char g_network_key[MENU_DATA_SIZE + 1]; +static char g_pskd[MENU_DATA_SIZE + 1]; +static char g_prov_url[MENU_DATA_SIZE + 1]; +static char g_vendor_name[MENU_DATA_SIZE + 1]; +static char g_vendor_model[MENU_DATA_SIZE + 1]; +static char g_vendor_sw_version[MENU_DATA_SIZE + 1]; +static char g_vendor_data[MENU_DATA_SIZE + 1]; +static char g_panid[MENU_DATA_SIZE + 1]; + +static void __thread_joiner_start_callback(int result, void* user_data) +{ + msg("Thread joiner start callback, result: %s", _thread_get_error_message(result)); + + return; +} +static int run_thread_joiner_join_by_network_key(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_joiner_join_by_network_key(g_instance, g_network_key, g_panid); + if (ret == THREAD_ERROR_NONE) + msg("thread_joiner_join_by_networkkey success"); + else + msg("thread_joiner_join_by_networkkey failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_joiner_stop(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_joiner_stop(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_joiner_stop success"); + else + msg("thread_joiner_stop failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_joiner_start(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_joiner_start(g_instance, g_pskd, g_prov_url, + g_vendor_name, g_vendor_model, g_vendor_sw_version, g_vendor_data, + __thread_joiner_start_callback, NULL); + + if (ret == THREAD_ERROR_NONE) + msg("thread_joiner_start success"); + else + msg("thread_joiner_start failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_joiner_join_by_network_key[] = { + { "1", "Type network_key", NULL, NULL, g_network_key}, + { "2", "Type panid", NULL, NULL, g_panid}, + { "3", "run", NULL, run_thread_joiner_join_by_network_key, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_joiner_start[] = { + { "1", "Type Pass key", NULL, NULL, g_pskd}, + { "2", "Type Prov url", NULL, NULL, g_prov_url}, + { "3", "Type Vendor Name", NULL, NULL, g_vendor_name}, + { "4", "Type Vendor Model", NULL, NULL, g_vendor_model}, + { "5", "Type Vendor sw_version", NULL, NULL, g_vendor_sw_version}, + { "6", "Type Vendor data", NULL, NULL, g_vendor_data}, + { "7", "run", NULL, run_thread_joiner_start, NULL}, + { NULL, NULL, }, +}; +struct menu_data menu_thread_joiner[] = { + { "1", "thread_joiner_join_by_networkkey", + menu_thread_joiner_join_by_network_key, NULL, NULL}, + { "2", "thread_joiner_start", + menu_thread_joiner_start, NULL, NULL }, + { "3", "thread_joiner_stop", + NULL, run_thread_joiner_stop, NULL }, + { NULL, NULL, }, +}; diff --git a/tests/thread-main.c b/tests/thread-main.c new file mode 100755 index 0000000..049d514 --- /dev/null +++ b/tests/thread-main.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" + + +extern struct menu_data menu_thread_init[]; +extern struct menu_data menu_thread_core[]; +extern struct menu_data menu_thread_joiner[]; +extern struct menu_data menu_thread_commissioner[]; +extern struct menu_data menu_thread_network[]; +extern struct menu_data menu_thread_br[]; +extern struct menu_data menu_thread_srp[]; + +static struct menu_data menu_main[] = { + { "1", "Core", menu_thread_core, NULL, NULL}, + { "2", "Joiner", menu_thread_joiner, NULL, NULL}, + { "3", "Commissioner", menu_thread_commissioner, NULL, NULL}, + { "4", "Network", menu_thread_network, NULL, NULL}, + { "5", "Border Router", menu_thread_br, NULL, NULL}, + { "6", "SRP", menu_thread_srp, NULL, NULL}, + { NULL, NULL, }, +}; + +static int __init_func(MManager *mm, struct menu_data *menu) +{ + msg("thread_initialize started..."); + + int ret = thread_initialize(); + + if (ret == THREAD_ERROR_NONE) + msg("thread_initialize_completed"); + else + msg("thread_initalize_failed"); + + return RET_SUCCESS; +} + +static gboolean __create_init_menu(struct menu_data init_menu[1]) +{ + init_menu[0].key = "1"; + init_menu[0].title = "Init"; + init_menu[0].sub_menu = menu_main; + init_menu[0].callback = __init_func; + init_menu[0].data = NULL; + + return TRUE; +} + +static void __deinit_func(void) +{ + msg("thread_deinit started..."); + + int ret = thread_deinitialize(); + + if (ret == THREAD_ERROR_NONE) + msg("thread_deinit_completed"); + else + msg("thread_deinit_failed"); + + return; +} + +int main(int arg, char **argv) +{ + GMainLoop *mainloop = NULL; + GIOChannel *channel = g_io_channel_unix_new(STDIN_FILENO); + MManager *manager; + struct menu_data init_menu[1+1] = { {NULL, NULL, } }; + +#if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); +#endif + mainloop = g_main_loop_new(NULL, FALSE); + + msg(""); + msg("* Thread test application "); + msg("* Build On: %s %s", __DATE__, __TIME__); + + if (__create_init_menu(init_menu) == FALSE) + goto OUT; + + manager = menu_manager_new(init_menu, mainloop); + if (!manager) + goto OUT; + + menu_manager_run(manager); + + g_io_add_watch(channel, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), + on_menu_manager_keyboard, manager); + g_main_loop_run(mainloop); + +OUT: + thread_disable(manager->t_instance); + __deinit_func(); + menu_manager_free(manager); + + g_main_loop_unref(mainloop); + msg("******* Bye bye *******"); + + return 0; +} diff --git a/tests/thread-menu.c b/tests/thread-menu.c new file mode 100755 index 0000000..7675fba --- /dev/null +++ b/tests/thread-menu.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "thread-menu.h" + +#define DEFAULT_MENU_MENU "m" +#define DEFAULT_MENU_NONE "t" +#define DEFAULT_MENU_PREV "p" +#define DEFAULT_MENU_QUIT "q" + +#define TAB_SPACE " " + +char key_buffer[MENU_DATA_SIZE]; +int flag_pid_display = 1; + +char g_thread_interface_str[MENU_DATA_SIZE + 1] = "thread.default.interface"; + +pid_t get_tid() +{ + return syscall(__NR_gettid); +} + +void hide_pid() +{ + flag_pid_display = 0; +} + +void show_pid() +{ + flag_pid_display = 1; +} + + +static void _show_prompt(void) +{ + msgn("(%5d) >> ", get_tid()); +} + +static void _show_reserved_menu(void) +{ + msg(ANSI_COLOR_DARKGRAY HR_SINGLE2 ANSI_COLOR_NORMAL); + + msg(ANSI_COLOR_DARKGRAY " [ " ANSI_COLOR_NORMAL "%s" ANSI_COLOR_DARKGRAY + " ] " ANSI_COLOR_NORMAL "Thread default interface [" ANSI_COLOR_YELLOW "%s" ANSI_COLOR_NORMAL + " ] ", DEFAULT_MENU_NONE, g_thread_interface_str); + + msg(ANSI_COLOR_DARKGRAY HR_SINGLE2 ANSI_COLOR_NORMAL); + + + msg(ANSI_COLOR_DARKGRAY HR_SINGLE2 ANSI_COLOR_NORMAL); + msg(ANSI_COLOR_DARKGRAY " [ " ANSI_COLOR_NORMAL "%s" ANSI_COLOR_DARKGRAY + " ] " ANSI_COLOR_NORMAL "Previous menu " , DEFAULT_MENU_PREV); + msg(ANSI_COLOR_DARKGRAY " [ " ANSI_COLOR_NORMAL "%s" ANSI_COLOR_DARKGRAY + " ] " ANSI_COLOR_NORMAL "Show Menu " , DEFAULT_MENU_MENU); + msg(ANSI_COLOR_DARKGRAY " [ " ANSI_COLOR_NORMAL "%s" ANSI_COLOR_DARKGRAY + " ] " ANSI_COLOR_NORMAL "Quit " , DEFAULT_MENU_QUIT); +} + +static void _show_input_ok(void) +{ + msg("OK."); +} + +static void _show_menu(MManager *m, struct menu_data menu[]) +{ + int i = 0; + int len = 0; + struct menu_data *item; + char title_buf[256] = { 0, }; + + if (!menu) + return; + + msg(""); + msg(HR_DOUBLE); + + len = g_queue_get_length(m->title_stack); + msgn(ANSI_COLOR_YELLOW " Main"); + if (len > 0) { + for (i = 0; i < len; i++) { + msgn(ANSI_COLOR_NORMAL " >> " ANSI_COLOR_YELLOW "%s", + (char *)g_queue_peek_nth(m->title_stack, i)); + } + } + msg(ANSI_COLOR_NORMAL); + msg(HR_SINGLE); + + hide_pid(); + i = 0; + + while (1) { + item = menu + i; + if (item->key == NULL) + break; + + if (!g_strcmp0(item->key, "-")) { + msgn(" "); + } else if (!g_strcmp0(item->key, "_")) { + msg(ANSI_COLOR_DARKGRAY HR_SINGLE2 ANSI_COLOR_NORMAL); + + if (item->callback) + item->callback(m, item); + + i++; + + continue; + } else if (!g_strcmp0(item->key, "*")) { + msg(" %s", item->title); + if (item->callback) + item->callback(m, item); + } else { + msgn(ANSI_COLOR_DARKGRAY " [" ANSI_COLOR_NORMAL "%3s" + ANSI_COLOR_DARKGRAY "] " ANSI_COLOR_NORMAL, item->key); + } + + memset(title_buf, 0, 256); + if (item->title) { + snprintf(title_buf, MENU_DATA_SIZE, "%s", item->title); + + if (strlen(item->title) >= MAX_TITLE) { + title_buf[MAX_TITLE - 2] = '.'; + title_buf[MAX_TITLE - 1] = '.'; + } + } + + if (item->data) { + msg("%s " ANSI_COLOR_LIGHTBLUE "(%s)" ANSI_COLOR_NORMAL, + title_buf, item->data); + } else if (!g_strcmp0(item->key, "*")) { + /* none */ + } else { + msg("%s", title_buf); + } + + if (item->sub_menu) + msg("\e[1A\e[%dC >", (int)POS_MORE); + + i++; + } + + show_pid(); + + _show_reserved_menu(); + + msg(HR_DOUBLE); + + _show_prompt(); +} + +static void _show_item_data_input_msg(struct menu_data *item) +{ + msg(""); + msg(HR_DOUBLE); + msg(" Input [%s] data ", item->title); + msg(HR_SINGLE); + msg(" current = [%s]", item->data); + msgn(" new >> "); +} + +static void _move_menu(MManager *mm, struct menu_data menu[], char *key) +{ + struct menu_data *item; + int i = 0; + + if (!mm->menu) + return; + + if (!g_strcmp0(DEFAULT_MENU_PREV, key)) { + if (g_queue_get_length(mm->stack) > 0) { + mm->menu = g_queue_pop_tail(mm->stack); + g_queue_pop_tail(mm->title_stack); + } + + _show_menu(mm, mm->menu); + mm->buf = key_buffer; + + return; + } else if (!g_strcmp0(DEFAULT_MENU_MENU, key)) { + _show_menu(mm, mm->menu); + return; + } else if (!g_strcmp0(DEFAULT_MENU_QUIT, key)) { + g_main_loop_quit(mm->mainloop); + return; + } + + while (1) { + int ret = RET_SUCCESS; + item = menu + i; + if (item->key == NULL) + break; + + if (!g_strcmp0(item->key, key)) { + if (item->callback) { + ret = item->callback(mm, item); + _show_prompt(); + } + if (RET_SUCCESS != ret) + return; + + if (item->sub_menu) { + g_queue_push_tail(mm->stack, mm->menu); + g_queue_push_tail(mm->title_stack, (gpointer *)item->title); + + mm->menu = item->sub_menu; + _show_menu(mm, mm->menu); + mm->buf = key_buffer; + } + + if (NULL == item->sub_menu && item->data) { + _show_item_data_input_msg(item); + mm->buf = item->data; + } + + return; + } + + i++; + } + + _show_prompt(); +} + +MManager *menu_manager_new(struct menu_data items[], GMainLoop *mainloop) +{ + MManager *mm; + + mm = calloc(sizeof(struct menu_manager), 1); + if (!mm) + return NULL; + + mm->stack = g_queue_new(); + mm->title_stack = g_queue_new(); + mm->menu = items; + mm->mainloop = mainloop; + mm->t_instance = NULL; + return mm; +} + +int menu_manager_free(MManager *mm) +{ + if (mm) { + if (mm->stack) + g_queue_free(mm->stack); + if (mm->title_stack) + g_queue_free(mm->title_stack); + free(mm); + } + return 0; +} + +int menu_manager_run(MManager *mm) +{ + _show_menu(mm, mm->menu); + + mm->buf = key_buffer; + + return 0; +} + +int menu_manager_set_user_data(MManager *mm, void *user_data) +{ + if (!mm) + return -1; + + mm->user_data = user_data; + + return 0; +} + +void *menu_manager_ref_user_data(MManager *mm) +{ + if (!mm) + return NULL; + + return mm->user_data; +} + +gboolean on_menu_manager_keyboard(GIOChannel *src, GIOCondition con, + gpointer data) +{ + MManager *mm = data; + char local_buf[MENU_DATA_SIZE + 1] = { 0, }; + + if (fgets(local_buf, MENU_DATA_SIZE, stdin) == NULL) + return TRUE; + + if (strlen(local_buf) > 0) { + if (local_buf[strlen(local_buf) - 1] == '\n') + local_buf[strlen(local_buf) - 1] = '\0'; + } + + if (mm->buf == key_buffer) { + if (strlen(local_buf) < 1) { + _show_prompt(); + return TRUE; + } + + _move_menu(mm, mm->menu, local_buf); + } else { + if (mm->buf) { + memset(mm->buf, 0, MENU_DATA_SIZE); + memcpy(mm->buf, local_buf, MENU_DATA_SIZE); + _show_input_ok(); + } + mm->buf = key_buffer; + _move_menu(mm, mm->menu, (char *)DEFAULT_MENU_MENU); + } + + return TRUE; +} diff --git a/tests/thread-menu.h b/tests/thread-menu.h new file mode 100755 index 0000000..b7ec3f4 --- /dev/null +++ b/tests/thread-menu.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __MENU_H__ +#define __MENU_H__ + +__BEGIN_DECLS + +#define ANSI_COLOR_NORMAL "\e[0m" + +#define ANSI_COLOR_BLACK "\e[0;30m" +#define ANSI_COLOR_RED "\e[0;31m" +#define ANSI_COLOR_GREEN "\e[0;32m" +#define ANSI_COLOR_BROWN "\e[0;33m" +#define ANSI_COLOR_BLUE "\e[0;34m" +#define ANSI_COLOR_MAGENTA "\e[0;35m" +#define ANSI_COLOR_CYAN "\e[0;36m" +#define ANSI_COLOR_LIGHTGRAY "\e[0;37m" + +#define ANSI_COLOR_DARKGRAY "\e[1;30m" +#define ANSI_COLOR_LIGHTRED "\e[1;31m" +#define ANSI_COLOR_LIGHTGREEN "\e[1;32m" +#define ANSI_COLOR_YELLOW "\e[1;33m" +#define ANSI_COLOR_LIGHTBLUE "\e[1;34m" +#define ANSI_COLOR_LIGHTMAGENTA "\e[1;35m" +#define ANSI_COLOR_LIGHTCYAN "\e[1;36m" +#define ANSI_COLOR_WHITE "\e[1;37m" + + +#define msg(fmt, args...) do { fprintf(stdout, fmt "\n", ##args); \ + fflush(stdout); } while (0) +#define msgn(fmt, args...) do { fprintf(stdout, fmt, ##args); \ + fflush(stdout); } while (0) + +/* Bold (red) */ +#define msgr(fmt, args...) do { fprintf(stdout, ANSI_COLOR_RED fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Bold (green) */ +#define msgb(fmt, args...) do { fprintf(stdout, ANSI_COLOR_LIGHTGREEN fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Property message */ +#define msgp(fmt, args...) do { fprintf(stdout, ANSI_COLOR_LIGHTMAGENTA fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Bold (Cyan) */ +#define msgc(fmt, args...) do { fprintf(stdout, ANSI_COLOR_CYAN fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Bold (Yellow) */ +#define msgy(fmt, args...) do { fprintf(stdout, ANSI_COLOR_YELLOW fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Bold (Light Red) */ +#define msglr(fmt, args...) do { fprintf(stdout, ANSI_COLOR_LIGHTRED fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +/* Bold (Blue) */ +#define msgbr(fmt, args...) do { fprintf(stdout, ANSI_COLOR_BLUE fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + + +#define msgt(n, fmt, args...) do { fprintf(stdout, "\e[%dC" fmt "\n", \ + 3 + ((n) * 2), ##args); fflush(stdout); } while (0) + +#define pmsg(fmt, args...) do { \ + if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \ + fprintf(stdout, fmt "\n", ##args); fflush(stdout); } while (0) + +#define pmsgb(fmt, args...) do { \ + if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \ + fprintf(stdout, ANSI_COLOR_LIGHTGREEN fmt \ + ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0) + +#define pmsgt(n, fmt, args...) do { \ + if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \ + fprintf(stdout, "\e[%dC" fmt "\n", \ + 3 + ((n) * 2), ##args); fflush(stdout); } while (0) + +#define ret_if(expr) \ +do { \ + if (expr) { \ + msgr("(%s) return", #expr); \ + return; \ + } \ +} while (0) + +#define retv_if(expr, val) \ +do { \ + if (expr) { \ + msgr("(%s) return", #expr); \ + return (val); \ + } \ +} while (0) + +/* Null check */ +#define check_if(expr) \ +do { \ + if (expr) { \ + msgr("(%s) ", #expr); \ + } \ +} while (0) + +#define MENU_DATA_SIZE 255 + +/* + * Horizontal Line - width: 65 + * .12345678901234567890123456789012345678901234567890. + */ +#define HR_SINGLE "----------------------------------------" \ + "-------------------------" +#define HR_DOUBLE "========================================" \ + "=========================" +#define HR_SINGLE2 " ---------------------------------------" \ + "------------------------ " + +#define MAX_WIDTH strlen(HR_SINGLE) +#define MAX_TITLE ((MAX_WIDTH) - 10) +#define POS_MORE ((MAX_WIDTH) - 3) +#define RET_SUCCESS 0 +#define RET_FAILURE -1 + +#include "thread-log.h" +#include "thread-util.h" + +struct menu_manager { + GQueue *stack; + GQueue *title_stack; + struct menu_data *menu; + char *buf; + void *user_data; + GMainLoop *mainloop; + thread_instance_h t_instance; +}; +typedef struct menu_manager MManager; + +struct menu_data { + const char *key; + const char *title; + struct menu_data *sub_menu; + int (*callback)(MManager *mm, struct menu_data *menu); + char *data; +}; + +MManager* menu_manager_new(struct menu_data items[], GMainLoop *mainloop); +int menu_manager_run(MManager *mm); +int menu_manager_set_user_data(MManager *mm, void *user_data); +void* menu_manager_ref_user_data(MManager *mm); +int menu_manager_free(MManager *mm); + +gboolean on_menu_manager_keyboard(GIOChannel *src, GIOCondition con, + gpointer data); + +pid_t get_tid(); +void hide_pid(); +void show_pid(); +int is_pid_show(); +void menu_print_dump(int data_len, void *data); + +__END_DECLS + +#endif diff --git a/tests/thread-network.c b/tests/thread-network.c new file mode 100644 index 0000000..2ad3fb3 --- /dev/null +++ b/tests/thread-network.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +static char g_name[MENU_DATA_SIZE + 1] = {"Thread-test"}; +static char g_key[MENU_DATA_SIZE + 1]; +static char g_pskc[MENU_DATA_SIZE + 1]; +static char g_str_channel[MENU_DATA_SIZE + 1] = {"07fff800"}; +static char g_str_extended_panid[MENU_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ +static char g_str_panid[MENU_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ +static char g_str_buf_length[MENU_DATA_SIZE + 1]; +static char g_str_tlvs_buffer[MENU_DATA_SIZE + 1]; +static thread_network_h g_network; + +uint32_t g_channel; +uint64_t g_extended_panid; +uint16_t g_panid; + +static char g_str_ipaddr_type[MENU_DATA_SIZE + 1] = "0"; + +static int run_thread_network_destroy_operational_network(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_network_destroy_operational_network(g_instance, g_network); + if (ret == THREAD_ERROR_NONE) + msg("thread_network_destroy_operational_network success"); + else + msg("thread_network_destroy_operational_network failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_network_create_operational_network(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + sscanf(g_str_channel, "%x", &g_channel); + sscanf(g_str_extended_panid, "%llu", &g_extended_panid); + sscanf(g_str_panid, "%hu", &g_panid); + + int ret = thread_network_create_operational_network(g_instance, g_name, g_key, + g_pskc, g_channel, g_extended_panid, g_panid, &g_network); + if (ret == THREAD_ERROR_NONE) + msg("thread_network_create_operational_network success"); + else + msg("thread_network_create_operational_network failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_network_set_active_dataset_tlvs(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int buf_length; + uint8_t tlvs_buffer[1024]; + + sscanf(g_str_buf_length, "%d", &buf_length); + msg("Set active dataset tlvs size: %d :: %s", + buf_length, g_str_tlvs_buffer); + + for (int i = 0; i < buf_length; i++) { + char subbuff[3]; + memcpy(subbuff, &g_str_tlvs_buffer[2*i], 2); + subbuff[2] = '\0'; + tlvs_buffer[i] = (uint8_t)strtol(subbuff, NULL, 16); + } + + int ret = thread_network_set_active_dataset_tlvs( + g_instance, tlvs_buffer, buf_length); + if (ret == THREAD_ERROR_NONE) + msg("thread_network_set_active_dataset_tlvs success"); + else + msg("thread_network_set_active_dataset_tlvs failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_network_get_active_dataset_tlvs(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int buf_length; + uint8_t *tlvs_buffer; + int ret = thread_network_get_active_dataset_tlvs(g_instance, &tlvs_buffer, &buf_length); + if (ret == THREAD_ERROR_NONE) { + msg("thread_network_get_active_dataset_tlvs success"); + msg("Active dataset tlvs size: %d :: %s", buf_length, tlvs_buffer); + } else { + msg("thread_network_get_active_dataset_tlvs failed"); + } +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_network_attach(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_network_attach(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_network_attach success"); + else + msg("thread_network_attach failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} +static void __get_ipaddr_callback(int index, char* ipaddr, + thread_ipaddr_type_e ipaddr_type, void *user_data) { + FUNC_ENTRY; + + if (index == 1) + msg("IP address type: %s", _thread_ipaddr_type_to_string(ipaddr_type)); + msg("IP address count: %d, ipv6 address: %s", index, ipaddr); + + FUNC_EXIT; +} +static int run_thread_get_ipaddr(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int type = atoi(g_str_ipaddr_type); + thread_ipaddr_type_e ipaddr_type; + switch (type) { + case 0: + ipaddr_type = THREAD_IPADDR_TYPE_ALL; + break; + case 1: + ipaddr_type = THREAD_IPADDR_TYPE_LINK_LOCAL; + break; + case 2: + ipaddr_type = THREAD_IPADDR_TYPE_RLOC; + break; + case 3: + ipaddr_type = THREAD_IPADDR_TYPE_MLEID; + break; + default: + goto OUT; + } + + int ret = thread_get_ipaddr(g_instance, __get_ipaddr_callback, ipaddr_type, NULL); + if (ret == THREAD_ERROR_NONE) + msg("thread_get_ipaddr success"); + else + msg("thread_get_ipaddr failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_network_set_active_dataset_tlvs[] = { + { "1", "Tlvs_buffer len", NULL, NULL, g_str_buf_length}, + { "2", "Tlvs_buffer", NULL, NULL, g_str_tlvs_buffer}, + { "3", "run", NULL, run_thread_network_set_active_dataset_tlvs, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_network_create_operational_network[] = { + { "1", "Network Name", NULL, NULL, g_name}, + { "2", "Network Key", NULL, NULL, g_key}, + { "3", "Network pskc", NULL, NULL, g_pskc}, + { "4", "Network Channel", NULL, NULL, g_str_channel}, + { "5", "Network Extended Panid", NULL, NULL, g_str_extended_panid}, + { "6", "Network panid", NULL, NULL, g_str_panid}, + { "7", "run", NULL, run_thread_network_create_operational_network, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_get_ipaddr[] = { + { "1", "Node Addr Type: ALL > 0, LINK LOCAL > 1, RLOC > 2, MLEID > 3", + NULL, NULL, g_str_ipaddr_type}, + { "2", "run", NULL, run_thread_get_ipaddr, NULL}, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_network[] = { + { "1", "thread_network_create_operational_network", + menu_thread_network_create_operational_network, NULL, NULL}, + { "2", "thread_network_destroy_operational_network", + NULL, run_thread_network_destroy_operational_network, NULL }, + { "3", "thread_network_set_active_dataset_tlvs", + menu_thread_network_set_active_dataset_tlvs, NULL, NULL}, + { "4", "thread_network_get_active_dataset_tlvs", + NULL, run_thread_network_get_active_dataset_tlvs, NULL }, + { "5", "thread_network_attach", + NULL, run_thread_network_attach, NULL}, + { "6", "thread_get_ipaddr", + menu_thread_get_ipaddr, NULL, NULL}, + { NULL, NULL, }, +}; diff --git a/tests/thread-srp.c b/tests/thread-srp.c new file mode 100644 index 0000000..460edc9 --- /dev/null +++ b/tests/thread-srp.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +const char *service_name; +const char *address; +uint64_t port; +bool is_deleted; +uint64_t g_port; + +static char g_host_address[MENU_DATA_SIZE + 1]; +static char g_service_name[MENU_DATA_SIZE + 1]; +static char g_service_type[MENU_DATA_SIZE + 1]; +static char g_str_port[MENU_DATA_SIZE + 1]; +static char g_host_name[MENU_DATA_SIZE + 1]; + +static int __run_thread_srp_client_start(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_client_start(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_start success"); + else + msg("thread_srp_client_start failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_client_stop(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_client_stop(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_stop success"); + else + msg("thread_srp_client_stop failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_client_remove_host(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_client_remove_host(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_remove_host success"); + else + msg("thread_srp_client_remove_host failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_client_set_host_name(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_client_set_host_name(g_instance, g_host_name); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_set_host_name success"); + else + msg("thread_srp_client_set_host_name failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_client_set_host_address(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_client_set_host_address(g_instance, g_host_address); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_set_host_address success"); + else + msg("thread_srp_client_set_host_address failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_client_register_service(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + g_port = (uint64_t)atoi(g_str_port); + int ret = thread_srp_client_register_service(g_instance, + g_service_name, g_service_type, g_port); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_client_register_service success"); + else + msg("thread_srp_client_register_service failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_server_start(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_server_start(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_server_start success"); + else + msg("thread_srp_server_start failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_server_stop(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_srp_server_stop(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_srp_server_stop success"); + else + msg("thread_srp_server_stop failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int __run_thread_srp_server_get_registered_service(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + int ret = thread_srp_server_get_registered_service(g_instance, &service_name, &address, &port, &is_deleted); + + if (ret == THREAD_ERROR_NONE) { + msg("thread_srp_get_registered_service success"); + msg("service: [%s], [%s], [%llu], [%s]", service_name, address, port, is_deleted ? "TRUE" : "FALSE"); + } else + msg("thread_srp_get_registered_service failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_srp_client_set_host_name[] = { + { "1", "Type host_name", NULL, NULL, g_host_name}, + { "2", "run", NULL, __run_thread_srp_client_set_host_name, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_srp_client_set_host_address[] = { + { "1", "Type host_address", NULL, NULL, g_host_address}, + { "2", "run", NULL, __run_thread_srp_client_set_host_address, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_srp_client_register_service[] = { + { "1", "Type service_name", NULL, NULL, g_service_name}, + { "2", "Type service_type", NULL, NULL, g_service_type}, + { "3", "Type port", NULL, NULL, g_str_port}, + { "4", "run", NULL, __run_thread_srp_client_register_service, NULL}, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_srp[] = { + + { "1", "thread_srp_client_start", + NULL, __run_thread_srp_client_start, NULL}, + { "2", "thread_srp_client_stop", + NULL, __run_thread_srp_client_stop, NULL }, + { "3", "thread_srp_client_set_host_name", + menu_thread_srp_client_set_host_name, NULL, NULL}, + { "4", "thread_srp_client_remove_host", + NULL, __run_thread_srp_client_remove_host, NULL }, + { "5", "thread_srp_client_set_host_address", + menu_thread_srp_client_set_host_address, NULL, NULL }, + { "6", "thread_srp_client_register_service", + menu_thread_srp_client_register_service, NULL, NULL }, + { "7", "thread_srp_server_start", + NULL, __run_thread_srp_server_start, NULL }, + { "8", "thread_srp_server_stop", + NULL, __run_thread_srp_server_stop, NULL }, + { "9", "thread_srp_server_get_registered_service", + NULL, __run_thread_srp_server_get_registered_service, NULL }, + { NULL, NULL, }, +}; + diff --git a/tests/thread-util.c b/tests/thread-util.c new file mode 100644 index 0000000..65812cb --- /dev/null +++ b/tests/thread-util.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "thread-log.h" +#include "thread-util.h" + +static thread_instance_h g_instance = NULL; + +bool _thread_check_instance() +{ + if (g_instance == NULL) { + msg("g_instance == NULL"); + return false; + } + return true; +} +thread_instance_h _thread_get_instance(void) +{ + return g_instance; +} + +const char* _thread_device_role_to_string(thread_device_role_e role) +{ + switch (role) { + CASE_TO_STR(THREAD_DEVICE_ROLE_DISABLED); + CASE_TO_STR(THREAD_DEVICE_ROLE_DETACHED); + CASE_TO_STR(THREAD_DEVICE_ROLE_CHILD); + CASE_TO_STR(THREAD_DEVICE_ROLE_ROUTER); + CASE_TO_STR(THREAD_DEVICE_ROLE_LEADER); + default: + return "NOT DEFINED"; + } +} + +const char* _thread_device_type_to_string(thread_device_type_e type) +{ + switch (type) { + CASE_TO_STR(THREAD_DEVICE_TYPE_NOT_SUPPORTED); + CASE_TO_STR(THREAD_DEVICE_TYPE_ROUTER); + CASE_TO_STR(THREAD_DEVICE_TYPE_FULL_END_DEVICE); + CASE_TO_STR(THREAD_DEVICE_TYPE_MINIMAL_END_DEVICE); + CASE_TO_STR(THREAD_DEVICE_TYPE_SLEEPY_END_DEVICE); + default: + return "NOT DEFINED"; + } +} +const char* _thread_ipaddr_type_to_string(thread_ipaddr_type_e type) +{ + switch (type) { + CASE_TO_STR(THREAD_IPADDR_TYPE_ALL); + CASE_TO_STR(THREAD_IPADDR_TYPE_LINK_LOCAL); + CASE_TO_STR(THREAD_IPADDR_TYPE_RLOC); + CASE_TO_STR(THREAD_IPADDR_TYPE_MLEID); + default: + return "NOT DEFINED"; + } +} + +const char* _thread_get_error_message(thread_error_e err) +{ + switch (err) { + CASE_TO_STR(THREAD_ERROR_NONE); + CASE_TO_STR(THREAD_ERROR_NOT_PERMITTED); + CASE_TO_STR(THREAD_ERROR_INVALID_PARAMETER); + CASE_TO_STR(THREAD_ERROR_OUT_OF_MEMORY); + CASE_TO_STR(THREAD_ERROR_RESOURCE_BUSY); + CASE_TO_STR(THREAD_ERROR_TIMED_OUT); + CASE_TO_STR(THREAD_ERROR_CANCELED); + CASE_TO_STR(THREAD_ERROR_NOW_IN_PROGRESS); + CASE_TO_STR(THREAD_ERROR_NOT_SUPPORTED); + CASE_TO_STR(THREAD_ERROR_NO_DATA); + CASE_TO_STR(THREAD_ERROR_NOT_INITIALIZED); + CASE_TO_STR(THREAD_ERROR_NOT_IN_PROGRESS); + CASE_TO_STR(THREAD_ERROR_ALREADY_DONE); + CASE_TO_STR(THREAD_ERROR_OPERATION_FAILED); + CASE_TO_STR(THREAD_ERROR_NOT_READY); + CASE_TO_STR(THREAD_ERROR_NOT_ENABLED); + CASE_TO_STR(THREAD_ERROR_NOT_FOUND); + CASE_TO_STR(THREAD_ERROR_ALREADY_REGISTERED); + CASE_TO_STR(THREAD_ERROR_DB_FAILED); + CASE_TO_STR(THREAD_ERROR_NOT_REGISTERED); + default: + return "NOT DEFINED"; + } +} + +int _preprocess_ipv6_prefix(char *prefix, uint8_t *ipv6_prefix) +{ + FUNC_ENTRY; + struct in6_addr result; + retv_if(inet_pton(AF_INET6, prefix, &result) == 0, + THREAD_ERROR_INVALID_PARAMETER); + + msg("ipv6 string parse successful"); + memcpy(ipv6_prefix, result.s6_addr, + THREAD_IPV6_PREFIX_SIZE*sizeof(uint8_t)); + + FUNC_EXIT; + return THREAD_ERROR_NONE; +} + diff --git a/tests/thread-util.h b/tests/thread-util.h new file mode 100644 index 0000000..1b79cc1 --- /dev/null +++ b/tests/thread-util.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. + * + */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +__BEGIN_DECLS + +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" + +#define CASE_TO_STR(x) case x: return #x; + +#define THREAD_DEFAULT_SCAN_TIME 80 +#define THREAD_IS_DEVICE_NEXT_HOP_DEFAULT TRUE +#define THREAD_IPV6_ADDRESS_SIZE 16 +#define THREAD_IPV6_PREFIX_SIZE 8 + +typedef struct { + thread_route_info_h handle; + uint8_t prefix_address[THREAD_IPV6_ADDRESS_SIZE]; + uint8_t prefix_length; +} thread_route_info_a; + +typedef struct { + thread_onmesh_prefix_info_h handle; + uint8_t prefix_address[THREAD_IPV6_ADDRESS_SIZE]; + uint8_t prefix_length; +} thread_onmesh_prefix_info_a; + +thread_instance_h _thread_get_instance(); +bool _thread_check_instance(); +const char* _thread_device_role_to_string(thread_device_role_e role); +const char* _thread_device_type_to_string(thread_device_type_e type); +const char* _thread_get_error_message(thread_error_e err); +int _preprocess_ipv6_prefix(char *prefix, uint8_t *ipv6_prefix); +const char* _thread_ipaddr_type_to_string(thread_ipaddr_type_e type); +#endif -- 2.7.4 From 6591bd608cb495be281d3740b5161c92a9ff02b3 Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Tue, 15 Feb 2022 23:09:38 +0530 Subject: [PATCH 3/9] Add thread commissioning scenarios to thread-test Change-Id: I9d327ac92bc1f2ed4c8c7e5b93a006aa8b90f01b Signed-off-by: Rohit Singh --- include/thread.h | 24 ++++- src/thread-core.c | 4 +- tests/CMakeLists.txt | 1 + tests/thread-main.c | 2 + tests/thread-network.c | 2 + tests/thread-scenarios.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+), 5 deletions(-) create mode 100644 tests/thread-scenarios.c diff --git a/include/thread.h b/include/thread.h index 86c4772..06b2ce1 100644 --- a/include/thread.h +++ b/include/thread.h @@ -808,7 +808,7 @@ int thread_srp_server_get_registered_service(thread_instance_h instance, const c /** * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE - * @brief Get registered service detail from the SRP server + * @brief Get node ip address of the thread network node * @since_tizen 7.0 * * @return 0 on success, otherwise a negative error value. @@ -817,12 +817,30 @@ int thread_srp_server_get_registered_service(thread_instance_h instance, const c * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported * - * @pre thread API must be initialized with thread_initialize(). - * @see thread_srp_server_start() + * @pre thread API must be initialized with thread_initialize() and + * enabled with thread_enable(). + * @see thread_initialize() and thread_enable() */ int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callback, thread_ipaddr_type_e ipaddr_type, void *user_data); +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Up the netwotk interface for the thread node. + * @since_tizen 7.0 + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize() and + * enabled with thread_enable(). + * @see thread_initialize() and thread_enable() + */ +int thread_ifconfig_up(thread_instance_h instance); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/thread-core.c b/src/thread-core.c index e3ebad6..3eb8896 100644 --- a/src/thread-core.c +++ b/src/thread-core.c @@ -183,7 +183,7 @@ int thread_disable(thread_instance_h instance) return THREAD_ERROR_NONE; } -static int __thread_ifconfig_up(thread_instance_h instance) +int thread_ifconfig_up(thread_instance_h instance) { FUNC_ENTRY; THREAD_VALIDATE_INPUT_PARAMETER(instance); @@ -212,7 +212,7 @@ int thread_start(thread_instance_h instance) retv_if(current_instance->is_thread_started, THREAD_ERROR_ALREADY_DONE); /* ifconfig up */ - ret = __thread_ifconfig_up(instance); + ret = thread_ifconfig_up(instance); if (ret != THREAD_ERROR_NONE) THREAD_DBG("Thread: ifconfig up failed"); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2ea7876..ad99a19 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,7 @@ SET(TEST_SRCS thread-network.c thread-br.c thread-srp.c + thread-scenarios.c ) SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") diff --git a/tests/thread-main.c b/tests/thread-main.c index 049d514..1d6204a 100755 --- a/tests/thread-main.c +++ b/tests/thread-main.c @@ -37,6 +37,7 @@ extern struct menu_data menu_thread_commissioner[]; extern struct menu_data menu_thread_network[]; extern struct menu_data menu_thread_br[]; extern struct menu_data menu_thread_srp[]; +extern struct menu_data menu_thread_scenarios[]; static struct menu_data menu_main[] = { { "1", "Core", menu_thread_core, NULL, NULL}, @@ -45,6 +46,7 @@ static struct menu_data menu_main[] = { { "4", "Network", menu_thread_network, NULL, NULL}, { "5", "Border Router", menu_thread_br, NULL, NULL}, { "6", "SRP", menu_thread_srp, NULL, NULL}, + { "7", "Scenarios", menu_thread_scenarios, NULL, NULL}, { NULL, NULL, }, }; diff --git a/tests/thread-network.c b/tests/thread-network.c index 2ad3fb3..c7a96da 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -156,6 +156,7 @@ OUT: FUNC_EXIT; return RET_SUCCESS; } + static void __get_ipaddr_callback(int index, char* ipaddr, thread_ipaddr_type_e ipaddr_type, void *user_data) { FUNC_ENTRY; @@ -166,6 +167,7 @@ static void __get_ipaddr_callback(int index, char* ipaddr, FUNC_EXIT; } + static int run_thread_get_ipaddr(MManager *mm, struct menu_data *menu) { FUNC_ENTRY; diff --git a/tests/thread-scenarios.c b/tests/thread-scenarios.c new file mode 100644 index 0000000..116e627 --- /dev/null +++ b/tests/thread-scenarios.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "thread.h" +#include "thread-menu.h" +#include "thread-type.h" +#include "thread-log.h" +#include "thread-util.h" + +static char g_name[MENU_DATA_SIZE + 1] = {"Thread-test"}; +static char g_key[MENU_DATA_SIZE + 1]; +static char g_pskc[MENU_DATA_SIZE + 1]; +static char g_str_channel[MENU_DATA_SIZE + 1] = {"07fff800"}; +static char g_str_extended_panid[MENU_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ +static char g_str_panid[MENU_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ +static thread_network_h g_network; + +static char g_joiner_uuid[MENU_DATA_SIZE + 1]; +static char g_joiner_passphrase[MENU_DATA_SIZE + 1]; + +uint32_t g_channel; +uint64_t g_extended_panid; +uint16_t g_panid; + +static char g_prov_url[MENU_DATA_SIZE + 1]; +static char g_vendor_name[MENU_DATA_SIZE + 1]; +static char g_vendor_model[MENU_DATA_SIZE + 1]; +static char g_vendor_sw_version[MENU_DATA_SIZE + 1]; +static char g_vendor_data[MENU_DATA_SIZE + 1]; + +void _thread_joiner_start_callback(int result, void* user_data) +{ + msg("Thread joiner start callback, result: %s", + _thread_get_error_message(result)); + + return; +} + +static int run_thread_scenario_startup(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + msg(" ### thread_scenario_startup ###"); + + thread_instance_h *g_instance = &(mm->t_instance); + + /* Initialize thread */ + ret = thread_initialize(); + msg(" - thread_initialize() ret: [0x%X] [%s]", ret, _thread_get_error_message(ret)); + retv_if(!(ret == THREAD_ERROR_NONE || ret == THREAD_ERROR_ALREADY_DONE), RET_SUCCESS); + + /* thread enable */ + ret = thread_enable(g_instance); + msg(" - thread_enable() ret: [0x%X] [%s]", ret, _thread_get_error_message(ret)); + retv_if(!(ret == THREAD_ERROR_NONE || ret == THREAD_ERROR_ALREADY_DONE + || ret == THREAD_ERROR_ALREADY_REGISTERED), RET_SUCCESS); + + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_scenario_cleanup(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + msg(" ### thread_scenario_cleanup ###"); + + thread_instance_h *g_instance = &(mm->t_instance); + + /* thread disable */ + ret = thread_disable(g_instance); + msg(" - thread_disable() ret: [0x%X] [%s]", ret, _thread_get_error_message(ret)); + retv_if(!(ret == THREAD_ERROR_NONE || ret == THREAD_ERROR_ALREADY_DONE + || ret == THREAD_ERROR_ALREADY_REGISTERED), RET_SUCCESS); + + /* De-initialize thread */ + ret = thread_deinitialize(); + msg(" - thread_deinitialize() ret: [0x%X] [%s]", ret, _thread_get_error_message(ret)); + retv_if(!(ret == THREAD_ERROR_NONE || ret == THREAD_ERROR_ALREADY_DONE), RET_SUCCESS); + + FUNC_EXIT; + return RET_SUCCESS; +} +static int run_thread_joiner_join_network(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + int ret = THREAD_ERROR_NONE; + + /*factoryreset */ + ret = thread_factoryreset(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /*thread ifconfig up */ + ret = thread_ifconfig_up(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /*Joiner start*/ + ret = thread_joiner_start(g_instance, g_joiner_passphrase, g_prov_url, + g_vendor_name, g_vendor_model, g_vendor_sw_version, + g_vendor_data, _thread_joiner_start_callback, NULL); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + msg("thread_joiner_join_network success"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_start_leader_as_commissioner(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + sscanf(g_str_channel, "%x", &g_channel); + sscanf(g_str_extended_panid, "%llu", &g_extended_panid); + sscanf(g_str_panid, "%hu", &g_panid); + + int ret = THREAD_ERROR_NONE; + + /*factoryreset */ + ret = thread_factoryreset(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /* create operational_network */ + ret = thread_network_create_operational_network(g_instance, g_name, + g_key, g_pskc, g_channel, g_extended_panid, + g_panid, &g_network); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /*attach operational network */ + ret = thread_network_attach(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /*thread ifconfig up */ + ret = thread_ifconfig_up(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /* thread commissioner start*/ + ret = thread_commissioner_start(g_instance); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + /* thread commissioner set commissioning data*/ + ret = thread_commissioner_set_commisioning_data(g_instance, g_joiner_uuid, + g_joiner_passphrase); + if (ret != THREAD_ERROR_NONE) { + msg("Failed: %s", _thread_get_error_message(ret)); + goto OUT; + } + + msg("thread_commissioner_set_commisioning_data success"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static struct menu_data menu_thread_joiner_join_network[] = { + { "1", "Type Joiner Passphrase", NULL, NULL, g_joiner_passphrase}, + { "2", "run", NULL, run_thread_joiner_join_network, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_start_leader_as_commissioner[] = { + { "1", "Joiner UUID", NULL, NULL, g_joiner_uuid}, + { "2", "Joiner Passphrase", NULL, NULL, g_joiner_passphrase}, + { "3", "run", NULL, run_thread_start_leader_as_commissioner, NULL}, + { NULL, NULL, }, +}; + +struct menu_data menu_thread_scenarios[] = { + { "1", "thread_scenario_startup", + NULL, run_thread_scenario_startup, NULL }, + { "2", "thread_scenario_cleanup", + NULL, run_thread_scenario_cleanup, NULL }, + { "3", "thread_start_leader_as_commissioner", + menu_thread_start_leader_as_commissioner, NULL, NULL}, + { "4", "thread_joiner_join_network", + menu_thread_joiner_join_network, NULL, NULL }, + { NULL, NULL, }, +}; -- 2.7.4 From 5dbd5018ad11f29668db81d2db8aaf2755f83394 Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Thu, 24 Feb 2022 14:01:46 +0530 Subject: [PATCH 4/9] Add support to add and remove ipaddr for thread node This patch adds support to add and remove ipv6 address for the thread network: - thread_add_ipaddr - thread_remove_ipaddr Change-Id: Ie12902e3f707938af7b856258bee8a5bd67cce99 Signed-off-by: Rohit Singh --- include/thread.h | 38 ++++++++++++++++++++++++ src/thread-network.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/thread-network.c | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) diff --git a/include/thread.h b/include/thread.h index 06b2ce1..f430ea6 100644 --- a/include/thread.h +++ b/include/thread.h @@ -841,6 +841,44 @@ int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callb */ int thread_ifconfig_up(thread_instance_h instance); +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Add Ipv6 address to the thread node. + * @since_tizen 7.0 + * + * @param[in] ipv6_address Byte list + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize() and + * enabled with thread_enable(). + * @see thread_initialize() and thread_enable() + */ +int thread_add_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Remove Ipv6 address from the thread node. + * @since_tizen 7.0 + * + * @param[in] ipv6_address Byte list + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize() and + * enabled with thread_enable(). + * @see thread_initialize() and thread_enable() + */ +int thread_remove_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/thread-network.c b/src/thread-network.c index 5cec98c..b48e195 100644 --- a/src/thread-network.c +++ b/src/thread-network.c @@ -412,3 +412,83 @@ int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callb FUNC_EXIT; return ret; } + +static bool __is_valid_ipv6(const uint8_t* ipv6_address) +{ + FUNC_ENTRY; + + int index = 0; + while (index < THREAD_IPV6_ADDRESS_SIZE) { + char buffer[THREAD_NETWORK_BUFFER_MAX]; + snprintf(buffer, THREAD_NETWORK_BUFFER_MAX, "%02x", ipv6_address[index]); + if ((buffer[0] < '0' || buffer[0] > '9') && + (buffer[0] < 'a' || buffer[0] > 'f')) + return FALSE; + if ((buffer[1] < '0' || buffer[1] > '9') && + (buffer[1] < 'a' || buffer[1] > 'f')) + return FALSE; + + index++; + } + THREAD_DBG("DEBUG: NETWORK MESSAGE -> return true"); + + FUNC_EXIT; + return TRUE; +} + +int thread_add_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address); + + int ret = THREAD_ERROR_NONE; + char msg[THREAD_NETWORK_BUFFER_MAX]; + + retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER); + + snprintf(msg, THREAD_NETWORK_BUFFER_MAX, + "ipaddr add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3], + ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7], + ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11], + ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully added address"); + + FUNC_EXIT; + return ret; +} + +int thread_remove_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address); + + int ret = THREAD_ERROR_NONE; + char msg[THREAD_NETWORK_BUFFER_MAX]; + + retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER); + + snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX, + "ipaddr del %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3], + ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7], + ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11], + ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]); + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg)); + retv_if(ret != THREAD_ERROR_NONE, ret); + THREAD_DBG("Successfully removed address"); + + FUNC_EXIT; + return ret; +} + diff --git a/tests/thread-network.c b/tests/thread-network.c index c7a96da..90f730a 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -47,6 +47,9 @@ uint64_t g_extended_panid; uint16_t g_panid; static char g_str_ipaddr_type[MENU_DATA_SIZE + 1] = "0"; +static char g_str_ipaddr[MENU_DATA_SIZE + 1]; + +uint8_t g_ipv6_address[THREAD_IPV6_ADDRESS_SIZE]; static int run_thread_network_destroy_operational_network(MManager *mm, struct menu_data *menu) { @@ -204,6 +207,46 @@ OUT: return RET_SUCCESS; } +static int run_thread_add_ipaddr(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = _preprocess_ipv6_prefix(g_str_ipaddr, g_ipv6_address); + retv_if(ret != THREAD_ERROR_NONE, ret); + + ret = thread_add_ipaddr(g_instance, g_ipv6_address); + if (ret == THREAD_ERROR_NONE) + msg("thread_add_ipaddr success"); + else + msg("thread_add_ipaddr failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + +static int run_thread_remove_ipaddr(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = _preprocess_ipv6_prefix(g_str_ipaddr, g_ipv6_address); + retv_if(ret != THREAD_ERROR_NONE, ret); + + ret = thread_remove_ipaddr(g_instance, g_ipv6_address); + if (ret == THREAD_ERROR_NONE) + msg("thread_remove_ipaddr success"); + else + msg("thread_remove_ipaddr failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + static struct menu_data menu_thread_network_set_active_dataset_tlvs[] = { { "1", "Tlvs_buffer len", NULL, NULL, g_str_buf_length}, { "2", "Tlvs_buffer", NULL, NULL, g_str_tlvs_buffer}, @@ -229,6 +272,18 @@ static struct menu_data menu_thread_get_ipaddr[] = { { NULL, NULL, }, }; +static struct menu_data menu_thread_add_ipaddr[] = { + { "1", "Type IPv6 address", NULL, NULL, g_str_ipaddr}, + { "2", "run", NULL, run_thread_add_ipaddr, NULL}, + { NULL, NULL, }, +}; + +static struct menu_data menu_thread_remove_ipaddr[] = { + { "1", "Type IPv6 address", NULL, NULL, g_str_ipaddr}, + { "2", "run", NULL, run_thread_remove_ipaddr, NULL}, + { NULL, NULL, }, +}; + struct menu_data menu_thread_network[] = { { "1", "thread_network_create_operational_network", menu_thread_network_create_operational_network, NULL, NULL}, @@ -242,5 +297,10 @@ struct menu_data menu_thread_network[] = { NULL, run_thread_network_attach, NULL}, { "6", "thread_get_ipaddr", menu_thread_get_ipaddr, NULL, NULL}, + { "7", "thread_add_ipaddr", + menu_thread_add_ipaddr, NULL, NULL}, + { "8", "thread_remove_ipaddr", + menu_thread_remove_ipaddr, NULL, NULL}, { NULL, NULL, }, }; + -- 2.7.4 From 1ea2bfca7a0a18c35fffdeeb7b1d0d6d45f98cbf Mon Sep 17 00:00:00 2001 From: Ravinder Date: Wed, 23 Feb 2022 16:41:00 +0530 Subject: [PATCH 5/9] Fix svace issues This patch handles the static analysis issues related to memory leak, deref after NULL, tainted int loop, vulnerable function uses etc. Change-Id: I9c1b6e6e6504433342544c406333e66abc98b7ac Signed-off-by: Abhay Agarwal --- src/thread-br.c | 26 +++++++++++++------------- src/thread-commissioner.c | 7 ++++--- src/thread-joiner.c | 2 -- src/thread-network.c | 8 +++++++- src/thread-socket-handler.c | 6 ++++-- tests/thread-core.c | 6 +++--- tests/thread-main.c | 2 +- tests/thread-network.c | 13 ++++++++++++- tests/thread-srp.c | 3 ++- 9 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/thread-br.c b/src/thread-br.c index 68010af..fa837c6 100644 --- a/src/thread-br.c +++ b/src/thread-br.c @@ -305,14 +305,14 @@ int thread_br_add_external_route(thread_instance_h instance, ipv6_prefix_len); if (is_stable) - strcat(msg, " s"); + strncat(msg, " s", 2); if (preference == 0) - strcat(msg, " low"); + strncat(msg, " low", 4); else if (preference == 1) - strcat(msg, " med"); + strncat(msg, " med", 4); else if (preference == 2) - strcat(msg, " high"); + strncat(msg, " high", 5); THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); int ret = _thread_socket_client_execute(_thread_get_socket_fd(), @@ -418,24 +418,24 @@ int thread_br_add_onmesh_prefix(thread_instance_h instance, ipv6_prefix_len); if (preference == 0) - strcat(msg, " low "); + strncat(msg, " low ", 5); else if (preference == 1) - strcat(msg, " med "); + strncat(msg, " med ", 5); else if (preference == 2) - strcat(msg, " high "); + strncat(msg, " high ", 6); if (preferred) - strcat(msg, "p"); + strncat(msg, "p", 1); if (slaac) - strcat(msg, "a"); + strncat(msg, "a", 1); if (configure) - strcat(msg, "c"); + strncat(msg, "c", 1); if (default_route) - strcat(msg, "r"); + strncat(msg, "r", 1); if (on_mesh) - strcat(msg, "o"); + strncat(msg, "o", 1); if (stable) - strcat(msg, "s"); + strncat(msg, "s", 1); THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); int ret = _thread_socket_client_execute(_thread_get_socket_fd(), diff --git a/src/thread-commissioner.c b/src/thread-commissioner.c index 4ee4788..922d9e0 100644 --- a/src/thread-commissioner.c +++ b/src/thread-commissioner.c @@ -68,6 +68,10 @@ int thread_commissioner_set_commisioning_data(thread_instance_h instance, THREAD_VALIDATE_INPUT_PARAMETER(joiner_passphrase); int joiner_passphrase_len = strlen(joiner_passphrase); + + if (!joiner_uuid || !strcmp(joiner_uuid, "")) + joiner_uuid = "*"; + int joiner_uuid_len = strlen(joiner_uuid); retv_if(joiner_passphrase_len < 6 || joiner_passphrase_len > 32, THREAD_ERROR_INVALID_PARAMETER); @@ -75,9 +79,6 @@ int thread_commissioner_set_commisioning_data(thread_instance_h instance, int ret = THREAD_ERROR_NONE; - if (!joiner_uuid || !strcmp(joiner_uuid, "")) - joiner_uuid = "*"; - char msg[THREAD_COMMISSIONER_JOINER_BUFFER_MAX]; snprintf(msg, THREAD_COMMISSIONER_JOINER_BUFFER_MAX, "commissioner joiner add %s %s", joiner_uuid, joiner_passphrase); diff --git a/src/thread-joiner.c b/src/thread-joiner.c index 5ff4bc0..24519bc 100644 --- a/src/thread-joiner.c +++ b/src/thread-joiner.c @@ -50,7 +50,6 @@ int thread_joiner_join_by_network_key(thread_instance_h instance, char buf[THREAD_MAX_BUFFER_SIZE]; snprintf(buf, sizeof(buf), "%s %s", set_network_key, network_key); ret = _thread_socket_client_execute(_thread_get_socket_fd(), buf, strlen(buf)); - retv_if(ret != THREAD_ERROR_NONE, ret); if (ret != THREAD_ERROR_NONE) { THREAD_DBG("socket dataset networkkey execute failed"); return ret; @@ -61,7 +60,6 @@ int thread_joiner_join_by_network_key(thread_instance_h instance, buf[0] = '\0'; snprintf(buf, sizeof(buf), "%s %s", set_panid, panid); ret = _thread_socket_client_execute(_thread_get_socket_fd(), buf, strlen(buf)); - retv_if(ret != THREAD_ERROR_NONE, ret); if (ret != THREAD_ERROR_NONE) { THREAD_DBG("socket dataset panid execute failed"); return ret; diff --git a/src/thread-network.c b/src/thread-network.c index 5cec98c..2e25d2c 100644 --- a/src/thread-network.c +++ b/src/thread-network.c @@ -145,7 +145,7 @@ int thread_network_set_active_dataset_tlvs(thread_instance_h instance, /* Print input data */ char buf[THREAD_MAX_BUFFER_SIZE]; for (int i = 0; i < buf_length; i++) - sprintf(buf + i*2, "%2.2x", tlvs_buffer[i]); + snprintf(buf + i*2, 3, "%2.2x", tlvs_buffer[i]); THREAD_DBG("Active dataset tlvs size: %d :: %s", buf_length, buf); bytes = g_bytes_new(tlvs_buffer, buf_length); @@ -216,6 +216,12 @@ int thread_network_get_active_dataset_tlvs(thread_instance_h instance, } *tlvs_buffer = g_malloc0(THREAD_MAX_BUFFER_SIZE*sizeof(uint8_t)); + if (!(*tlvs_buffer)) { + /* LCOV_EXCL_START */ + THREAD_ERR("g_malloc0 failed"); + return THREAD_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } index = 0; while (index < THREAD_MAX_BUFFER_SIZE) { if (buffer[index] == 'D') diff --git a/src/thread-socket-handler.c b/src/thread-socket-handler.c index f198622..553d9db 100644 --- a/src/thread-socket-handler.c +++ b/src/thread-socket-handler.c @@ -60,8 +60,10 @@ int _thread_socket_client_init(int *socket_fd, const char *if_name) ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, if_name); - retv_if(!(ret >= 0 && (size_t)ret < sizeof(sockname.sun_path)), - THREAD_ERROR_OPERATION_FAILED); + if (!(ret >= 0 && (size_t)ret < sizeof(sockname.sun_path))) { + close(session_fd); + return THREAD_ERROR_OPERATION_FAILED; + } THREAD_DBG("Connect on socket fd %d path %s", session_fd, sockname.sun_path); diff --git a/tests/thread-core.c b/tests/thread-core.c index 79af951..57c9749 100755 --- a/tests/thread-core.c +++ b/tests/thread-core.c @@ -78,9 +78,9 @@ static void __thread_scan_callback(int result, thread_network_scanning_state_e s void thread_device_role_callback(thread_device_role_e device_role, void *user_data) { - FUNC_ENTRY; - THREAD_DBG("Device Role is [%d]", device_role); - FUNC_EXIT; + FUNC_ENTRY; + THREAD_DBG("Device Role is [%d]", device_role); + FUNC_EXIT; } diff --git a/tests/thread-main.c b/tests/thread-main.c index 049d514..6f92c9f 100755 --- a/tests/thread-main.c +++ b/tests/thread-main.c @@ -115,9 +115,9 @@ int main(int arg, char **argv) g_io_add_watch(channel, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), on_menu_manager_keyboard, manager); g_main_loop_run(mainloop); + thread_disable(manager->t_instance); OUT: - thread_disable(manager->t_instance); __deinit_func(); menu_manager_free(manager); diff --git a/tests/thread-network.c b/tests/thread-network.c index 2ad3fb3..54c8ed9 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -101,6 +101,10 @@ static int run_thread_network_set_active_dataset_tlvs(MManager *mm, struct menu_ msg("Set active dataset tlvs size: %d :: %s", buf_length, g_str_tlvs_buffer); + if (!buf_length || buf_length > (MENU_DATA_SIZE + 1)) { + msg("Invalid Input"); + goto OUT; + } for (int i = 0; i < buf_length; i++) { char subbuff[3]; memcpy(subbuff, &g_str_tlvs_buffer[2*i], 2); @@ -128,10 +132,17 @@ static int run_thread_network_get_active_dataset_tlvs(MManager *mm, struct menu_ int buf_length; uint8_t *tlvs_buffer; + char buf[1024]; + int ret = thread_network_get_active_dataset_tlvs(g_instance, &tlvs_buffer, &buf_length); if (ret == THREAD_ERROR_NONE) { msg("thread_network_get_active_dataset_tlvs success"); - msg("Active dataset tlvs size: %d :: %s", buf_length, tlvs_buffer); + + for (int i = 0; i < buf_length; i++) + snprintf(buf + i*2, 3, "%2.2x", tlvs_buffer[i]); + + msg("Active dataset tlvs size: %d :: %s", buf_length, buf); + free(tlvs_buffer); } else { msg("thread_network_get_active_dataset_tlvs failed"); } diff --git a/tests/thread-srp.c b/tests/thread-srp.c index 460edc9..70fb291 100644 --- a/tests/thread-srp.c +++ b/tests/thread-srp.c @@ -136,7 +136,8 @@ static int __run_thread_srp_client_register_service(MManager *mm, struct menu_da if (g_instance == NULL) goto OUT; - g_port = (uint64_t)atoi(g_str_port); + g_port = (uint64_t)strtoll(g_str_port, (char **)NULL, 10); + int ret = thread_srp_client_register_service(g_instance, g_service_name, g_service_type, g_port); if (ret == THREAD_ERROR_NONE) -- 2.7.4 From 4f36e7421b78028e5a3852f5fe5b400c0e733d3b Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Wed, 2 Mar 2022 12:57:59 +0530 Subject: [PATCH 6/9] Fix coverity issue Change-Id: Ica1bd60af2fe5fd831d9941704ec3ed4ccb3dcb7 Signed-off-by: Rohit Singh --- src/thread-commissioner.c | 7 +++---- src/thread-dbus-handler.c | 6 +++++- src/thread-network.c | 6 +++--- tests/thread-menu.h | 2 +- tests/thread-network.c | 33 ++++++++++++++++++--------------- tests/thread-scenarios.c | 14 +++++++------- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/thread-commissioner.c b/src/thread-commissioner.c index 922d9e0..eb0ffb5 100644 --- a/src/thread-commissioner.c +++ b/src/thread-commissioner.c @@ -66,19 +66,18 @@ int thread_commissioner_set_commisioning_data(thread_instance_h instance, THREAD_CHECK_INIT_STATUS(); THREAD_VALIDATE_INPUT_PARAMETER(instance); THREAD_VALIDATE_INPUT_PARAMETER(joiner_passphrase); + THREAD_VALIDATE_INPUT_PARAMETER(joiner_uuid); + int ret = THREAD_ERROR_NONE; int joiner_passphrase_len = strlen(joiner_passphrase); - if (!joiner_uuid || !strcmp(joiner_uuid, "")) + if (strcmp(joiner_uuid, "") == 0) joiner_uuid = "*"; - int joiner_uuid_len = strlen(joiner_uuid); retv_if(joiner_passphrase_len < 6 || joiner_passphrase_len > 32, THREAD_ERROR_INVALID_PARAMETER); retv_if(joiner_uuid_len > 16, THREAD_ERROR_INVALID_PARAMETER); - int ret = THREAD_ERROR_NONE; - char msg[THREAD_COMMISSIONER_JOINER_BUFFER_MAX]; snprintf(msg, THREAD_COMMISSIONER_JOINER_BUFFER_MAX, "commissioner joiner add %s %s", joiner_uuid, joiner_passphrase); diff --git a/src/thread-dbus-handler.c b/src/thread-dbus-handler.c index 6796cf8..fff8369 100644 --- a/src/thread-dbus-handler.c +++ b/src/thread-dbus-handler.c @@ -294,7 +294,11 @@ int _thread_dbus_register_event(const char *event_name, const char *interface, retv_if(event_data == NULL, THREAD_ERROR_OUT_OF_MEMORY); event_data->event_name = g_strdup(event_name); - retv_if(event_data->event_name == NULL, THREAD_ERROR_OUT_OF_MEMORY); + if (event_data->event_name == NULL) { + THREAD_DBG("Event Name is NULL"); + g_free(event_data); + return THREAD_ERROR_OUT_OF_MEMORY; + } /* Register event */ event_data->event_id = g_dbus_connection_signal_subscribe(g_system_connection, diff --git a/src/thread-network.c b/src/thread-network.c index f2a35e2..2f3caa9 100644 --- a/src/thread-network.c +++ b/src/thread-network.c @@ -89,9 +89,9 @@ int thread_network_create_operational_network(thread_instance_h instance, } new_network->is_network_active = FALSE; - g_strlcpy(new_network->name, name, THREAD_NETWORK_NAME_MAX + 1); - g_strlcpy(new_network->key, key, THREAD_NETWORK_KEY_STRING_MAX + 1); - g_strlcpy(new_network->pskc, pskc, THREAD_NETWORK_PSKC_STRING_MAX + 1); + (void)g_strlcpy(new_network->name, name, THREAD_NETWORK_NAME_MAX + 1); + (void)g_strlcpy(new_network->key, key, THREAD_NETWORK_KEY_STRING_MAX + 1); + (void)g_strlcpy(new_network->pskc, pskc, THREAD_NETWORK_PSKC_STRING_MAX + 1); new_network->channel = channel; new_network->extended_panid = extended_panid; new_network->panid = panid; diff --git a/tests/thread-menu.h b/tests/thread-menu.h index b7ec3f4..c871fc3 100755 --- a/tests/thread-menu.h +++ b/tests/thread-menu.h @@ -117,7 +117,7 @@ do { \ } while (0) #define MENU_DATA_SIZE 255 - +#define NETWORK_DATA_SIZE 256 /* * Horizontal Line - width: 65 * .12345678901234567890123456789012345678901234567890. diff --git a/tests/thread-network.c b/tests/thread-network.c index caecbe0..d2002e6 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -32,22 +32,22 @@ #include "thread-log.h" #include "thread-util.h" -static char g_name[MENU_DATA_SIZE + 1] = {"Thread-test"}; -static char g_key[MENU_DATA_SIZE + 1]; -static char g_pskc[MENU_DATA_SIZE + 1]; -static char g_str_channel[MENU_DATA_SIZE + 1] = {"07fff800"}; -static char g_str_extended_panid[MENU_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ -static char g_str_panid[MENU_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ -static char g_str_buf_length[MENU_DATA_SIZE + 1]; -static char g_str_tlvs_buffer[MENU_DATA_SIZE + 1]; +static char g_name[NETWORK_DATA_SIZE + 1] = {"Thread-test"}; +static char g_key[NETWORK_DATA_SIZE + 1]; +static char g_pskc[NETWORK_DATA_SIZE + 1]; +static char g_str_channel[NETWORK_DATA_SIZE + 1] = {"07fff800"}; +static char g_str_extended_panid[NETWORK_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ +static char g_str_panid[NETWORK_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ +static char g_str_buf_length[NETWORK_DATA_SIZE + 1]; +static char g_str_tlvs_buffer[2*NETWORK_DATA_SIZE + 1]; static thread_network_h g_network; uint32_t g_channel; uint64_t g_extended_panid; uint16_t g_panid; -static char g_str_ipaddr_type[MENU_DATA_SIZE + 1] = "0"; -static char g_str_ipaddr[MENU_DATA_SIZE + 1]; +static char g_str_ipaddr_type[NETWORK_DATA_SIZE + 1] = "0"; +static char g_str_ipaddr[NETWORK_DATA_SIZE + 1]; uint8_t g_ipv6_address[THREAD_IPV6_ADDRESS_SIZE]; @@ -129,14 +129,15 @@ OUT: static int run_thread_network_get_active_dataset_tlvs(MManager *mm, struct menu_data *menu) { FUNC_ENTRY; + + uint8_t *tlvs_buffer = NULL; + char buf[1024]; + int buf_length; + thread_instance_h g_instance = mm->t_instance; if (g_instance == NULL) goto OUT; - int buf_length; - uint8_t *tlvs_buffer; - char buf[1024]; - int ret = thread_network_get_active_dataset_tlvs(g_instance, &tlvs_buffer, &buf_length); if (ret == THREAD_ERROR_NONE) { msg("thread_network_get_active_dataset_tlvs success"); @@ -145,11 +146,13 @@ static int run_thread_network_get_active_dataset_tlvs(MManager *mm, struct menu_ snprintf(buf + i*2, 3, "%2.2x", tlvs_buffer[i]); msg("Active dataset tlvs size: %d :: %s", buf_length, buf); - free(tlvs_buffer); } else { msg("thread_network_get_active_dataset_tlvs failed"); } OUT: + if (tlvs_buffer) + free(tlvs_buffer); + FUNC_EXIT; return RET_SUCCESS; } diff --git a/tests/thread-scenarios.c b/tests/thread-scenarios.c index 116e627..d7fc126 100644 --- a/tests/thread-scenarios.c +++ b/tests/thread-scenarios.c @@ -32,12 +32,12 @@ #include "thread-log.h" #include "thread-util.h" -static char g_name[MENU_DATA_SIZE + 1] = {"Thread-test"}; -static char g_key[MENU_DATA_SIZE + 1]; -static char g_pskc[MENU_DATA_SIZE + 1]; -static char g_str_channel[MENU_DATA_SIZE + 1] = {"07fff800"}; -static char g_str_extended_panid[MENU_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ -static char g_str_panid[MENU_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ +static char g_name[NETWORK_DATA_SIZE + 1] = {"Thread-test"}; +static char g_key[NETWORK_DATA_SIZE + 1]; +static char g_pskc[NETWORK_DATA_SIZE + 1]; +static char g_str_channel[NETWORK_DATA_SIZE + 1] = {"07fff800"}; +static char g_str_extended_panid[NETWORK_DATA_SIZE + 1] = {"18446744073709551615"}; /* UINT64_MAX */ +static char g_str_panid[NETWORK_DATA_SIZE + 1] = {"65535"}; /* UINT16_MAX */ static thread_network_h g_network; static char g_joiner_uuid[MENU_DATA_SIZE + 1]; @@ -90,7 +90,7 @@ static int run_thread_scenario_cleanup(MManager *mm, struct menu_data *menu) int ret = THREAD_ERROR_NONE; msg(" ### thread_scenario_cleanup ###"); - thread_instance_h *g_instance = &(mm->t_instance); + thread_instance_h g_instance = mm->t_instance; /* thread disable */ ret = thread_disable(g_instance); -- 2.7.4 From fb34ca69f3d53c440172f7e1ac5d006c4b748032 Mon Sep 17 00:00:00 2001 From: Wootak Jung Date: Mon, 7 Mar 2022 08:32:27 +0900 Subject: [PATCH 7/9] Fix 64bit build error Change-Id: Icc9ddd60b872c37cfaad84fbeee5efd2255408d5 --- src/thread-br.c | 26 +++++++++++++------------- src/thread-core.c | 2 +- src/thread-network.c | 14 +++++++------- src/thread-socket-handler.c | 2 +- src/thread-srp.c | 4 ++-- src/thread-util.c | 4 ++-- tests/thread-core.c | 10 +++++----- tests/thread-network.c | 2 +- tests/thread-scenarios.c | 2 +- tests/thread-srp.c | 2 +- 10 files changed, 34 insertions(+), 34 deletions(-) mode change 100755 => 100644 src/thread-util.c diff --git a/src/thread-br.c b/src/thread-br.c index fa837c6..7fa9d07 100644 --- a/src/thread-br.c +++ b/src/thread-br.c @@ -305,14 +305,14 @@ int thread_br_add_external_route(thread_instance_h instance, ipv6_prefix_len); if (is_stable) - strncat(msg, " s", 2); + strncat(msg, " s", 3); if (preference == 0) - strncat(msg, " low", 4); + strncat(msg, " low", 5); else if (preference == 1) - strncat(msg, " med", 4); + strncat(msg, " med", 5); else if (preference == 2) - strncat(msg, " high", 5); + strncat(msg, " high", 6); THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); int ret = _thread_socket_client_execute(_thread_get_socket_fd(), @@ -418,24 +418,24 @@ int thread_br_add_onmesh_prefix(thread_instance_h instance, ipv6_prefix_len); if (preference == 0) - strncat(msg, " low ", 5); + strncat(msg, " low ", 6); else if (preference == 1) - strncat(msg, " med ", 5); + strncat(msg, " med ", 6); else if (preference == 2) - strncat(msg, " high ", 6); + strncat(msg, " high ", 7); if (preferred) - strncat(msg, "p", 1); + strncat(msg, "p", 2); if (slaac) - strncat(msg, "a", 1); + strncat(msg, "a", 2); if (configure) - strncat(msg, "c", 1); + strncat(msg, "c", 2); if (default_route) - strncat(msg, "r", 1); + strncat(msg, "r", 2); if (on_mesh) - strncat(msg, "o", 1); + strncat(msg, "o", 2); if (stable) - strncat(msg, "s", 1); + strncat(msg, "s", 2); THREAD_DBG("DEBUG: BORDER ROUTER MESSAGE -> [%s]", msg); int ret = _thread_socket_client_execute(_thread_get_socket_fd(), diff --git a/src/thread-core.c b/src/thread-core.c index 3eb8896..66a1620 100644 --- a/src/thread-core.c +++ b/src/thread-core.c @@ -546,7 +546,7 @@ int thread_get_extended_address(thread_instance_h instance, uint64_t *extended_a retv_if(ret != THREAD_ERROR_NONE, ret); g_variant_get(out, "t", extended_address); - THREAD_DBG("Thread extended address: %llu", *extended_address); + THREAD_DBG("Thread extended address: %zu", (size_t)*extended_address); g_variant_unref(out); FUNC_EXIT; diff --git a/src/thread-network.c b/src/thread-network.c index 2f3caa9..bdfe802 100644 --- a/src/thread-network.c +++ b/src/thread-network.c @@ -70,7 +70,7 @@ int thread_network_create_operational_network(thread_instance_h instance, THREAD_DBG("Network key: %s", key); THREAD_DBG("Network pskc: %s", pskc); THREAD_DBG("Network channel: 0x%8.8x", channel); - THREAD_DBG("Network extended_panid: %llu", extended_panid); + THREAD_DBG("Network extended_panid: %zu", (size_t)extended_panid); THREAD_DBG("Network panid: %u", panid); /* Free existing current network */ @@ -206,7 +206,7 @@ int thread_network_get_active_dataset_tlvs(thread_instance_h instance, THREAD_DBG("Failed to execute command %s", cmd_buffer); return ret; } - THREAD_DBG("Executed command '%s' with size %d", cmd_buffer, strlen(cmd_buffer)); + THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, strlen(cmd_buffer)); /* Check response */ ret = _thread_socket_client_read(session_fd, buffer); @@ -276,7 +276,7 @@ int thread_network_attach(thread_instance_h instance) THREAD_DBG("Network pskc: %s", network->pskc); THREAD_DBG("Network channel: 0x%8.8x", network->channel); - THREAD_DBG("Network extended_panid: %llu", network->extended_panid); + THREAD_DBG("Network extended_panid: %zu", (size_t)network->extended_panid); if (network->extended_panid == UINT64_MAX) THREAD_DBG("extended_panid is UINT64_MAX, "\ "Random extended_panid will be used"); @@ -297,7 +297,7 @@ int thread_network_attach(thread_instance_h instance) /* Network key builder */ GVariantBuilder *key_builder; key_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); - THREAD_DBG("key str length: %d", strlen(network->key)); + THREAD_DBG("key str length: %zu", strlen(network->key)); for (int i = 0; i < strlen(network->key); i++) { g_variant_builder_add(key_builder, "y", (unsigned char)network->key[i]); @@ -306,7 +306,7 @@ int thread_network_attach(thread_instance_h instance) /* pskc builder */ GVariantBuilder *pskc_builder; pskc_builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); - THREAD_DBG("pskc str length: %d", strlen(network->pskc)); + THREAD_DBG("pskc str length: %zu", strlen(network->pskc)); for (int i = 0; i < strlen(network->pskc); i++) { g_variant_builder_add(pskc_builder, "y", (unsigned char)network->pskc[i]); @@ -387,7 +387,7 @@ int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callb THREAD_DBG("Failed to execute command %s", cmd_buffer); return ret; } - THREAD_DBG("Executed command '%s' with size %d", cmd_buffer, buf_size); + THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, buf_size); /* Check response */ ret = _thread_socket_client_read(session_fd, buffer); @@ -406,7 +406,7 @@ int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callb } else { ipaddr[pos] = '\0'; if (pos > 0) { - THREAD_DBG("IP address: %s, length: %d", ipaddr, + THREAD_DBG("IP address: %s, length: %zu", ipaddr, strlen(ipaddr)); callback(++count, ipaddr, ipaddr_type, user_data); } diff --git a/src/thread-socket-handler.c b/src/thread-socket-handler.c index 553d9db..5de3fe0 100644 --- a/src/thread-socket-handler.c +++ b/src/thread-socket-handler.c @@ -254,7 +254,7 @@ int _thread_socket_client_write(int session_fd, if (!request_buffer || buf_size <= 0) return THREAD_ERROR_INVALID_PARAMETER; - THREAD_DBG("Socket write command '%s' with size %d", + THREAD_DBG("Socket write command '%s' with size %zu", request_buffer, buf_size); rval = write(session_fd, request_buffer, buf_size); diff --git a/src/thread-srp.c b/src/thread-srp.c index edb5066..5417c4e 100644 --- a/src/thread-srp.c +++ b/src/thread-srp.c @@ -161,8 +161,8 @@ int thread_srp_client_register_service(thread_instance_h instance, const char *msg = THREAD_SRP_CLIENT_REGISTER_SERVICE_CMD; char buffer[THREAD_MAX_BUFFER_SIZE] = {0}; - snprintf(buffer, sizeof(buffer), "%s %s %s %llu", msg, - service_name, service_type, port); + snprintf(buffer, sizeof(buffer), "%s %s %s %zu", msg, + service_name, service_type, (size_t)port); ret = _thread_socket_client_execute(_thread_get_socket_fd(), buffer, strlen(buffer)); if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { diff --git a/src/thread-util.c b/src/thread-util.c old mode 100755 new mode 100644 index 1225fa9..fc9eebd --- a/src/thread-util.c +++ b/src/thread-util.c @@ -188,9 +188,9 @@ void __thread_dbus_handle_scan_cb(gboolean res, &version, &is_native, &is_native)) { THREAD_DBG("Got the thread beacon..."); - THREAD_DBG("ext_address: %llu", ext_address); + THREAD_DBG("ext_address: %zu", (size_t)ext_address); THREAD_DBG("network_name: %s", network_name); - THREAD_DBG("ext panid: %llu", ext_panid); + THREAD_DBG("ext panid: %zu", (size_t)ext_panid); int i = 0; while (steering_data[i] != '\0') { diff --git a/tests/thread-core.c b/tests/thread-core.c index 57c9749..7d2d987 100755 --- a/tests/thread-core.c +++ b/tests/thread-core.c @@ -57,9 +57,9 @@ static void __thread_scan_callback(int result, thread_network_scanning_state_e s else { msg("thread_network_scanning_state: [%d]", state); msg("network_name: [%s]", network_name); - msg("ext_address: [%llu]", ext_address); - msg("ext_panidi: [%llu]", ext_panidi); - msg("steering_data: [%d]", (int)steering_data); + msg("ext_address: [%zu]", (size_t)ext_address); + msg("ext_panidi: [%zu]", (size_t)ext_panidi); + msg("steering_data: [%s]", steering_data); msg("length: [%d]", length); msg("panid: [%hu]", panid); msg("joiner_udp_port: [%hu]", joiner_udp_port); @@ -318,8 +318,8 @@ static int run_thread_get_extended_address(MManager *mm, struct menu_data *menu) int ret = thread_get_extended_address(g_instance, &g_extended_address); if (ret == THREAD_ERROR_NONE) { msg("thread_get_extended_address success"); - msg("- thread_get_exenteded_address() ret: Device extended address->[%llu]", - g_extended_address); + msg("- thread_get_exenteded_address() ret: Device extended address->[%zu]", + (size_t)g_extended_address); } else msg("thread_get_extended_address failed"); OUT: diff --git a/tests/thread-network.c b/tests/thread-network.c index d2002e6..2ed4fbd 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -76,7 +76,7 @@ static int run_thread_network_create_operational_network(MManager *mm, struct me goto OUT; sscanf(g_str_channel, "%x", &g_channel); - sscanf(g_str_extended_panid, "%llu", &g_extended_panid); + sscanf(g_str_extended_panid, "%zu", (size_t *)&g_extended_panid); sscanf(g_str_panid, "%hu", &g_panid); int ret = thread_network_create_operational_network(g_instance, g_name, g_key, diff --git a/tests/thread-scenarios.c b/tests/thread-scenarios.c index d7fc126..369282c 100644 --- a/tests/thread-scenarios.c +++ b/tests/thread-scenarios.c @@ -151,7 +151,7 @@ static int run_thread_start_leader_as_commissioner(MManager *mm, struct menu_dat goto OUT; sscanf(g_str_channel, "%x", &g_channel); - sscanf(g_str_extended_panid, "%llu", &g_extended_panid); + sscanf(g_str_extended_panid, "%zu", (size_t *)&g_extended_panid); sscanf(g_str_panid, "%hu", &g_panid); int ret = THREAD_ERROR_NONE; diff --git a/tests/thread-srp.c b/tests/thread-srp.c index 70fb291..8b50389 100644 --- a/tests/thread-srp.c +++ b/tests/thread-srp.c @@ -193,7 +193,7 @@ static int __run_thread_srp_server_get_registered_service(MManager *mm, struct m if (ret == THREAD_ERROR_NONE) { msg("thread_srp_get_registered_service success"); - msg("service: [%s], [%s], [%llu], [%s]", service_name, address, port, is_deleted ? "TRUE" : "FALSE"); + msg("service: [%s], [%s], [%zu], [%s]", service_name, address, (size_t)port, is_deleted ? "TRUE" : "FALSE"); } else msg("thread_srp_get_registered_service failed"); OUT: -- 2.7.4 From c5e2ec50b4a578feef011b557a91f9a5320846f1 Mon Sep 17 00:00:00 2001 From: Ravinder Date: Fri, 4 Mar 2022 17:09:15 +0530 Subject: [PATCH 8/9] Update network API's Change-Id: I57e218960a6f0d5a0350de1cfc242ba18b25cfdb --- src/thread-network.c | 35 ++++++++++++++++++++++++++++++++++- tests/thread-network.c | 25 ++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/thread-network.c b/src/thread-network.c index 2f3caa9..b2be07d 100644 --- a/src/thread-network.c +++ b/src/thread-network.c @@ -333,15 +333,48 @@ done: return ret; } +static int __thread_detach_active_network() +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + + THREAD_DBG("Detach current active network dataset"); + ret = _thread_dbus_sync_method_call(THREAD_DBUS_DETACH_METHOD, + g_variant_new("()")); + if (ret != THREAD_ERROR_NONE) + THREAD_ERR("Thread Detach failed"); + else + THREAD_DBG("Thread Detach successful"); + + FUNC_EXIT; + return ret; +} + int thread_network_detach(thread_instance_h instance) { FUNC_ENTRY; THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); THREAD_CHECK_INIT_STATUS(); THREAD_VALIDATE_INPUT_PARAMETER(instance); - int ret = THREAD_ERROR_NOT_SUPPORTED; + int ret = THREAD_ERROR_NONE; + + thread_instance_s *current_instance = instance; + thread_network_s *network = current_instance->network; + + if (!network) + return THREAD_ERROR_INVALID_PARAMETER; + if (network->is_network_active == TRUE) + ret = __thread_detach_active_network(); + if (ret != THREAD_ERROR_NONE) { + THREAD_ERR("Thread Detach failed"); + goto done; + } + network->is_network_active = FALSE; + THREAD_DBG("Thread Detach successful"); + +done: FUNC_EXIT; return ret; } diff --git a/tests/thread-network.c b/tests/thread-network.c index d2002e6..1f4cc81 100644 --- a/tests/thread-network.c +++ b/tests/thread-network.c @@ -174,6 +174,23 @@ OUT: return RET_SUCCESS; } +static int run_thread_network_detach(MManager *mm, struct menu_data *menu) +{ + FUNC_ENTRY; + thread_instance_h g_instance = mm->t_instance; + if (g_instance == NULL) + goto OUT; + + int ret = thread_network_detach(g_instance); + if (ret == THREAD_ERROR_NONE) + msg("thread_network_detach success"); + else + msg("thread_network_detach failed"); +OUT: + FUNC_EXIT; + return RET_SUCCESS; +} + static void __get_ipaddr_callback(int index, char* ipaddr, thread_ipaddr_type_e ipaddr_type, void *user_data) { FUNC_ENTRY; @@ -309,11 +326,13 @@ struct menu_data menu_thread_network[] = { NULL, run_thread_network_get_active_dataset_tlvs, NULL }, { "5", "thread_network_attach", NULL, run_thread_network_attach, NULL}, - { "6", "thread_get_ipaddr", + { "6", "thread_network_detach", + NULL, run_thread_network_detach, NULL}, + { "7", "thread_get_ipaddr", menu_thread_get_ipaddr, NULL, NULL}, - { "7", "thread_add_ipaddr", + { "8", "thread_add_ipaddr", menu_thread_add_ipaddr, NULL, NULL}, - { "8", "thread_remove_ipaddr", + { "9", "thread_remove_ipaddr", menu_thread_remove_ipaddr, NULL, NULL}, { NULL, NULL, }, }; -- 2.7.4 From c0d1ef35d7543fbbc15af8cb1a7c2485fa9d0e3f Mon Sep 17 00:00:00 2001 From: "hyunuk.tak" Date: Fri, 18 Mar 2022 15:20:50 +0900 Subject: [PATCH 9/9] Move test files to thread-test folder Change-Id: Iaccf336e0d02b79c718f961e089c51215758206a Signed-off-by: hyunuk.tak --- CMakeLists.txt | 5 +---- tests/{ => thread-test}/CMakeLists.txt | 0 tests/{ => thread-test}/thread-br.c | 0 tests/{ => thread-test}/thread-commissioner.c | 0 tests/{ => thread-test}/thread-core.c | 0 tests/{ => thread-test}/thread-init.c | 0 tests/{ => thread-test}/thread-joiner.c | 0 tests/{ => thread-test}/thread-main.c | 0 tests/{ => thread-test}/thread-menu.c | 0 tests/{ => thread-test}/thread-menu.h | 0 tests/{ => thread-test}/thread-network.c | 0 tests/{ => thread-test}/thread-srp.c | 0 tests/{ => thread-test}/thread-util.c | 0 tests/{ => thread-test}/thread-util.h | 0 14 files changed, 1 insertion(+), 4 deletions(-) rename tests/{ => thread-test}/CMakeLists.txt (100%) rename tests/{ => thread-test}/thread-br.c (100%) rename tests/{ => thread-test}/thread-commissioner.c (100%) rename tests/{ => thread-test}/thread-core.c (100%) rename tests/{ => thread-test}/thread-init.c (100%) rename tests/{ => thread-test}/thread-joiner.c (100%) rename tests/{ => thread-test}/thread-main.c (100%) rename tests/{ => thread-test}/thread-menu.c (100%) rename tests/{ => thread-test}/thread-menu.h (100%) rename tests/{ => thread-test}/thread-network.c (100%) rename tests/{ => thread-test}/thread-srp.c (100%) rename tests/{ => thread-test}/thread-util.c (100%) rename tests/{ => thread-test}/thread-util.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9da0bc..59a94cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,10 +74,7 @@ CONFIGURE_FILE( ) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -#ADD_SUBDIRECTORY(tests/test) -#ADD_SUBDIRECTORY(tests/unittest) - -ADD_SUBDIRECTORY(tests) +ADD_SUBDIRECTORY(tests/thread-test) IF(UNIX) diff --git a/tests/CMakeLists.txt b/tests/thread-test/CMakeLists.txt similarity index 100% rename from tests/CMakeLists.txt rename to tests/thread-test/CMakeLists.txt diff --git a/tests/thread-br.c b/tests/thread-test/thread-br.c similarity index 100% rename from tests/thread-br.c rename to tests/thread-test/thread-br.c diff --git a/tests/thread-commissioner.c b/tests/thread-test/thread-commissioner.c similarity index 100% rename from tests/thread-commissioner.c rename to tests/thread-test/thread-commissioner.c diff --git a/tests/thread-core.c b/tests/thread-test/thread-core.c similarity index 100% rename from tests/thread-core.c rename to tests/thread-test/thread-core.c diff --git a/tests/thread-init.c b/tests/thread-test/thread-init.c similarity index 100% rename from tests/thread-init.c rename to tests/thread-test/thread-init.c diff --git a/tests/thread-joiner.c b/tests/thread-test/thread-joiner.c similarity index 100% rename from tests/thread-joiner.c rename to tests/thread-test/thread-joiner.c diff --git a/tests/thread-main.c b/tests/thread-test/thread-main.c similarity index 100% rename from tests/thread-main.c rename to tests/thread-test/thread-main.c diff --git a/tests/thread-menu.c b/tests/thread-test/thread-menu.c similarity index 100% rename from tests/thread-menu.c rename to tests/thread-test/thread-menu.c diff --git a/tests/thread-menu.h b/tests/thread-test/thread-menu.h similarity index 100% rename from tests/thread-menu.h rename to tests/thread-test/thread-menu.h diff --git a/tests/thread-network.c b/tests/thread-test/thread-network.c similarity index 100% rename from tests/thread-network.c rename to tests/thread-test/thread-network.c diff --git a/tests/thread-srp.c b/tests/thread-test/thread-srp.c similarity index 100% rename from tests/thread-srp.c rename to tests/thread-test/thread-srp.c diff --git a/tests/thread-util.c b/tests/thread-test/thread-util.c similarity index 100% rename from tests/thread-util.c rename to tests/thread-test/thread-util.c diff --git a/tests/thread-util.h b/tests/thread-test/thread-util.h similarity index 100% rename from tests/thread-util.h rename to tests/thread-test/thread-util.h -- 2.7.4