Fix for svace issues
[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         g_free(scan_item);
552 }
553
554 static void _on_peer_info_destroy(gpointer data)
555 {
556         mesh_peer_info_s *peer = (mesh_peer_info_s *)data;
557
558         if (peer)
559                 g_free(peer->address);
560         g_free(peer);
561 }
562
563 static void _get_joined_network(mesh_service *service, GVariant *variant)
564 {
565         GVariantIter *peer = NULL;
566         GVariantIter *property = NULL;
567         gchar *key = NULL;
568         GVariant *val = NULL;
569         gsize len = 0;
570         GVariant *child;
571         const gchar* obj_path = NULL;
572         const gchar* buf = NULL;
573
574         g_variant_get(variant, "(a(oa{sv}))", &peer);
575         while ((child = g_variant_iter_next_value(peer))) {
576                 mesh_network_info_s *joined_info = NULL;
577                 gboolean valid_state = TRUE;
578
579                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
580                 MESH_LOGD("  Object: [%s]", obj_path);
581                 if (NULL == obj_path) {
582                         MESH_LOGE("Null object");
583                         continue;
584                 }
585
586                 /* Create an information structure for joined network */
587                 joined_info = g_try_new0(mesh_network_info_s, 1);
588                 if (NULL == joined_info) {
589                         MESH_LOGE("Failed to allocate !");
590                         return;
591                 }
592
593                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
594                         if (strcasecmp(key, "Name") == 0)  {
595                                 buf = g_variant_get_string(val, &len);
596                                 joined_info->mesh_id = g_strdup(buf);
597                         }
598                         else if (strcasecmp(key, "BSSID") == 0)  {
599                                 buf = g_variant_get_string(val, &len);
600                                 joined_info->bssid = g_strdup(buf);
601                         }
602                         else if (strcasecmp(key, "State") == 0)  {
603                                 buf = g_variant_get_string(val, &len);
604                                 MESH_LOGD("    State : %s", buf);
605
606                                 /* Skip ignorable state */
607                                 if (g_strcmp0(buf, "idle") == 0
608                                         || g_strcmp0(buf, "disconnect") == 0
609                                         || g_strcmp0(buf, "failure") == 0) {
610                                         valid_state = FALSE;
611                                         break;
612                                 } else if (g_strcmp0(buf, "association") == 0) {
613                                         joined_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
614                                 } else if (g_strcmp0(buf, "configuration") == 0) {
615                                         joined_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
616                                 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
617                                         joined_info->state = MESHD_CONNECTION_STATE_CONNECTED;
618                                 }
619                         }
620                         else if (strcasecmp(key, "Security") == 0)  {
621                                 buf = g_variant_get_string(val, &len);
622                                 if (g_strcmp0("sae", buf) == 0)
623                                         joined_info->security = MESHD_SECURITY_SAE;
624                                 else
625                                         joined_info->security = MESHD_SECURITY_NONE;
626                         }
627                         else if (strcasecmp(key, "Frequency") == 0)  {
628                                 joined_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
629                         }
630                 }
631
632                 /* Skip ignorable state */
633                 if (FALSE == valid_state) {
634                         g_free(joined_info->mesh_id);
635                         g_free(joined_info->bssid);
636                         continue;
637                 }
638
639                 MESH_LOGD("    Mesh ID  : %s", joined_info->mesh_id);
640                 MESH_LOGD("    BSSID    : %s", joined_info->bssid);
641                 MESH_LOGD("    Channel  : %d", joined_info->channel);
642                 MESH_LOGD("    Security : %s",
643                         (MESHD_SECURITY_SAE == joined_info->security) ? "SAE" : "NONE");
644                 service->joined_network = joined_info;
645
646                 g_variant_iter_free(property);
647
648                 /* If found, stop loop iteration */
649                 break;
650         }
651         g_variant_iter_free(peer);
652 }
653
654 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
655 {
656         GVariantIter *peer = NULL;
657         GVariantIter *property = NULL;
658         gchar *key = NULL;
659         GVariant *val = NULL;
660         gsize len = 0;
661         GVariant *child;
662         const gchar* obj_path = NULL;
663
664         g_variant_get(variant, "(a(oa{sv}))", &peer);
665         while ((child = g_variant_iter_next_value(peer))) {
666                 mesh_scan_result_s *scan_info = NULL;
667
668                 scan_info = g_try_new0(mesh_scan_result_s, 1);
669                 if (NULL == scan_info) {
670                         MESH_LOGE("Failed to allocate !");
671                         return;
672                 }
673
674                 g_variant_get(child, "(oa{sv})", &obj_path, &property);
675                 if (NULL == obj_path) {
676                         MESH_LOGE("Null object");
677                         g_free(scan_info);
678                         continue;
679                 }
680                 MESH_LOGD("    Obj path : [%s]", obj_path);
681                 scan_info->object_path = g_strdup(obj_path);
682
683                 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
684                         if (strcasecmp(key, "Name") == 0)  {
685                                 const char *buf = g_variant_get_string(val, &len);
686                                 scan_info->mesh_id = g_strdup(buf);
687                                 MESH_LOGD("    Mesh ID : %s", scan_info->mesh_id);
688                         }
689                         else if (strcasecmp(key, "BSSID") == 0)  {
690                                 const char *buf = g_variant_get_string(val, &len);
691                                 scan_info->bssid = g_strdup(buf);
692                                 MESH_LOGD("    BSSID : %s", scan_info->bssid);
693                         }
694                         else if (strcasecmp(key, "State") == 0)  {
695                                 const char *buf = g_variant_get_string(val, &len);
696                                 MESH_LOGD("    State : %s", buf);
697
698                                 if (g_strcmp0(buf, "idle") == 0
699                                         || g_strcmp0(buf, "disconnect") == 0
700                                         || g_strcmp0(buf, "failure") == 0) {
701                                         scan_info->state = MESHD_CONNECTION_STATE_DISCONNECTED;
702                                 } else if (g_strcmp0(buf, "association") == 0) {
703                                         scan_info->state = MESHD_CONNECTION_STATE_ASSOCIATION;
704                                 } else if (g_strcmp0(buf, "configuration") == 0) {
705                                         scan_info->state = MESHD_CONNECTION_STATE_CONFIGURATION;
706                                 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
707                                         scan_info->state = MESHD_CONNECTION_STATE_CONNECTED;
708                                 }
709                         }
710                         else if (strcasecmp(key, "Security") == 0)  {
711                                 const char *buf = g_variant_get_string(val, &len);
712                                 MESH_LOGD("    Security : %s", buf);
713                                 if (g_strcmp0("sae", buf) == 0)
714                                         scan_info->security = MESHD_SECURITY_SAE;
715                                 else
716                                         scan_info->security = MESHD_SECURITY_NONE;
717                         }
718                         else if (strcasecmp(key, "Frequency") == 0)  {
719                                 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
720                                 MESH_LOGD("    Channel : %d", scan_info->channel);
721                         }
722                         else if (strcasecmp(key, "Favorite") == 0)  {
723                                 const char *buf = g_variant_get_string(val, &len);
724                                 MESH_LOGD("    Favorite : %s", buf);
725                         }
726                         else if (strcasecmp(key, "Strength") == 0)  {
727                                 scan_info->rssi = (gint)g_variant_get_byte(val);
728                                 MESH_LOGD("    RSSI : %d", scan_info->rssi);
729                         }
730                 }
731                 /* Last element */
732                 service->scanned_mesh_network =
733                         g_list_prepend(service->scanned_mesh_network, scan_info);
734
735                 g_variant_iter_free(property);
736         }
737         g_variant_iter_free(peer);
738 }
739
740 static void _get_connected_mesh_peers(mesh_service *service, GVariant *variant)
741 {
742         GVariantIter *peer = NULL;
743         GVariant *val = NULL;
744         gsize len = 0;
745         GVariant *child;
746         GVariant *dict = NULL;
747
748         g_variant_get(variant, "(a(a{sv}))", &peer);
749         while ((child = g_variant_iter_next_value(peer))) {
750                 mesh_peer_info_s *peer_info = NULL;
751
752                 peer_info = g_try_new0(mesh_peer_info_s, 1);
753                 if (NULL == peer_info) {
754                         MESH_LOGE("Failed to allocate !");
755                         return;
756                 }
757
758                 /* a{sv} <- (a{sv}) */
759                 dict = g_variant_get_child_value(child, 0);
760                 val = g_variant_lookup_value(dict, "PeerAddress", NULL);
761                 if (NULL != val) {
762                         const char *buf = g_variant_get_string(val, &len);
763                         peer_info->address = g_strdup(buf);
764                         MESH_LOGD("    Address : %s", peer_info->address);
765                         g_variant_unref(val);
766                 } else {
767                         MESH_LOGE("Unable to get address !");
768                         g_free(peer_info);
769                         continue;
770                 }
771
772                 service->connected_mesh_peers =
773                         g_list_prepend(service->connected_mesh_peers, peer_info);
774         }
775         g_variant_iter_free(peer);
776 }
777
778 int mesh_gdbus_get_mesh_networks(mesh_service *service)
779 {
780         GVariant *variant = NULL;
781         GError *error = NULL;
782
783         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
784         meshd_check_null_ret_error("connection", service->connection,
785                         MESHD_ERROR_INVALID_PARAMETER);
786         meshd_check_null_ret_error("_gproxy_connman",
787                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
788
789         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
790                                 NULL,
791                                 G_DBUS_CALL_FLAGS_NONE,
792                                 -1, NULL, &error);
793         if (variant) {
794                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
795
796                 if (service->scanned_mesh_network) {
797                         g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
798                         service->scanned_mesh_network = NULL;
799                 }
800
801                 _get_mesh_peers(service, variant);
802
803                 /* List item is saved with reversed order for efficiency. */
804                 service->scanned_mesh_network =
805                                 g_list_reverse(service->scanned_mesh_network);
806         } else if (error) {
807                 MESH_LOGE("Failed DBus call [%s]", error->message);
808                 g_error_free(error);
809                 return MESHD_ERROR_IO_ERROR;
810         }
811
812         return MESHD_ERROR_NONE;
813 }
814
815 int mesh_gdbus_get_joined_mesh_network(mesh_service *service)
816 {
817         GVariant *variant = NULL;
818         GError *error = NULL;
819
820         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
821         meshd_check_null_ret_error("connection", service->connection,
822                         MESHD_ERROR_INVALID_PARAMETER);
823         meshd_check_null_ret_error("_gproxy_connman",
824                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
825
826         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
827                                 NULL,
828                                 G_DBUS_CALL_FLAGS_NONE,
829                                 -1, NULL, &error);
830         if (variant) {
831                 MESH_LOGD("Successfully requested. [GetMeshPeers]");
832
833                 if (service->joined_network) {
834                         g_free(service->joined_network->mesh_id);
835                         g_free(service->joined_network->bssid);
836                         g_free(service->joined_network);
837                         service->joined_network = NULL;
838                 }
839
840                 _get_joined_network(service, variant);
841         } else if (error) {
842                 MESH_LOGE("Failed DBus call [%s]", error->message);
843                 g_error_free(error);
844                 return MESHD_ERROR_IO_ERROR;
845         }
846
847         return MESHD_ERROR_NONE;
848 }
849
850 int mesh_gdbus_get_connected_peers(mesh_service *service)
851 {
852         GVariant *variant = NULL;
853         GError *error = NULL;
854
855         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
856         meshd_check_null_ret_error("connection", service->connection,
857                         MESHD_ERROR_INVALID_PARAMETER);
858         meshd_check_null_ret_error("_gproxy_connman",
859                         _gproxy_connman, MESHD_ERROR_IO_ERROR);
860
861         variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetConnectedMeshPeers",
862                                 NULL,
863                                 G_DBUS_CALL_FLAGS_NONE,
864                                 -1, NULL, &error);
865         if (variant) {
866                 MESH_LOGD("Successfully requested. [GetConnectedMeshPeers]");
867
868                 if (service->connected_mesh_peers) {
869                         g_list_free_full(service->connected_mesh_peers, _on_peer_info_destroy);
870                         service->connected_mesh_peers = NULL;
871                 }
872
873                 _get_connected_mesh_peers(service, variant);
874
875                 /* List item is saved with reversed order for efficiency. */
876                 service->connected_mesh_peers =
877                                 g_list_reverse(service->connected_mesh_peers);
878         } else if (error) {
879                 MESH_LOGE("Failed DBus call [%s]", error->message);
880                 g_error_free(error);
881                 return MESHD_ERROR_IO_ERROR;
882         }
883
884         return MESHD_ERROR_NONE;
885 }
886
887 static void _get_mesh_property(GVariant *variant, mesh_network_info_s *result)
888 {
889         GVariantIter *property = NULL;
890         gchar *key = NULL;
891         GVariant *val = NULL;
892         gsize len = 0;
893
894         MESH_LOGD("Type [%s]", g_variant_get_type_string(variant));
895
896         g_variant_get(variant, "(a{sv})", &property);
897
898         while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
899                 if (strcasecmp(key, "Name") == 0)  {
900                         const char *buf = g_variant_get_string(val, &len);
901                         result->mesh_id = g_strdup(buf);
902                         MESH_LOGD("    Mesh ID : %s", result->mesh_id);
903                 }
904                 else if (strcasecmp(key, "BSSID") == 0)  {
905                         const char *buf = g_variant_get_string(val, &len);
906                         result->bssid = g_strdup(buf);
907                         MESH_LOGD("    BSSID : %s", result->bssid);
908                 }
909                 else if (strcasecmp(key, "State") == 0)  {
910                         const char *buf = g_variant_get_string(val, &len);
911                         MESH_LOGD("    State : %s", buf);
912
913                         if (g_strcmp0(buf, "idle") == 0
914                                 || g_strcmp0(buf, "disconnect") == 0
915                                 || g_strcmp0(buf, "failure") == 0) {
916                                 result->state = MESHD_CONNECTION_STATE_DISCONNECTED;
917                         } else if (g_strcmp0(buf, "association") == 0) {
918                                 result->state = MESHD_CONNECTION_STATE_ASSOCIATION;
919                         } else if (g_strcmp0(buf, "configuration") == 0) {
920                                 result->state = MESHD_CONNECTION_STATE_CONFIGURATION;
921                         } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
922                                 result->state = MESHD_CONNECTION_STATE_CONNECTED;
923                         }
924                 }
925                 else if (strcasecmp(key, "Security") == 0)  {
926                         const char *buf = g_variant_get_string(val, &len);
927                         MESH_LOGD("    Security : %s", buf);
928                         if (g_strcmp0("sae", buf) == 0)
929                                 result->security = MESHD_SECURITY_SAE;
930                         else
931                                 result->security = MESHD_SECURITY_NONE;
932                 }
933                 else if (strcasecmp(key, "Frequency") == 0)  {
934                         result->channel = __frequency_to_channel(g_variant_get_uint16(val));
935                         MESH_LOGD("    Channel : %d", result->channel);
936                 }
937                 else if (strcasecmp(key, "Favorite") == 0)  {
938                         const char *buf = g_variant_get_string(val, &len);
939                         MESH_LOGD("    Favorite : %s", buf);
940                 }
941                 else if (strcasecmp(key, "Strength") == 0)  {
942                         gint rssi = (gint)g_variant_get_byte(val);
943                         MESH_LOGD("    RSSI : %d", rssi);
944                 }
945         }
946         g_variant_iter_free(property);
947 }
948
949 static int _mesh_gdbus_get_mesh_network_property(mesh_service *service,
950         const gchar* object_path, mesh_network_info_s *result)
951 {
952         GVariant *variant = NULL;
953         GError *error = NULL;
954
955         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
956         meshd_check_null_ret_error("connection", service->connection,
957                         MESHD_ERROR_INVALID_PARAMETER);
958         meshd_check_null_ret_error("result", result, MESHD_ERROR_INVALID_PARAMETER);
959
960         variant = g_dbus_connection_call_sync(service->connection,
961                         CONNMAN_SERVER_NAME,
962                         object_path,
963                         CONNMAN_INTERFACE_MESH,
964                         "GetProperties",
965                         NULL, NULL,
966                         G_DBUS_CALL_FLAGS_NONE,
967                         -1, NULL, &error);
968         if (variant) {
969                 MESH_LOGD("Successfully requested. [GetProperties]");
970
971                 /* Get properties */
972                 _get_mesh_property(variant, result);
973         } else if (error) {
974                 LOGE("Failed DBus call [%s]", error->message);
975                 g_error_free(error);
976                 return MESHD_ERROR_IO_ERROR;
977         }
978
979         return MESHD_ERROR_NONE;
980 }
981
982 int mesh_gdbus_create_network(mesh_service *service, gchar *mesh_id,
983                 gint channel, meshd_security_type_e sec)
984 {
985         GVariant *variant = NULL;
986         GError *error = NULL;
987         GVariant *var_dict = NULL;
988         GVariantBuilder builder;
989         const gchar* security = (MESHD_SECURITY_SAE == sec) ? "sae" : "none";
990
991         enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
992         gushort freq = __channel_to_frequency(channel, band);
993
994         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
995         meshd_check_null_ret_error("connection", service->connection,
996                         MESHD_ERROR_INVALID_PARAMETER);
997         meshd_check_null_ret_error("_gproxy_connman_technology",
998                         _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
999
1000         g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
1001         g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
1002
1003         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1004         g_variant_builder_add(&builder, "s", "Name");
1005         g_variant_builder_add(&builder, "v", g_variant_new_string(mesh_id));
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", "Frequency");
1010         g_variant_builder_add(&builder, "v", g_variant_new_uint16(freq));
1011         g_variant_builder_close(&builder); /* {sv} */
1012
1013         g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1014         g_variant_builder_add(&builder, "s", "Security");
1015         g_variant_builder_add(&builder, "v", g_variant_new_string(security));
1016         g_variant_builder_close(&builder); /* {sv} */
1017
1018         g_variant_builder_close(&builder); /* a{sv} */
1019
1020         var_dict = g_variant_builder_end(&builder);
1021
1022         variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
1023                                 g_variant_new("(sv)", "MeshCreateNetwork", var_dict),
1024                                 G_DBUS_CALL_FLAGS_NONE,
1025                                 -1, NULL, &error);
1026         if (variant) {
1027                 MESH_LOGD("Successfully requested. [MeshCreateNetwork]");
1028         } else if (error) {
1029                 MESH_LOGE("Failed DBus call [%s]", error->message);
1030                 g_error_free(error);
1031                 return MESHD_ERROR_IO_ERROR;
1032         }
1033
1034         return MESHD_ERROR_NONE;
1035 }
1036
1037 int mesh_gdbus_set_passphrase(mesh_service *service, mesh_scan_result_s *info,
1038         gchar *passphrase)
1039 {
1040         GVariant *variant = NULL;
1041         GError *error = NULL;
1042
1043         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1044         meshd_check_null_ret_error("passphrase", passphrase, MESHD_ERROR_INVALID_PARAMETER);
1045
1046         variant = g_dbus_connection_call_sync(service->connection,
1047                         CONNMAN_SERVER_NAME,
1048                         info->object_path,
1049                         CONNMAN_INTERFACE_MESH,
1050                         "SetProperty",
1051                         g_variant_new("(sv)", "Passphrase", g_variant_new_string(passphrase)),
1052                         NULL,
1053                         G_DBUS_CALL_FLAGS_NONE,
1054                         -1, NULL, &error);
1055         if (variant) {
1056                 MESH_LOGD("Successfully requested. [SetProperty]");
1057         } else if (error) {
1058                 LOGE("Failed DBus call [%s]", error->message);
1059                 g_error_free(error);
1060                 return MESHD_ERROR_IO_ERROR;
1061         }
1062
1063         return MESHD_ERROR_NONE;
1064 }
1065
1066 #if 0
1067 static void on_response_connect_network(GObject *source_object,
1068         GAsyncResult *res, gpointer user_data)
1069 {
1070         int ret = MESHD_ERROR_NONE;
1071         GError *error = NULL;
1072         GVariant *variant = NULL;
1073
1074         NOTUSED(user_data);
1075
1076         variant = g_dbus_connection_call_finish(
1077                         G_DBUS_CONNECTION(source_object), res, &error);
1078         if (variant) {
1079                 MESH_LOGD("Successfully requested. [Connect]");
1080
1081                 /* TODO: Unregister property change event */
1082         } else if (error) {
1083                 ret = MESHD_ERROR_IO_ERROR;
1084                 LOGE("Failed DBus call [%s]", error->message);
1085
1086                 if (g_strrstr(error->message, "Already exists"))
1087                         ret = MESHD_ERROR_ALREADY_REGISTERED;
1088                 else if (g_strrstr(error->message, "In progress"))
1089                         ret = MESHD_ERROR_IN_PROGRESS;
1090                 else
1091                         ret = MESHD_ERROR_IO_ERROR;
1092
1093                 g_error_free(error);
1094         }
1095 }
1096 #endif
1097
1098 int mesh_gdbus_connect_network(mesh_service *service, mesh_scan_result_s *info)
1099 {
1100         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1101         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1102
1103         g_dbus_connection_call(service->connection,
1104                         CONNMAN_SERVER_NAME,
1105                         info->object_path,
1106                         CONNMAN_INTERFACE_MESH,
1107                         "Connect",
1108                         NULL, NULL,
1109                         G_DBUS_CALL_FLAGS_NONE,
1110                         -1,
1111                         NULL, /* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED */
1112                         NULL, NULL);
1113         MESH_LOGD("Successfully requested. [Connect]");
1114
1115         return MESHD_ERROR_NONE;
1116 }
1117
1118 int mesh_gdbus_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
1119 {
1120         GVariant *variant = NULL;
1121         GError *error = NULL;
1122
1123         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1124         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1125
1126         variant = g_dbus_connection_call_sync(service->connection,
1127                         CONNMAN_SERVER_NAME,
1128                         info->object_path,
1129                         CONNMAN_INTERFACE_MESH,
1130                         "Disconnect",
1131                         NULL, NULL,
1132                         G_DBUS_CALL_FLAGS_NONE,
1133                         -1, NULL, &error);
1134         if (variant) {
1135                 MESH_LOGD("Successfully requested. [Disconnect]");
1136         } else if (error) {
1137                 LOGE("Failed DBus call [%s]", error->message);
1138                 g_error_free(error);
1139                 return MESHD_ERROR_IO_ERROR;
1140         }
1141
1142         return MESHD_ERROR_NONE;
1143 }
1144
1145 int mesh_gdbus_remove_network(mesh_service *service, mesh_scan_result_s *info)
1146 {
1147         GVariant *variant = NULL;
1148         GError *error = NULL;
1149
1150         meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1151         meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1152
1153         variant = g_dbus_connection_call_sync(service->connection,
1154                         CONNMAN_SERVER_NAME,
1155                         info->object_path,
1156                         CONNMAN_INTERFACE_MESH,
1157                         "Remove",
1158                         NULL, NULL,
1159                         G_DBUS_CALL_FLAGS_NONE,
1160                         -1, NULL, &error);
1161         if (variant) {
1162                 MESH_LOGD("Successfully requested. [Remove]");
1163         } else if (error) {
1164                 LOGE("Failed DBus call [%s]", error->message);
1165                 g_error_free(error);
1166                 return MESHD_ERROR_IO_ERROR;
1167         }
1168
1169         return MESHD_ERROR_NONE;
1170 }