Add getting global ipaddr function
[platform/core/api/thread.git] / src / thread-network.c
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <errno.h>
18 #include <tizen.h>
19 #include <dlog.h>
20
21 #include <glib.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include <arpa/inet.h>
28
29 #include "thread.h"
30 #include "thread-log.h"
31 #include "thread-private.h"
32 #include "thread-dbus-handler.h"
33 #include "thread-socket-handler.h"
34
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
41
42 void _thread_network_free(thread_network_h network)
43 {
44         FUNC_ENTRY;
45         if (!network)
46                 return;
47
48         g_free(network);
49
50         FUNC_EXIT;
51 }
52
53 int thread_network_create(thread_network_h *network)
54 {
55         FUNC_ENTRY;
56         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
57         THREAD_CHECK_INIT_STATUS();
58         THREAD_VALIDATE_INPUT_PARAMETER(network);
59
60         thread_network_s *new_network = NULL;
61         new_network = g_malloc0(sizeof(thread_network_s));
62         if (!new_network) {
63                 /* LCOV_EXCL_START */
64                 THREAD_ERR("g_malloc0 failed");
65                 return THREAD_ERROR_OUT_OF_MEMORY;
66                 /* LCOV_EXCL_STOP */
67         }
68
69         new_network->is_network_active = FALSE;
70         new_network->is_operational_network_set = FALSE;
71         (void)g_strlcpy(new_network->name,
72                 THREAD_NETWORK_DEFAULT_NAME, THREAD_NETWORK_NAME_MAX + 1);
73         (void)g_strlcpy(new_network->key,
74                 THREAD_NETWORK_DEFAULT_KEY, THREAD_NETWORK_KEY_STRING_MAX + 1);
75         (void)g_strlcpy(new_network->pskc,
76                 THREAD_NETWORK_DEFAULT_PSKC, THREAD_NETWORK_PSKC_STRING_MAX + 1);
77         new_network->channel = THREAD_NETWORK_DEFAULT_CHANNEL;
78         new_network->extended_panid = THREAD_NETWORK_DEFAULT_EXTENDED_PANID;
79         new_network->panid = THREAD_NETWORK_DEFAULT_PANID;
80         *network = (thread_network_h)new_network;
81
82         FUNC_EXIT;
83         return THREAD_ERROR_NONE;
84 }
85
86 int thread_network_destroy(thread_network_h network)
87 {
88         FUNC_ENTRY;
89         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
90         THREAD_CHECK_INIT_STATUS();
91         THREAD_VALIDATE_INPUT_PARAMETER(network);
92
93         thread_network_s *current_network = network;
94
95         if (current_network->is_operational_network_set) {
96                 THREAD_DBG("Thread operational network set, can't be destroyed:: \
97                                                 first unset the operational network");
98                 return THREAD_ERROR_OPERATION_FAILED;
99         }
100
101         if (current_network->is_network_active) {
102                 THREAD_DBG("Thread network active, can't be destroyed:: \
103                                                 first reset the network");
104                 return THREAD_ERROR_OPERATION_FAILED;
105         }
106
107         _thread_network_free(current_network);
108         current_network = NULL;
109
110         FUNC_EXIT;
111         return THREAD_ERROR_NONE;
112 }
113
114 int thread_network_set_name(thread_network_h network, const char *name)
115 {
116         FUNC_ENTRY;
117         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
118         THREAD_CHECK_INIT_STATUS();
119         THREAD_VALIDATE_INPUT_PARAMETER(network);
120         THREAD_VALIDATE_INPUT_PARAMETER(name);
121
122         retv_if(strlen(name) > THREAD_NETWORK_NAME_MAX,
123                                 THREAD_ERROR_INVALID_PARAMETER);
124
125         THREAD_DBG("Network Name: %s", name);
126
127         thread_network_s *current_network = network;
128         (void)g_strlcpy(current_network->name, name, THREAD_NETWORK_NAME_MAX + 1);
129
130         FUNC_EXIT;
131         return THREAD_ERROR_NONE;
132 }
133
134 int thread_network_set_key(thread_network_h network, const char *key)
135 {
136         FUNC_ENTRY;
137         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
138         THREAD_CHECK_INIT_STATUS();
139         THREAD_VALIDATE_INPUT_PARAMETER(network);
140         THREAD_VALIDATE_INPUT_PARAMETER(key);
141
142         retv_if(strlen(key) > THREAD_NETWORK_KEY_STRING_MAX,
143                                 THREAD_ERROR_INVALID_PARAMETER);
144
145         THREAD_DBG("Network key: %s", key);
146
147         thread_network_s *current_network = network;
148         (void)g_strlcpy(current_network->key, key, THREAD_NETWORK_KEY_STRING_MAX + 1);
149
150         FUNC_EXIT;
151         return THREAD_ERROR_NONE;
152 }
153
154 int thread_network_set_pskc(thread_network_h network, const char *pskc)
155 {
156         FUNC_ENTRY;
157         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
158         THREAD_CHECK_INIT_STATUS();
159         THREAD_VALIDATE_INPUT_PARAMETER(network);
160         THREAD_VALIDATE_INPUT_PARAMETER(pskc);
161
162         retv_if(strlen(pskc) > THREAD_NETWORK_PSKC_STRING_MAX,
163                                 THREAD_ERROR_INVALID_PARAMETER);
164
165         THREAD_DBG("Network pskc: %s", pskc);
166
167         thread_network_s *current_network = network;
168         (void)g_strlcpy(current_network->pskc, pskc, THREAD_NETWORK_PSKC_STRING_MAX + 1);
169
170         FUNC_EXIT;
171         return THREAD_ERROR_NONE;
172 }
173
174 int thread_network_set_channel(thread_network_h network, uint32_t channel)
175 {
176         FUNC_ENTRY;
177         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
178         THREAD_CHECK_INIT_STATUS();
179         THREAD_VALIDATE_INPUT_PARAMETER(network);
180
181         THREAD_DBG("Network channel: 0x%8.8x", channel);
182
183         thread_network_s *current_network = network;
184         current_network->channel = channel;
185
186         FUNC_EXIT;
187         return THREAD_ERROR_NONE;
188 }
189
190 int thread_network_set_extended_panid(thread_network_h network, uint64_t extended_panid)
191 {
192         FUNC_ENTRY;
193         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
194         THREAD_CHECK_INIT_STATUS();
195         THREAD_VALIDATE_INPUT_PARAMETER(network);
196
197         THREAD_DBG("Network extended_panid: %zu", (size_t)extended_panid);
198
199         thread_network_s *current_network = network;
200         current_network->extended_panid = extended_panid;
201
202         FUNC_EXIT;
203         return THREAD_ERROR_NONE;
204 }
205
206 int thread_network_set_panid(thread_network_h network, uint16_t panid)
207 {
208         FUNC_ENTRY;
209         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
210         THREAD_CHECK_INIT_STATUS();
211         THREAD_VALIDATE_INPUT_PARAMETER(network);
212
213         THREAD_DBG("Network panid: %u", panid);
214
215         thread_network_s *current_network = network;
216         current_network->panid = panid;
217
218         FUNC_EXIT;
219         return THREAD_ERROR_NONE;
220 }
221
222 int thread_set_operational_network(thread_instance_h instance, thread_network_h network)
223 {
224         FUNC_ENTRY;
225         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
226         THREAD_CHECK_INIT_STATUS();
227         THREAD_VALIDATE_INPUT_PARAMETER(instance);
228         THREAD_VALIDATE_INPUT_PARAMETER(network);
229
230         thread_instance_s *current_instance = instance;
231         thread_network_s *current_network = network;
232         current_instance->network = network;
233         current_network->is_operational_network_set = TRUE;
234
235         FUNC_EXIT;
236         return THREAD_ERROR_NONE;
237 }
238
239 int thread_unset_operational_network(thread_instance_h instance)
240 {
241         FUNC_ENTRY;
242         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
243         THREAD_CHECK_INIT_STATUS();
244         THREAD_VALIDATE_INPUT_PARAMETER(instance);
245
246         thread_instance_s *current_instance = instance;
247         thread_network_s *current_network = current_instance->network;
248
249         if (!current_network)
250                 goto exit;
251
252         if (current_network->is_network_active) {
253                 THREAD_DBG("Thread network active, can't be destroyed:: \
254                                                 first reset the network");
255                 return THREAD_ERROR_OPERATION_FAILED;
256         }
257
258         current_network->is_operational_network_set = FALSE;
259         current_instance->network = NULL;
260
261 exit:
262         FUNC_EXIT;
263         return THREAD_ERROR_NONE;
264 }
265
266 int thread_network_set_active_dataset_tlvs(thread_instance_h instance,
267         const uint8_t *tlvs_buffer, int buf_length)
268 {
269         FUNC_ENTRY;
270         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
271         THREAD_CHECK_INIT_STATUS();
272         THREAD_VALIDATE_INPUT_PARAMETER(instance);
273         THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer);
274
275         int ret = THREAD_ERROR_NONE;
276         GBytes *bytes = NULL;
277         GVariant *value = NULL;
278
279         /* Print input data */
280         char buf[THREAD_MAX_BUFFER_SIZE];
281         for (int i = 0; i < buf_length; i++)
282                 snprintf(buf + i*2, 3, "%2.2x", tlvs_buffer[i]);
283         THREAD_DBG("Active dataset tlvs size: %d :: %s", buf_length, buf);
284
285         bytes = g_bytes_new(tlvs_buffer, buf_length);
286         if (bytes == NULL) {
287                 ret = THREAD_ERROR_OPERATION_FAILED;
288                 goto exit;
289         }
290
291         value = g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, bytes, true);
292         if (value == NULL) {
293                 ret = THREAD_ERROR_OPERATION_FAILED;
294                 goto exit;
295         }
296
297         /* set "ActiveDatasetTlvs" dbus property */
298         ret = _thread_dbus_set_property(
299                 THREAD_DBUS_PROPERTY_ACTIVE_DATASET_TLVS, value);
300         if (ret != THREAD_ERROR_NONE) {
301                 ret = THREAD_ERROR_OPERATION_FAILED;
302                 goto exit;
303         }
304         THREAD_DBG("Thread set active dataset tlvs successful");
305
306 exit:
307         if (value)
308                 g_variant_unref(value);
309         if (bytes)
310                 g_bytes_unref(bytes);
311
312         FUNC_EXIT;
313         return ret;
314 }
315
316 int thread_network_get_active_dataset_tlvs(thread_instance_h instance,
317         uint8_t **tlvs_buffer, int *buf_len)
318 {
319         FUNC_ENTRY;
320         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
321         THREAD_CHECK_INIT_STATUS();
322         THREAD_VALIDATE_INPUT_PARAMETER(instance);
323         THREAD_VALIDATE_INPUT_PARAMETER(tlvs_buffer);
324         THREAD_VALIDATE_INPUT_PARAMETER(buf_len);
325
326         /* get "ActiveDatasetTlvs" */
327         int ret = THREAD_ERROR_NONE;
328         char buffer[THREAD_MAX_BUFFER_SIZE];
329
330         int session_fd = _thread_get_socket_fd();
331         char cmd_buffer[THREAD_NETWORK_BUFFER_MAX];
332         int index;
333
334         snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "dataset active -x");
335
336         THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer);
337
338         ret = _thread_socket_client_write(session_fd, cmd_buffer, strlen(cmd_buffer));
339         if (ret != THREAD_ERROR_NONE) {
340                 THREAD_DBG("Failed to execute command %s", cmd_buffer);
341                 return ret;
342         }
343         THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, strlen(cmd_buffer));
344
345         /* Check response */
346         ret = _thread_socket_client_read(session_fd, buffer);
347         if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) {
348                 THREAD_DBG("Socket response failed..");
349                 return ret;
350         }
351
352         *tlvs_buffer = g_malloc0(THREAD_MAX_BUFFER_SIZE*sizeof(uint8_t));
353         if (!(*tlvs_buffer)) {
354                 /* LCOV_EXCL_START */
355                 THREAD_ERR("g_malloc0 failed");
356                 return THREAD_ERROR_OUT_OF_MEMORY;
357                 /* LCOV_EXCL_STOP */
358         }
359         index = 0;
360         while (index < THREAD_MAX_BUFFER_SIZE) {
361                 if (buffer[index] == 'D')
362                         break;
363
364                 (*tlvs_buffer)[index] = (uint8_t)buffer[index];
365                 index++;
366         }
367         *buf_len = index;
368
369         FUNC_EXIT;
370         return ret;
371 }
372
373 int thread_network_get_panid(thread_instance_h instance, uint16_t *panid)
374 {
375         FUNC_ENTRY;
376         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
377         THREAD_CHECK_INIT_STATUS();
378         THREAD_VALIDATE_INPUT_PARAMETER(instance);
379         THREAD_VALIDATE_INPUT_PARAMETER(panid);
380
381         int ret = THREAD_ERROR_NONE;
382         GVariant *out = NULL;
383
384         /* get "PanId" dbus property */
385         ret = _thread_dbus_get_property(
386                 THREAD_DBUS_PROPERTY_PANID, &out);
387         retv_if(ret != THREAD_ERROR_NONE, ret);
388
389         g_variant_get(out, "q", panid);
390         THREAD_DBG("Thread PanId: %zu", (size_t)*panid);
391         g_variant_unref(out);
392
393         FUNC_EXIT;
394         return THREAD_ERROR_NONE;
395 }
396
397 static int __thread_attach_active_network()
398 {
399         FUNC_ENTRY;
400         int ret = THREAD_ERROR_NONE;
401
402         THREAD_DBG("Attach current active network dataset");
403         ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD,
404                                                 g_variant_new("()"));
405         if (ret != THREAD_ERROR_NONE)
406                 THREAD_ERR("Thread Attach failed");
407         else
408                 THREAD_DBG("Thread Attach successful");
409
410         return ret;
411
412         FUNC_EXIT;
413 }
414
415 int thread_network_attach(thread_instance_h instance)
416 {
417         FUNC_ENTRY;
418         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
419         THREAD_CHECK_INIT_STATUS();
420         THREAD_VALIDATE_INPUT_PARAMETER(instance);
421         int ret = THREAD_ERROR_NONE;
422
423         thread_instance_s *current_instance = instance;
424         thread_network_s *network = current_instance->network;
425
426         if (!network) {
427                 ret = __thread_attach_active_network();
428                 goto done;
429         }
430
431         /* Network Info */
432         THREAD_DBG("Network Name: %s", network->name);
433         THREAD_DBG("Network key: %s", network->key);
434         THREAD_DBG("Network pskc: %s", network->pskc);
435         THREAD_DBG("Network channel: 0x%8.8x", network->channel);
436
437         THREAD_DBG("Network extended_panid: %zu", (size_t)network->extended_panid);
438         if (network->extended_panid == UINT64_MAX)
439                 THREAD_DBG("extended_panid is UINT64_MAX, "\
440                         "Random extended_panid will be used");
441
442         THREAD_DBG("Network panid: %u", network->panid);
443         if (network->panid == UINT16_MAX)
444                 THREAD_DBG("panid is UINT16_MAX, Random panid will be used");
445
446         THREAD_DBG("Network is_active: %s",
447                         network->is_network_active ? "Active" : "Not Active");
448
449         if (network->is_network_active) {
450                 ret = __thread_attach_active_network();
451                 goto done;
452         }
453
454         THREAD_DBG("Attach the current device to Thread Network");
455         /* Network key builder */
456         GVariantBuilder *key_builder;
457         key_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
458         THREAD_DBG("key str length: %zu", strlen(network->key));
459         for (int i = 0; i < strlen(network->key); i++) {
460                 g_variant_builder_add(key_builder, "y",
461                                 (unsigned char)network->key[i]);
462         }
463
464         /* pskc builder */
465         GVariantBuilder *pskc_builder;
466         pskc_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
467         THREAD_DBG("pskc str length: %zu", strlen(network->pskc));
468         for (int i = 0; i < strlen(network->pskc); i++) {
469                 g_variant_builder_add(pskc_builder, "y",
470                                 (unsigned char)network->pskc[i]);
471         }
472
473         THREAD_DBG("Thread dbus sync call...");
474         ret = _thread_dbus_sync_method_call(THREAD_DBUS_ATTACH_METHOD,
475                 g_variant_new("(ayqstayu)", key_builder, network->panid,
476                 network->name, network->extended_panid, pskc_builder, network->channel));
477
478         g_variant_builder_unref(key_builder);
479         g_variant_builder_unref(pskc_builder);
480
481         if (ret != THREAD_ERROR_NONE) {
482                 THREAD_ERR("Thread Attach failed");
483                 goto done;
484         }
485         network->is_network_active = TRUE;
486
487         THREAD_DBG("Thread Attach successful");
488
489 done:
490         FUNC_EXIT;
491         return ret;
492 }
493
494 static int __thread_detach_active_network()
495 {
496         FUNC_ENTRY;
497         int ret = THREAD_ERROR_NONE;
498
499         THREAD_DBG("Detach current active network dataset");
500         ret = _thread_dbus_sync_method_call(THREAD_DBUS_DETACH_METHOD,
501                                                 g_variant_new("()"));
502         if (ret != THREAD_ERROR_NONE)
503                 THREAD_ERR("Thread Detach failed");
504         else
505                 THREAD_DBG("Thread Detach successful");
506
507         FUNC_EXIT;
508         return ret;
509 }
510
511 int thread_network_detach(thread_instance_h instance)
512 {
513         FUNC_ENTRY;
514         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
515         THREAD_CHECK_INIT_STATUS();
516         THREAD_VALIDATE_INPUT_PARAMETER(instance);
517         int ret = THREAD_ERROR_NONE;
518
519         thread_instance_s *current_instance = instance;
520         thread_network_s *network = current_instance->network;
521
522         if (!network)
523                 return THREAD_ERROR_INVALID_PARAMETER;
524
525         if (network->is_network_active == TRUE)
526                 ret = __thread_detach_active_network();
527
528         if (ret != THREAD_ERROR_NONE) {
529                 THREAD_ERR("Thread Detach failed");
530                 goto done;
531         }
532         network->is_network_active = FALSE;
533         THREAD_DBG("Thread Detach successful");
534
535 done:
536         FUNC_EXIT;
537         return ret;
538 }
539
540 int thread_get_ipaddr(thread_instance_h instance, thread_ipaddr_foreach_cb callback,
541                                 thread_ipaddr_type_e ipaddr_type, void *user_data)
542 {
543         FUNC_ENTRY;
544         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
545         THREAD_CHECK_INIT_STATUS();
546         THREAD_VALIDATE_INPUT_PARAMETER(instance);
547
548         int ret = THREAD_ERROR_NONE;
549         char buffer[THREAD_MAX_BUFFER_SIZE];
550         int index = 0;
551         int pos = 0;
552         int count = 0;
553         char ipaddr[THREAD_IPV6_ADDRESS_LEN];
554
555         int session_fd = _thread_get_socket_fd();
556         char cmd_buffer[THREAD_NETWORK_BUFFER_MAX];
557
558         switch (ipaddr_type) {
559         case THREAD_IPADDR_TYPE_LINK_LOCAL:
560                 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr linklocal");
561                 break;
562         case THREAD_IPADDR_TYPE_RLOC:
563                 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr rloc");
564                 break;
565         case THREAD_IPADDR_TYPE_MLEID:
566                 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr mleid");
567                 break;
568         default:
569                 snprintf(cmd_buffer, THREAD_NETWORK_BUFFER_MAX, "ipaddr");
570         }
571
572         size_t buf_size = strlen(cmd_buffer);
573
574         THREAD_DBG("DEBUG: NETWORK MESSAGE -> [%s]", cmd_buffer);
575
576         ret = _thread_socket_client_write(session_fd, cmd_buffer, buf_size);
577         if (ret != THREAD_ERROR_NONE) {
578                 THREAD_DBG("Failed to execute command %s", cmd_buffer);
579                 return ret;
580         }
581         THREAD_DBG("Executed command '%s' with size %zu", cmd_buffer, buf_size);
582
583         /* Check response */
584         ret = _thread_socket_client_read(session_fd, buffer);
585         if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) {
586                 THREAD_DBG("Socket response failed..");
587                 return ret;
588         }
589
590         while (true) {
591                 if ((buffer[index] >= 'a' && buffer[index] <= 'f') || buffer[index] == ':'
592                                 || (buffer[index] >= '0' && buffer[index] <= '9')) {
593                         ipaddr[pos++] = buffer[index];
594                 } else if (buffer[index] == 'D') {
595                          THREAD_DBG("Socket read response buffer: Done");
596                          break;
597                 } else {
598                         ipaddr[pos] = '\0';
599                         if (pos > 0) {
600                                 THREAD_DBG("IP address: %s, length: %zu", ipaddr,
601                                                                 strlen(ipaddr));
602                                 callback(++count, ipaddr, ipaddr_type, user_data);
603                         }
604                         pos = 0;
605                 }
606                 index++;
607         }
608
609         FUNC_EXIT;
610         return ret;
611 }
612
613 static bool __is_valid_ipv6(const uint8_t* ipv6_address)
614 {
615         FUNC_ENTRY;
616
617         int index = 0;
618         while (index < THREAD_IPV6_ADDRESS_SIZE) {
619                 char buffer[THREAD_NETWORK_BUFFER_MAX];
620                 snprintf(buffer, THREAD_NETWORK_BUFFER_MAX, "%02x", ipv6_address[index]);
621                 if ((buffer[0] < '0' || buffer[0] > '9') &&
622                                 (buffer[0] < 'a' ||  buffer[0] > 'f'))
623                         return FALSE;
624                 if ((buffer[1] < '0' || buffer[1] > '9') &&
625                                 (buffer[1] < 'a' ||  buffer[1] > 'f'))
626                         return FALSE;
627
628                 index++;
629         }
630         THREAD_DBG("DEBUG: NETWORK MESSAGE -> return true");
631
632         FUNC_EXIT;
633         return TRUE;
634 }
635
636 int thread_add_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address)
637 {
638         FUNC_ENTRY;
639         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
640         THREAD_CHECK_INIT_STATUS();
641         THREAD_VALIDATE_INPUT_PARAMETER(instance);
642         THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address);
643
644         int ret = THREAD_ERROR_NONE;
645         char msg[THREAD_NETWORK_BUFFER_MAX];
646
647         retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER);
648
649         snprintf(msg, THREAD_NETWORK_BUFFER_MAX,
650                 "ipaddr add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
651                 ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3],
652                 ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7],
653                 ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11],
654                 ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]);
655
656         ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg));
657         retv_if(ret != THREAD_ERROR_NONE, ret);
658         THREAD_DBG("Successfully added address");
659
660         FUNC_EXIT;
661         return ret;
662 }
663
664 int thread_remove_ipaddr(thread_instance_h instance, const uint8_t *ipv6_address)
665 {
666         FUNC_ENTRY;
667         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
668         THREAD_CHECK_INIT_STATUS();
669         THREAD_VALIDATE_INPUT_PARAMETER(instance);
670         THREAD_VALIDATE_INPUT_PARAMETER(ipv6_address);
671
672         int ret = THREAD_ERROR_NONE;
673         char msg[THREAD_NETWORK_BUFFER_MAX];
674
675         retv_if(!__is_valid_ipv6(ipv6_address), THREAD_ERROR_INVALID_PARAMETER);
676
677         snprintf(msg, THREAD_BORDER_ROUTER_BUFFER_MAX,
678                 "ipaddr del %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
679                 ipv6_address[0], ipv6_address[1], ipv6_address[2], ipv6_address[3],
680                 ipv6_address[4], ipv6_address[5], ipv6_address[6], ipv6_address[7],
681                 ipv6_address[8], ipv6_address[9], ipv6_address[10], ipv6_address[11],
682                 ipv6_address[12], ipv6_address[13], ipv6_address[14], ipv6_address[15]);
683
684         ret = _thread_socket_client_execute(_thread_get_socket_fd(), msg, strlen(msg));
685         retv_if(ret != THREAD_ERROR_NONE, ret);
686         THREAD_DBG("Successfully removed address");
687
688         FUNC_EXIT;
689         return ret;
690 }
691
692 int thread_get_global_ipaddr(thread_instance_h instance, const char **ipaddr)
693 {
694         FUNC_ENTRY;
695         THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON);
696         THREAD_CHECK_INIT_STATUS();
697         THREAD_VALIDATE_INPUT_PARAMETER(instance);
698
699         int ret = THREAD_ERROR_NONE;
700         char buffer[THREAD_MAX_BUFFER_SIZE];
701         int session_fd = _thread_get_socket_fd();
702         const char *msg = THREAD_IPADDR_V;
703         char *ret_ptr, *next_ptr;
704
705         ret = _thread_socket_client_write(session_fd, msg, strlen(msg));
706         if (ret != THREAD_ERROR_NONE) {
707                 THREAD_DBG("Failed to execute command %s", msg);
708                 return ret;
709         }
710         THREAD_DBG("Executed command '%s' with size %zu", msg, strlen(msg));
711
712         /* Check response */
713         ret = _thread_socket_client_read(session_fd, buffer);
714         if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) {
715                 THREAD_DBG("Socket response failed..");
716                 return ret;
717         }
718
719         /* result is like below:
720          * > ipaddr -v
721          * fdd6:54c2:ee47:f2d2:0:ff:fe00:9400 origin:thread
722          * fd0b:8d9c:ac8c:1:2c82:12dd:825b:70c4 origin:slaac
723          * fdd6:54c2:ee47:f2d2:b267:e8fa:5bd6:2891 origin:thread
724          * fe80:0:0:0:5857:6a63:d5f1:91b6 origin:thread
725          * Done
726          */
727         ret_ptr = strtok_r(buffer, "\n", &next_ptr);
728         while (ret_ptr) {
729                 if (strstr(ret_ptr, "origin:slaac")) {
730                         strtok_r(ret_ptr, " ", &next_ptr);
731                         THREAD_DBG("Global Ipaddr: %s", ret_ptr);
732                         *ipaddr = g_strdup(ret_ptr);
733                         return THREAD_ERROR_NONE;
734                 }
735                 ret_ptr = strtok_r(NULL, "\n", &next_ptr);
736         }
737
738         FUNC_EXIT;
739         return ret;
740 }
741