--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mesh-log.h"
+#include "mesh-util.h"
+#include "mesh-gdbus.h"
+
+static GDBusProxy *_gproxy_connman = NULL;
+static GDBusProxy *_gproxy_connman_mesh = NULL;
+static GDBusProxy *_gproxy_connman_technology = NULL;
+
+static int _meshd_close_gdbus_call(mesh_service *service);
+
+static GDBusProxy *_proxy_get_connman(mesh_service *service)
+{
+ GDBusProxy *proxy = NULL;
+ meshd_check_null_ret_error("service", service, NULL);
+
+ if (NULL == _gproxy_connman) {
+ proxy = g_dbus_proxy_new_sync(service->connection,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ CONNMAN_SERVER_NAME,
+ CONNMAN_OBJECT_PATH,
+ CONNMAN_INTERFACE_MANAGER,
+ NULL, NULL);
+ } else
+ proxy = _gproxy_connman;
+
+ return proxy;
+}
+
+static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
+{
+ GDBusProxy *proxy = NULL;
+ meshd_check_null_ret_error("service", service, NULL);
+
+ if (NULL == _gproxy_connman_mesh) {
+ proxy = g_dbus_proxy_new_sync(service->connection,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ CONNMAN_SERVER_NAME,
+ CONNMAN_OBJECT_PATH_MESH,
+ CONNMAN_INTERFACE_MESH,
+ NULL, NULL);
+ } else
+ proxy = _gproxy_connman_mesh;
+
+ return proxy;
+}
+
+static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
+{
+ GDBusProxy *proxy = NULL;
+ meshd_check_null_ret_error("service", service, NULL);
+
+ if (NULL == _gproxy_connman_technology) {
+ proxy = g_dbus_proxy_new_sync(service->connection,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ CONNMAN_SERVER_NAME,
+ CONNMAN_OBJECT_PATH_TECH_MESH,
+ CONNMAN_INTERFACE_TECH,
+ NULL, NULL);
+ } else
+ proxy = _gproxy_connman_technology;
+
+ return proxy;
+}
+
+static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
+ gpointer *user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY(object);
+ gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
+ mesh_service *service = (mesh_service*)user_data;
+
+ NOTUSED(pspec);
+
+ if (NULL == name_owner) {
+ MESH_LOGE("name_owner is not exists !");
+ _meshd_close_gdbus_call(service);
+ }
+
+ g_free(name_owner);
+}
+
+static int _meshd_create_gdbus_call(mesh_service *service)
+{
+ int id;
+ GError *error = NULL;
+
+ if (NULL == service)
+ return MESHD_ERROR_INVALID_PARAMETER;
+
+ if (NULL != service->connection)
+ return MESHD_ERROR_ALREADY_REGISTERED;
+
+ service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (service->connection == NULL) {
+ if (error != NULL) {
+ MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
+ g_error_free(error);
+ }
+ return MESHD_ERROR_IO_ERROR;
+ }
+
+ id = g_signal_connect(service->connection, "notify::g-name-owner",
+ G_CALLBACK(_dbus_name_owner_notify), service);
+ if (0 == id) {
+ LOGE("g_signal_connect() Fail");
+ g_object_unref(service->connection);
+ service->connection = NULL;
+ return MESHD_ERROR_IO_ERROR;
+ }
+
+ return MESHD_ERROR_NONE;
+}
+
+static int _meshd_close_gdbus_call(mesh_service *service)
+{
+ /* CHECK: is connection ref count required? */
+ g_object_unref(service->connection);
+ service->connection = NULL;
+
+ return MESHD_ERROR_NONE;
+}
+
+static void _meshd_signal_handler(GDBusConnection *connection,
+ const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
+ const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+ mesh_service *service = (mesh_service*)user_data;
+
+ meshd_check_null_ret("user_data", user_data);
+ //meshd_check_null_ret("event_handler", service->event_handler);
+ NOTUSED(connection);
+ NOTUSED(sender_name);
+ NOTUSED(object_path);
+ NOTUSED(interface_name);
+ NOTUSED(signal_name);
+ NOTUSED(parameters);
+
+ NOTUSED(service);
+
+ LOGD("signal received = %s", signal_name);
+ if (0 == g_strcmp0(signal_name, "scan_done")) {
+ /* TODO: Handle event */
+ }
+}
+
+static void _meshd_subscribe_event(mesh_service *service)
+{
+ unsigned int id;
+
+ id = g_dbus_connection_signal_subscribe(
+ (GDBusConnection *)service->connection,
+ CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
+ "ScanDone", "/", NULL,
+ G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
+ if (0 == id) {
+ LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
+ return;
+ }
+ service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
+ LOGD("[Signal subscribe] : ScanDone (%d)", id);
+
+ /* End of subscription */
+}
+
+int meshd_dbus_start(mesh_service *service)
+{
+ int rv;
+
+ rv = _meshd_create_gdbus_call(service);
+ if (MESHD_ERROR_NONE != rv)
+ return rv;
+
+ service->ca = g_cancellable_new();
+
+ /* Create all required proxies here */
+ _gproxy_connman = _proxy_get_connman(service);
+ meshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
+ MESHD_ERROR_IO_ERROR);
+ g_dbus_proxy_set_default_timeout(
+ G_DBUS_PROXY(_gproxy_connman), MESH_DBUS_PROXY_TIMEOUT);
+
+ _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
+ meshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
+ MESHD_ERROR_IO_ERROR);
+ g_dbus_proxy_set_default_timeout(
+ G_DBUS_PROXY(_gproxy_connman_mesh), MESH_DBUS_PROXY_TIMEOUT);
+
+ _gproxy_connman_technology = _proxy_get_connman_technology(service);
+ meshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
+ MESHD_ERROR_IO_ERROR);
+ g_dbus_proxy_set_default_timeout(
+ G_DBUS_PROXY(_gproxy_connman_technology), MESH_DBUS_PROXY_TIMEOUT);
+
+ /* Subscribe events */
+ _meshd_subscribe_event(service);
+
+ return MESHD_ERROR_NONE;
+}
+
+int meshd_dbus_stop(mesh_service *service)
+{
+ int rv;
+
+ if (NULL == service)
+ return MESHD_ERROR_INVALID_PARAMETER;
+
+ /* Unref all proxies here */
+ if (_gproxy_connman) {
+ g_object_unref(_gproxy_connman);
+ _gproxy_connman = NULL;
+ }
+ if (_gproxy_connman_mesh) {
+ g_object_unref(_gproxy_connman_mesh);
+ _gproxy_connman_mesh = NULL;
+ }
+ if (_gproxy_connman_technology) {
+ g_object_unref(_gproxy_connman_technology);
+ _gproxy_connman_technology = NULL;
+ }
+
+ g_cancellable_cancel(service->ca);
+ g_object_unref(service->ca);
+ service->ca = NULL;
+
+ rv = _meshd_close_gdbus_call(service);
+ return rv;
+}
+
+int mesh_ipc_create_mesh_interface(mesh_service *service)
+{
+ GVariant *variant = NULL;
+ GError *error = NULL;
+ GVariant *var_dict = NULL;
+ GVariantDict dict;
+
+ meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
+ meshd_check_null_ret_error("connection", service->connection,
+ MESHD_ERROR_INVALID_PARAMETER);
+ meshd_check_null_ret_error("_gproxy_connman_technology",
+ _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
+
+ g_variant_dict_init(&dict, NULL);
+ g_variant_dict_insert(&dict, "Ifname", "s", "mesh0");
+ g_variant_dict_insert(&dict, "ParentIfname", "s", "wlan0");
+ g_variant_dict_insert(&dict, "BridgeIfname", "s", "br0");
+ var_dict = g_variant_dict_end(&dict);
+
+ variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
+ g_variant_new("sv", "MeshInterfaceAdd", var_dict),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, &error);
+ if (variant) {
+ MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
+ } else if (error) {
+ LOGE("Failed DBus call [%s]", error->message);
+ g_error_free(error);
+ return MESHD_ERROR_IO_ERROR;
+ }
+
+ return MESHD_ERROR_NONE;
+}
+
+#if 0
+struct mesh_network_list_s {
+ int count;
+ GList *list;
+};
+struct mesh_network_list_s g_networks;
+
+static void _mesh_free_network(gpointer data)
+{
+ struct mesh_network_s *network = data;
+ if (network) g_free(network);
+ network = NULL;
+}
+
+static void _mesh_append_network(gpointer data)
+{
+ g_networks.list = g_list_append(g_networks.list, data);
+ g_networks.count++;
+ LOGE("%dth item added", g_networks.count);
+}
+
+static void _mesh_remove_networks()
+{
+ if (g_networks.list)
+ g_list_free_full(g_networks.list, _mesh_free_network);
+ g_networks.list = NULL;
+ g_networks.count = 0;
+}
+
+static int _mesh_get_scan_result(mesh_h handle)
+{
+ GVariant *variant = NULL;
+ unsigned int result;
+ GError *error = NULL;
+ struct mesh_handle *h = handle;
+
+ GVariantIter *iter = NULL;
+ GVariantIter *iter_row = NULL;
+
+ gchar *key;
+ GVariant *val;
+ gsize len = 0;
+
+ /* Clear previous scan results */
+ _mesh_remove_networks();
+
+ RETV_IF(NULL == h->dbus_connection, MESH_ITNL_ERR_IO_ERROR);
+ RETV_IF(NULL == _gproxy_mesh_service, MESH_ITNL_ERR_IO_ERROR);
+
+ variant = g_dbus_proxy_call_sync(_gproxy_mesh_service, "get_found_mesh_networks",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, &error);
+ if (variant) {
+ g_variant_get(variant, "(aa{sv}u)", &iter, &result);
+ while (g_variant_iter_next(iter, "a{sv}", &iter_row)) {
+ struct mesh_network_s *network_info =
+ g_malloc0(sizeof(struct mesh_network_s));
+ while (g_variant_iter_loop(iter_row, "{sv}", &key, &val)) {
+ if (strcasecmp(key, "mesh_id") == 0) {
+ const char *buf = g_variant_get_string(val, &len);
+ memcpy(network_info->meshid, buf, len);
+ //LOGD("meshid=%s", network_info->meshid);
+ }
+ else if (strcasecmp(key, "bssid") == 0) {
+ const char *buf = g_variant_get_string(val, &len);
+ memcpy(network_info->bssid, buf, len);
+ //LOGD("bssid = %s", network_info->bssid);
+ }
+ else if (strcasecmp(key, "rssi") == 0) {
+ network_info->rssi = g_variant_get_int32(val);
+ //LOGD("rssi = %d", network_info->rssi);
+ }
+ else if (strcasecmp(key, "channel") == 0) {
+ network_info->channel = g_variant_get_uint32(val);
+ //LOGD("channel = %d", network_info->channel);
+
+ /* Last element */
+ _mesh_append_network(network_info);
+ }
+ }
+ g_variant_iter_free(iter_row);
+ }
+ g_variant_iter_free(iter);
+
+ } else if (error) {
+ LOGE("Failed DBus call [%s]", error->message);
+ g_error_free(error);
+ return MESH_ITNL_ERR_IO_ERROR;
+ }
+
+ return MESH_ITNL_ERR_NONE;
+}
+#endif