Initial commit for thread CAPI
authorDohyun Pyun <dh79.pyun@samsung.com>
Wed, 23 Feb 2022 04:30:36 +0000 (13:30 +0900)
committerDohyun Pyun <dh79.pyun@samsung.com>
Wed, 23 Feb 2022 04:31:16 +0000 (13:31 +0900)
Change-Id: I139bbbc03acc77127d04f82f8081adf0ffd90a85
Signed-off-by: Dohyun Pyun <dh79.pyun@samsung.com>
37 files changed:
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0755]
NOTICE [new file with mode: 0755]
README.md [new file with mode: 0644]
capi-network-thread.pc.in [new file with mode: 0755]
include/thread-dbus-handler.h [new file with mode: 0644]
include/thread-log.h [new file with mode: 0755]
include/thread-private.h [new file with mode: 0755]
include/thread-socket-handler.h [new file with mode: 0644]
include/thread-type.h [new file with mode: 0755]
include/thread.h [new file with mode: 0644]
packaging/capi-network-thread-devel.manifest [new file with mode: 0755]
packaging/capi-network-thread.manifest [new file with mode: 0755]
packaging/capi-network-thread.spec [new file with mode: 0644]
src/thread-br.c [new file with mode: 0644]
src/thread-commissioner.c [new file with mode: 0644]
src/thread-core.c [new file with mode: 0644]
src/thread-dbus-handler.c [new file with mode: 0644]
src/thread-joiner.c [new file with mode: 0644]
src/thread-network.c [new file with mode: 0644]
src/thread-socket-handler.c [new file with mode: 0644]
src/thread-srp.c [new file with mode: 0644]
src/thread-util.c [new file with mode: 0755]
tests/CMakeLists.txt [new file with mode: 0755]
tests/thread-br.c [new file with mode: 0644]
tests/thread-commissioner.c [new file with mode: 0644]
tests/thread-core.c [new file with mode: 0755]
tests/thread-init.c [new file with mode: 0755]
tests/thread-joiner.c [new file with mode: 0644]
tests/thread-main.c [new file with mode: 0755]
tests/thread-menu.c [new file with mode: 0755]
tests/thread-menu.h [new file with mode: 0755]
tests/thread-network.c [new file with mode: 0644]
tests/thread-srp.c [new file with mode: 0644]
tests/thread-util.c [new file with mode: 0644]
tests/thread-util.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..f949861
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Anupam Roy <anupam.r@samsung.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a9da0bc
--- /dev/null
@@ -0,0 +1,112 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_name "capi-network-thread")
+
+PROJECT(${fw_name})
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+SET(INC_DIR include)
+INCLUDE_DIRECTORIES(${INC_DIR})
+
+SET(dependents "dlog glib-2.0 gio-2.0 gio-unix-2.0 gobject-2.0 gmodule-2.0 capi-base-common capi-system-info")
+SET(pc_dependents "capi-base-common glib-2.0")
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+FOREACH(flag ${${fw_name}_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DTIZEN_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}")
+
+
+SET(SOURCES
+src/thread-core.c
+src/thread-br.c
+src/thread-joiner.c
+src/thread-network.c
+src/thread-commissioner.c
+src/thread-srp.c
+src/thread-util.c
+src/thread-dbus-handler.c
+src/thread-socket-handler.c
+)
+
+ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
+
+TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+
+SET_TARGET_PROPERTIES(${fw_name}
+     PROPERTIES
+     VERSION ${FULLVER}
+     SOVERSION ${MAJORVER}
+     CLEAN_DIRECT_OUTPUT 1
+)
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
+
+INSTALL(
+        DIRECTORY ${INC_DIR}/ DESTINATION include/network
+        FILES_MATCHING
+        PATTERN "*_private.h" EXCLUDE
+        PATTERN "${INC_DIR}/*.h"
+        )
+
+SET(PC_NAME ${fw_name})
+SET(PC_REQUIRED ${pc_dependents})
+SET(PC_LDFLAGS -l${fw_name})
+
+CONFIGURE_FILE(
+    capi-network-thread.pc.in
+    ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc
+    @ONLY
+)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
+#ADD_SUBDIRECTORY(tests/test)
+#ADD_SUBDIRECTORY(tests/unittest)
+
+ADD_SUBDIRECTORY(tests)
+
+IF(UNIX)
+
+ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
+ADD_CUSTOM_COMMAND(
+        DEPENDS clean
+        COMMENT "distribution clean"
+        COMMAND find
+        ARGS    .
+        -not -name config.cmake -and \(
+        -name tester.c -or
+        -name Testing -or
+        -name CMakeFiles -or
+        -name cmake.depends -or
+        -name cmake.check_depends -or
+        -name CMakeCache.txt -or
+        -name cmake.check_cache -or
+        -name *.cmake -or
+        -name Makefile -or
+        -name core -or
+        -name core.* -or
+        -name gmon.out -or
+        -name install_manifest.txt -or
+        -name *.pc -or
+        -name *~ \)
+        | grep -v TC | xargs rm -rf
+        TARGET  distclean
+        VERBATIM
+)
+
+ENDIF(UNIX)
+
diff --git a/LICENSE b/LICENSE
new file mode 100755 (executable)
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/NOTICE b/NOTICE
new file mode 100755 (executable)
index 0000000..0e0f016
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE.APLv2 file for Apache License terms and conditions.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..a20725a
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+This is Thread CAPI library for Tizen
diff --git a/capi-network-thread.pc.in b/capi-network-thread.pc.in
new file mode 100755 (executable)
index 0000000..85a129a
--- /dev/null
@@ -0,0 +1,14 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@/network
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@ 
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
+
diff --git a/include/thread-dbus-handler.h b/include/thread-dbus-handler.h
new file mode 100644 (file)
index 0000000..28b6a25
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __TIZEN_CAPI_NETWORK_THREAD_DBUS_HANDLER_H__
+#define __TIZEN_CAPI_NETWORK_THREAD_DBUS_HANDLER_H__
+
+#include <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__ */
diff --git a/include/thread-log.h b/include/thread-log.h
new file mode 100755 (executable)
index 0000000..bba55b1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __TIZEN_CAPI_NETWORK_THREAD_LOG_H__
+#define __TIZEN_CAPI_NETWORK_THREAD_LOG_H__
+
+#include <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__ */
diff --git a/include/thread-private.h b/include/thread-private.h
new file mode 100755 (executable)
index 0000000..c6ae2e1
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __TIZEN_CAPI_NETWORK_THREAD_PRIVATE_H__
+#define __TIZEN_CAPI_NETWORK_THREAD_PRIVATE_H__
+
+
+#include <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__ */
diff --git a/include/thread-socket-handler.h b/include/thread-socket-handler.h
new file mode 100644 (file)
index 0000000..9c8cdad
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __TIZEN_CAPI_NETWORK_THREAD_SOCKET_HANDLER_H__
+#define __TIZEN_CAPI_NETWORK_THREAD_SOCKET_HANDLER_H__
+
+#include <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__ */
diff --git a/include/thread-type.h b/include/thread-type.h
new file mode 100755 (executable)
index 0000000..bb0bbe8
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __TIZEN_CAPI_NETWORK_THREAD_TYPE_H__
+#define __TIZEN_CAPI_NETWORK_THREAD_TYPE_H__
+
+#include <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__ */
diff --git a/include/thread.h b/include/thread.h
new file mode 100644 (file)
index 0000000..86c4772
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * 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__ */
diff --git a/packaging/capi-network-thread-devel.manifest b/packaging/capi-network-thread-devel.manifest
new file mode 100755 (executable)
index 0000000..c00c25b
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+        <request>
+                <domain name="_" />
+        </request>
+</manifest>
diff --git a/packaging/capi-network-thread.manifest b/packaging/capi-network-thread.manifest
new file mode 100755 (executable)
index 0000000..c00c25b
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+        <request>
+                <domain name="_" />
+        </request>
+</manifest>
diff --git a/packaging/capi-network-thread.spec b/packaging/capi-network-thread.spec
new file mode 100644 (file)
index 0000000..1309292
--- /dev/null
@@ -0,0 +1,91 @@
+Name:       capi-network-thread
+Summary:    Network Thread Framework
+Version:    0.1.0
+Release:    1
+Group:      Connectivity/API
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Source1001:    %{name}.manifest
+Source1002:    %{name}-devel.manifest
+#Requires(post): /sbin/ldconfig
+#Requires(postun): /sbin/ldconfig
+
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(capi-appfw-app-control)
+BuildRequires:  pkgconfig(capi-base-common)
+BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  cmake
+
+%description
+Network Thread Framework
+
+%package devel
+Summary:    Network Thread Framework (DEV)
+Group:      Development/Connectivit
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+Network Thread Framework.
+
+%devel_desc
+
+%package test
+Summary: Network Thread Framework test application
+Group:   TO_BE/FILLED
+Requires: %{name} = %{version}-%{release}
+
+%description test
+This package is for Network Thread Framework CAPI test application
+
+%prep
+%setup -q
+cp %{SOURCE1001} %{SOURCE1002} .
+
+%ifarch aarch64
+echo arch64
+export CFLAGS+=" -DARCH64"
+export CXXFLAGS+=" -DARCH64"
+export FFLAGS+=" -DARCH64"
+%endif
+
+%ifarch x86_64
+echo x86_64
+export CFLAGS+=" -DARCH64"
+export CXXFLAGS+=" -DARCH64"
+export FFLAGS+=" -DARCH64"
+%endif
+
+%cmake
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%license LICENSE
+%{_libdir}/libcapi-network-thread.so.*
+
+%files devel
+%manifest %{name}-devel.manifest
+%{_includedir}/network/*
+%{_libdir}/pkgconfig/%{name}.pc
+
+%{_libdir}/pkgconfig/capi-network-thread.pc
+%{_libdir}/libcapi-network-thread.so
+
+%files test
+%manifest %{name}.manifest
+%attr(777,network_fw,network_fw) %{_bindir}/thread-test
+
diff --git a/src/thread-br.c b/src/thread-br.c
new file mode 100644 (file)
index 0000000..68010af
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-commissioner.c b/src/thread-commissioner.c
new file mode 100644 (file)
index 0000000..4ee4788
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+
+}
diff --git a/src/thread-core.c b/src/thread-core.c
new file mode 100644 (file)
index 0000000..e3ebad6
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-dbus-handler.c b/src/thread-dbus-handler.c
new file mode 100644 (file)
index 0000000..6796cf8
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-joiner.c b/src/thread-joiner.c
new file mode 100644 (file)
index 0000000..5ff4bc0
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-network.c b/src/thread-network.c
new file mode 100644 (file)
index 0000000..5cec98c
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-socket-handler.c b/src/thread-socket-handler.c
new file mode 100644 (file)
index 0000000..f198622
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-srp.c b/src/thread-srp.c
new file mode 100644 (file)
index 0000000..edb5066
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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;
+}
diff --git a/src/thread-util.c b/src/thread-util.c
new file mode 100755 (executable)
index 0000000..1225fa9
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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;
+}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..2ea7876
--- /dev/null
@@ -0,0 +1,31 @@
+SET(test thread-test)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${test} REQUIRED
+        glib-2.0
+)
+
+FOREACH(flag ${${test}_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror")
+
+SET(TEST_SRCS
+       thread-init.c
+       thread-menu.c
+       thread-main.c
+       thread-core.c
+       thread-util.c
+       thread-joiner.c
+       thread-commissioner.c
+       thread-network.c
+       thread-br.c
+       thread-srp.c
+)
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
+ADD_EXECUTABLE(${test} ${TEST_SRCS})
+TARGET_LINK_LIBRARIES(${test} ${PROJECT_NAME} ${test_LDFLAGS})
+INSTALL(TARGETS ${test} DESTINATION bin)
+
diff --git a/tests/thread-br.c b/tests/thread-br.c
new file mode 100644 (file)
index 0000000..8c40d19
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-commissioner.c b/tests/thread-commissioner.c
new file mode 100644 (file)
index 0000000..e2baf2b
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-core.c b/tests/thread-core.c
new file mode 100755 (executable)
index 0000000..79af951
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-init.c b/tests/thread-init.c
new file mode 100755 (executable)
index 0000000..a8b2733
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-joiner.c b/tests/thread-joiner.c
new file mode 100644 (file)
index 0000000..c71e0c3
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-main.c b/tests/thread-main.c
new file mode 100755 (executable)
index 0000000..049d514
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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;
+}
diff --git a/tests/thread-menu.c b/tests/thread-menu.c
new file mode 100755 (executable)
index 0000000..7675fba
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <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;
+}
diff --git a/tests/thread-menu.h b/tests/thread-menu.h
new file mode 100755 (executable)
index 0000000..b7ec3f4
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MENU_H__
+#define __MENU_H__
+
+__BEGIN_DECLS
+
+#define ANSI_COLOR_NORMAL              "\e[0m"
+
+#define ANSI_COLOR_BLACK               "\e[0;30m"
+#define ANSI_COLOR_RED                 "\e[0;31m"
+#define ANSI_COLOR_GREEN               "\e[0;32m"
+#define ANSI_COLOR_BROWN               "\e[0;33m"
+#define ANSI_COLOR_BLUE                        "\e[0;34m"
+#define ANSI_COLOR_MAGENTA             "\e[0;35m"
+#define ANSI_COLOR_CYAN                        "\e[0;36m"
+#define ANSI_COLOR_LIGHTGRAY   "\e[0;37m"
+
+#define ANSI_COLOR_DARKGRAY            "\e[1;30m"
+#define ANSI_COLOR_LIGHTRED            "\e[1;31m"
+#define ANSI_COLOR_LIGHTGREEN  "\e[1;32m"
+#define ANSI_COLOR_YELLOW              "\e[1;33m"
+#define ANSI_COLOR_LIGHTBLUE   "\e[1;34m"
+#define ANSI_COLOR_LIGHTMAGENTA "\e[1;35m"
+#define ANSI_COLOR_LIGHTCYAN   "\e[1;36m"
+#define ANSI_COLOR_WHITE               "\e[1;37m"
+
+
+#define msg(fmt, args...)      do { fprintf(stdout, fmt "\n", ##args); \
+               fflush(stdout); } while (0)
+#define msgn(fmt, args...)     do { fprintf(stdout, fmt, ##args); \
+               fflush(stdout); } while (0)
+
+/* Bold (red) */
+#define msgr(fmt, args...)  do { fprintf(stdout, ANSI_COLOR_RED fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Bold (green) */
+#define msgb(fmt, args...)  do { fprintf(stdout, ANSI_COLOR_LIGHTGREEN fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Property message */
+#define msgp(fmt, args...) do { fprintf(stdout, ANSI_COLOR_LIGHTMAGENTA fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Bold (Cyan) */
+#define msgc(fmt, args...) do { fprintf(stdout, ANSI_COLOR_CYAN fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Bold (Yellow) */
+#define msgy(fmt, args...) do { fprintf(stdout, ANSI_COLOR_YELLOW fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Bold (Light Red) */
+#define msglr(fmt, args...) do { fprintf(stdout, ANSI_COLOR_LIGHTRED fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+/* Bold (Blue) */
+#define msgbr(fmt, args...) do { fprintf(stdout, ANSI_COLOR_BLUE fmt \
+               ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+
+#define msgt(n, fmt, args...) do { fprintf(stdout, "\e[%dC" fmt "\n", \
+               3 + ((n) * 2), ##args); fflush(stdout); } while (0)
+
+#define pmsg(fmt, args...) do { \
+       if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \
+       fprintf(stdout, fmt "\n", ##args); fflush(stdout); } while (0)
+
+#define pmsgb(fmt, args...) do { \
+       if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \
+       fprintf(stdout, ANSI_COLOR_LIGHTGREEN fmt \
+                       ANSI_COLOR_NORMAL "\n", ##args); fflush(stdout); } while (0)
+
+#define pmsgt(n, fmt, args...) do { \
+       if (is_pid_show()) fprintf(stdout, "(%5d) ", get_tid()); \
+       fprintf(stdout, "\e[%dC" fmt "\n", \
+                       3 + ((n) * 2), ##args); fflush(stdout); } while (0)
+
+#define ret_if(expr) \
+do { \
+       if (expr) { \
+               msgr("(%s) return", #expr); \
+                       return; \
+       } \
+} while (0)
+
+#define retv_if(expr, val) \
+do { \
+       if (expr) { \
+               msgr("(%s) return", #expr); \
+                       return (val); \
+       } \
+} while (0)
+
+/* Null check */
+#define check_if(expr) \
+do { \
+       if (expr) { \
+               msgr("(%s) ", #expr); \
+       } \
+} while (0)
+
+#define MENU_DATA_SIZE 255
+
+/*
+ * Horizontal Line - width: 65
+ *                                     .12345678901234567890123456789012345678901234567890.
+ */
+#define HR_SINGLE      "----------------------------------------" \
+                                       "-------------------------"
+#define HR_DOUBLE      "========================================" \
+                                       "========================="
+#define HR_SINGLE2     " ---------------------------------------" \
+                                       "------------------------ "
+
+#define MAX_WIDTH      strlen(HR_SINGLE)
+#define MAX_TITLE      ((MAX_WIDTH) - 10)
+#define POS_MORE       ((MAX_WIDTH) - 3)
+#define RET_SUCCESS 0
+#define RET_FAILURE -1
+
+#include "thread-log.h"
+#include "thread-util.h"
+
+struct menu_manager {
+       GQueue *stack;
+       GQueue *title_stack;
+       struct menu_data *menu;
+       char *buf;
+       void *user_data;
+       GMainLoop *mainloop;
+       thread_instance_h t_instance;
+};
+typedef struct menu_manager MManager;
+
+struct menu_data {
+       const char *key;
+       const char *title;
+       struct menu_data *sub_menu;
+       int (*callback)(MManager *mm, struct menu_data *menu);
+       char *data;
+};
+
+MManager* menu_manager_new(struct menu_data items[], GMainLoop *mainloop);
+int menu_manager_run(MManager *mm);
+int menu_manager_set_user_data(MManager *mm, void *user_data);
+void* menu_manager_ref_user_data(MManager *mm);
+int menu_manager_free(MManager *mm);
+
+gboolean  on_menu_manager_keyboard(GIOChannel *src, GIOCondition con,
+               gpointer data);
+
+pid_t get_tid();
+void hide_pid();
+void show_pid();
+int is_pid_show();
+void menu_print_dump(int data_len, void *data);
+
+__END_DECLS
+
+#endif
diff --git a/tests/thread-network.c b/tests/thread-network.c
new file mode 100644 (file)
index 0000000..2ad3fb3
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
diff --git a/tests/thread-srp.c b/tests/thread-srp.c
new file mode 100644 (file)
index 0000000..460edc9
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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, },
+};
+
diff --git a/tests/thread-util.c b/tests/thread-util.c
new file mode 100644 (file)
index 0000000..65812cb
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <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;
+}
+
diff --git a/tests/thread-util.h b/tests/thread-util.h
new file mode 100644 (file)
index 0000000..1b79cc1
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+__BEGIN_DECLS
+
+#include <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