Fix mismatched function call
[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 static int _mesh_gdbus_get_mesh_network_property(mesh_service *service,
30         const gchar* object_path, mesh_network_info_s *result);
31
32 static int __channel_to_frequency(int channel, enum nl80211_band band)
33 {
34         if (channel <= 0)
35                 return 0;
36
37         switch (band) {
38         case NL80211_BAND_2GHZ:
39                 if (channel == 14)
40                         return 2484;
41                 else if (channel < 14)
42                         return 2407 + channel * 5;
43                 break;
44         case NL80211_BAND_5GHZ:
45                 if (channel >= 182 && channel <= 196)
46                         return 4000 + channel * 5;
47                 else
48                         return 5000 + channel * 5;
49                 break;
50         default:
51                 break;
52         }
53
54         /* not supported */
55         return 0;
56 }
57
58 static int __frequency_to_channel(int freq)
59 {
60         if (freq == 2484)
61                 return 14;
62         else if (freq < 2484)
63                 return (freq - 2407) / 5;
64         else if (freq >= 4910 && freq <= 4980)
65                 return (freq - 4000) / 5;
66         else if (freq <= 45000)
67                 return (freq - 5000) / 5;
68         else if (freq >= 58320 && freq <= 64800)
69                 return (freq - 56160) / 2160;
70         else
71                 return 0;
72 }
73
74 static GDBusProxy *_proxy_get_connman(mesh_service *service)
75 {
76         GDBusProxy *proxy = NULL;
77         meshd_check_null_ret_error("service", service, NULL);
78
79         if (NULL == _gproxy_connman) {
80                 proxy = g_dbus_proxy_new_sync(service->connection,
81                         G_DBUS_PROXY_FLAGS_NONE, NULL,
82                         CONNMAN_SERVER_NAME,
83                         CONNMAN_OBJECT_PATH,
84                         CONNMAN_INTERFACE_MANAGER,
85                         NULL, NULL);
86         } else
87                 proxy = _gproxy_connman;
88
89         return proxy;
90 }
91
92 static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
93 {
94         GDBusProxy *proxy = NULL;
95         meshd_check_null_ret_error("service", service, NULL);
96
97         if (NULL == _gproxy_connman_mesh) {
98                 proxy = g_dbus_proxy_new_sync(service->connection,
99                         G_DBUS_PROXY_FLAGS_NONE, NULL,
100                         CONNMAN_SERVER_NAME,
101                         CONNMAN_OBJECT_PATH_MESH,
102                         CONNMAN_INTERFACE_MESH,
103                         NULL, NULL);
104         } else
105                 proxy = _gproxy_connman_mesh;
106
107         return proxy;
108 }
109
110 static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
111 {
112         GDBusProxy *proxy = NULL;
113         meshd_check_null_ret_error("service", service, NULL);
114
115         if (NULL == _gproxy_connman_technology) {
116                 proxy = g_dbus_proxy_new_sync(service->connection,
117                         G_DBUS_PROXY_FLAGS_NONE, NULL,
118                         CONNMAN_SERVER_NAME,
119                         CONNMAN_OBJECT_PATH_TECH_MESH,
120                         CONNMAN_INTERFACE_TECH,
121                         NULL, NULL);
122         } else
123                 proxy = _gproxy_connman_technology;
124
125         return proxy;
126 }
127
128 static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
129                 gpointer *user_data)
130 {
131         GDBusProxy *proxy = G_DBUS_PROXY(object);
132         gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
133         mesh_service *service = (mesh_service*)user_data;
134
135         NOTUSED(pspec);
136
137         if (NULL == name_owner) {
138                 MESH_LOGE("name_owner is not exists !");
139                 _meshd_close_gdbus_call(service);
140         }
141
142         g_free(name_owner);
143 }
144
145 static int _meshd_create_gdbus_call(mesh_service *service)
146 {
147         int id;
148         GError *error = NULL;
149
150         if (NULL == service)
151                 return MESHD_ERROR_INVALID_PARAMETER;
152
153         if (NULL != service->connection)
154                 return MESHD_ERROR_ALREADY_REGISTERED;
155
156         service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
157         if (service->connection == NULL) {
158                 if (error != NULL) {
159                         MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
160                         g_error_free(error);
161                 }
162                 return MESHD_ERROR_IO_ERROR;
163         }
164
165         id = g_signal_connect(service->connection, "notify::g-name-owner",
166                         G_CALLBACK(_dbus_name_owner_notify), service);
167         if (0 == id) {
168                 MESH_LOGE("g_signal_connect() Fail");
169                 g_object_unref(service->connection);
170                 service->connection = NULL;
171                 return MESHD_ERROR_IO_ERROR;
172         }
173
174         return MESHD_ERROR_NONE;
175 }
176
177 static int _meshd_close_gdbus_call(mesh_service *service)
178 {
179         /* CHECK: is connection ref count required? */
180         g_object_unref(service->connection);
181         service->connection = NULL;
182
183         return MESHD_ERROR_NONE;
184 }
185
186 static void _meshd_signal_handler(GDBusConnection *connection,
187                 const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
188                 const gchar *signal_name, GVariant *parameters, gpointer user_data)
189 {
190         mesh_service *service = (mesh_service*)user_data;
191         mesh_network_info_s network_info = { 0, 0, 0, 0, 0 };
192         int ret = MESHD_ERROR_NONE;
193
194         meshd_check_null_ret("user_data", user_data);
195         NOTUSED(connection);
196         NOTUSED(sender_name);
197         NOTUSED(interface_name);
198
199         MESH_LOGD("signal received = %s", signal_name);
200         if (0 == g_strcmp0(signal_name, "ScanDone")) {
201                 /* TODO: Handle event */
202                 mesh_notify_scan_done();
203         } else if (0 == g_strcmp0(signal_name, "PropertyChanged")) {
204                 const gchar* var = NULL;
205                 gchar* key = NULL;
206                 GVariant *variant = NULL;
207                 meshd_connection_state_e state = MESHD_CONNECTION_STATE_DISCONNECTED;
208
209                 if (NULL == parameters) {
210                         MESH_LOGE("Unexpected parameter");
211                         return;
212                 }
213
214                 g_variant_get(parameters, "(sv)", &key, &variant);
215                 if (NULL == variant) {
216                         MESH_LOGE("Invalid variant");
217                         return;
218                 }
219
220                 /* State [???] */
221                 var = g_variant_get_string(variant, NULL);
222                 MESH_LOGD("  %s [%s]", key, var);
223                 MESH_LOGD("    %s", object_path);
224
225                 ret = _mesh_gdbus_get_mesh_network_property(service, object_path, &network_info);
226                 if (MESHD_ERROR_NONE != ret)
227                         MESH_LOGE("Cannot get valid network property !");
228
229                 if (g_strcmp0("association", var) == 0) {
230                         /* Joined mesh network */
231                         state = MESHD_CONNECTION_STATE_ASSOCIATION;
232                 } else if (g_strcmp0("configuration", var) == 0) {
233                         /* Trying to get IP address */
234                         state = MESHD_CONNECTION_STATE_CONFIGURATION;
235                 } else if (g_strcmp0("ready", var) == 0 || g_strcmp0("online", var) == 0) {
236                         /* IP address is obtained */
237                         state = MESHD_CONNECTION_STATE_CONNECTED;
238                 } else if (g_strcmp0("disconnect", var) == 0 || g_strcmp0("failure", var) == 0) {
239                         state = MESHD_CONNECTION_STATE_DISCONNECTED;
240                 } else {
241                         MESH_LOGE("  Unhandled state !");
242                         g_free(network_info.mesh_id);
243                         g_free(network_info.bssid);
244                         return;
245                 }
246
247                 mesh_notify_connection_state(network_info.mesh_id, network_info.bssid,
248                         network_info.channel, network_info.security, state);
249
250                 g_free(network_info.mesh_id);
251                 g_free(network_info.bssid);
252         }
253 }
254
255 static void _meshd_subscribe_event(mesh_service *service)
256 {
257         unsigned int id = 0;
258
259         meshd_check_null_ret("service", service);
260
261         id = g_dbus_connection_signal_subscribe(
262                         (GDBusConnection *)service->connection,
263                         CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
264                         "ScanDone", "/", NULL,
265                         G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
266         if (0 == id) {
267                 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
268                 return;
269         }
270         service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
271         MESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
272
273         /* To monitor mesh profiles */
274         id = g_dbus_connection_signal_subscribe(
275                         (GDBusConnection *)service->connection,
276                         CONNMAN_SERVER_NAME,
277                         CONNMAN_INTERFACE_MESH,
278                         "PropertyChanged",
279                         NULL, /* Path */
280                         NULL,
281                         G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
282         if (0 == id) {
283                 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
284                 return;
285         }
286         service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
287         MESH_LOGD("[Signal subscribe] : PropertyChanged (%d)", id);
288
289         /* End of subscription */
290 }
291
292 static void _on_unsubscribe_ids(gpointer data, gpointer user_data)
293 {
294         unsigned int id = GPOINTER_TO_UINT(data);
295         mesh_service *service = (mesh_service*)user_data;
296
297         MESH_LOGD("[Signal unsubscribe] : %d", id);
298         g_dbus_connection_signal_unsubscribe(
299                 (GDBusConnection *)service->connection, id);
300 }
301
302 static void _meshd_unsubscribe_event(mesh_service *service)
303 {
304         meshd_check_null_ret("service", service);
305
306         g_list_foreach(service->dbus_sub_ids, _on_unsubscribe_ids, service);
307
308         g_list_free(service->dbus_sub_ids);
309         service->dbus_sub_ids = NULL;
310 }
311
312 int meshd_dbus_start(mesh_service *service)
313 {
314         int rv;
315
316         rv = _meshd_create_gdbus_call(service);
317         if (MESHD_ERROR_NONE != rv)
318                 return rv;
319
320         service->ca = g_cancellable_new();
321
322         /* Create all required proxies here */
323         _gproxy_connman = _proxy_get_connman(service);
324         meshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
325                                 MESHD_ERROR_IO_ERROR);
326         g_dbus_proxy_set_default_timeout(
327                         G_DBUS_PROXY(_gproxy_connman), MESH_DBUS_PROXY_TIMEOUT);
328
329         _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
330         meshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
331                                 MESHD_ERROR_IO_ERROR);
332         g_dbus_proxy_set_default_timeout(
333                         G_DBUS_PROXY(_gproxy_connman_mesh), MESH_DBUS_PROXY_TIMEOUT);
334
335         _gproxy_connman_technology = _proxy_get_connman_technology(service);
336         meshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
337                                 MESHD_ERROR_IO_ERROR);
338         g_dbus_proxy_set_default_timeout(
339                         G_DBUS_PROXY(_gproxy_connman_technology), MESH_DBUS_PROXY_TIMEOUT);
340
341         /* Subscribe events */
342         _meshd_subscribe_event(service);
343
344         return MESHD_ERROR_NONE;
345 }
346
347 int meshd_dbus_stop(mesh_service *service)
348 {
349         int rv;
350
351         if (NULL == service)
352                 return MESHD_ERROR_INVALID_PARAMETER;
353
354         /* Unsubscribe events */
355         _meshd_unsubscribe_event(service);
356
357         /* Unref all proxies here */
358         if (_gproxy_connman) {
359                 g_object_unref(_gproxy_connman);
360                 _gproxy_connman = NULL;
361         }
362         if (_gproxy_connman_mesh) {
363                 g_object_unref(_gproxy_connman_mesh);
364                 _gproxy_connman_mesh = NULL;
365         }
366         if (_gproxy_connman_technology) {
367                 g_object_unref(_gproxy_connman_technology);
368                 _gproxy_connman_technology = NULL;
369         }
370
371         g_cancellable_cancel(service->ca);
372         g_object_unref(service->ca);
373         service->ca = NULL;
374
375         rv = _meshd_close_gdbus_call(service);
376         return rv;
377 }
378
379 int mesh_gdbus_create_mesh_interface(mesh_service *service)
380 {
381         int ret = MESHD_ERROR_NONE;
382         GVariant *variant = NULL;
383         GError *error = NULL;
384         GVariant *var_dict = NULL;
385         GVariantDict dict;
386         mesh_interface_s *info = NULL;
387
388         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
389         meshd_check_null_ret_error("connection", service->connection,
390                         MESHD_ERROR_INVALID_PARAMETER);
391         meshd_check_null_ret_error("_gproxy_connman_technology",
392                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
393
394         info = service->interface_info;
395
396         g_variant_dict_init(&dict, NULL);
397         g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
398         g_variant_dict_insert(&dict, "ParentIfname", "s", info->base_interface);
399         g_variant_dict_insert(&dict, "BridgeIfname", "s", info->bridge_interface);
400         var_dict = g_variant_dict_end(&dict);
401
402         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
403                                 g_variant_new("(sv)", "MeshInterfaceAdd", var_dict),
404                                 G_DBUS_CALL_FLAGS_NONE,
405                                 -1, NULL, &error);
406         if (variant) {
407                 MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
408         } else if (error) {
409                 ret = MESHD_ERROR_IO_ERROR;
410                 MESH_LOGE("Failed DBus call [%s]", error->message);
411
412                 /* Interface not exists */
413                 if (g_strrstr(error->message, "No such device"))
414                         ret = MESHD_ERROR_INVALID_PARAMETER;
415                 g_error_free(error);
416         }
417
418         return ret;
419 }
420
421 int mesh_gdbus_remove_mesh_interface(mesh_service *service)
422 {
423         GVariant *variant = NULL;
424         GError *error = NULL;
425         GVariant *var_dict = NULL;
426         GVariantDict dict;
427         mesh_interface_s *info = NULL;
428
429         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
430         meshd_check_null_ret_error("connection", service->connection,
431                         MESHD_ERROR_INVALID_PARAMETER);
432         meshd_check_null_ret_error("_gproxy_connman_technology",
433                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
434
435         info = service->interface_info;
436
437         g_variant_dict_init(&dict, NULL);
438         g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
439         var_dict = g_variant_dict_end(&dict);
440
441         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
442                                 g_variant_new("(sv)", "MeshInterfaceRemove", var_dict),
443                                 G_DBUS_CALL_FLAGS_NONE,
444                                 -1, NULL, &error);
445         if (variant) {
446                 MESH_LOGD("Successfully requested. [MeshInterfaceRemove]");
447         } else if (error) {
448                 MESH_LOGE("Failed DBus call [%s]", error->message);
449                 g_error_free(error);
450                 return MESHD_ERROR_IO_ERROR;
451         }
452
453         return MESHD_ERROR_NONE;
454 }
455
456 int mesh_gdbus_mesh_scan(mesh_service *service)
457 {
458         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
459         meshd_check_null_ret_error("connection", service->connection,
460                         MESHD_ERROR_INVALID_PARAMETER);
461         meshd_check_null_ret_error("_gproxy_connman_technology",
462                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
463
464         g_dbus_proxy_call(_gproxy_connman_technology, "Scan",
465                                 NULL,
466                                 G_DBUS_CALL_FLAGS_NONE,
467                                 -1, NULL, NULL, NULL);
468
469         MESH_LOGD("Successfully requested. [Scan]");
470
471         return MESHD_ERROR_NONE;
472 }
473
474 int mesh_gdbus_mesh_specific_scan(mesh_service *service, gchar *mesh_id,
475         gint channel)
476 {
477         GVariant *variant = NULL;
478         GError *error = NULL;
479         GVariant *var_dict = NULL;
480         GVariantDict dict;
481
482         enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
483         gushort freq = __channel_to_frequency(channel, band);
484
485         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
486         meshd_check_null_ret_error("connection", service->connection,
487                         MESHD_ERROR_INVALID_PARAMETER);
488         meshd_check_null_ret_error("_gproxy_connman_technology",
489                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
490
491         g_variant_dict_init(&dict, NULL);
492         g_variant_dict_insert(&dict, "Name", "s", mesh_id);
493         g_variant_dict_insert(&dict, "Frequency", "q", freq);
494         var_dict = g_variant_dict_end(&dict);
495
496         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
497                                 g_variant_new("(sv)", "MeshSpecificScan", var_dict),
498                                 G_DBUS_CALL_FLAGS_NONE,
499                                 -1, NULL, &error);
500         if (variant) {
501                 MESH_LOGD("Successfully requested. [MeshSpecificScan]");
502         } else if (error) {
503                 MESH_LOGE("Failed DBus call [%s]", error->message);
504                 g_error_free(error);
505                 return MESHD_ERROR_IO_ERROR;
506         }
507
508         return MESHD_ERROR_NONE;
509 }
510
511 int mesh_gdbus_mesh_cancel_scan(mesh_service *service)
512 {
513         GVariant *variant = NULL;
514         GError *error = NULL;
515         GVariant *var_dict = NULL;
516         GVariantDict dict;
517
518         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
519         meshd_check_null_ret_error("connection", service->connection,
520                         MESHD_ERROR_INVALID_PARAMETER);
521         meshd_check_null_ret_error("_gproxy_connman_technology",
522                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
523
524         g_variant_dict_init(&dict, NULL);
525         var_dict = g_variant_dict_end(&dict);
526
527         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
528                                 g_variant_new("(sv)", "AbortScan", var_dict),
529                                 G_DBUS_CALL_FLAGS_NONE,
530                                 -1, NULL, &error);
531         if (variant) {
532                 MESH_LOGD("Successfully requested. [AbortScan]");
533         } else if (error) {
534                 MESH_LOGE("Failed DBus call [%s]", error->message);
535                 g_error_free(error);
536                 return MESHD_ERROR_IO_ERROR;
537         }
538
539         return MESHD_ERROR_NONE;
540 }
541
542 static void _on_scan_result_destroy(gpointer data)
543 {
544         mesh_scan_result_s *scan_item = (mesh_scan_result_s *)data;
545
546         if (scan_item) {
547                 g_free(scan_item->mesh_id);
548                 g_free(scan_item->bssid);
549                 g_free(scan_item->object_path);
550         }
551 }
552
553 static void _on_peer_info_destroy(gpointer data)
554 {
555         mesh_peer_info_s *peer = (mesh_peer_info_s *)data;
556         if (peer)
557                 g_free(peer->address);
558 }
559
560 static void _get_joined_network(mesh_service *service, GVariant *variant)
561 {
562         GVariantIter *peer = NULL;
563         GVariantIter *property = NULL;
564         gchar *key = NULL;
565         GVariant *val = NULL;
566         gsize len = 0;
567         GVariant *child;
568         const gchar* obj_path = NULL;
569         const gchar* buf = NULL;
570
571         g_variant_get(variant, "(a(oa{sv}))", &peer);
572         while ((child = g_variant_iter_next_value(peer))) {
573                 mesh_network_info_s *joined_info = NULL;
574                 gboolean valid_state = TRUE;
575
576                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
577                 MESH_LOGD("  Object: [%s]", obj_path);
578                 if (NULL == obj_path) {
579                         MESH_LOGE("Null object");
580                         continue;
581                 }
582
583                 /* Create an information structure for joined network */
584                 joined_info = g_try_new0(mesh_network_info_s, 1);
585                 if (NULL == joined_info) {
586                         MESH_LOGE("Failed to allocate !");
587                         return;
588                 }
589
590                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
591                         if (strcasecmp(key, "Name") == 0)  {
592                                 buf = g_variant_get_string(val, &len);
593                                 joined_info->mesh_id = g_strdup(buf);
594                         }
595                         else if (strcasecmp(key, "BSSID") == 0)  {
596                                 buf = g_variant_get_string(val, &len);
597                                 joined_info->bssid = g_strdup(buf);
598                         }
599                         else if (strcasecmp(key, "State") == 0)  {
600                                 buf = g_variant_get_string(val, &len);
601                                 MESH_LOGD("    State : %s", buf);
602
603                                 /* Skip ignorable state */
604                                 if (g_strcmp0(buf, "idle") == 0
605                                         || g_strcmp0(buf, "disconnect") == 0
606                                         || g_strcmp0(buf, "failure") == 0) {
607                                         valid_state = FALSE;
608                                         break;
609                                 } else if (g_strcmp0(buf, "association") == 0) {
610                                         joined_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
611                                 } else if (g_strcmp0(buf, "configuration") == 0) {
612                                         joined_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
613                                 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
614                                         joined_info->state = MESHD_CONNECTION_STATE_CONNECTED;
615                                 }
616                         }
617                         else if (strcasecmp(key, "Security") == 0)  {
618                                 buf = g_variant_get_string(val, &len);
619                                 if (g_strcmp0("sae", buf) == 0)
620                                         joined_info->security = MESHD_SECURITY_SAE;
621                                 else
622                                         joined_info->security = MESHD_SECURITY_NONE;
623                         }
624                         else if (strcasecmp(key, "Frequency") == 0)  {
625                                 joined_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
626                         }
627                 }
628
629                 /* Skip ignorable state */
630                 if (FALSE == valid_state) {
631                         g_free(joined_info->mesh_id);
632                         g_free(joined_info->bssid);
633                         continue;
634                 }
635
636                 MESH_LOGD("    Mesh ID  : %s", joined_info->mesh_id);
637                 MESH_LOGD("    BSSID    : %s", joined_info->bssid);
638                 MESH_LOGD("    Channel  : %d", joined_info->channel);
639                 MESH_LOGD("    Security : %s",
640                         (MESHD_SECURITY_SAE == joined_info->security) ? "SAE" : "NONE");
641                 service->joined_network = joined_info;
642
643                 g_variant_iter_free(property);
644
645                 /* If found, stop loop iteration */
646                 break;
647         }
648         g_variant_iter_free(peer);
649 }
650
651 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
652 {
653         GVariantIter *peer = NULL;
654         GVariantIter *property = NULL;
655         gchar *key = NULL;
656         GVariant *val = NULL;
657         gsize len = 0;
658         GVariant *child;
659         const gchar* obj_path = NULL;
660
661         g_variant_get(variant, "(a(oa{sv}))", &peer);
662         while ((child = g_variant_iter_next_value(peer))) {
663                 mesh_scan_result_s *scan_info = NULL;
664
665                 scan_info = g_try_new0(mesh_scan_result_s, 1);
666                 if (NULL == scan_info) {
667                         MESH_LOGE("Failed to allocate !");
668                         return;
669                 }
670
671                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
672                 if (NULL == obj_path) {
673                         MESH_LOGE("Null object");
674                         g_free(scan_info);
675                         continue;
676                 }
677                 MESH_LOGD("    Obj path : [%s]", obj_path);
678                 scan_info->object_path = g_strdup(obj_path);
679
680                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
681                         if (strcasecmp(key, "Name") == 0)  {
682                                 const char *buf = g_variant_get_string(val, &len);
683                                 scan_info->mesh_id = g_strdup(buf);
684                                 MESH_LOGD("    Mesh ID : %s", scan_info->mesh_id);
685                         }
686                         else if (strcasecmp(key, "BSSID") == 0)  {
687                                 const char *buf = g_variant_get_string(val, &len);
688                                 scan_info->bssid = g_strdup(buf);
689                                 MESH_LOGD("    BSSID : %s", scan_info->bssid);
690                         }
691                         else if (strcasecmp(key, "State") == 0)  {
692                                 const char *buf = g_variant_get_string(val, &len);
693                                 MESH_LOGD("    State : %s", buf);
694
695                                 if (g_strcmp0(buf, "idle") == 0
696                                         || g_strcmp0(buf, "disconnect") == 0
697                                         || g_strcmp0(buf, "failure") == 0) {
698                                         scan_info->state = MESHD_CONNECTION_STATE_DISCONNECTED;
699                                 } else if (g_strcmp0(buf, "association") == 0) {
700                                         scan_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
701                                 } else if (g_strcmp0(buf, "configuration") == 0) {
702                                         scan_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
703                                 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
704                                         scan_info->state = MESHD_CONNECTION_STATE_CONNECTED;
705                                 }
706                         }
707                         else if (strcasecmp(key, "Security") == 0)  {
708                                 const char *buf = g_variant_get_string(val, &len);
709                                 MESH_LOGD("    Security : %s", buf);
710                                 if (g_strcmp0("sae", buf) == 0)
711                                         scan_info->security = MESHD_SECURITY_SAE;
712                                 else
713                                         scan_info->security = MESHD_SECURITY_NONE;
714                         }
715                         else if (strcasecmp(key, "Frequency") == 0)  {
716                                 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
717                                 MESH_LOGD("    Channel : %d", scan_info->channel);
718                         }
719                         else if (strcasecmp(key, "Favorite") == 0)  {
720                                 const char *buf = g_variant_get_string(val, &len);
721                                 MESH_LOGD("    Favorite : %s", buf);
722                         }
723                         else if (strcasecmp(key, "Strength") == 0)  {
724                                 scan_info->rssi = (gint)g_variant_get_byte(val);
725                                 MESH_LOGD("    RSSI : %d", scan_info->rssi);
726                         }
727                 }
728                 /* Last element */
729                 service->scanned_mesh_network =
730                         g_list_prepend(service->scanned_mesh_network, scan_info);
731
732                 g_variant_iter_free(property);
733         }
734         g_variant_iter_free(peer);
735 }
736
737 static void _get_connected_mesh_peers(mesh_service *service, GVariant *variant)
738 {
739         GVariantIter *peer = NULL;
740         GVariantIter *property = NULL;
741         gchar *key = NULL;
742         GVariant *val = NULL;
743         gsize len = 0;
744         GVariant *child;
745
746         g_variant_get(variant, "(a(a{sv}))", &peer);
747         while ((child = g_variant_iter_next_value(peer))) {
748                 mesh_peer_info_s *peer_info = NULL;
749
750                 peer_info = g_try_new0(mesh_peer_info_s, 1);
751                 if (NULL == peer_info) {
752                         MESH_LOGE("Failed to allocate !");
753                         return;
754                 }
755
756                 g_variant_get(child, "(a{sv})", &property);
757                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
758                         if (strcasecmp(key, "PeerAddress") == 0)  {
759                                 const char *buf = g_variant_get_string(val, &len);
760                                 peer_info->address = g_strdup(buf);
761                                 MESH_LOGD("    Address : %s", peer_info->address);
762                         }
763                 }
764                 /* Last element */
765                 service->connected_mesh_peers =
766                         g_list_prepend(service->connected_mesh_peers, peer_info);
767
768                 g_variant_iter_free(property);
769         }
770         g_variant_iter_free(peer);
771 }
772
773 int mesh_gdbus_get_mesh_networks(mesh_service *service)
774 {
775         GVariant *variant = NULL;
776         GError *error = NULL;
777
778         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
779         meshd_check_null_ret_error("connection", service->connection,
780                         MESHD_ERROR_INVALID_PARAMETER);
781         meshd_check_null_ret_error("_gproxy_connman",
782                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
783
784         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
785                                 NULL,
786                                 G_DBUS_CALL_FLAGS_NONE,
787                                 -1, NULL, &error);
788         if (variant) {
789                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
790
791                 if (service->scanned_mesh_network) {
792                         g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
793                         service->scanned_mesh_network = NULL;
794                 }
795
796                 _get_mesh_peers(service, variant);
797
798                 /* List item is saved with reversed order for efficiency. */
799                 service->scanned_mesh_network =
800                                 g_list_reverse(service->scanned_mesh_network);
801         } else if (error) {
802                 MESH_LOGE("Failed DBus call [%s]", error->message);
803                 g_error_free(error);
804                 return MESHD_ERROR_IO_ERROR;
805         }
806
807         return MESHD_ERROR_NONE;
808 }
809
810 int mesh_gdbus_get_joined_mesh_network(mesh_service *service)
811 {
812         GVariant *variant = NULL;
813         GError *error = NULL;
814
815         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
816         meshd_check_null_ret_error("connection", service->connection,
817                         MESHD_ERROR_INVALID_PARAMETER);
818         meshd_check_null_ret_error("_gproxy_connman",
819                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
820
821         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
822                                 NULL,
823                                 G_DBUS_CALL_FLAGS_NONE,
824                                 -1, NULL, &error);
825         if (variant) {
826                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
827
828                 if (service->joined_network) {
829                         g_free(service->joined_network->mesh_id);
830                         g_free(service->joined_network->bssid);
831                         g_free(service->joined_network);
832                         service->joined_network = NULL;
833                 }
834
835                 _get_joined_network(service, variant);
836         } else if (error) {
837                 MESH_LOGE("Failed DBus call [%s]", error->message);
838                 g_error_free(error);
839                 return MESHD_ERROR_IO_ERROR;
840         }
841
842         return MESHD_ERROR_NONE;
843 }
844
845 int mesh_gdbus_get_connected_peers(mesh_service *service)
846 {
847         GVariant *variant = NULL;
848         GError *error = NULL;
849
850         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
851         meshd_check_null_ret_error("connection", service->connection,
852                         MESHD_ERROR_INVALID_PARAMETER);
853         meshd_check_null_ret_error("_gproxy_connman",
854                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
855
856         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetConnectedMeshPeers",
857                                 NULL,
858                                 G_DBUS_CALL_FLAGS_NONE,
859                                 -1, NULL, &error);
860         if (variant) {
861                 MESH_LOGD("Successfully requested. [GetConnectedMeshPeers]");
862
863                 if (service->connected_mesh_peers) {
864                         g_list_free_full(service->connected_mesh_peers, _on_peer_info_destroy);
865                         service->connected_mesh_peers = NULL;
866                 }
867
868                 _get_connected_mesh_peers(service, variant);
869
870                 /* List item is saved with reversed order for efficiency. */
871                 service->connected_mesh_peers =
872                                 g_list_reverse(service->connected_mesh_peers);
873         } else if (error) {
874                 MESH_LOGE("Failed DBus call [%s]", error->message);
875                 g_error_free(error);
876                 return MESHD_ERROR_IO_ERROR;
877         }
878
879         return MESHD_ERROR_NONE;
880 }
881
882 static void _get_mesh_property(GVariant *variant, mesh_network_info_s *result)
883 {
884         GVariantIter *property = NULL;
885         gchar *key = NULL;
886         GVariant *val = NULL;
887         gsize len = 0;
888
889         MESH_LOGD("Type [%s]", g_variant_get_type_string(variant));
890
891         g_variant_get(variant, "(a{sv})", &property);
892
893         while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
894                 if (strcasecmp(key, "Name") == 0)  {
895                         const char *buf = g_variant_get_string(val, &len);
896                         result->mesh_id = g_strdup(buf);
897                         MESH_LOGD("    Mesh ID : %s", result->mesh_id);
898                 }
899                 else if (strcasecmp(key, "BSSID") == 0)  {
900                         const char *buf = g_variant_get_string(val, &len);
901                         result->bssid = g_strdup(buf);
902                         MESH_LOGD("    BSSID : %s", result->bssid);
903                 }
904                 else if (strcasecmp(key, "State") == 0)  {
905                         const char *buf = g_variant_get_string(val, &len);
906                         MESH_LOGD("    State : %s", buf);
907
908                         if (g_strcmp0(buf, "idle") == 0
909                                 || g_strcmp0(buf, "disconnect") == 0
910                                 || g_strcmp0(buf, "failure") == 0) {
911                                 result->state = MESHD_CONNECTION_STATE_DISCONNECTED;
912                         } else if (g_strcmp0(buf, "association") == 0) {
913                                 result->state = MESHD_CONNECTION_STATE_ASSOCIATION;
914                         } else if (g_strcmp0(buf, "configuration") == 0) {
915                                 result->state = MESHD_CONNECTION_STATE_CONFIGURATION;
916                         } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
917                                 result->state = MESHD_CONNECTION_STATE_CONNECTED;
918                         }
919                 }
920                 else if (strcasecmp(key, "Security") == 0)  {
921                         const char *buf = g_variant_get_string(val, &len);
922                         MESH_LOGD("    Security : %s", buf);
923                         if (g_strcmp0("sae", buf) == 0)
924                                 result->security = MESHD_SECURITY_SAE;
925                         else
926                                 result->security = MESHD_SECURITY_NONE;
927                 }
928                 else if (strcasecmp(key, "Frequency") == 0)  {
929                         result->channel = __frequency_to_channel(g_variant_get_uint16(val));
930                         MESH_LOGD("    Channel : %d", result->channel);
931                 }
932                 else if (strcasecmp(key, "Favorite") == 0)  {
933                         const char *buf = g_variant_get_string(val, &len);
934                         MESH_LOGD("    Favorite : %s", buf);
935                 }
936                 else if (strcasecmp(key, "Strength") == 0)  {
937                         gint rssi = (gint)g_variant_get_byte(val);
938                         MESH_LOGD("    RSSI : %d", rssi);
939                 }
940         }
941         g_variant_iter_free(property);
942 }
943
944 static int _mesh_gdbus_get_mesh_network_property(mesh_service *service,
945         const gchar* object_path, mesh_network_info_s *result)
946 {
947         GVariant *variant = NULL;
948         GError *error = NULL;
949
950         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
951         meshd_check_null_ret_error("connection", service->connection,
952                         MESHD_ERROR_INVALID_PARAMETER);
953         meshd_check_null_ret_error("result", result, MESHD_ERROR_INVALID_PARAMETER);
954
955         variant = g_dbus_connection_call_sync(service->connection,
956                         CONNMAN_SERVER_NAME,
957                         object_path,
958                         CONNMAN_INTERFACE_MESH,
959                         "GetProperties",
960                         NULL, NULL,
961                         G_DBUS_CALL_FLAGS_NONE,
962                         -1, NULL, &error);
963         if (variant) {
964                 MESH_LOGD("Successfully requested. [GetProperties]");
965
966                 /* Get properties */
967                 _get_mesh_property(variant, result);
968         } else if (error) {
969                 LOGE("Failed DBus call [%s]", error->message);
970                 g_error_free(error);
971                 return MESHD_ERROR_IO_ERROR;
972         }
973
974         return MESHD_ERROR_NONE;
975 }
976
977 int mesh_gdbus_create_network(mesh_service *service, gchar *mesh_id,
978                 gint channel, meshd_security_type_e sec)
979 {
980         GVariant *variant = NULL;
981         GError *error = NULL;
982         GVariant *var_dict = NULL;
983         GVariantBuilder builder;
984         const gchar* security = (MESHD_SECURITY_SAE == sec) ? "sae" : "none";
985
986         enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
987         gushort freq = __channel_to_frequency(channel, band);
988
989         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
990         meshd_check_null_ret_error("connection", service->connection,
991                         MESHD_ERROR_INVALID_PARAMETER);
992         meshd_check_null_ret_error("_gproxy_connman_technology",
993                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
994
995         g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
996         g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
997
998         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
999         g_variant_builder_add(&builder, "s", "Name");
1000         g_variant_builder_add(&builder, "v", g_variant_new_string(mesh_id));
1001         g_variant_builder_close(&builder); /* {sv} */
1002
1003         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1004         g_variant_builder_add(&builder, "s", "Frequency");
1005         g_variant_builder_add(&builder, "v", g_variant_new_uint16(freq));
1006         g_variant_builder_close(&builder); /* {sv} */
1007
1008         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1009         g_variant_builder_add(&builder, "s", "Security");
1010         g_variant_builder_add(&builder, "v", g_variant_new_string(security));
1011         g_variant_builder_close(&builder); /* {sv} */
1012
1013         g_variant_builder_close(&builder); /* a{sv} */
1014
1015         var_dict = g_variant_builder_end(&builder);
1016
1017         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
1018                                 g_variant_new("(sv)", "MeshCreateNetwork", var_dict),
1019                                 G_DBUS_CALL_FLAGS_NONE,
1020                                 -1, NULL, &error);
1021         if (variant) {
1022                 MESH_LOGD("Successfully requested. [MeshCreateNetwork]");
1023         } else if (error) {
1024                 MESH_LOGE("Failed DBus call [%s]", error->message);
1025                 g_error_free(error);
1026                 return MESHD_ERROR_IO_ERROR;
1027         }
1028
1029         return MESHD_ERROR_NONE;
1030 }
1031
1032 int mesh_gdbus_set_passphrase(mesh_service *service, mesh_scan_result_s *info,
1033         gchar *passphrase)
1034 {
1035         GVariant *variant = NULL;
1036         GError *error = NULL;
1037
1038         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1039         meshd_check_null_ret_error("passphrase", passphrase, MESHD_ERROR_INVALID_PARAMETER);
1040
1041         variant = g_dbus_connection_call_sync(service->connection,
1042                         CONNMAN_SERVER_NAME,
1043                         info->object_path,
1044                         CONNMAN_INTERFACE_MESH,
1045                         "SetProperty",
1046                         g_variant_new("(sv)", "Passphrase", g_variant_new_string(passphrase)),
1047                         NULL,
1048                         G_DBUS_CALL_FLAGS_NONE,
1049                         -1, NULL, &error);
1050         if (variant) {
1051                 MESH_LOGD("Successfully requested. [SetProperty]");
1052         } else if (error) {
1053                 LOGE("Failed DBus call [%s]", error->message);
1054                 g_error_free(error);
1055                 return MESHD_ERROR_IO_ERROR;
1056         }
1057
1058         return MESHD_ERROR_NONE;
1059 }
1060
1061 #if 0
1062 static void on_response_connect_network(GObject *source_object,
1063         GAsyncResult *res, gpointer user_data)
1064 {
1065         int ret = MESHD_ERROR_NONE;
1066         GError *error = NULL;
1067         GVariant *variant = NULL;
1068
1069         NOTUSED(user_data);
1070
1071         variant = g_dbus_connection_call_finish(
1072                         G_DBUS_CONNECTION(source_object), res, &error);
1073         if (variant) {
1074                 MESH_LOGD("Successfully requested. [Connect]");
1075
1076                 /* TODO: Unregister property change event */
1077         } else if (error) {
1078                 ret = MESHD_ERROR_IO_ERROR;
1079                 LOGE("Failed DBus call [%s]", error->message);
1080
1081                 if (g_strrstr(error->message, "Already exists"))
1082                         ret = MESHD_ERROR_ALREADY_REGISTERED;
1083                 else if (g_strrstr(error->message, "In progress"))
1084                         ret = MESHD_ERROR_IN_PROGRESS;
1085                 else
1086                         ret = MESHD_ERROR_IO_ERROR;
1087
1088                 g_error_free(error);
1089         }
1090 }
1091 #endif
1092
1093 int mesh_gdbus_connect_network(mesh_service *service, mesh_scan_result_s *info)
1094 {
1095         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1096         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1097
1098         g_dbus_connection_call(service->connection,
1099                         CONNMAN_SERVER_NAME,
1100                         info->object_path,
1101                         CONNMAN_INTERFACE_MESH,
1102                         "Connect",
1103                         NULL, NULL,
1104                         G_DBUS_CALL_FLAGS_NONE,
1105                         -1,
1106                         NULL, /* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED */
1107                         NULL, NULL);
1108         MESH_LOGD("Successfully requested. [Connect]");
1109
1110         return MESHD_ERROR_NONE;
1111 }
1112
1113 int mesh_gdbus_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
1114 {
1115         GVariant *variant = NULL;
1116         GError *error = NULL;
1117
1118         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1119         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1120
1121         variant = g_dbus_connection_call_sync(service->connection,
1122                         CONNMAN_SERVER_NAME,
1123                         info->object_path,
1124                         CONNMAN_INTERFACE_MESH,
1125                         "Disconnect",
1126                         NULL, NULL,
1127                         G_DBUS_CALL_FLAGS_NONE,
1128                         -1, NULL, &error);
1129         if (variant) {
1130                 MESH_LOGD("Successfully requested. [Disconnect]");
1131         } else if (error) {
1132                 LOGE("Failed DBus call [%s]", error->message);
1133                 g_error_free(error);
1134                 return MESHD_ERROR_IO_ERROR;
1135         }
1136
1137         return MESHD_ERROR_NONE;
1138 }
1139
1140 int mesh_gdbus_remove_network(mesh_service *service, mesh_scan_result_s *info)
1141 {
1142         GVariant *variant = NULL;
1143         GError *error = NULL;
1144
1145         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1146         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1147
1148         variant = g_dbus_connection_call_sync(service->connection,
1149                         CONNMAN_SERVER_NAME,
1150                         info->object_path,
1151                         CONNMAN_INTERFACE_MESH,
1152                         "Remove",
1153                         NULL, NULL,
1154                         G_DBUS_CALL_FLAGS_NONE,
1155                         -1, NULL, &error);
1156         if (variant) {
1157                 MESH_LOGD("Successfully requested. [Remove]");
1158         } else if (error) {
1159                 LOGE("Failed DBus call [%s]", error->message);
1160                 g_error_free(error);
1161                 return MESHD_ERROR_IO_ERROR;
1162         }
1163
1164         return MESHD_ERROR_NONE;
1165 }