Add interface to get mesh connected peers
[platform/core/connectivity/wifi-mesh-manager.git] / src / mesh-gdbus.c
1 /*
2  * Copyright (c) 2017 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 "mesh-log.h"
18 #include "mesh-util.h"
19 #include "mesh-gdbus.h"
20 #include "mesh-request.h"
21
22 #include "nl80211.h"
23
24 static GDBusProxy *_gproxy_connman = NULL;
25 static GDBusProxy *_gproxy_connman_mesh = NULL;
26 static GDBusProxy *_gproxy_connman_technology = NULL;
27
28 static int _meshd_close_gdbus_call(mesh_service *service);
29
30 static int __channel_to_frequency(int channel, enum nl80211_band band)
31 {
32         if (channel <= 0)
33                 return 0;
34
35         switch (band) {
36         case NL80211_BAND_2GHZ:
37                 if (channel == 14)
38                         return 2484;
39                 else if (channel < 14)
40                         return 2407 + channel * 5;
41                 break;
42         case NL80211_BAND_5GHZ:
43                 if (channel >= 182 && channel <= 196)
44                         return 4000 + channel * 5;
45                 else
46                         return 5000 + channel * 5;
47                 break;
48         default:
49                 break;
50         }
51
52         /* not supported */
53         return 0;
54 }
55
56 static int __frequency_to_channel(int freq)
57 {
58         if (freq == 2484)
59                 return 14;
60         else if (freq < 2484)
61                 return (freq - 2407) / 5;
62         else if (freq >= 4910 && freq <= 4980)
63                 return (freq - 4000) / 5;
64         else if (freq <= 45000)
65                 return (freq - 5000) / 5;
66         else if (freq >= 58320 && freq <= 64800)
67                 return (freq - 56160) / 2160;
68         else
69                 return 0;
70 }
71
72 static GDBusProxy *_proxy_get_connman(mesh_service *service)
73 {
74         GDBusProxy *proxy = NULL;
75         meshd_check_null_ret_error("service", service, NULL);
76
77         if (NULL == _gproxy_connman) {
78                 proxy = g_dbus_proxy_new_sync(service->connection,
79                         G_DBUS_PROXY_FLAGS_NONE, NULL,
80                         CONNMAN_SERVER_NAME,
81                         CONNMAN_OBJECT_PATH,
82                         CONNMAN_INTERFACE_MANAGER,
83                         NULL, NULL);
84         } else
85                 proxy = _gproxy_connman;
86
87         return proxy;
88 }
89
90 static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
91 {
92         GDBusProxy *proxy = NULL;
93         meshd_check_null_ret_error("service", service, NULL);
94
95         if (NULL == _gproxy_connman_mesh) {
96                 proxy = g_dbus_proxy_new_sync(service->connection,
97                         G_DBUS_PROXY_FLAGS_NONE, NULL,
98                         CONNMAN_SERVER_NAME,
99                         CONNMAN_OBJECT_PATH_MESH,
100                         CONNMAN_INTERFACE_MESH,
101                         NULL, NULL);
102         } else
103                 proxy = _gproxy_connman_mesh;
104
105         return proxy;
106 }
107
108 static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
109 {
110         GDBusProxy *proxy = NULL;
111         meshd_check_null_ret_error("service", service, NULL);
112
113         if (NULL == _gproxy_connman_technology) {
114                 proxy = g_dbus_proxy_new_sync(service->connection,
115                         G_DBUS_PROXY_FLAGS_NONE, NULL,
116                         CONNMAN_SERVER_NAME,
117                         CONNMAN_OBJECT_PATH_TECH_MESH,
118                         CONNMAN_INTERFACE_TECH,
119                         NULL, NULL);
120         } else
121                 proxy = _gproxy_connman_technology;
122
123         return proxy;
124 }
125
126 static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
127                 gpointer *user_data)
128 {
129         GDBusProxy *proxy = G_DBUS_PROXY(object);
130         gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
131         mesh_service *service = (mesh_service*)user_data;
132
133         NOTUSED(pspec);
134
135         if (NULL == name_owner) {
136                 MESH_LOGE("name_owner is not exists !");
137                 _meshd_close_gdbus_call(service);
138         }
139
140         g_free(name_owner);
141 }
142
143 static int _meshd_create_gdbus_call(mesh_service *service)
144 {
145         int id;
146         GError *error = NULL;
147
148         if (NULL == service)
149                 return MESHD_ERROR_INVALID_PARAMETER;
150
151         if (NULL != service->connection)
152                 return MESHD_ERROR_ALREADY_REGISTERED;
153
154         service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
155         if (service->connection == NULL) {
156                 if (error != NULL) {
157                         MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
158                         g_error_free(error);
159                 }
160                 return MESHD_ERROR_IO_ERROR;
161         }
162
163         id = g_signal_connect(service->connection, "notify::g-name-owner",
164                         G_CALLBACK(_dbus_name_owner_notify), service);
165         if (0 == id) {
166                 MESH_LOGE("g_signal_connect() Fail");
167                 g_object_unref(service->connection);
168                 service->connection = NULL;
169                 return MESHD_ERROR_IO_ERROR;
170         }
171
172         return MESHD_ERROR_NONE;
173 }
174
175 static int _meshd_close_gdbus_call(mesh_service *service)
176 {
177         /* CHECK: is connection ref count required? */
178         g_object_unref(service->connection);
179         service->connection = NULL;
180
181         return MESHD_ERROR_NONE;
182 }
183
184 static void _meshd_signal_handler(GDBusConnection *connection,
185                 const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
186                 const gchar *signal_name, GVariant *parameters, gpointer user_data)
187 {
188         mesh_service *service = (mesh_service*)user_data;
189
190         meshd_check_null_ret("user_data", user_data);
191         //meshd_check_null_ret("event_handler", service->event_handler);
192         NOTUSED(connection);
193         NOTUSED(sender_name);
194         NOTUSED(object_path);
195         NOTUSED(interface_name);
196         NOTUSED(signal_name);
197         NOTUSED(parameters);
198
199         NOTUSED(service);
200
201         MESH_LOGD("signal received = %s", signal_name);
202         if (0 == g_strcmp0(signal_name, "ScanDone")) {
203                 /* TODO: Handle event */
204                 mesh_notify_scan_done();
205         }
206 }
207
208 static void _meshd_subscribe_event(mesh_service *service)
209 {
210         unsigned int id;
211
212         id = g_dbus_connection_signal_subscribe(
213                         (GDBusConnection *)service->connection,
214                         CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
215                         "ScanDone", "/", NULL,
216                         G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
217         if (0 == id) {
218                 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
219                 return;
220         }
221         service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
222         MESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
223
224         /* End of subscription */
225 }
226
227 int meshd_dbus_start(mesh_service *service)
228 {
229         int rv;
230
231         rv = _meshd_create_gdbus_call(service);
232         if (MESHD_ERROR_NONE != rv)
233                 return rv;
234
235         service->ca = g_cancellable_new();
236
237         /* Create all required proxies here */
238         _gproxy_connman = _proxy_get_connman(service);
239         meshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
240                                 MESHD_ERROR_IO_ERROR);
241         g_dbus_proxy_set_default_timeout(
242                         G_DBUS_PROXY(_gproxy_connman), MESH_DBUS_PROXY_TIMEOUT);
243
244         _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
245         meshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
246                                 MESHD_ERROR_IO_ERROR);
247         g_dbus_proxy_set_default_timeout(
248                         G_DBUS_PROXY(_gproxy_connman_mesh), MESH_DBUS_PROXY_TIMEOUT);
249
250         _gproxy_connman_technology = _proxy_get_connman_technology(service);
251         meshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
252                                 MESHD_ERROR_IO_ERROR);
253         g_dbus_proxy_set_default_timeout(
254                         G_DBUS_PROXY(_gproxy_connman_technology), MESH_DBUS_PROXY_TIMEOUT);
255
256         /* Subscribe events */
257         _meshd_subscribe_event(service);
258
259         return MESHD_ERROR_NONE;
260 }
261
262 int meshd_dbus_stop(mesh_service *service)
263 {
264         int rv;
265
266         if (NULL == service)
267                 return MESHD_ERROR_INVALID_PARAMETER;
268
269         /* Unref all proxies here */
270         if (_gproxy_connman) {
271                 g_object_unref(_gproxy_connman);
272                 _gproxy_connman = NULL;
273         }
274         if (_gproxy_connman_mesh) {
275                 g_object_unref(_gproxy_connman_mesh);
276                 _gproxy_connman_mesh = NULL;
277         }
278         if (_gproxy_connman_technology) {
279                 g_object_unref(_gproxy_connman_technology);
280                 _gproxy_connman_technology = NULL;
281         }
282
283         g_cancellable_cancel(service->ca);
284         g_object_unref(service->ca);
285         service->ca = NULL;
286
287         rv = _meshd_close_gdbus_call(service);
288         return rv;
289 }
290
291 int mesh_ipc_create_mesh_interface(mesh_service *service)
292 {
293         int ret = MESHD_ERROR_NONE;
294         GVariant *variant = NULL;
295         GError *error = NULL;
296         GVariant *var_dict = NULL;
297         GVariantDict dict;
298         mesh_interface_s *info = NULL;
299
300         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
301         meshd_check_null_ret_error("connection", service->connection,
302                         MESHD_ERROR_INVALID_PARAMETER);
303         meshd_check_null_ret_error("_gproxy_connman_technology",
304                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
305
306         info = service->interface_info;
307
308         g_variant_dict_init(&dict, NULL);
309         g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
310         g_variant_dict_insert(&dict, "ParentIfname", "s", info->base_interface);
311         g_variant_dict_insert(&dict, "BridgeIfname", "s", info->bridge_interface);
312         var_dict = g_variant_dict_end(&dict);
313
314         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
315                                 g_variant_new("(sv)", "MeshInterfaceAdd", var_dict),
316                                 G_DBUS_CALL_FLAGS_NONE,
317                                 -1, NULL, &error);
318         if (variant) {
319                 MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
320         } else if (error) {
321                 ret = MESHD_ERROR_IO_ERROR;
322                 MESH_LOGE("Failed DBus call [%s]", error->message);
323
324                 /* Interface not exists */
325                 if (g_strrstr(error->message, "No such device"))
326                         ret = MESHD_ERROR_INVALID_PARAMETER;
327                 g_error_free(error);
328         }
329
330         return ret;
331 }
332
333 int mesh_ipc_remove_mesh_interface(mesh_service *service)
334 {
335         GVariant *variant = NULL;
336         GError *error = NULL;
337         GVariant *var_dict = NULL;
338         GVariantDict dict;
339         mesh_interface_s *info = NULL;
340
341         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
342         meshd_check_null_ret_error("connection", service->connection,
343                         MESHD_ERROR_INVALID_PARAMETER);
344         meshd_check_null_ret_error("_gproxy_connman_technology",
345                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
346
347         info = service->interface_info;
348
349         g_variant_dict_init(&dict, NULL);
350         g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
351         var_dict = g_variant_dict_end(&dict);
352
353         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
354                                 g_variant_new("(sv)", "MeshInterfaceRemove", var_dict),
355                                 G_DBUS_CALL_FLAGS_NONE,
356                                 -1, NULL, &error);
357         if (variant) {
358                 MESH_LOGD("Successfully requested. [MeshInterfaceRemove]");
359         } else if (error) {
360                 MESH_LOGE("Failed DBus call [%s]", error->message);
361                 g_error_free(error);
362                 return MESHD_ERROR_IO_ERROR;
363         }
364
365         return MESHD_ERROR_NONE;
366 }
367
368 int mesh_ipc_mesh_scan(mesh_service *service)
369 {
370         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
371         meshd_check_null_ret_error("connection", service->connection,
372                         MESHD_ERROR_INVALID_PARAMETER);
373         meshd_check_null_ret_error("_gproxy_connman_technology",
374                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
375
376         g_dbus_proxy_call(_gproxy_connman_technology, "Scan",
377                                 NULL,
378                                 G_DBUS_CALL_FLAGS_NONE,
379                                 -1, NULL, NULL, NULL);
380
381         MESH_LOGD("Successfully requested. [Scan]");
382
383         return MESHD_ERROR_NONE;
384 }
385
386 int mesh_ipc_mesh_specific_scan(mesh_service *service, gchar *mesh_id,
387         gint channel)
388 {
389         GVariant *variant = NULL;
390         GError *error = NULL;
391         GVariant *var_dict = NULL;
392         GVariantDict dict;
393
394         enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
395         gushort freq = __channel_to_frequency(channel, band);
396
397         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
398         meshd_check_null_ret_error("connection", service->connection,
399                         MESHD_ERROR_INVALID_PARAMETER);
400         meshd_check_null_ret_error("_gproxy_connman_technology",
401                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
402
403         g_variant_dict_init(&dict, NULL);
404         g_variant_dict_insert(&dict, "Name", "s", mesh_id);
405         g_variant_dict_insert(&dict, "Frequency", "q", freq);
406         var_dict = g_variant_dict_end(&dict);
407
408         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
409                                 g_variant_new("(sv)", "MeshSpecificScan", var_dict),
410                                 G_DBUS_CALL_FLAGS_NONE,
411                                 -1, NULL, &error);
412         if (variant) {
413                 MESH_LOGD("Successfully requested. [MeshSpecificScan]");
414         } else if (error) {
415                 MESH_LOGE("Failed DBus call [%s]", error->message);
416                 g_error_free(error);
417                 return MESHD_ERROR_IO_ERROR;
418         }
419
420         return MESHD_ERROR_NONE;
421 }
422
423 int mesh_ipc_mesh_cancel_scan(mesh_service *service)
424 {
425         GVariant *variant = NULL;
426         GError *error = NULL;
427         GVariant *var_dict = NULL;
428         GVariantDict dict;
429
430         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
431         meshd_check_null_ret_error("connection", service->connection,
432                         MESHD_ERROR_INVALID_PARAMETER);
433         meshd_check_null_ret_error("_gproxy_connman_technology",
434                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
435
436         g_variant_dict_init(&dict, NULL);
437         var_dict = g_variant_dict_end(&dict);
438
439         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
440                                 g_variant_new("(sv)", "AbortScan", var_dict),
441                                 G_DBUS_CALL_FLAGS_NONE,
442                                 -1, NULL, &error);
443         if (variant) {
444                 MESH_LOGD("Successfully requested. [AbortScan]");
445         } else if (error) {
446                 MESH_LOGE("Failed DBus call [%s]", error->message);
447                 g_error_free(error);
448                 return MESHD_ERROR_IO_ERROR;
449         }
450
451         return MESHD_ERROR_NONE;
452 }
453
454 static void _on_scan_result_destroy(gpointer data)
455 {
456         mesh_scan_result_s *scan_item = (mesh_scan_result_s *)data;
457
458         if (scan_item) {
459                 g_free(scan_item->mesh_id);
460                 g_free(scan_item->bssid);
461                 g_free(scan_item->object_path);
462         }
463 }
464
465 static void _on_peer_info_destroy(gpointer data)
466 {
467         mesh_peer_info_s *peer = (mesh_peer_info_s *)data;
468         if (peer)
469                 g_free(peer->address);
470 }
471
472 static void _get_joined_network(mesh_service *service, GVariant *variant)
473 {
474         GVariantIter *peer = NULL;
475         GVariantIter *property = NULL;
476         gchar *key = NULL;
477         GVariant *val = NULL;
478         gsize len = 0;
479         GVariant *child;
480         const gchar* obj_path = NULL;
481         const gchar* buf = NULL;
482
483         g_variant_get(variant, "(a(oa{sv}))", &peer);
484         while ((child = g_variant_iter_next_value(peer))) {
485                 mesh_network_info_s *joined_info = NULL;
486                 gboolean valid_state = TRUE;
487
488                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
489                 MESH_LOGD("  Object: [%s]", obj_path);
490                 if (NULL == obj_path) {
491                         MESH_LOGE("Null object");
492                         continue;
493                 }
494
495                 /* Create an information structure for joined network */
496                 joined_info = g_try_new0(mesh_network_info_s, 1);
497                 if (NULL == joined_info) {
498                         MESH_LOGE("Failed to allocate !");
499                         return;
500                 }
501
502                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
503                         if (strcasecmp(key, "Name") == 0)  {
504                                 buf = g_variant_get_string(val, &len);
505                                 joined_info->mesh_id = g_strdup(buf);
506                         }
507                         else if (strcasecmp(key, "Address") == 0)  {
508                                 buf = g_variant_get_string(val, &len);
509                                 joined_info->bssid = g_strdup(buf);
510                         }
511                         else if (strcasecmp(key, "State") == 0)  {
512                                 buf = g_variant_get_string(val, &len);
513                                 MESH_LOGD("    State : %s", buf);
514
515                                 /* Skip ignorable state */
516                                 if (g_strcmp0(buf, "idle") == 0
517                                         || g_strcmp0(buf, "disconnect") == 0
518                                         || g_strcmp0(buf, "failure") == 0) {
519                                         valid_state = FALSE;
520                                         break;
521                                 }
522                         }
523                         else if (strcasecmp(key, "Frequency") == 0)  {
524                                 joined_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
525                         }
526                 }
527
528                 /* Skip ignorable state */
529                 if (FALSE == valid_state) {
530                         g_free(joined_info->mesh_id);
531                         g_free(joined_info->bssid);
532                         continue;
533                 }
534
535                 MESH_LOGD("    Mesh ID : %s", joined_info->mesh_id);
536                 MESH_LOGD("    BSSID   : %s", joined_info->bssid);
537                 MESH_LOGD("    Channel : %d", joined_info->channel);
538                 service->joined_network = joined_info;
539
540                 g_variant_iter_free(property);
541
542                 /* If found, stop loop iteration */
543                 break;
544         }
545         g_variant_iter_free(peer);
546 }
547
548 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
549 {
550         GVariantIter *peer = NULL;
551         GVariantIter *property = NULL;
552         gchar *key = NULL;
553         GVariant *val = NULL;
554         gsize len = 0;
555         GVariant *child;
556         const gchar* obj_path = NULL;
557
558         g_variant_get(variant, "(a(oa{sv}))", &peer);
559         while ((child = g_variant_iter_next_value(peer))) {
560                 mesh_scan_result_s *scan_info = NULL;
561
562                 scan_info = g_try_new0(mesh_scan_result_s, 1);
563                 if (NULL == scan_info) {
564                         MESH_LOGE("Failed to allocate !");
565                         return;
566                 }
567
568                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
569                 if (NULL == obj_path) {
570                         MESH_LOGE("Null object");
571                         g_free(scan_info);
572                         continue;
573                 }
574                 MESH_LOGD("    Obj path : [%s]", obj_path);
575                 scan_info->object_path = g_strdup(obj_path);
576
577                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
578                         if (strcasecmp(key, "Name") == 0)  {
579                                 const char *buf = g_variant_get_string(val, &len);
580                                 scan_info->mesh_id = g_strdup(buf);
581                                 MESH_LOGD("    Mesh ID : %s", scan_info->mesh_id);
582                         }
583                         else if (strcasecmp(key, "Address") == 0)  {
584                                 const char *buf = g_variant_get_string(val, &len);
585                                 scan_info->bssid = g_strdup(buf);
586                                 MESH_LOGD("    BSSID : %s", scan_info->bssid);
587                         }
588                         else if (strcasecmp(key, "State") == 0)  {
589                                 const char *buf = g_variant_get_string(val, &len);
590                                 MESH_LOGD("    State : %s", buf);
591                         }
592                         else if (strcasecmp(key, "Security") == 0)  {
593                                 const char *buf = g_variant_get_string(val, &len);
594                                 MESH_LOGD("    Security : %s", buf);
595                         }
596                         else if (strcasecmp(key, "Frequency") == 0)  {
597                                 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
598                                 MESH_LOGD("    Channel : %d", scan_info->channel);
599                         }
600                         else if (strcasecmp(key, "Favorite") == 0)  {
601                                 const char *buf = g_variant_get_string(val, &len);
602                                 MESH_LOGD("    Favorite : %s", buf);
603                         }
604                         else if (strcasecmp(key, "Strength") == 0)  {
605                                 scan_info->rssi = (gint)g_variant_get_byte(val);
606                                 MESH_LOGD("    RSSI : %d", scan_info->rssi);
607                         }
608                 }
609                 /* Last element */
610                 service->scanned_mesh_network =
611                         g_list_prepend(service->scanned_mesh_network, scan_info);
612
613                 g_variant_iter_free(property);
614         }
615         g_variant_iter_free(peer);
616 }
617
618 static void _get_connected_mesh_peers(mesh_service *service, GVariant *variant)
619 {
620         GVariantIter *peer = NULL;
621         GVariantIter *property = NULL;
622         gchar *key = NULL;
623         GVariant *val = NULL;
624         gsize len = 0;
625         GVariant *child;
626
627         g_variant_get(variant, "(a(a{sv}))", &peer);
628         while ((child = g_variant_iter_next_value(peer))) {
629                 mesh_peer_info_s *peer_info = NULL;
630
631                 peer_info = g_try_new0(mesh_peer_info_s, 1);
632                 if (NULL == peer_info) {
633                         MESH_LOGE("Failed to allocate !");
634                         return;
635                 }
636
637                 g_variant_get(child, "(a{sv})", &property);
638                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
639                         if (strcasecmp(key, "PeerAddress") == 0)  {
640                                 const char *buf = g_variant_get_string(val, &len);
641                                 peer_info->address = g_strdup(buf);
642                                 MESH_LOGD("    Address : %s", peer_info->address);
643                         }
644                 }
645                 /* Last element */
646                 service->connected_mesh_peers =
647                         g_list_prepend(service->connected_mesh_peers, peer_info);
648
649                 g_variant_iter_free(property);
650         }
651         g_variant_iter_free(peer);
652 }
653
654 int mesh_ipc_get_mesh_peers(mesh_service *service)
655 {
656         GVariant *variant = NULL;
657         GError *error = NULL;
658
659         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
660         meshd_check_null_ret_error("connection", service->connection,
661                         MESHD_ERROR_INVALID_PARAMETER);
662         meshd_check_null_ret_error("_gproxy_connman",
663                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
664
665         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
666                                 NULL,
667                                 G_DBUS_CALL_FLAGS_NONE,
668                                 -1, NULL, &error);
669         if (variant) {
670                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
671
672                 if (service->scanned_mesh_network) {
673                         g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
674                         service->scanned_mesh_network = NULL;
675                 }
676
677                 _get_mesh_peers(service, variant);
678
679                 /* List item is saved with reversed order for efficiency. */
680                 service->scanned_mesh_network =
681                                 g_list_reverse(service->scanned_mesh_network);
682         } else if (error) {
683                 MESH_LOGE("Failed DBus call [%s]", error->message);
684                 g_error_free(error);
685                 return MESHD_ERROR_IO_ERROR;
686         }
687
688         return MESHD_ERROR_NONE;
689 }
690
691 int mesh_ipc_get_connected_peers(mesh_service *service)
692 {
693         GVariant *variant = NULL;
694         GError *error = NULL;
695
696         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
697         meshd_check_null_ret_error("connection", service->connection,
698                         MESHD_ERROR_INVALID_PARAMETER);
699         meshd_check_null_ret_error("_gproxy_connman",
700                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
701
702         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetConnectedMeshPeers",
703                                 NULL,
704                                 G_DBUS_CALL_FLAGS_NONE,
705                                 -1, NULL, &error);
706         if (variant) {
707                 MESH_LOGD("Successfully requested. [GetConnectedMeshPeers]");
708
709                 if (service->connected_mesh_peers) {
710                         g_list_free_full(service->connected_mesh_peers, _on_peer_info_destroy);
711                         service->connected_mesh_peers = NULL;
712                 }
713
714                 _get_connected_mesh_peers(service, variant);
715
716                 /* List item is saved with reversed order for efficiency. */
717                 service->connected_mesh_peers =
718                                 g_list_reverse(service->connected_mesh_peers);
719         } else if (error) {
720                 MESH_LOGE("Failed DBus call [%s]", error->message);
721                 g_error_free(error);
722                 return MESHD_ERROR_IO_ERROR;
723         }
724
725         return MESHD_ERROR_NONE;
726 }
727
728 int mesh_ipc_get_joined_mesh_network(mesh_service *service)
729 {
730         GVariant *variant = NULL;
731         GError *error = NULL;
732
733         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
734         meshd_check_null_ret_error("connection", service->connection,
735                         MESHD_ERROR_INVALID_PARAMETER);
736         meshd_check_null_ret_error("_gproxy_connman",
737                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
738
739         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
740                                 NULL,
741                                 G_DBUS_CALL_FLAGS_NONE,
742                                 -1, NULL, &error);
743         if (variant) {
744                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
745
746                 if (service->joined_network) {
747                         g_free(service->joined_network->mesh_id);
748                         g_free(service->joined_network->bssid);
749                         g_free(service->joined_network);
750                         service->joined_network = NULL;
751                 }
752
753                 _get_joined_network(service, variant);
754         } else if (error) {
755                 MESH_LOGE("Failed DBus call [%s]", error->message);
756                 g_error_free(error);
757                 return MESHD_ERROR_IO_ERROR;
758         }
759
760         return MESHD_ERROR_NONE;
761 }
762
763 int mesh_ipc_create_network(mesh_service *service, gchar *mesh_id, gint channel,
764         gint security)
765 {
766         GVariant *variant = NULL;
767         GError *error = NULL;
768         GVariant *var_dict = NULL;
769         GVariantBuilder builder;
770         const gchar* secu = (security == 0) ? "none" : "SAE";
771
772         enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
773         gushort freq = __channel_to_frequency(channel, band);
774
775         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
776         meshd_check_null_ret_error("connection", service->connection,
777                         MESHD_ERROR_INVALID_PARAMETER);
778         meshd_check_null_ret_error("_gproxy_connman_technology",
779                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
780
781         g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
782         g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
783
784         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
785         g_variant_builder_add(&builder, "s", "Name");
786         g_variant_builder_add(&builder, "v", g_variant_new_string(mesh_id));
787         g_variant_builder_close(&builder); /* {sv} */
788
789         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
790         g_variant_builder_add(&builder, "s", "Frequency");
791         g_variant_builder_add(&builder, "v", g_variant_new_uint16(freq));
792         g_variant_builder_close(&builder); /* {sv} */
793
794         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
795         g_variant_builder_add(&builder, "s", "Security");
796         g_variant_builder_add(&builder, "v", g_variant_new_string(secu));
797         g_variant_builder_close(&builder); /* {sv} */
798
799         g_variant_builder_close(&builder); /* a{sv} */
800
801         var_dict = g_variant_builder_end(&builder);
802
803         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
804                                 g_variant_new("(sv)", "MeshCreateNetwork", var_dict),
805                                 G_DBUS_CALL_FLAGS_NONE,
806                                 -1, NULL, &error);
807         if (variant) {
808                 MESH_LOGD("Successfully requested. [MeshCreateNetwork]");
809         } else if (error) {
810                 MESH_LOGE("Failed DBus call [%s]", error->message);
811                 g_error_free(error);
812                 return MESHD_ERROR_IO_ERROR;
813         }
814
815         return MESHD_ERROR_NONE;
816 }
817
818 int mesh_ipc_connect_network(mesh_service *service, mesh_scan_result_s *info)
819 {
820         int ret = MESHD_ERROR_NONE;
821         GVariant *variant = NULL;
822         GError *error = NULL;
823
824         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
825         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
826
827         variant = g_dbus_connection_call_sync(service->connection,
828                         CONNMAN_SERVER_NAME,
829                         info->object_path,
830                         CONNMAN_INTERFACE_MESH,
831                         "Connect",
832                         NULL, NULL,
833                         G_DBUS_CALL_FLAGS_NONE,
834                         -1, NULL, &error);
835         if (variant) {
836                 MESH_LOGD("Successfully requested. [Connect]");
837         } else if (error) {
838                 ret = MESHD_ERROR_IO_ERROR;
839                 LOGE("Failed DBus call [%s]", error->message);
840
841                 if (g_strrstr(error->message, "Already exists"))
842                         ret = MESHD_ERROR_ALREADY_REGISTERED;
843                 else
844                         ret = MESHD_ERROR_IO_ERROR;
845
846                 g_error_free(error);
847         }
848
849         return ret;
850 }
851
852 int mesh_ipc_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
853 {
854         GVariant *variant = NULL;
855         GError *error = NULL;
856
857         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
858         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
859
860         variant = g_dbus_connection_call_sync(service->connection,
861                         CONNMAN_SERVER_NAME,
862                         info->object_path,
863                         CONNMAN_INTERFACE_MESH,
864                         "Disconnect",
865                         NULL, NULL,
866                         G_DBUS_CALL_FLAGS_NONE,
867                         -1, NULL, &error);
868         if (variant) {
869                 MESH_LOGD("Successfully requested. [Disconnect]");
870         } else if (error) {
871                 LOGE("Failed DBus call [%s]", error->message);
872                 g_error_free(error);
873                 return MESHD_ERROR_IO_ERROR;
874         }
875
876         return MESHD_ERROR_NONE;
877 }
878
879 int mesh_ipc_remove_network(mesh_service *service, mesh_scan_result_s *info)
880 {
881         GVariant *variant = NULL;
882         GError *error = NULL;
883
884         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
885         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
886
887         variant = g_dbus_connection_call_sync(service->connection,
888                         CONNMAN_SERVER_NAME,
889                         info->object_path,
890                         CONNMAN_INTERFACE_MESH,
891                         "Remove",
892                         NULL, NULL,
893                         G_DBUS_CALL_FLAGS_NONE,
894                         -1, NULL, &error);
895         if (variant) {
896                 MESH_LOGD("Successfully requested. [Remove]");
897         } else if (error) {
898                 LOGE("Failed DBus call [%s]", error->message);
899                 g_error_free(error);
900                 return MESHD_ERROR_IO_ERROR;
901         }
902
903         return MESHD_ERROR_NONE;
904 }