2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
27 #include <arpa/inet.h>
30 #include "thread-log.h"
31 #include "thread-private.h"
32 #include "thread-dbus-handler.h"
33 #include "thread-socket-handler.h"
35 #define THREAD_NETWORK_DEFAULT_NAME ""
36 #define THREAD_NETWORK_DEFAULT_KEY ""
37 #define THREAD_NETWORK_DEFAULT_PSKC ""
38 #define THREAD_NETWORK_DEFAULT_CHANNEL 0
39 #define THREAD_NETWORK_DEFAULT_EXTENDED_PANID 0
40 #define THREAD_NETWORK_DEFAULT_PANID 0
43 void _thread_network_free(thread_network_h network)
54 int thread_network_create(thread_network_h *network)
57 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
58 THREAD_CHECK_INIT_STATUS();
59 THREAD_VALIDATE_INPUT_PARAMETER(network);
61 thread_network_s *new_network = NULL;
62 new_network = g_malloc0(sizeof(thread_network_s));
65 THREAD_ERR("g_malloc0 failed");
67 return THREAD_ERROR_OUT_OF_MEMORY;
71 new_network->is_network_active = FALSE;
72 (void)g_strlcpy(new_network->name,
73 THREAD_NETWORK_DEFAULT_NAME, THREAD_NETWORK_NAME_MAX + 1);
74 (void)g_strlcpy(new_network->key,
75 THREAD_NETWORK_DEFAULT_KEY, THREAD_NETWORK_KEY_STRING_MAX + 1);
76 (void)g_strlcpy(new_network->pskc,
77 THREAD_NETWORK_DEFAULT_PSKC, THREAD_NETWORK_PSKC_STRING_MAX + 1);
78 new_network->channel = THREAD_NETWORK_DEFAULT_CHANNEL;
79 new_network->extended_panid = THREAD_NETWORK_DEFAULT_EXTENDED_PANID;
80 new_network->panid = THREAD_NETWORK_DEFAULT_PANID;
81 *network = (thread_network_h)new_network;
84 return THREAD_ERROR_NONE;
87 int thread_network_destroy(thread_network_h network)
90 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
91 THREAD_CHECK_INIT_STATUS();
92 THREAD_VALIDATE_INPUT_PARAMETER(network);
94 thread_network_s *current_network = network;
96 if (current_network->is_network_active) {
97 THREAD_DBG("Thread network active, can't be destroyed:: \
98 First Reset the Network");
100 return THREAD_ERROR_OPERATION_FAILED;
103 _thread_network_free(current_network);
104 current_network = NULL;
107 return THREAD_ERROR_NONE;
110 /* Network leader/Creator */
111 int thread_network_create_operational_network(thread_instance_h instance,
112 const char *name, const char *key, const char *pskc, uint32_t channel,
113 uint64_t extended_panid, uint16_t panid, thread_network_h *network)
116 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
117 THREAD_CHECK_INIT_STATUS();
118 THREAD_VALIDATE_INPUT_PARAMETER(instance);
119 THREAD_VALIDATE_INPUT_PARAMETER(name);
120 THREAD_VALIDATE_INPUT_PARAMETER(key);
121 THREAD_VALIDATE_INPUT_PARAMETER(pskc);
122 THREAD_VALIDATE_INPUT_PARAMETER(network);
124 retv_if(strlen(name) > THREAD_NETWORK_NAME_MAX,
125 THREAD_ERROR_INVALID_PARAMETER);
126 retv_if(strlen(key) > THREAD_NETWORK_KEY_STRING_MAX,
127 THREAD_ERROR_INVALID_PARAMETER);
128 retv_if(strlen(pskc) > THREAD_NETWORK_PSKC_STRING_MAX,
129 THREAD_ERROR_INVALID_PARAMETER);
131 THREAD_DBG("Network Name: %s", name);
132 THREAD_DBG("Network key: %s", key);
133 THREAD_DBG("Network pskc: %s", pskc);
134 THREAD_DBG("Network channel: 0x%8.8x", channel);
135 THREAD_DBG("Network extended_panid: %zu", (size_t)extended_panid);
136 THREAD_DBG("Network panid: %u", panid);
138 /* Free existing current network */
139 thread_instance_s *current_instance = instance;
140 _thread_network_free(current_instance->network);
141 current_instance->network = NULL;
143 /* Create New Network */
144 thread_network_s *new_network = NULL;
145 new_network = g_malloc0(sizeof(thread_network_s));
147 /* LCOV_EXCL_START */
148 THREAD_ERR("g_malloc0 failed");
149 return THREAD_ERROR_OUT_OF_MEMORY;
153 new_network->is_network_active = FALSE;
154 (void)g_strlcpy(new_network->name, name, THREAD_NETWORK_NAME_MAX + 1);
155 (void)g_strlcpy(new_network->key, key, THREAD_NETWORK_KEY_STRING_MAX + 1);
156 (void)g_strlcpy(new_network->pskc, pskc, THREAD_NETWORK_PSKC_STRING_MAX + 1);
157 new_network->channel = channel;
158 new_network->extended_panid = extended_panid;
159 new_network->panid = panid;
160 *network = (thread_network_h)new_network;
162 current_instance->network = *network;
165 return THREAD_ERROR_NONE;
168 int thread_network_destroy_operational_network(thread_instance_h instance,
169 thread_network_h network)
172 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
173 THREAD_CHECK_INIT_STATUS();
174 THREAD_VALIDATE_INPUT_PARAMETER(instance);
175 THREAD_VALIDATE_INPUT_PARAMETER(network);
177 thread_instance_s *current_instance = instance;
178 thread_network_s *current_network = network;
180 if (current_network->is_network_active) {
181 THREAD_DBG("Thread network active, can't be destroyed:: \
182 First Reset the Network");
183 return THREAD_ERROR_OPERATION_FAILED;
186 _thread_network_free(current_network);
187 current_network = NULL;
188 current_instance->network = NULL;
191 return THREAD_ERROR_NONE;
194 int thread_network_set_active_dataset_tlvs(thread_instance_h instance,
195 const uint8_t *tlvs_buffer, int buf_length)
198 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
199 THREAD_CHECK_INIT_STATUS();
200 THREAD_VALIDATE_INPUT_PARAMETER(instance);
201 THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer);
203 int ret = THREAD_ERROR_NONE;
204 GBytes *bytes = NULL;
205 GVariant *value = NULL;
207 /* Print input data */
208 char buf[THREAD_MAX_BUFFER_SIZE];
209 for (int i = 0; i < buf_length; i++)
210 snprintf(buf + i*2, 3, "%2.2x", tlvs_buffer[i]);
211 THREAD_DBG("Active dataset tlvs size: %d :: %s", buf_length, buf);
213 bytes = g_bytes_new(tlvs_buffer, buf_length);
215 ret = THREAD_ERROR_OPERATION_FAILED;
219 value = g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, bytes, true);
221 ret = THREAD_ERROR_OPERATION_FAILED;
225 /* set "ActiveDatasetTlvs" dbus property */
226 ret = _thread_dbus_set_property(
227 THREAD_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, value);
228 if (ret != THREAD_ERROR_NONE) {
229 ret = THREAD_ERROR_OPERATION_FAILED;
232 THREAD_DBG("Thread set active dataset tlvs successful");
236 g_variant_unref(value);
238 g_bytes_unref(bytes);
244 int thread_network_get_active_dataset_tlvs(thread_instance_h instance,
245 uint8_t **tlvs_buffer, int *buf_len)
248 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
249 THREAD_CHECK_INIT_STATUS();
250 THREAD_VALIDATE_INPUT_PARAMETER(instance);
251 THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer);
252 THREAD_VALIDATE_INPUT_PARAMETER(buf_len);
254 /* get "ActiveDatasetTlvs" */
255 int ret = THREAD_ERROR_NONE;
256 char buffer[THREAD_MAX_BUFFER_SIZE];
258 int session_fd = _thread_get_socket_fd();
259 char cmd_buffer[THREAD_NETWORK_BUFFER_MAX];
262 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "dataset active -x");
264 THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer);
266 ret = _thread_socket_client_write(session_fd, cmd_buffer, strlen(cmd_buffer));
267 if (ret != THREAD_ERROR_NONE) {
268 THREAD_DBG("Failed to execute command %s", cmd_buffer);
271 THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, strlen(cmd_buffer));
274 ret = _thread_socket_client_read(session_fd, buffer);
275 if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) {
276 THREAD_DBG("Socket response failed..");
280 *tlvs_buffer = g_malloc0(THREAD_MAX_BUFFER_SIZE*sizeof(uint8_t));
281 if (!(*tlvs_buffer)) {
282 /* LCOV_EXCL_START */
283 THREAD_ERR("g_malloc0 failed");
284 return THREAD_ERROR_OUT_OF_MEMORY;
288 while (index < THREAD_MAX_BUFFER_SIZE) {
289 if (buffer[index] == 'D')
292 (*tlvs_buffer)[index] = (uint8_t)buffer[index];
301 int thread_network_get_panid(thread_instance_h instance, uint16_t *panid)
304 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
305 THREAD_CHECK_INIT_STATUS();
306 THREAD_VALIDATE_INPUT_PARAMETER(instance);
307 THREAD_VALIDATE_INPUT_PARAMETER(panid);
309 int ret = THREAD_ERROR_NONE;
310 GVariant *out = NULL;
312 /* get "PanId" dbus property */
313 ret = _thread_dbus_get_property(
314 THREAD_DBUS_PROPERTY_PANID, &out);
315 retv_if(ret != THREAD_ERROR_NONE, ret);
317 g_variant_get(out, "q", panid);
318 THREAD_DBG("Thread PanId: %u", (size_t)*panid);
319 g_variant_unref(out);
322 return THREAD_ERROR_NONE;
325 static int __thread_attach_active_network()
328 int ret = THREAD_ERROR_NONE;
330 THREAD_DBG("Attach current active network dataset");
331 ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD,
332 g_variant_new("()"));
333 if (ret != THREAD_ERROR_NONE)
334 THREAD_ERR("Thread Attach failed");
336 THREAD_DBG("Thread Attach successful");
343 int thread_network_attach(thread_instance_h instance)
346 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
347 THREAD_CHECK_INIT_STATUS();
348 THREAD_VALIDATE_INPUT_PARAMETER(instance);
349 int ret = THREAD_ERROR_NONE;
351 thread_instance_s *current_instance = instance;
352 thread_network_s *network = current_instance->network;
355 ret = __thread_attach_active_network();
360 THREAD_DBG("Network Name: %s", network->name);
361 THREAD_DBG("Network key: %s", network->key);
362 THREAD_DBG("Network pskc: %s", network->pskc);
363 THREAD_DBG("Network channel: 0x%8.8x", network->channel);
365 THREAD_DBG("Network extended_panid: %zu", (size_t)network->extended_panid);
366 if (network->extended_panid == UINT64_MAX)
367 THREAD_DBG("extended_panid is UINT64_MAX, "\
368 "Random extended_panid will be used");
370 THREAD_DBG("Network panid: %u", network->panid);
371 if (network->panid == UINT16_MAX)
372 THREAD_DBG("panid is UINT16_MAX, Random panid will be used");
374 THREAD_DBG("Network is_active: %s",
375 network->is_network_active ? "Active" : "Not Active");
377 if (network->is_network_active) {
378 ret = __thread_attach_active_network();
382 THREAD_DBG("Attach the current device to Thread Network");
383 /* Network key builder */
384 GVariantBuilder *key_builder;
385 key_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
386 THREAD_DBG("key str length: %zu", strlen(network->key));
387 for (int i = 0; i < strlen(network->key); i++) {
388 g_variant_builder_add(key_builder, "y",
389 (unsigned char)network->key[i]);
393 GVariantBuilder *pskc_builder;
394 pskc_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
395 THREAD_DBG("pskc str length: %zu", strlen(network->pskc));
396 for (int i = 0; i < strlen(network->pskc); i++) {
397 g_variant_builder_add(pskc_builder, "y",
398 (unsigned char)network->pskc[i]);
401 THREAD_DBG("Thread dbus sync call...");
402 ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD,
403 g_variant_new("(ayqstayu)", key_builder, network->panid,
404 network->name, network->extended_panid, pskc_builder, network->channel));
406 g_variant_builder_unref(key_builder);
407 g_variant_builder_unref(pskc_builder);
409 if (ret != THREAD_ERROR_NONE) {
410 THREAD_ERR("Thread Attach failed");
413 network->is_network_active = TRUE;
415 THREAD_DBG("Thread Attach successful");
422 static int __thread_detach_active_network()
425 int ret = THREAD_ERROR_NONE;
427 THREAD_DBG("Detach current active network dataset");
428 ret = _thread_dbus_sync_method_call(THREAD_DBUS_DETACH_METHOD,
429 g_variant_new("()"));
430 if (ret != THREAD_ERROR_NONE)
431 THREAD_ERR("Thread Detach failed");
433 THREAD_DBG("Thread Detach successful");
439 int thread_network_detach(thread_instance_h instance)
442 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
443 THREAD_CHECK_INIT_STATUS();
444 THREAD_VALIDATE_INPUT_PARAMETER(instance);
445 int ret = THREAD_ERROR_NONE;
447 thread_instance_s *current_instance = instance;
448 thread_network_s *network = current_instance->network;
451 return THREAD_ERROR_INVALID_PARAMETER;
453 if (network->is_network_active == TRUE)
454 ret = __thread_detach_active_network();
456 if (ret != THREAD_ERROR_NONE) {
457 THREAD_ERR("Thread Detach failed");
460 network->is_network_active = FALSE;
461 THREAD_DBG("Thread Detach successful");
468 int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callback,
469 thread_ipaddr_type_e ipaddr_type, void *user_data)
472 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
473 THREAD_CHECK_INIT_STATUS();
474 THREAD_VALIDATE_INPUT_PARAMETER(instance);
476 int ret = THREAD_ERROR_NONE;
477 char buffer[THREAD_MAX_BUFFER_SIZE];
481 char ipaddr[THREAD_IPV6_ADDRESS_LEN];
483 int session_fd = _thread_get_socket_fd();
484 char cmd_buffer[THREAD_NETWORK_BUFFER_MAX];
486 switch (ipaddr_type) {
487 case THREAD_IPADDR_TYPE_LINK_LOCAL:
488 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr linklocal");
490 case THREAD_IPADDR_TYPE_RLOC:
491 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr rloc");
493 case THREAD_IPADDR_TYPE_MLEID:
494 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr mleid");
497 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr");
500 size_t buf_size = strlen(cmd_buffer);
502 THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer);
504 ret = _thread_socket_client_write(session_fd, cmd_buffer, buf_size);
505 if (ret != THREAD_ERROR_NONE) {
506 THREAD_DBG("Failed to execute command %s", cmd_buffer);
509 THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, buf_size);
512 ret = _thread_socket_client_read(session_fd, buffer);
513 if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) {
514 THREAD_DBG("Socket response failed..");
519 if ((buffer[index] >= 'a' && buffer[index] <= 'f') || buffer[index] == ':'
520 || (buffer[index] >= '0' && buffer[index] <= '9')) {
521 ipaddr[pos++] = buffer[index];
522 } else if (buffer[index] == 'D') {
523 THREAD_DBG("Socket read response buffer: Done");
528 THREAD_DBG("IP address: %s, length: %zu", ipaddr,
530 callback(++count, ipaddr, ipaddr_type, user_data);
541 static bool __is_valid_ipv6(const uint8_t* ipv6_address)
546 while (index < THREAD_IPV6_ADDRESS_SIZE) {
547 char buffer[THREAD_NETWORK_BUFFER_MAX];
548 snprintf(buffer, THREAD_NETWORK_BUFFER_MAX, "%02x", ipv6_address[index]);
549 if ((buffer[0] < '0' || buffer[0] > '9') &&
550 (buffer[0] < 'a' || buffer[0] > 'f'))
552 if ((buffer[1] < '0' || buffer[1] > '9') &&
553 (buffer[1] < 'a' || buffer[1] > 'f'))
558 THREAD_DBG("DEBUG: NETWORK MESSAGE -> return true");
564 int thread_add_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address)
567 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
568 THREAD_CHECK_INIT_STATUS();
569 THREAD_VALIDATE_INPUT_PARAMETER(instance);
570 THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address);
572 int ret = THREAD_ERROR_NONE;
573 char msg[THREAD_NETWORK_BUFFER_MAX];
575 retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER);
577 snprintf(msg, THREAD_NETWORK_BUFFER_MAX,
578 "ipaddr add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
579 ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3],
580 ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7],
581 ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11],
582 ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]);
584 ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg));
585 retv_if(ret != THREAD_ERROR_NONE, ret);
586 THREAD_DBG("Successfully added address");
592 int thread_remove_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address)
595 THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
596 THREAD_CHECK_INIT_STATUS();
597 THREAD_VALIDATE_INPUT_PARAMETER(instance);
598 THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address);
600 int ret = THREAD_ERROR_NONE;
601 char msg[THREAD_NETWORK_BUFFER_MAX];
603 retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER);
605 snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX,
606 "ipaddr del %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
607 ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3],
608 ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7],
609 ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11],
610 ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]);
612 ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg));
613 retv_if(ret != THREAD_ERROR_NONE, ret);
614 THREAD_DBG("Successfully removed address");