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.
17 #include "wmesh-log.h"
18 #include "wmesh-util.h"
19 #include "wmesh-gdbus.h"
20 #include "wmesh-request.h"
22 #include <linux/nl80211.h>
24 static GDBusProxy *_gproxy_connman = NULL;
25 static GDBusProxy *_gproxy_connman_mesh = NULL;
26 static GDBusProxy *_gproxy_connman_technology = NULL;
27 static GDBusProxy *_gproxy_connman_ethernet = NULL;
29 static int _wmeshd_close_gdbus_call(wmesh_service *service);
30 static int _wmesh_gdbus_get_mesh_network_property(wmesh_service *service,
31 const gchar* object_path, wmesh_network_info_s *result);
33 static int __channel_to_frequency(int channel, enum nl80211_band band)
39 case NL80211_BAND_2GHZ:
42 else if (channel < 14)
43 return 2407 + channel * 5;
45 case NL80211_BAND_5GHZ:
46 if (channel >= 182 && channel <= 196)
47 return 4000 + channel * 5;
49 return 5000 + channel * 5;
59 static int __frequency_to_channel(int freq)
64 return (freq - 2407) / 5;
65 else if (freq >= 4910 && freq <= 4980)
66 return (freq - 4000) / 5;
67 else if (freq <= 45000)
68 return (freq - 5000) / 5;
69 else if (freq >= 58320 && freq <= 64800)
70 return (freq - 56160) / 2160;
75 static GDBusProxy *_proxy_get_connman(wmesh_service *service)
77 GDBusProxy *proxy = NULL;
78 wmeshd_check_null_ret_error("service", service, NULL);
80 if (NULL == _gproxy_connman) {
81 proxy = g_dbus_proxy_new_sync(service->connection,
82 G_DBUS_PROXY_FLAGS_NONE, NULL,
85 CONNMAN_INTERFACE_MANAGER,
88 proxy = _gproxy_connman;
93 static GDBusProxy *_proxy_get_connman_mesh(wmesh_service *service)
95 GDBusProxy *proxy = NULL;
96 wmeshd_check_null_ret_error("service", service, NULL);
98 if (NULL == _gproxy_connman_mesh) {
99 proxy = g_dbus_proxy_new_sync(service->connection,
100 G_DBUS_PROXY_FLAGS_NONE, NULL,
102 CONNMAN_OBJECT_PATH_MESH,
103 CONNMAN_INTERFACE_MESH,
106 proxy = _gproxy_connman_mesh;
111 static GDBusProxy *_proxy_get_connman_ethernet(wmesh_service *service)
113 GDBusProxy *proxy = NULL;
114 wmeshd_check_null_ret_error("service", service, NULL);
116 if (NULL == _gproxy_connman_ethernet) {
117 proxy = g_dbus_proxy_new_sync(service->connection,
118 G_DBUS_PROXY_FLAGS_NONE, NULL,
119 CONNMAN_SERVER_NAME, /* Name */
120 "/net/connman/technology/ethernet", /* Object Path */
121 CONNMAN_INTERFACE_TECH, /* interface Name */
124 proxy = _gproxy_connman_ethernet;
129 static GDBusProxy *_proxy_get_connman_technology(wmesh_service *service)
131 GDBusProxy *proxy = NULL;
132 wmeshd_check_null_ret_error("service", service, NULL);
134 if (NULL == _gproxy_connman_technology) {
135 proxy = g_dbus_proxy_new_sync(service->connection,
136 G_DBUS_PROXY_FLAGS_NONE, NULL,
138 CONNMAN_OBJECT_PATH_TECH_MESH,
139 CONNMAN_INTERFACE_TECH,
142 proxy = _gproxy_connman_technology;
147 static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
150 GDBusProxy *proxy = G_DBUS_PROXY(object);
151 gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
152 wmesh_service *service = (wmesh_service*)user_data;
156 if (NULL == name_owner) {
157 WMESH_LOGE("name_owner is not exists !");
158 _wmeshd_close_gdbus_call(service);
164 static int _wmeshd_create_gdbus_call(wmesh_service *service)
167 GError *error = NULL;
170 return WMESHD_ERROR_INVALID_PARAMETER;
172 if (NULL != service->connection)
173 return WMESHD_ERROR_ALREADY_REGISTERED;
175 service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
176 if (service->connection == NULL) {
178 WMESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
181 return WMESHD_ERROR_IO_ERROR;
184 id = g_signal_connect(service->connection, "notify::g-name-owner",
185 G_CALLBACK(_dbus_name_owner_notify), service);
187 WMESH_LOGE("g_signal_connect() Fail");
188 g_object_unref(service->connection);
189 service->connection = NULL;
190 return WMESHD_ERROR_IO_ERROR;
193 return WMESHD_ERROR_NONE;
196 static int _wmeshd_close_gdbus_call(wmesh_service *service)
198 /* CHECK: is connection ref count required? */
199 g_object_unref(service->connection);
200 service->connection = NULL;
202 return WMESHD_ERROR_NONE;
205 static void _wmeshd_signal_handler(GDBusConnection *connection,
206 const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
207 const gchar *signal_name, GVariant *parameters, gpointer user_data)
209 wmesh_service *service = (wmesh_service*)user_data;
210 wmesh_network_info_s network_info = { 0, 0, 0, 0, 0, 0, 0, 0};
211 int ret = WMESHD_ERROR_NONE;
213 wmeshd_check_null_ret("user_data", user_data);
215 NOTUSED(sender_name);
216 NOTUSED(interface_name);
218 WMESH_LOGD("signal received = %s", signal_name);
219 if (0 == g_strcmp0(signal_name, "ScanDone")) {
220 /* TODO: Handle event */
221 wmesh_notify_scan_done();
222 } else if (0 == g_strcmp0(signal_name, "PropertyChanged")) {
223 const gchar* var = NULL;
225 GVariant *variant = NULL;
226 wmeshd_connection_state_e state = WMESHD_CONNECTION_STATE_DISCONNECTED;
228 if (NULL == parameters) {
229 WMESH_LOGE("Unexpected parameter");
233 g_variant_get(parameters, "(sv)", &key, &variant);
234 if (NULL == variant) {
235 WMESH_LOGE("Invalid variant");
240 var = g_variant_get_string(variant, NULL);
241 WMESH_LOGD(" %s [%s]", key, var);
242 WMESH_LOGD(" %s", object_path);
244 ret = _wmesh_gdbus_get_mesh_network_property(service, object_path, &network_info);
245 if (WMESHD_ERROR_NONE != ret)
246 WMESH_LOGE("Cannot get valid network property !");
248 if (g_strcmp0("association", var) == 0) {
249 /* Joined mesh network */
250 state = WMESHD_CONNECTION_STATE_ASSOCIATION;
251 } else if (g_strcmp0("configuration", var) == 0) {
252 /* Trying to get IP address */
253 state = WMESHD_CONNECTION_STATE_CONFIGURATION;
254 } else if (g_strcmp0("ready", var) == 0 || g_strcmp0("online", var) == 0) {
255 /* IP address is obtained */
256 state = WMESHD_CONNECTION_STATE_CONNECTED;
257 } else if (g_strcmp0("disconnect", var) == 0 || g_strcmp0("failure", var) == 0) {
258 state = WMESHD_CONNECTION_STATE_DISCONNECTED;
260 WMESH_LOGE(" Unhandled state !");
261 g_free(network_info.mesh_id);
262 g_free(network_info.bssid);
266 wmesh_notify_connection_state(network_info.mesh_id, network_info.bssid,
267 network_info.channel, network_info.security, state);
269 g_free(network_info.mesh_id);
270 g_free(network_info.bssid);
274 static void _wmeshd_subscribe_event(wmesh_service *service)
278 wmeshd_check_null_ret("service", service);
280 id = g_dbus_connection_signal_subscribe(
281 (GDBusConnection *)service->connection,
282 CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
283 "ScanDone", "/", NULL,
284 G_DBUS_CALL_FLAGS_NONE, _wmeshd_signal_handler, service, NULL);
286 WMESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
289 service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
290 WMESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
292 /* To monitor mesh profiles */
293 id = g_dbus_connection_signal_subscribe(
294 (GDBusConnection *)service->connection,
296 CONNMAN_INTERFACE_MESH,
300 G_DBUS_CALL_FLAGS_NONE, _wmeshd_signal_handler, service, NULL);
302 WMESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
305 service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
306 WMESH_LOGD("[Signal subscribe] : PropertyChanged (%d)", id);
308 /* End of subscription */
311 static void _on_unsubscribe_ids(gpointer data, gpointer user_data)
313 unsigned int id = GPOINTER_TO_UINT(data);
314 wmesh_service *service = (wmesh_service*)user_data;
316 WMESH_LOGD("[Signal unsubscribe] : %d", id);
317 g_dbus_connection_signal_unsubscribe(
318 (GDBusConnection *)service->connection, id);
321 static void _wmeshd_unsubscribe_event(wmesh_service *service)
323 wmeshd_check_null_ret("service", service);
325 g_list_foreach(service->dbus_sub_ids, _on_unsubscribe_ids, service);
327 g_list_free(service->dbus_sub_ids);
328 service->dbus_sub_ids = NULL;
331 int wmeshd_dbus_start(wmesh_service *service)
335 rv = _wmeshd_create_gdbus_call(service);
336 if (WMESHD_ERROR_NONE != rv)
339 service->ca = g_cancellable_new();
341 /* Create all required proxies here */
342 _gproxy_connman = _proxy_get_connman(service);
343 wmeshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
344 WMESHD_ERROR_IO_ERROR);
345 g_dbus_proxy_set_default_timeout(
346 G_DBUS_PROXY(_gproxy_connman), WMESH_DBUS_PROXY_TIMEOUT);
348 _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
349 wmeshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
350 WMESHD_ERROR_IO_ERROR);
351 g_dbus_proxy_set_default_timeout(
352 G_DBUS_PROXY(_gproxy_connman_mesh), WMESH_DBUS_PROXY_TIMEOUT);
354 _gproxy_connman_technology = _proxy_get_connman_technology(service);
355 wmeshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
356 WMESHD_ERROR_IO_ERROR);
357 g_dbus_proxy_set_default_timeout(
358 G_DBUS_PROXY(_gproxy_connman_technology), WMESH_DBUS_PROXY_TIMEOUT);
360 _gproxy_connman_ethernet = _proxy_get_connman_ethernet(service);
361 wmeshd_check_null_ret_error("_gproxy_connman_ethernet", _gproxy_connman_ethernet,
362 WMESHD_ERROR_IO_ERROR);
363 g_dbus_proxy_set_default_timeout(
364 G_DBUS_PROXY(_gproxy_connman_ethernet), WMESH_DBUS_PROXY_TIMEOUT);
366 /* Subscribe events */
367 _wmeshd_subscribe_event(service);
369 return WMESHD_ERROR_NONE;
372 int wmeshd_dbus_stop(wmesh_service *service)
377 return WMESHD_ERROR_INVALID_PARAMETER;
379 /* Unsubscribe events */
380 _wmeshd_unsubscribe_event(service);
382 /* Unref all proxies here */
383 if (_gproxy_connman) {
384 g_object_unref(_gproxy_connman);
385 _gproxy_connman = NULL;
387 if (_gproxy_connman_mesh) {
388 g_object_unref(_gproxy_connman_mesh);
389 _gproxy_connman_mesh = NULL;
391 if (_gproxy_connman_technology) {
392 g_object_unref(_gproxy_connman_technology);
393 _gproxy_connman_technology = NULL;
396 g_cancellable_cancel(service->ca);
397 g_object_unref(service->ca);
400 rv = _wmeshd_close_gdbus_call(service);
404 int wmesh_gdbus_create_mesh_interface(wmesh_service *service)
406 int ret = WMESHD_ERROR_NONE;
407 GVariant *variant = NULL;
408 GError *error = NULL;
409 GVariant *var_dict = NULL;
411 wmesh_interface_s *info = NULL;
413 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
414 wmeshd_check_null_ret_error("connection", service->connection,
415 WMESHD_ERROR_INVALID_PARAMETER);
416 wmeshd_check_null_ret_error("_gproxy_connman_technology",
417 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
419 info = service->interface_info;
421 g_variant_dict_init(&dict, NULL);
422 g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
423 g_variant_dict_insert(&dict, "ParentIfname", "s", info->base_interface);
424 g_variant_dict_insert(&dict, "BridgeIfname", "s", info->bridge_interface);
425 var_dict = g_variant_dict_end(&dict);
427 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
428 g_variant_new("(sv)", "MeshInterfaceAdd", var_dict),
429 G_DBUS_CALL_FLAGS_NONE,
432 WMESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
434 ret = WMESHD_ERROR_IO_ERROR;
435 WMESH_LOGE("Failed DBus call [%s]", error->message);
437 /* Interface not exists */
438 if (g_strrstr(error->message, "No such device"))
439 ret = WMESHD_ERROR_INVALID_PARAMETER;
446 int wmesh_gdbus_remove_mesh_interface(wmesh_service *service)
448 int ret = WMESHD_ERROR_NONE;
449 GVariant *variant = NULL;
450 GError *error = NULL;
451 GVariant *var_dict = NULL;
453 wmesh_interface_s *info = NULL;
455 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
456 wmeshd_check_null_ret_error("connection", service->connection,
457 WMESHD_ERROR_INVALID_PARAMETER);
458 wmeshd_check_null_ret_error("_gproxy_connman_technology",
459 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
461 info = service->interface_info;
463 g_variant_dict_init(&dict, NULL);
464 g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
465 var_dict = g_variant_dict_end(&dict);
467 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
468 g_variant_new("(sv)", "MeshInterfaceRemove", var_dict),
469 G_DBUS_CALL_FLAGS_NONE,
472 WMESH_LOGD("Successfully requested. [MeshInterfaceRemove]");
474 ret = WMESHD_ERROR_IO_ERROR;
475 WMESH_LOGE("Failed DBus call [%s]", error->message);
477 /* Interface not exists (Not created yet) */
478 if (g_strrstr(error->message, "No such device"))
479 ret = WMESHD_ERROR_NONE;
486 int wmesh_gdbus_mesh_scan(wmesh_service *service)
488 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
489 wmeshd_check_null_ret_error("connection", service->connection,
490 WMESHD_ERROR_INVALID_PARAMETER);
491 wmeshd_check_null_ret_error("_gproxy_connman_technology",
492 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
494 g_dbus_proxy_call(_gproxy_connman_technology, "Scan",
496 G_DBUS_CALL_FLAGS_NONE,
497 -1, NULL, NULL, NULL);
499 WMESH_LOGD("Successfully requested. [Scan]");
501 return WMESHD_ERROR_NONE;
504 int wmesh_gdbus_mesh_specific_scan(wmesh_service *service, gchar *mesh_id, gint channel)
506 GVariant *variant = NULL;
507 GError *error = NULL;
508 GVariant *var_dict = NULL;
511 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
512 gushort freq = __channel_to_frequency(channel, band);
514 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
515 wmeshd_check_null_ret_error("connection", service->connection,
516 WMESHD_ERROR_INVALID_PARAMETER);
517 wmeshd_check_null_ret_error("_gproxy_connman_technology",
518 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
520 g_variant_dict_init(&dict, NULL);
521 g_variant_dict_insert(&dict, "Name", "s", mesh_id);
522 g_variant_dict_insert(&dict, "Frequency", "q", freq);
523 var_dict = g_variant_dict_end(&dict);
525 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
526 g_variant_new("(sv)", "MeshSpecificScan", var_dict),
527 G_DBUS_CALL_FLAGS_NONE,
530 WMESH_LOGD("Successfully requested. [MeshSpecificScan]");
532 WMESH_LOGE("Failed DBus call [%s]", error->message);
534 return WMESHD_ERROR_IO_ERROR;
537 return WMESHD_ERROR_NONE;
540 int wmesh_gdbus_mesh_cancel_scan(wmesh_service *service)
542 int ret = WMESHD_ERROR_NONE;
543 GVariant *variant = NULL;
544 GError *error = NULL;
545 GVariant *var_dict = NULL;
548 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
549 wmeshd_check_null_ret_error("connection", service->connection,
550 WMESHD_ERROR_INVALID_PARAMETER);
551 wmeshd_check_null_ret_error("_gproxy_connman_technology",
552 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
554 g_variant_dict_init(&dict, NULL);
555 var_dict = g_variant_dict_end(&dict);
557 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
558 g_variant_new("(sv)", "AbortScan", var_dict),
559 G_DBUS_CALL_FLAGS_NONE,
562 WMESH_LOGD("Successfully requested. [AbortScan]");
564 ret = WMESHD_ERROR_IO_ERROR;
565 WMESH_LOGE("Failed DBus call [%s]", error->message);
567 /* Scan is not in progress */
568 if (g_strrstr(error->message, "Already exists"))
569 ret = WMESHD_ERROR_NONE;
577 static void _on_scan_result_destroy(gpointer data)
579 wmesh_scan_result_s *scan_item = (wmesh_scan_result_s *)data;
582 g_free(scan_item->mesh_id);
583 g_free(scan_item->bssid);
584 g_free(scan_item->object_path);
589 static void _on_peer_info_destroy(gpointer data)
591 wmesh_peer_info_s *peer = (wmesh_peer_info_s *)data;
594 g_free(peer->address);
598 static void _get_joined_network(wmesh_service *service, GVariant *variant)
600 GVariantIter *peer = NULL;
601 GVariantIter *property = NULL;
602 GVariantIter *iter = NULL;
604 gchar *sub_key = NULL;
605 GVariant *val = NULL;
606 GVariant *sub_val = NULL;
609 const gchar* obj_path = NULL;
610 const gchar* buf = NULL;
612 g_variant_get(variant, "(a(oa{sv}))", &peer);
613 while ((child = g_variant_iter_next_value(peer))) {
614 wmesh_network_info_s *joined_info = NULL;
615 gboolean valid_state = TRUE;
617 g_variant_get(child, "(oa{sv})", &obj_path, &property);
618 WMESH_LOGD(" Object: [%s]", obj_path);
619 if (NULL == obj_path) {
620 WMESH_LOGE("Null object");
624 /* Create an information structure for joined network */
625 joined_info = g_try_new0(wmesh_network_info_s, 1);
626 if (NULL == joined_info) {
627 WMESH_LOGE("Failed to allocate !");
631 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
632 if (strcasecmp(key, "Name") == 0) {
633 buf = g_variant_get_string(val, &len);
634 joined_info->mesh_id = g_strdup(buf);
635 } else if (strcasecmp(key, "BSSID") == 0) {
636 buf = g_variant_get_string(val, &len);
637 joined_info->bssid = g_strdup(buf);
638 } else if (strcasecmp(key, "State") == 0) {
639 buf = g_variant_get_string(val, &len);
640 WMESH_LOGD(" State : %s", buf);
642 /* Skip ignorable state */
643 if (g_strcmp0(buf, "idle") == 0
644 || g_strcmp0(buf, "disconnect") == 0
645 || g_strcmp0(buf, "failure") == 0) {
648 } else if (g_strcmp0(buf, "association") == 0) {
649 joined_info->state = WMESHD_CONNECTION_STATE_ASSOCIATION;
650 } else if (g_strcmp0(buf, "configuration") == 0) {
651 joined_info->state = WMESHD_CONNECTION_STATE_CONFIGURATION;
652 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
653 joined_info->state = WMESHD_CONNECTION_STATE_CONNECTED;
655 } else if (strcasecmp(key, "Security") == 0) {
656 buf = g_variant_get_string(val, &len);
657 if (g_strcmp0("sae", buf) == 0)
658 joined_info->security = WMESHD_SECURITY_SAE;
660 joined_info->security = WMESHD_SECURITY_NONE;
661 } else if (strcasecmp(key, "Frequency") == 0) {
662 joined_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
663 } else if (strcasecmp(key, "IPv4") == 0) {
664 g_variant_get(val, "a{sv}", &iter);
665 while (g_variant_iter_loop(iter, "{sv}", &sub_key, &sub_val)) {
667 if (strcasecmp(sub_key, "Method") == 0) {
668 buf = g_variant_get_string(sub_val, &len);
669 WMESH_LOGD("Method %s", buf);
671 if (strcasecmp(buf, "dhcp") == 0)
672 joined_info->ipv4_type =
673 WMESHD_IP_CONFIG_TYPE_DYNAMIC;
674 else if (strcasecmp(buf, "manual") == 0)
675 joined_info->ipv4_type =
676 WMESHD_IP_CONFIG_TYPE_STATIC;
678 joined_info->ipv4_type =
679 WMESHD_IP_CONFIG_TYPE_UNKNOWN;
680 } else if (strcasecmp(sub_key, "Address") == 0) {
681 buf = g_variant_get_string(sub_val, &len);
682 WMESH_LOGD("Address %s", buf);
683 joined_info->ipv4_address = g_strdup(buf);
684 } else if (strcasecmp(sub_key, "Netmask") == 0) {
685 buf = g_variant_get_string(sub_val, &len);
686 WMESH_LOGD("Netmask %s", buf);
687 joined_info->ipv4_netmask = g_strdup(buf);
690 g_variant_iter_free(iter);
694 /* Skip ignorable state */
695 if (FALSE == valid_state) {
696 g_free(joined_info->mesh_id);
697 g_free(joined_info->bssid);
698 g_free(joined_info->ipv4_address);
699 g_free(joined_info->ipv4_netmask);
703 WMESH_LOGD(" Mesh ID : %s", joined_info->mesh_id);
704 WMESH_LOGD(" BSSID : %s", joined_info->bssid);
705 WMESH_LOGD(" Channel : %d", joined_info->channel);
706 WMESH_LOGD(" Security : %s",
707 (WMESHD_SECURITY_SAE == joined_info->security) ? "SAE" : "NONE");
708 service->joined_network = joined_info;
710 g_variant_iter_free(property);
712 /* If found, stop loop iteration */
715 g_variant_iter_free(peer);
718 static void _get_mesh_peers(wmesh_service *service, GVariant *variant)
720 GVariantIter *peer = NULL;
721 GVariantIter *property = NULL;
723 GVariant *val = NULL;
726 const gchar* obj_path = NULL;
728 g_variant_get(variant, "(a(oa{sv}))", &peer);
729 while ((child = g_variant_iter_next_value(peer))) {
730 wmesh_scan_result_s *scan_info = NULL;
732 scan_info = g_try_new0(wmesh_scan_result_s, 1);
733 if (NULL == scan_info) {
734 WMESH_LOGE("Failed to allocate !");
738 g_variant_get(child, "(oa{sv})", &obj_path, &property);
739 if (NULL == obj_path) {
740 WMESH_LOGE("Null object");
744 WMESH_LOGD(" Obj path : [%s]", obj_path);
745 scan_info->object_path = g_strdup(obj_path);
747 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
748 if (strcasecmp(key, "Name") == 0) {
749 const char *buf = g_variant_get_string(val, &len);
750 scan_info->mesh_id = g_strdup(buf);
751 WMESH_LOGD(" Mesh ID : %s", scan_info->mesh_id);
752 } else if (strcasecmp(key, "BSSID") == 0) {
753 const char *buf = g_variant_get_string(val, &len);
754 scan_info->bssid = g_strdup(buf);
755 WMESH_LOGD(" BSSID : %s", scan_info->bssid);
756 } else if (strcasecmp(key, "State") == 0) {
757 const char *buf = g_variant_get_string(val, &len);
758 WMESH_LOGD(" State : %s", buf);
760 if (g_strcmp0(buf, "idle") == 0
761 || g_strcmp0(buf, "disconnect") == 0
762 || g_strcmp0(buf, "failure") == 0) {
763 scan_info->state = WMESHD_CONNECTION_STATE_DISCONNECTED;
764 } else if (g_strcmp0(buf, "association") == 0) {
765 scan_info->state = WMESHD_CONNECTION_STATE_ASSOCIATION;
766 } else if (g_strcmp0(buf, "configuration") == 0) {
767 scan_info->state = WMESHD_CONNECTION_STATE_CONFIGURATION;
768 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
769 scan_info->state = WMESHD_CONNECTION_STATE_CONNECTED;
771 } else if (strcasecmp(key, "Security") == 0) {
772 const char *buf = g_variant_get_string(val, &len);
773 WMESH_LOGD(" Security : %s", buf);
774 if (g_strcmp0("sae", buf) == 0)
775 scan_info->security = WMESHD_SECURITY_SAE;
777 scan_info->security = WMESHD_SECURITY_NONE;
778 } else if (strcasecmp(key, "Frequency") == 0) {
779 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
780 WMESH_LOGD(" Channel : %d", scan_info->channel);
781 } else if (strcasecmp(key, "Favorite") == 0) {
782 const char *buf = g_variant_get_string(val, &len);
783 WMESH_LOGD(" Favorite : %s", buf);
784 } else if (strcasecmp(key, "Strength") == 0) {
785 scan_info->rssi = (gint)g_variant_get_byte(val);
786 WMESH_LOGD(" RSSI : %d", scan_info->rssi);
790 service->scanned_mesh_network =
791 g_list_prepend(service->scanned_mesh_network, scan_info);
793 g_variant_iter_free(property);
795 g_variant_iter_free(peer);
798 static void _get_connected_mesh_peers(wmesh_service *service, GVariant *variant)
800 GVariantIter *peer = NULL;
801 GVariant *val = NULL;
804 GVariant *dict = NULL;
806 g_variant_get(variant, "(a(a{sv}))", &peer);
807 while ((child = g_variant_iter_next_value(peer))) {
808 wmesh_peer_info_s *peer_info = NULL;
810 peer_info = g_try_new0(wmesh_peer_info_s, 1);
811 if (NULL == peer_info) {
812 WMESH_LOGE("Failed to allocate !");
816 /* a{sv} <- (a{sv}) */
817 dict = g_variant_get_child_value(child, 0);
818 val = g_variant_lookup_value(dict, "PeerAddress", NULL);
820 const char *buf = g_variant_get_string(val, &len);
821 peer_info->address = g_strdup(buf);
822 WMESH_LOGD(" Address : %s", peer_info->address);
823 g_variant_unref(val);
825 WMESH_LOGE("Unable to get address !");
830 service->connected_mesh_peers =
831 g_list_prepend(service->connected_mesh_peers, peer_info);
833 g_variant_iter_free(peer);
836 int wmesh_gdbus_get_mesh_networks(wmesh_service *service)
838 GVariant *variant = NULL;
839 GError *error = NULL;
841 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
842 wmeshd_check_null_ret_error("connection", service->connection,
843 WMESHD_ERROR_INVALID_PARAMETER);
844 wmeshd_check_null_ret_error("_gproxy_connman",
845 _gproxy_connman, WMESHD_ERROR_IO_ERROR);
847 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
849 G_DBUS_CALL_FLAGS_NONE,
852 WMESH_LOGD("Successfully requested. [GetMeshPeers]");
854 if (service->scanned_mesh_network) {
855 g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
856 service->scanned_mesh_network = NULL;
859 _get_mesh_peers(service, variant);
861 /* List item is saved with reversed order for efficiency. */
862 service->scanned_mesh_network =
863 g_list_reverse(service->scanned_mesh_network);
865 WMESH_LOGE("Failed DBus call [%s]", error->message);
867 return WMESHD_ERROR_IO_ERROR;
870 return WMESHD_ERROR_NONE;
873 int wmesh_gdbus_get_joined_mesh_network(wmesh_service *service)
875 GVariant *variant = NULL;
876 GError *error = NULL;
878 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
879 wmeshd_check_null_ret_error("connection", service->connection,
880 WMESHD_ERROR_INVALID_PARAMETER);
881 wmeshd_check_null_ret_error("_gproxy_connman",
882 _gproxy_connman, WMESHD_ERROR_IO_ERROR);
884 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
886 G_DBUS_CALL_FLAGS_NONE,
889 WMESH_LOGD("Successfully requested. [GetMeshPeers]");
891 if (service->joined_network) {
892 g_free(service->joined_network->mesh_id);
893 g_free(service->joined_network->bssid);
894 g_free(service->joined_network->ipv4_address);
895 g_free(service->joined_network->ipv4_netmask);
896 g_free(service->joined_network);
897 service->joined_network = NULL;
900 _get_joined_network(service, variant);
902 WMESH_LOGE("Failed DBus call [%s]", error->message);
904 return WMESHD_ERROR_IO_ERROR;
907 return WMESHD_ERROR_NONE;
910 int wmesh_gdbus_get_connected_peers(wmesh_service *service)
912 GVariant *variant = NULL;
913 GError *error = NULL;
915 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
916 wmeshd_check_null_ret_error("connection", service->connection,
917 WMESHD_ERROR_INVALID_PARAMETER);
918 wmeshd_check_null_ret_error("_gproxy_connman",
919 _gproxy_connman, WMESHD_ERROR_IO_ERROR);
921 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetConnectedMeshPeers",
923 G_DBUS_CALL_FLAGS_NONE,
926 WMESH_LOGD("Successfully requested. [GetConnectedMeshPeers]");
928 if (service->connected_mesh_peers) {
929 g_list_free_full(service->connected_mesh_peers, _on_peer_info_destroy);
930 service->connected_mesh_peers = NULL;
933 _get_connected_mesh_peers(service, variant);
935 /* List item is saved with reversed order for efficiency. */
936 service->connected_mesh_peers =
937 g_list_reverse(service->connected_mesh_peers);
939 WMESH_LOGE("Failed DBus call [%s]", error->message);
941 return WMESHD_ERROR_IO_ERROR;
944 return WMESHD_ERROR_NONE;
947 static void _get_mesh_property(GVariant *variant, wmesh_network_info_s *result)
949 GVariantIter *property = NULL;
951 GVariant *val = NULL;
954 WMESH_LOGD("Type [%s]", g_variant_get_type_string(variant));
956 g_variant_get(variant, "(a{sv})", &property);
958 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
959 if (strcasecmp(key, "Name") == 0) {
960 const char *buf = g_variant_get_string(val, &len);
961 result->mesh_id = g_strdup(buf);
962 WMESH_LOGD(" Mesh ID : %s", result->mesh_id);
963 } else if (strcasecmp(key, "BSSID") == 0) {
964 const char *buf = g_variant_get_string(val, &len);
965 result->bssid = g_strdup(buf);
966 WMESH_LOGD(" BSSID : %s", result->bssid);
967 } else if (strcasecmp(key, "State") == 0) {
968 const char *buf = g_variant_get_string(val, &len);
969 WMESH_LOGD(" State : %s", buf);
971 if (g_strcmp0(buf, "idle") == 0
972 || g_strcmp0(buf, "disconnect") == 0
973 || g_strcmp0(buf, "failure") == 0) {
974 result->state = WMESHD_CONNECTION_STATE_DISCONNECTED;
975 } else if (g_strcmp0(buf, "association") == 0) {
976 result->state = WMESHD_CONNECTION_STATE_ASSOCIATION;
977 } else if (g_strcmp0(buf, "configuration") == 0) {
978 result->state = WMESHD_CONNECTION_STATE_CONFIGURATION;
979 } else if (g_strcmp0(buf, "ready") == 0 || g_strcmp0(buf, "online") == 0) {
980 result->state = WMESHD_CONNECTION_STATE_CONNECTED;
982 } else if (strcasecmp(key, "Security") == 0) {
983 const char *buf = g_variant_get_string(val, &len);
984 WMESH_LOGD(" Security : %s", buf);
985 if (g_strcmp0("sae", buf) == 0)
986 result->security = WMESHD_SECURITY_SAE;
988 result->security = WMESHD_SECURITY_NONE;
989 } else if (strcasecmp(key, "Frequency") == 0) {
990 result->channel = __frequency_to_channel(g_variant_get_uint16(val));
991 WMESH_LOGD(" Channel : %d", result->channel);
992 } else if (strcasecmp(key, "Favorite") == 0) {
993 const char *buf = g_variant_get_string(val, &len);
994 WMESH_LOGD(" Favorite : %s", buf);
995 } else if (strcasecmp(key, "Strength") == 0) {
996 gint rssi = (gint)g_variant_get_byte(val);
997 WMESH_LOGD(" RSSI : %d", rssi);
1000 g_variant_iter_free(property);
1003 static int _wmesh_gdbus_get_mesh_network_property(wmesh_service *service,
1004 const gchar* object_path, wmesh_network_info_s *result)
1006 GVariant *variant = NULL;
1007 GError *error = NULL;
1009 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1010 wmeshd_check_null_ret_error("connection", service->connection,
1011 WMESHD_ERROR_INVALID_PARAMETER);
1012 wmeshd_check_null_ret_error("result", result, WMESHD_ERROR_INVALID_PARAMETER);
1014 variant = g_dbus_connection_call_sync(service->connection,
1015 CONNMAN_SERVER_NAME,
1017 CONNMAN_INTERFACE_MESH,
1020 G_DBUS_CALL_FLAGS_NONE,
1023 WMESH_LOGD("Successfully requested. [GetProperties]");
1025 /* Get properties */
1026 _get_mesh_property(variant, result);
1028 WMESH_LOGE("Failed DBus call [%s]", error->message);
1029 g_error_free(error);
1030 return WMESHD_ERROR_IO_ERROR;
1033 return WMESHD_ERROR_NONE;
1036 int wmesh_gdbus_create_network(wmesh_service *service, gchar *mesh_id,
1037 gint channel, wmeshd_security_type_e sec)
1039 GVariant *variant = NULL;
1040 GError *error = NULL;
1041 GVariant *var_dict = NULL;
1042 GVariantBuilder builder;
1043 const gchar* security = (WMESHD_SECURITY_SAE == sec) ? "sae" : "none";
1045 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
1046 gushort freq = __channel_to_frequency(channel, band);
1048 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1049 wmeshd_check_null_ret_error("connection", service->connection,
1050 WMESHD_ERROR_INVALID_PARAMETER);
1051 wmeshd_check_null_ret_error("_gproxy_connman_technology",
1052 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
1054 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
1055 g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
1057 g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1058 g_variant_builder_add(&builder, "s", "Name");
1059 g_variant_builder_add(&builder, "v", g_variant_new_string(mesh_id));
1060 g_variant_builder_close(&builder); /* {sv} */
1062 g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1063 g_variant_builder_add(&builder, "s", "Frequency");
1064 g_variant_builder_add(&builder, "v", g_variant_new_uint16(freq));
1065 g_variant_builder_close(&builder); /* {sv} */
1067 g_variant_builder_open(&builder, G_VARIANT_TYPE("{sv}"));
1068 g_variant_builder_add(&builder, "s", "Security");
1069 g_variant_builder_add(&builder, "v", g_variant_new_string(security));
1070 g_variant_builder_close(&builder); /* {sv} */
1072 g_variant_builder_close(&builder); /* a{sv} */
1074 var_dict = g_variant_builder_end(&builder);
1076 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
1077 g_variant_new("(sv)", "MeshCreateNetwork", var_dict),
1078 G_DBUS_CALL_FLAGS_NONE,
1081 WMESH_LOGD("Successfully requested. [MeshCreateNetwork]");
1083 WMESH_LOGE("Failed DBus call [%s]", error->message);
1084 g_error_free(error);
1085 return WMESHD_ERROR_IO_ERROR;
1088 return WMESHD_ERROR_NONE;
1091 int wmesh_gdbus_set_passphrase(wmesh_service *service, wmesh_scan_result_s *info, gchar *passphrase)
1093 GVariant *variant = NULL;
1094 GError *error = NULL;
1096 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1097 wmeshd_check_null_ret_error("passphrase", passphrase, WMESHD_ERROR_INVALID_PARAMETER);
1099 variant = g_dbus_connection_call_sync(service->connection,
1100 CONNMAN_SERVER_NAME,
1102 CONNMAN_INTERFACE_MESH,
1104 g_variant_new("(sv)", "Passphrase", g_variant_new_string(passphrase)),
1106 G_DBUS_CALL_FLAGS_NONE,
1109 WMESH_LOGD("Successfully requested. [SetProperty]");
1111 WMESH_LOGE("Failed DBus call [%s]", error->message);
1112 g_error_free(error);
1113 return WMESHD_ERROR_IO_ERROR;
1116 return WMESHD_ERROR_NONE;
1120 static void on_response_connect_network(GObject *source_object,
1121 GAsyncResult *res, gpointer user_data)
1123 int ret = WMESHD_ERROR_NONE;
1124 GError *error = NULL;
1125 GVariant *variant = NULL;
1129 variant = g_dbus_connection_call_finish(
1130 G_DBUS_CONNECTION(source_object), res, &error);
1132 WMESH_LOGD("Successfully requested. [Connect]");
1134 /* TODO: Unregister property change event */
1136 ret = WMESHD_ERROR_IO_ERROR;
1137 LOGE("Failed DBus call [%s]", error->message);
1139 if (g_strrstr(error->message, "Already exists"))
1140 ret = WMESHD_ERROR_ALREADY_REGISTERED;
1141 else if (g_strrstr(error->message, "In progress"))
1142 ret = WMESHD_ERROR_IN_PROGRESS;
1144 ret = WMESHD_ERROR_IO_ERROR;
1146 g_error_free(error);
1151 int wmesh_gdbus_connect_network(wmesh_service *service, wmesh_scan_result_s *info)
1153 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1154 wmeshd_check_null_ret_error("info", info, WMESHD_ERROR_INVALID_PARAMETER);
1156 g_dbus_connection_call(service->connection,
1157 CONNMAN_SERVER_NAME,
1159 CONNMAN_INTERFACE_MESH,
1162 G_DBUS_CALL_FLAGS_NONE,
1164 NULL, /* G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED */
1166 WMESH_LOGD("Successfully requested. [Connect]");
1168 return WMESHD_ERROR_NONE;
1171 int wmesh_gdbus_disconnect_network(wmesh_service *service, wmesh_scan_result_s *info)
1173 GVariant *variant = NULL;
1174 GError *error = NULL;
1176 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1177 wmeshd_check_null_ret_error("info", info, WMESHD_ERROR_INVALID_PARAMETER);
1179 variant = g_dbus_connection_call_sync(service->connection,
1180 CONNMAN_SERVER_NAME,
1182 CONNMAN_INTERFACE_MESH,
1185 G_DBUS_CALL_FLAGS_NONE,
1188 WMESH_LOGD("Successfully requested. [Disconnect]");
1190 WMESH_LOGE("Failed DBus call [%s]", error->message);
1191 g_error_free(error);
1192 return WMESHD_ERROR_IO_ERROR;
1195 return WMESHD_ERROR_NONE;
1198 int wmesh_gdbus_remove_network(wmesh_service *service, wmesh_scan_result_s *info)
1200 GVariant *variant = NULL;
1201 GError *error = NULL;
1203 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1204 wmeshd_check_null_ret_error("info", info, WMESHD_ERROR_INVALID_PARAMETER);
1206 variant = g_dbus_connection_call_sync(service->connection,
1207 CONNMAN_SERVER_NAME,
1209 CONNMAN_INTERFACE_MESH,
1212 G_DBUS_CALL_FLAGS_NONE,
1215 WMESH_LOGD("Successfully requested. [Remove]");
1217 WMESH_LOGE("Failed DBus call [%s]", error->message);
1218 g_error_free(error);
1219 return WMESHD_ERROR_IO_ERROR;
1222 return WMESHD_ERROR_NONE;
1226 int wmesh_gdbus_enable_ethernet_interface(wmesh_service *service, bool state)
1228 int ret = WMESHD_ERROR_NONE;
1229 GVariant *variant = NULL;
1230 GError *error = NULL;
1231 wmesh_interface_s *info = NULL;
1233 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1234 wmeshd_check_null_ret_error("connection", service->connection,
1235 WMESHD_ERROR_INVALID_PARAMETER);
1236 wmeshd_check_null_ret_error("_gproxy_connman_technology",
1237 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
1239 info = service->interface_info;
1240 wmeshd_check_null_ret_error("info", info, WMESHD_ERROR_INVALID_PARAMETER);
1242 variant = g_dbus_proxy_call_sync(_gproxy_connman_ethernet, "SetProperty",
1243 g_variant_new("(sv)", "Powered", g_variant_new_boolean(state)),
1244 G_DBUS_CALL_FLAGS_NONE,
1247 WMESH_LOGD("Successfully requested. [Powered]");
1249 ret = WMESHD_ERROR_IO_ERROR;
1250 WMESH_LOGE("Failed DBus call [%s]", error->message);
1252 /* Interface not exists (Not created yet) */
1253 if (g_strrstr(error->message, "No such device"))
1254 ret = WMESHD_ERROR_NONE;
1255 g_error_free(error);
1261 int wmesh_gdbus_set_mesh_gate(wmesh_service *service)
1263 int ret = WMESHD_ERROR_NONE;
1264 GVariant *variant = NULL;
1265 GError *error = NULL;
1266 GVariant *var_dict = NULL;
1268 wmesh_interface_s *info = NULL;
1270 wmeshd_check_null_ret_error("service", service, WMESHD_ERROR_INVALID_PARAMETER);
1271 wmeshd_check_null_ret_error("connection", service->connection,
1272 WMESHD_ERROR_INVALID_PARAMETER);
1273 wmeshd_check_null_ret_error("_gproxy_connman_technology",
1274 _gproxy_connman_technology, WMESHD_ERROR_IO_ERROR);
1276 info = service->interface_info;
1278 g_variant_dict_init(&dict, NULL);
1279 g_variant_dict_insert(&dict, "GateAnnounce", "b", info->gate_announce);
1280 g_variant_dict_insert(&dict, "HWMPRootMode", "q", info->hwmp_root_mode);
1281 g_variant_dict_insert(&dict, "STP", "q", info->stp);
1282 var_dict = g_variant_dict_end(&dict);
1284 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
1285 g_variant_new("(sv)", "SetMeshGate", var_dict),
1286 G_DBUS_CALL_FLAGS_NONE,
1289 WMESH_LOGD("Successfully requested. [SetMeshGate]");
1291 ret = WMESHD_ERROR_IO_ERROR;
1292 WMESH_LOGE("Failed DBus call [%s]", error->message);
1294 /* Interface not exists */
1295 if (g_strrstr(error->message, "No such device"))
1296 ret = WMESHD_ERROR_INVALID_PARAMETER;
1297 g_error_free(error);
1303 int wmesh_gdbus_mesh_remove_peer(wmesh_service *service, char *peer)
1305 GVariant *variant = NULL;
1306 GError *error = NULL;
1307 int ret = WMESHD_ERROR_NONE;
1309 wmeshd_check_null_ret_error("service", service,
1310 WMESHD_ERROR_INVALID_PARAMETER);
1311 wmeshd_check_null_ret_error("connection", service->connection,
1312 WMESHD_ERROR_INVALID_PARAMETER);
1313 wmeshd_check_null_ret_error("_gproxy_connman",
1314 _gproxy_connman, WMESHD_ERROR_IO_ERROR);
1316 variant = g_dbus_proxy_call_sync(_gproxy_connman, "MeshRemovePeer",
1317 g_variant_new("(s)", peer), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
1320 WMESH_LOGD("Successfully requested. [MeshRemovePeer]");
1322 ret = WMESHD_ERROR_IO_ERROR;
1323 WMESH_LOGE("Failed DBus call [%s]", error->message);
1325 /* Interface not exists */
1326 if (g_strrstr(error->message, "No such device"))
1327 ret = WMESHD_ERROR_INVALID_PARAMETER;
1328 g_error_free(error);