--- /dev/null
+Anupam Roy <anupam.r@samsung.com>
--- /dev/null
+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)
+
--- /dev/null
+
+ 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.
--- /dev/null
+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.
--- /dev/null
+This is Thread CAPI library for Tizen
--- /dev/null
+# 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}
+
--- /dev/null
+/*
+ * 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 <dlog.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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 <dlog.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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 <glib.h>
+#include <thread-log.h>
+#include <thread.h>
+
+#include <system_info.h>
+
+#include <thread-type.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <glib.h>
+#include <tizen.h>
+#include <tizen_error.h>
+
+#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 /**<Max length of Commissioner joiner message buffer (bytes)*/
+#define THREAD_BORDER_ROUTER_BUFFER_MAX 1024 /**<Max length of Border Router message buffer (bytes) */
+#define THREAD_NETWORK_BUFFER_MAX 1024
+/**
+* Maximum length of Active Operational Dataset in bytes.
+ */
+#define THREAD_OPERATIONAL_DATASET_MAX_LENGTH 254
+
+#define THREAD_EUI_64_SIZE 8 /*< in Bytes */
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Enumerations of Tizen thread framework error codes.
+ * @since_tizen 7.0
+ */
+typedef enum {
+ THREAD_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful*/
+ THREAD_ERROR_NOT_PERMITTED = TIZEN_ERROR_NOT_PERMITTED, /**< Operation not permitted */
+ THREAD_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ THREAD_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+ THREAD_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+ THREAD_ERROR_RESOURCE_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /**< Device or resource busy */
+ THREAD_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< Timeout error */
+ THREAD_ERROR_CANCELED = TIZEN_ERROR_CANCELED, /**< Operation canceled */
+ THREAD_ERROR_NOW_IN_PROGRESS = TIZEN_ERROR_NOW_IN_PROGRESS, /**< Operation now in progress */
+ THREAD_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not Supported */
+ THREAD_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< No data available */
+ THREAD_ERROR_NOT_INITIALIZED = TIZEN_ERROR_THREAD | 0x01, /**< Not initialized */
+ THREAD_ERROR_NOT_IN_PROGRESS = TIZEN_ERROR_THREAD | 0x02, /**< Operation Not in progress */
+ THREAD_ERROR_ALREADY_DONE = TIZEN_ERROR_THREAD | 0x03, /**< Operation already done */
+ THREAD_ERROR_OPERATION_FAILED = TIZEN_ERROR_THREAD | 0x04, /**< Operation Failed */
+ THREAD_ERROR_NOT_READY = TIZEN_ERROR_THREAD | 0x05, /**< Resource not ready */
+ THREAD_ERROR_NOT_ENABLED = TIZEN_ERROR_THREAD | 0x06, /**< Not enabled */
+ THREAD_ERROR_NOT_FOUND = TIZEN_ERROR_THREAD | 0x10, /**< Not found */
+ THREAD_ERROR_ALREADY_REGISTERED = TIZEN_ERROR_THREAD | 0x11, /**< Already registered */
+ THREAD_ERROR_DB_FAILED = TIZEN_ERROR_THREAD | 0x12, /**< DB operation faield */
+ THREAD_ERROR_NOT_REGISTERED = TIZEN_ERROR_THREAD | 0x13, /**< Not registered */
+} thread_error_e;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Enumerations of thread device role
+ * @since_tizen 7.0
+ */
+typedef enum {
+ THREAD_DEVICE_ROLE_DISABLED = 0, ///< The Thread stack is disabled.
+ THREAD_DEVICE_ROLE_DETACHED = 1, ///< Not currently participating in a Thread network/partition.
+ THREAD_DEVICE_ROLE_CHILD = 2, ///< The Thread Child role.
+ THREAD_DEVICE_ROLE_ROUTER = 3, ///< The Thread Router role.
+ THREAD_DEVICE_ROLE_LEADER = 4, ///< The Thread Leader role.
+} thread_device_role_e;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Enumerations of thread ip address type
+ * @since_tizen 7.0
+ */
+typedef enum {
+ THREAD_IPADDR_TYPE_ALL = 0,
+ THREAD_IPADDR_TYPE_LINK_LOCAL = 1,
+ THREAD_IPADDR_TYPE_RLOC = 2,
+ THREAD_IPADDR_TYPE_MLEID = 3,
+} thread_ipaddr_type_e;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Enumerations of thread device type
+ * @since_tizen 7.0
+ */
+typedef enum {
+ THREAD_DEVICE_TYPE_NOT_SUPPORTED = 0,
+ THREAD_DEVICE_TYPE_ROUTER = 1,
+ THREAD_DEVICE_TYPE_FULL_END_DEVICE = 2,
+ THREAD_DEVICE_TYPE_MINIMAL_END_DEVICE = 3,
+ THREAD_DEVICE_TYPE_SLEEPY_END_DEVICE = 4,
+} thread_device_type_e;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief The handle of a Thread Route Info
+ * @since_tizen 7.0
+ */
+typedef void *thread_route_info_h;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @since_tizen 7.0
+ *
+ * @see thread_get_external_routes()
+ *
+ */
+typedef bool (*thread_external_route_foreach_cb) (int total, thread_route_info_h route_info, void *user_data);
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @since_tizen 7.0
+ *
+ * @see thread_get_ipaddr()
+ *
+ */
+
+typedef void (*thread_ipaddr_foreach_cb) (int index, char *ipaddr,
+ thread_ipaddr_type_e ipaddr_type, void *user_data);
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Enumerations of the scanning state of Provisioner device.
+ * @since_tizen 7.0
+ */
+typedef enum {
+ THREAD_SCANNING_STARTED, /**< Scanning is started */
+ THREAD_SCANNING_FINISHED, /**< Scanning is finished */
+ THREAD_SCAN_DEVICE_FOUND, /**< Thread device is found */
+} thread_network_scanning_state_e;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @since_tizen 7.0
+ *
+ * @see thread_network_scan()
+ *
+ */
+typedef void (*thread_network_scan_result_cb)(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);
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Callback of Thread device role changed.
+ * @since_tizen 7.0
+ */
+typedef void (*thread_device_role_cb)(thread_device_role_e device_role, void *user_data);
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief The handle of a OT Hardware instance.
+ * @since_tizen 7.0
+ */
+typedef void *thread_instance_h;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief Callback of Thread join operation.
+ * @since_tizen 7.0
+ */
+typedef void (*thread_joiner_result_cb)(int result, void *user_data);
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief The handle of a Thread Operational network instance.
+ * @since_tizen 7.0
+ */
+typedef void *thread_network_h;
+
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief The handle of a Thread Scan Param.
+ * @since_tizen 7.0
+ */
+typedef void *thread_scan_param_h;
+
+/**
+ * @ingroup CAPI_NETWORK_THREAD_MODULE
+ * @brief The handle of a Thread OnMesh Prefix Info
+ * @since_tizen 7.0
+ */
+typedef void *thread_onmesh_prefix_info_h;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_CAPI_NETWORK_THREAD_TYPE_H__ */
--- /dev/null
+/*
+ * 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_NETWORK_THREAD_H__
+#define __TIZEN_NETWORK_THREAD_H__
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <tizen_error.h>
+#include <tizen.h>
+
+#include <thread-type.h>
+
+#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__ */
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <errno.h>
+#include <tizen.h>
+#include <dlog.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <glib.h>
+
+#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;
+}
--- /dev/null
+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)
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <asm/unistd.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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, },
+};
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#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;
+}
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#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