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);
30 static int __channel_to_frequency(int channel, enum nl80211_band band)
36 case NL80211_BAND_2GHZ:
39 else if (channel < 14)
40 return 2407 + channel * 5;
42 case NL80211_BAND_5GHZ:
43 if (channel >= 182 && channel <= 196)
44 return 4000 + channel * 5;
46 return 5000 + channel * 5;
56 static int __frequency_to_channel(int freq)
61 return (freq - 2407) / 5;
62 else if (freq >= 4910 && freq <= 4980)
63 return (freq - 4000) / 5;
64 else if (freq <= 45000)
65 return (freq - 5000) / 5;
66 else if (freq >= 58320 && freq <= 64800)
67 return (freq - 56160) / 2160;
72 static GDBusProxy *_proxy_get_connman(mesh_service *service)
74 GDBusProxy *proxy = NULL;
75 meshd_check_null_ret_error("service", service, NULL);
77 if (NULL == _gproxy_connman) {
78 proxy = g_dbus_proxy_new_sync(service->connection,
79 G_DBUS_PROXY_FLAGS_NONE, NULL,
82 CONNMAN_INTERFACE_MANAGER,
85 proxy = _gproxy_connman;
90 static GDBusProxy *_proxy_get_connman_mesh(mesh_service *service)
92 GDBusProxy *proxy = NULL;
93 meshd_check_null_ret_error("service", service, NULL);
95 if (NULL == _gproxy_connman_mesh) {
96 proxy = g_dbus_proxy_new_sync(service->connection,
97 G_DBUS_PROXY_FLAGS_NONE, NULL,
99 CONNMAN_OBJECT_PATH_MESH,
100 CONNMAN_INTERFACE_MESH,
103 proxy = _gproxy_connman_mesh;
108 static GDBusProxy *_proxy_get_connman_technology(mesh_service *service)
110 GDBusProxy *proxy = NULL;
111 meshd_check_null_ret_error("service", service, NULL);
113 if (NULL == _gproxy_connman_technology) {
114 proxy = g_dbus_proxy_new_sync(service->connection,
115 G_DBUS_PROXY_FLAGS_NONE, NULL,
117 CONNMAN_OBJECT_PATH_TECH_MESH,
118 CONNMAN_INTERFACE_TECH,
121 proxy = _gproxy_connman_technology;
126 static void _dbus_name_owner_notify(GObject *object, GParamSpec *pspec,
129 GDBusProxy *proxy = G_DBUS_PROXY(object);
130 gchar *name_owner = g_dbus_proxy_get_name_owner(proxy);
131 mesh_service *service = (mesh_service*)user_data;
135 if (NULL == name_owner) {
136 MESH_LOGE("name_owner is not exists !");
137 _meshd_close_gdbus_call(service);
143 static int _meshd_create_gdbus_call(mesh_service *service)
146 GError *error = NULL;
149 return MESHD_ERROR_INVALID_PARAMETER;
151 if (NULL != service->connection)
152 return MESHD_ERROR_ALREADY_REGISTERED;
154 service->connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
155 if (service->connection == NULL) {
157 MESH_LOGE("Failed to connect to the D-BUS daemon [%s]", error->message);
160 return MESHD_ERROR_IO_ERROR;
163 id = g_signal_connect(service->connection, "notify::g-name-owner",
164 G_CALLBACK(_dbus_name_owner_notify), service);
166 MESH_LOGE("g_signal_connect() Fail");
167 g_object_unref(service->connection);
168 service->connection = NULL;
169 return MESHD_ERROR_IO_ERROR;
172 return MESHD_ERROR_NONE;
175 static int _meshd_close_gdbus_call(mesh_service *service)
177 /* CHECK: is connection ref count required? */
178 g_object_unref(service->connection);
179 service->connection = NULL;
181 return MESHD_ERROR_NONE;
184 static void _meshd_signal_handler(GDBusConnection *connection,
185 const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
186 const gchar *signal_name, GVariant *parameters, gpointer user_data)
188 mesh_service *service = (mesh_service*)user_data;
190 meshd_check_null_ret("user_data", user_data);
191 //meshd_check_null_ret("event_handler", service->event_handler);
193 NOTUSED(sender_name);
194 NOTUSED(object_path);
195 NOTUSED(interface_name);
196 NOTUSED(signal_name);
201 MESH_LOGD("signal received = %s", signal_name);
202 if (0 == g_strcmp0(signal_name, "ScanDone")) {
203 /* TODO: Handle event */
204 mesh_notify_scan_done();
208 static void _meshd_subscribe_event(mesh_service *service)
212 id = g_dbus_connection_signal_subscribe(
213 (GDBusConnection *)service->connection,
214 CONNMAN_SERVER_NAME, CONNMAN_INTERFACE_MANAGER,
215 "ScanDone", "/", NULL,
216 G_DBUS_CALL_FLAGS_NONE, _meshd_signal_handler, service, NULL);
218 MESH_LOGE("g_dbus_connection_signal_subscribe(ScanDone) Fail(%d)", errno);
221 service->dbus_sub_ids = g_list_append(service->dbus_sub_ids, GUINT_TO_POINTER(id));
222 MESH_LOGD("[Signal subscribe] : ScanDone (%d)", id);
224 /* End of subscription */
227 int meshd_dbus_start(mesh_service *service)
231 rv = _meshd_create_gdbus_call(service);
232 if (MESHD_ERROR_NONE != rv)
235 service->ca = g_cancellable_new();
237 /* Create all required proxies here */
238 _gproxy_connman = _proxy_get_connman(service);
239 meshd_check_null_ret_error("_gproxy_connman", _gproxy_connman,
240 MESHD_ERROR_IO_ERROR);
241 g_dbus_proxy_set_default_timeout(
242 G_DBUS_PROXY(_gproxy_connman), MESH_DBUS_PROXY_TIMEOUT);
244 _gproxy_connman_mesh = _proxy_get_connman_mesh(service);
245 meshd_check_null_ret_error("_gproxy_connman_mesh", _gproxy_connman_mesh,
246 MESHD_ERROR_IO_ERROR);
247 g_dbus_proxy_set_default_timeout(
248 G_DBUS_PROXY(_gproxy_connman_mesh), MESH_DBUS_PROXY_TIMEOUT);
250 _gproxy_connman_technology = _proxy_get_connman_technology(service);
251 meshd_check_null_ret_error("_gproxy_connman_technology", _gproxy_connman_technology,
252 MESHD_ERROR_IO_ERROR);
253 g_dbus_proxy_set_default_timeout(
254 G_DBUS_PROXY(_gproxy_connman_technology), MESH_DBUS_PROXY_TIMEOUT);
256 /* Subscribe events */
257 _meshd_subscribe_event(service);
259 return MESHD_ERROR_NONE;
262 int meshd_dbus_stop(mesh_service *service)
267 return MESHD_ERROR_INVALID_PARAMETER;
269 /* Unref all proxies here */
270 if (_gproxy_connman) {
271 g_object_unref(_gproxy_connman);
272 _gproxy_connman = NULL;
274 if (_gproxy_connman_mesh) {
275 g_object_unref(_gproxy_connman_mesh);
276 _gproxy_connman_mesh = NULL;
278 if (_gproxy_connman_technology) {
279 g_object_unref(_gproxy_connman_technology);
280 _gproxy_connman_technology = NULL;
283 g_cancellable_cancel(service->ca);
284 g_object_unref(service->ca);
287 rv = _meshd_close_gdbus_call(service);
291 int mesh_ipc_create_mesh_interface(mesh_service *service)
293 GVariant *variant = NULL;
294 GError *error = NULL;
295 GVariant *var_dict = NULL;
297 mesh_interface_s *info = NULL;
299 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
300 meshd_check_null_ret_error("connection", service->connection,
301 MESHD_ERROR_INVALID_PARAMETER);
302 meshd_check_null_ret_error("_gproxy_connman_technology",
303 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
305 info = service->interface_info;
307 g_variant_dict_init(&dict, NULL);
308 g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
309 g_variant_dict_insert(&dict, "ParentIfname", "s", info->base_interface);
310 g_variant_dict_insert(&dict, "BridgeIfname", "s", info->bridge_interface);
311 var_dict = g_variant_dict_end(&dict);
313 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
314 g_variant_new("(sv)", "MeshInterfaceAdd", var_dict),
315 G_DBUS_CALL_FLAGS_NONE,
318 MESH_LOGD("Successfully requested. [MeshInterfaceAdd]");
320 MESH_LOGE("Failed DBus call [%s]", error->message);
322 return MESHD_ERROR_IO_ERROR;
325 return MESHD_ERROR_NONE;
328 int mesh_ipc_remove_mesh_interface(mesh_service *service)
330 GVariant *variant = NULL;
331 GError *error = NULL;
332 GVariant *var_dict = NULL;
334 mesh_interface_s *info = NULL;
336 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
337 meshd_check_null_ret_error("connection", service->connection,
338 MESHD_ERROR_INVALID_PARAMETER);
339 meshd_check_null_ret_error("_gproxy_connman_technology",
340 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
342 info = service->interface_info;
344 g_variant_dict_init(&dict, NULL);
345 g_variant_dict_insert(&dict, "Ifname", "s", info->mesh_interface);
346 var_dict = g_variant_dict_end(&dict);
348 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
349 g_variant_new("(sv)", "MeshInterfaceRemove", var_dict),
350 G_DBUS_CALL_FLAGS_NONE,
353 MESH_LOGD("Successfully requested. [MeshInterfaceRemove]");
355 MESH_LOGE("Failed DBus call [%s]", error->message);
357 return MESHD_ERROR_IO_ERROR;
360 return MESHD_ERROR_NONE;
363 int mesh_ipc_mesh_scan(mesh_service *service)
365 GVariant *variant = NULL;
366 GError *error = NULL;
368 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
369 meshd_check_null_ret_error("connection", service->connection,
370 MESHD_ERROR_INVALID_PARAMETER);
371 meshd_check_null_ret_error("_gproxy_connman_technology",
372 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
374 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "Scan",
376 G_DBUS_CALL_FLAGS_NONE,
379 MESH_LOGD("Successfully requested. [Scan]");
381 MESH_LOGE("Failed DBus call [%s]", error->message);
383 return MESHD_ERROR_IO_ERROR;
386 return MESHD_ERROR_NONE;
389 int mesh_ipc_mesh_specific_scan(mesh_service *service, gchar *mesh_id,
392 GVariant *variant = NULL;
393 GError *error = NULL;
394 GVariant *var_dict = NULL;
397 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
398 gushort freq = __channel_to_frequency(channel, band);
400 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
401 meshd_check_null_ret_error("connection", service->connection,
402 MESHD_ERROR_INVALID_PARAMETER);
403 meshd_check_null_ret_error("_gproxy_connman_technology",
404 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
406 g_variant_dict_init(&dict, NULL);
407 g_variant_dict_insert(&dict, "Name", "s", mesh_id);
408 g_variant_dict_insert(&dict, "Frequency", "q", freq);
409 var_dict = g_variant_dict_end(&dict);
411 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
412 g_variant_new("(sv)", "MeshSpecificScan", var_dict),
413 G_DBUS_CALL_FLAGS_NONE,
416 MESH_LOGD("Successfully requested. [MeshSpecificScan]");
418 MESH_LOGE("Failed DBus call [%s]", error->message);
420 return MESHD_ERROR_IO_ERROR;
423 return MESHD_ERROR_NONE;
426 static void _on_scan_result_destroy(gpointer data)
428 mesh_scan_result_s *scan_item = (mesh_scan_result_s *)data;
431 g_free(scan_item->mesh_id);
432 g_free(scan_item->bssid);
433 g_free(scan_item->object_path);
437 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
439 GVariantIter *peer = NULL;
440 GVariantIter *property = NULL;
442 GVariant *val = NULL;
445 gchar *var_string = NULL;
446 const gchar* obj_path = NULL;
448 g_variant_get(variant, "(a(oa{sv}))", &peer);
449 //while (g_variant_iter_next(peer, "oa{sv}", &tmp, &property)) {
450 while ((child = g_variant_iter_next_value(peer))) {
451 mesh_scan_result_s *scan_info = NULL;
453 scan_info = g_try_new0(mesh_scan_result_s, 1);
454 if (NULL == scan_info) {
455 MESH_LOGE("Failed to allocate !");
459 MESH_LOGD(" Child : [%s]", g_variant_get_type_string(child));
460 var_string = g_variant_print(child, FALSE);
461 MESH_LOGD(" %s", var_string);
464 g_variant_get(child, "(oa{sv})", &obj_path, &property);
465 if (NULL == obj_path) {
466 MESH_LOGE("Null object");
469 MESH_LOGD(" Obj path : [%s]", obj_path);
470 scan_info->object_path = g_strdup(obj_path);
472 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
473 if (strcasecmp(key, "Name") == 0) {
474 const char *buf = g_variant_get_string(val, &len);
475 scan_info->mesh_id = g_strdup(buf);
476 MESH_LOGD(" Mesh ID : %s", scan_info->mesh_id);
478 else if (strcasecmp(key, "Address") == 0) {
479 const char *buf = g_variant_get_string(val, &len);
480 scan_info->bssid = g_strdup(buf);
481 MESH_LOGD(" BSSID : %s", scan_info->bssid);
483 else if (strcasecmp(key, "Frequency") == 0) {
484 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
485 MESH_LOGD(" Channel : %d", scan_info->channel);
487 else if (strcasecmp(key, "Strength") == 0) {
488 scan_info->rssi = (gint)g_variant_get_byte(val);
489 MESH_LOGD(" RSSI : %d", scan_info->rssi);
492 service->scanned_mesh_network =
493 g_list_prepend(service->scanned_mesh_network, scan_info);
496 g_variant_iter_free(property);
498 g_variant_iter_free(peer);
501 int mesh_ipc_get_mesh_peers(mesh_service *service)
503 GVariant *variant = NULL;
504 GError *error = NULL;
506 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
507 meshd_check_null_ret_error("connection", service->connection,
508 MESHD_ERROR_INVALID_PARAMETER);
509 meshd_check_null_ret_error("_gproxy_connman",
510 _gproxy_connman, MESHD_ERROR_IO_ERROR);
512 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
514 G_DBUS_CALL_FLAGS_NONE,
517 MESH_LOGD("Successfully requested. [GetMeshPeers]");
519 if (service->scanned_mesh_network) {
520 g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
521 service->scanned_mesh_network = NULL;
524 _get_mesh_peers(service, variant);
526 /* List item is saved with reversed order for efficiency. */
527 service->scanned_mesh_network =
528 g_list_reverse(service->scanned_mesh_network);
530 MESH_LOGE("Failed DBus call [%s]", error->message);
532 return MESHD_ERROR_IO_ERROR;
535 return MESHD_ERROR_NONE;
538 int mesh_ipc_connect_network(mesh_service *service, mesh_scan_result_s *info)
540 GVariant *variant = NULL;
541 GError *error = NULL;
543 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
544 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
546 variant = g_dbus_connection_call_sync(service->connection,
549 CONNMAN_INTERFACE_MESH,
552 G_DBUS_CALL_FLAGS_NONE,
555 MESH_LOGD("Successfully requested. [Connect]");
557 LOGE("Failed DBus call [%s]", error->message);
559 return MESHD_ERROR_IO_ERROR;
562 return MESHD_ERROR_NONE;
565 int mesh_ipc_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
567 GVariant *variant = NULL;
568 GError *error = NULL;
570 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
571 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
573 variant = g_dbus_connection_call_sync(service->connection,
576 CONNMAN_INTERFACE_MESH,
579 G_DBUS_CALL_FLAGS_NONE,
582 MESH_LOGD("Successfully requested. [Disconnect]");
584 LOGE("Failed DBus call [%s]", error->message);
586 return MESHD_ERROR_IO_ERROR;
589 return MESHD_ERROR_NONE;
592 int mesh_ipc_remove_network(mesh_service *service, mesh_scan_result_s *info)
594 GVariant *variant = NULL;
595 GError *error = NULL;
597 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
598 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
600 variant = g_dbus_connection_call_sync(service->connection,
603 CONNMAN_INTERFACE_MESH,
606 G_DBUS_CALL_FLAGS_NONE,
609 MESH_LOGD("Successfully requested. [Remove]");
611 LOGE("Failed DBus call [%s]", error->message);
613 return MESHD_ERROR_IO_ERROR;
616 return MESHD_ERROR_NONE;