2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "mesh-util.h"
19 #include "mesh-gdbus.h"
20 #include "mesh-request.h"
24 static GDBusProxy *_gproxy_connman = NULL;
25 static GDBusProxy *_gproxy_connman_mesh = NULL;
26 static GDBusProxy *_gproxy_connman_technology = NULL;
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);
32 static int __channel_to_frequency(int channel, enum nl80211_band band)
38 case NL80211_BAND_2GHZ:
41 else if (channel < 14)
42 return 2407 + channel * 5;
44 case NL80211_BAND_5GHZ:
45 if (channel >= 182 && channel <= 196)
46 return 4000 + channel * 5;
48 return 5000 + channel * 5;
58 static int __frequency_to_channel(int freq)
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;
74 static GDBusProxy *_proxy_get_connman(mesh_service *service)
76 GDBusProxy *proxy = NULL;
77 meshd_check_null_ret_error("service", service, NULL);
79 if (NULL == _gproxy_connman) {
80 proxy = g_dbus_proxy_new_sync(service->connection,
81 G_DBUS_PROXY_FLAGS_NONE, NULL,
84 CONNMAN_INTERFACE_MANAGER,
87 proxy = _gproxy_connman;
92 static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
94 GDBusProxy *proxy = NULL;
95 meshd_check_null_ret_error("service", service, NULL);
97 if (NULL == _gproxy_connman_mesh) {
98 proxy = g_dbus_proxy_new_sync(service->connection,
99 G_DBUS_PROXY_FLAGS_NONE, NULL,
101 CONNMAN_OBJECT_PATH_MESH,
102 CONNMAN_INTERFACE_MESH,
105 proxy = _gproxy_connman_mesh;
110 static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
112 GDBusProxy *proxy = NULL;
113 meshd_check_null_ret_error("service", service, NULL);
115 if (NULL == _gproxy_connman_technology) {
116 proxy = g_dbus_proxy_new_sync(service->connection,
117 G_DBUS_PROXY_FLAGS_NONE, NULL,
119 CONNMAN_OBJECT_PATH_TECH_MESH,
120 CONNMAN_INTERFACE_TECH,
123 proxy = _gproxy_connman_technology;
128 static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
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;
137 if (NULL == name_owner) {
138 MESH_LOGE("name_owner is not exists !");
139 _meshd_close_gdbus_call(service);
145 static int _meshd_create_gdbus_call(mesh_service *service)
148 GError *error = NULL;
151 return MESHD_ERROR_INVALID_PARAMETER;
153 if (NULL != service->connection)
154 return MESHD_ERROR_ALREADY_REGISTERED;
156 service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
157 if (service->connection == NULL) {
159 MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
162 return MESHD_ERROR_IO_ERROR;
165 id = g_signal_connect(service->connection, "notify::g-name-owner",
166 G_CALLBACK(_dbus_name_owner_notify), service);
168 MESH_LOGE("g_signal_connect() Fail");
169 g_object_unref(service->connection);
170 service->connection = NULL;
171 return MESHD_ERROR_IO_ERROR;
174 return MESHD_ERROR_NONE;
177 static int _meshd_close_gdbus_call(mesh_service *service)
179 /* CHECK: is connection ref count required? */
180 g_object_unref(service->connection);
181 service->connection = NULL;
183 return MESHD_ERROR_NONE;
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)
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;
194 meshd_check_null_ret("user_data", user_data);
196 NOTUSED(sender_name);
197 NOTUSED(interface_name);
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;
206 GVariant *variant = NULL;
207 meshd_connection_state_e state = MESHD_CONNECTION_STATE_DISCONNECTED;
209 if (NULL == parameters) {
210 MESH_LOGE("Unexpected parameter");
214 g_variant_get(parameters, "(sv)", &key, &variant);
215 if (NULL == variant) {
216 MESH_LOGE("Invalid variant");
221 var = g_variant_get_string(variant, NULL);
222 MESH_LOGD(" %s [%s]", key, var);
223 MESH_LOGD(" %s", object_path);
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 !");
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;
241 MESH_LOGE(" Unhandled state !");
242 g_free(network_info.mesh_id);
243 g_free(network_info.bssid);
247 mesh_notify_connection_state(network_info.mesh_id, network_info.bssid,
248 network_info.channel, network_info.security, state);
250 g_free(network_info.mesh_id);
251 g_free(network_info.bssid);
255 static void _meshd_subscribe_event(mesh_service *service)
259 meshd_check_null_ret("service", service);
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);
267 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
270 service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
271 MESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
273 /* To monitor mesh profiles */
274 id = g_dbus_connection_signal_subscribe(
275 (GDBusConnection *)service->connection,
277 CONNMAN_INTERFACE_MESH,
281 G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
283 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
286 service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
287 MESH_LOGD("[Signal subscribe] : PropertyChanged (%d)", id);
289 /* End of subscription */
292 static void _on_unsubscribe_ids(gpointer data, gpointer user_data)
294 unsigned int id = GPOINTER_TO_UINT(data);
295 mesh_service *service = (mesh_service*)user_data;
297 MESH_LOGD("[Signal unsubscribe] : %d", id);
298 g_dbus_connection_signal_unsubscribe(
299 (GDBusConnection *)service->connection, id);
302 static void _meshd_unsubscribe_event(mesh_service *service)
304 meshd_check_null_ret("service", service);
306 g_list_foreach(service->dbus_sub_ids, _on_unsubscribe_ids, service);
308 g_list_free(service->dbus_sub_ids);
309 service->dbus_sub_ids = NULL;
312 int meshd_dbus_start(mesh_service *service)
316 rv = _meshd_create_gdbus_call(service);
317 if (MESHD_ERROR_NONE != rv)
320 service->ca = g_cancellable_new();
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);
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);
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);
341 /* Subscribe events */
342 _meshd_subscribe_event(service);
344 return MESHD_ERROR_NONE;
347 int meshd_dbus_stop(mesh_service *service)
352 return MESHD_ERROR_INVALID_PARAMETER;
354 /* Unsubscribe events */
355 _meshd_unsubscribe_event(service);
357 /* Unref all proxies here */
358 if (_gproxy_connman) {
359 g_object_unref(_gproxy_connman);
360 _gproxy_connman = NULL;
362 if (_gproxy_connman_mesh) {
363 g_object_unref(_gproxy_connman_mesh);
364 _gproxy_connman_mesh = NULL;
366 if (_gproxy_connman_technology) {
367 g_object_unref(_gproxy_connman_technology);
368 _gproxy_connman_technology = NULL;
371 g_cancellable_cancel(service->ca);
372 g_object_unref(service->ca);
375 rv = _meshd_close_gdbus_call(service);
379 int mesh_gdbus_create_mesh_interface(mesh_service *service)
381 int ret = MESHD_ERROR_NONE;
382 GVariant *variant = NULL;
383 GError *error = NULL;
384 GVariant *var_dict = NULL;
386 mesh_interface_s *info = NULL;
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);
394 info = service->interface_info;
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);
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,
407 MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
409 ret = MESHD_ERROR_IO_ERROR;
410 MESH_LOGE("Failed DBus call [%s]", error->message);
412 /* Interface not exists */
413 if (g_strrstr(error->message, "No such device"))
414 ret = MESHD_ERROR_INVALID_PARAMETER;
421 int mesh_gdbus_remove_mesh_interface(mesh_service *service)
423 GVariant *variant = NULL;
424 GError *error = NULL;
425 GVariant *var_dict = NULL;
427 mesh_interface_s *info = NULL;
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);
435 info = service->interface_info;
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);
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,
446 MESH_LOGD("Successfully requested. [MeshInterfaceRemove]");
448 MESH_LOGE("Failed DBus call [%s]", error->message);
450 return MESHD_ERROR_IO_ERROR;
453 return MESHD_ERROR_NONE;
456 int mesh_gdbus_mesh_scan(mesh_service *service)
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);
464 g_dbus_proxy_call(_gproxy_connman_technology, "Scan",
466 G_DBUS_CALL_FLAGS_NONE,
467 -1, NULL, NULL, NULL);
469 MESH_LOGD("Successfully requested. [Scan]");
471 return MESHD_ERROR_NONE;
474 int mesh_gdbus_mesh_specific_scan(mesh_service *service, gchar *mesh_id,
477 GVariant *variant = NULL;
478 GError *error = NULL;
479 GVariant *var_dict = NULL;
482 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
483 gushort freq = __channel_to_frequency(channel, band);
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);
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);
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,
501 MESH_LOGD("Successfully requested. [MeshSpecificScan]");
503 MESH_LOGE("Failed DBus call [%s]", error->message);
505 return MESHD_ERROR_IO_ERROR;
508 return MESHD_ERROR_NONE;
511 int mesh_gdbus_mesh_cancel_scan(mesh_service *service)
513 GVariant *variant = NULL;
514 GError *error = NULL;
515 GVariant *var_dict = NULL;
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);
524 g_variant_dict_init(&dict, NULL);
525 var_dict = g_variant_dict_end(&dict);
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,
532 MESH_LOGD("Successfully requested. [AbortScan]");
534 MESH_LOGE("Failed DBus call [%s]", error->message);
536 return MESHD_ERROR_IO_ERROR;
539 return MESHD_ERROR_NONE;
542 static void _on_scan_result_destroy(gpointer data)
544 mesh_scan_result_s *scan_item = (mesh_scan_result_s *)data;
547 g_free(scan_item->mesh_id);
548 g_free(scan_item->bssid);
549 g_free(scan_item->object_path);
554 static void _on_peer_info_destroy(gpointer data)
556 mesh_peer_info_s *peer = (mesh_peer_info_s *)data;
559 g_free(peer->address);
563 static void _get_joined_network(mesh_service *service, GVariant *variant)
565 GVariantIter *peer = NULL;
566 GVariantIter *property = NULL;
568 GVariant *val = NULL;
571 const gchar* obj_path = NULL;
572 const gchar* buf = NULL;
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;
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");
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 !");
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);
598 else if (strcasecmp(key, "BSSID") == 0) {
599 buf = g_variant_get_string(val, &len);
600 joined_info->bssid = g_strdup(buf);
602 else if (strcasecmp(key, "State") == 0) {
603 buf = g_variant_get_string(val, &len);
604 MESH_LOGD(" State : %s", buf);
606 /* Skip ignorable state */
607 if (g_strcmp0(buf, "idle") == 0
608 || g_strcmp0(buf, "disconnect") == 0
609 || g_strcmp0(buf, "failure") == 0) {
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;
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;
625 joined_info->security = MESHD_SECURITY_NONE;
627 else if (strcasecmp(key, "Frequency") == 0) {
628 joined_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
632 /* Skip ignorable state */
633 if (FALSE == valid_state) {
634 g_free(joined_info->mesh_id);
635 g_free(joined_info->bssid);
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;
646 g_variant_iter_free(property);
648 /* If found, stop loop iteration */
651 g_variant_iter_free(peer);
654 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
656 GVariantIter *peer = NULL;
657 GVariantIter *property = NULL;
659 GVariant *val = NULL;
662 const gchar* obj_path = NULL;
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;
668 scan_info = g_try_new0(mesh_scan_result_s, 1);
669 if (NULL == scan_info) {
670 MESH_LOGE("Failed to allocate !");
674 g_variant_get(child, "(oa{sv})", &obj_path, &property);
675 if (NULL == obj_path) {
676 MESH_LOGE("Null object");
680 MESH_LOGD(" Obj path : [%s]", obj_path);
681 scan_info->object_path = g_strdup(obj_path);
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);
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);
694 else if (strcasecmp(key, "State") == 0) {
695 const char *buf = g_variant_get_string(val, &len);
696 MESH_LOGD(" State : %s", buf);
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;
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;
716 scan_info->security = MESHD_SECURITY_NONE;
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);
722 else if (strcasecmp(key, "Favorite") == 0) {
723 const char *buf = g_variant_get_string(val, &len);
724 MESH_LOGD(" Favorite : %s", buf);
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);
732 service->scanned_mesh_network =
733 g_list_prepend(service->scanned_mesh_network, scan_info);
735 g_variant_iter_free(property);
737 g_variant_iter_free(peer);
740 static void _get_connected_mesh_peers(mesh_service *service, GVariant *variant)
742 GVariantIter *peer = NULL;
743 GVariant *val = NULL;
746 GVariant *dict = NULL;
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;
752 peer_info = g_try_new0(mesh_peer_info_s, 1);
753 if (NULL == peer_info) {
754 MESH_LOGE("Failed to allocate !");
758 /* a{sv} <- (a{sv}) */
759 dict = g_variant_get_child_value(child, 0);
760 val = g_variant_lookup_value(dict, "PeerAddress", NULL);
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);
767 MESH_LOGE("Unable to get address !");
772 service->connected_mesh_peers =
773 g_list_prepend(service->connected_mesh_peers, peer_info);
775 g_variant_iter_free(peer);
778 int mesh_gdbus_get_mesh_networks(mesh_service *service)
780 GVariant *variant = NULL;
781 GError *error = NULL;
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);
789 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
791 G_DBUS_CALL_FLAGS_NONE,
794 MESH_LOGD("Successfully requested. [GetMeshPeers]");
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;
801 _get_mesh_peers(service, variant);
803 /* List item is saved with reversed order for efficiency. */
804 service->scanned_mesh_network =
805 g_list_reverse(service->scanned_mesh_network);
807 MESH_LOGE("Failed DBus call [%s]", error->message);
809 return MESHD_ERROR_IO_ERROR;
812 return MESHD_ERROR_NONE;
815 int mesh_gdbus_get_joined_mesh_network(mesh_service *service)
817 GVariant *variant = NULL;
818 GError *error = NULL;
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);
826 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
828 G_DBUS_CALL_FLAGS_NONE,
831 MESH_LOGD("Successfully requested. [GetMeshPeers]");
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;
840 _get_joined_network(service, variant);
842 MESH_LOGE("Failed DBus call [%s]", error->message);
844 return MESHD_ERROR_IO_ERROR;
847 return MESHD_ERROR_NONE;
850 int mesh_gdbus_get_connected_peers(mesh_service *service)
852 GVariant *variant = NULL;
853 GError *error = NULL;
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);
861 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetConnectedMeshPeers",
863 G_DBUS_CALL_FLAGS_NONE,
866 MESH_LOGD("Successfully requested. [GetConnectedMeshPeers]");
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;
873 _get_connected_mesh_peers(service, variant);
875 /* List item is saved with reversed order for efficiency. */
876 service->connected_mesh_peers =
877 g_list_reverse(service->connected_mesh_peers);
879 MESH_LOGE("Failed DBus call [%s]", error->message);
881 return MESHD_ERROR_IO_ERROR;
884 return MESHD_ERROR_NONE;
887 static void _get_mesh_property(GVariant *variant, mesh_network_info_s *result)
889 GVariantIter *property = NULL;
891 GVariant *val = NULL;
894 MESH_LOGD("Type [%s]", g_variant_get_type_string(variant));
896 g_variant_get(variant, "(a{sv})", &property);
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);
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);
909 else if (strcasecmp(key, "State") == 0) {
910 const char *buf = g_variant_get_string(val, &len);
911 MESH_LOGD(" State : %s", buf);
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;
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;
931 result->security = MESHD_SECURITY_NONE;
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);
937 else if (strcasecmp(key, "Favorite") == 0) {
938 const char *buf = g_variant_get_string(val, &len);
939 MESH_LOGD(" Favorite : %s", buf);
941 else if (strcasecmp(key, "Strength") == 0) {
942 gint rssi = (gint)g_variant_get_byte(val);
943 MESH_LOGD(" RSSI : %d", rssi);
946 g_variant_iter_free(property);
949 static int _mesh_gdbus_get_mesh_network_property(mesh_service *service,
950 const gchar* object_path, mesh_network_info_s *result)
952 GVariant *variant = NULL;
953 GError *error = NULL;
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);
960 variant = g_dbus_connection_call_sync(service->connection,
963 CONNMAN_INTERFACE_MESH,
966 G_DBUS_CALL_FLAGS_NONE,
969 MESH_LOGD("Successfully requested. [GetProperties]");
972 _get_mesh_property(variant, result);
974 LOGE("Failed DBus call [%s]", error->message);
976 return MESHD_ERROR_IO_ERROR;
979 return MESHD_ERROR_NONE;
982 int mesh_gdbus_create_network(mesh_service *service, gchar *mesh_id,
983 gint channel, meshd_security_type_e sec)
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";
991 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
992 gushort freq = __channel_to_frequency(channel, band);
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);
1000 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
1001 g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
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} */
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} */
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} */
1018 g_variant_builder_close(&builder); /* a{sv} */
1020 var_dict = g_variant_builder_end(&builder);
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,
1027 MESH_LOGD("Successfully requested. [MeshCreateNetwork]");
1029 MESH_LOGE("Failed DBus call [%s]", error->message);
1030 g_error_free(error);
1031 return MESHD_ERROR_IO_ERROR;
1034 return MESHD_ERROR_NONE;
1037 int mesh_gdbus_set_passphrase(mesh_service *service, mesh_scan_result_s *info,
1040 GVariant *variant = NULL;
1041 GError *error = NULL;
1043 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1044 meshd_check_null_ret_error("passphrase", passphrase, MESHD_ERROR_INVALID_PARAMETER);
1046 variant = g_dbus_connection_call_sync(service->connection,
1047 CONNMAN_SERVER_NAME,
1049 CONNMAN_INTERFACE_MESH,
1051 g_variant_new("(sv)", "Passphrase", g_variant_new_string(passphrase)),
1053 G_DBUS_CALL_FLAGS_NONE,
1056 MESH_LOGD("Successfully requested. [SetProperty]");
1058 LOGE("Failed DBus call [%s]", error->message);
1059 g_error_free(error);
1060 return MESHD_ERROR_IO_ERROR;
1063 return MESHD_ERROR_NONE;
1067 static void on_response_connect_network(GObject *source_object,
1068 GAsyncResult *res, gpointer user_data)
1070 int ret = MESHD_ERROR_NONE;
1071 GError *error = NULL;
1072 GVariant *variant = NULL;
1076 variant = g_dbus_connection_call_finish(
1077 G_DBUS_CONNECTION(source_object), res, &error);
1079 MESH_LOGD("Successfully requested. [Connect]");
1081 /* TODO: Unregister property change event */
1083 ret = MESHD_ERROR_IO_ERROR;
1084 LOGE("Failed DBus call [%s]", error->message);
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;
1091 ret = MESHD_ERROR_IO_ERROR;
1093 g_error_free(error);
1098 int mesh_gdbus_connect_network(mesh_service *service, mesh_scan_result_s *info)
1100 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1101 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1103 g_dbus_connection_call(service->connection,
1104 CONNMAN_SERVER_NAME,
1106 CONNMAN_INTERFACE_MESH,
1109 G_DBUS_CALL_FLAGS_NONE,
1111 NULL, /* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED */
1113 MESH_LOGD("Successfully requested. [Connect]");
1115 return MESHD_ERROR_NONE;
1118 int mesh_gdbus_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
1120 GVariant *variant = NULL;
1121 GError *error = NULL;
1123 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1124 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1126 variant = g_dbus_connection_call_sync(service->connection,
1127 CONNMAN_SERVER_NAME,
1129 CONNMAN_INTERFACE_MESH,
1132 G_DBUS_CALL_FLAGS_NONE,
1135 MESH_LOGD("Successfully requested. [Disconnect]");
1137 LOGE("Failed DBus call [%s]", error->message);
1138 g_error_free(error);
1139 return MESHD_ERROR_IO_ERROR;
1142 return MESHD_ERROR_NONE;
1145 int mesh_gdbus_remove_network(mesh_service *service, mesh_scan_result_s *info)
1147 GVariant *variant = NULL;
1148 GError *error = NULL;
1150 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
1151 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
1153 variant = g_dbus_connection_call_sync(service->connection,
1154 CONNMAN_SERVER_NAME,
1156 CONNMAN_INTERFACE_MESH,
1159 G_DBUS_CALL_FLAGS_NONE,
1162 MESH_LOGD("Successfully requested. [Remove]");
1164 LOGE("Failed DBus call [%s]", error->message);
1165 g_error_free(error);
1166 return MESHD_ERROR_IO_ERROR;
1169 return MESHD_ERROR_NONE;