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 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
366 meshd_check_null_ret_error("connection", service->connection,
367 MESHD_ERROR_INVALID_PARAMETER);
368 meshd_check_null_ret_error("_gproxy_connman_technology",
369 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
371 g_dbus_proxy_call(_gproxy_connman_technology, "Scan",
373 G_DBUS_CALL_FLAGS_NONE,
374 -1, NULL, NULL, NULL);
376 MESH_LOGD("Successfully requested. [Scan]");
378 return MESHD_ERROR_NONE;
381 int mesh_ipc_mesh_specific_scan(mesh_service *service, gchar *mesh_id,
384 GVariant *variant = NULL;
385 GError *error = NULL;
386 GVariant *var_dict = NULL;
389 enum nl80211_band band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
390 gushort freq = __channel_to_frequency(channel, band);
392 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
393 meshd_check_null_ret_error("connection", service->connection,
394 MESHD_ERROR_INVALID_PARAMETER);
395 meshd_check_null_ret_error("_gproxy_connman_technology",
396 _gproxy_connman_technology, MESHD_ERROR_IO_ERROR);
398 g_variant_dict_init(&dict, NULL);
399 g_variant_dict_insert(&dict, "Name", "s", mesh_id);
400 g_variant_dict_insert(&dict, "Frequency", "q", freq);
401 var_dict = g_variant_dict_end(&dict);
403 variant = g_dbus_proxy_call_sync(_gproxy_connman_technology, "MeshCommands",
404 g_variant_new("(sv)", "MeshSpecificScan", var_dict),
405 G_DBUS_CALL_FLAGS_NONE,
408 MESH_LOGD("Successfully requested. [MeshSpecificScan]");
410 MESH_LOGE("Failed DBus call [%s]", error->message);
412 return MESHD_ERROR_IO_ERROR;
415 return MESHD_ERROR_NONE;
418 static void _on_scan_result_destroy(gpointer data)
420 mesh_scan_result_s *scan_item = (mesh_scan_result_s *)data;
423 g_free(scan_item->mesh_id);
424 g_free(scan_item->bssid);
425 g_free(scan_item->object_path);
429 static void _get_mesh_peers(mesh_service *service, GVariant *variant)
431 GVariantIter *peer = NULL;
432 GVariantIter *property = NULL;
434 GVariant *val = NULL;
437 gchar *var_string = NULL;
438 const gchar* obj_path = NULL;
440 g_variant_get(variant, "(a(oa{sv}))", &peer);
441 //while (g_variant_iter_next(peer, "oa{sv}", &tmp, &property)) {
442 while ((child = g_variant_iter_next_value(peer))) {
443 mesh_scan_result_s *scan_info = NULL;
445 scan_info = g_try_new0(mesh_scan_result_s, 1);
446 if (NULL == scan_info) {
447 MESH_LOGE("Failed to allocate !");
451 MESH_LOGD(" Child : [%s]", g_variant_get_type_string(child));
452 var_string = g_variant_print(child, FALSE);
453 MESH_LOGD(" %s", var_string);
456 g_variant_get(child, "(oa{sv})", &obj_path, &property);
457 if (NULL == obj_path) {
458 MESH_LOGE("Null object");
461 MESH_LOGD(" Obj path : [%s]", obj_path);
462 scan_info->object_path = g_strdup(obj_path);
464 while (g_variant_iter_loop(property, "{sv}", &key, &val)) {
465 if (strcasecmp(key, "Name") == 0) {
466 const char *buf = g_variant_get_string(val, &len);
467 scan_info->mesh_id = g_strdup(buf);
468 MESH_LOGD(" Mesh ID : %s", scan_info->mesh_id);
470 else if (strcasecmp(key, "Address") == 0) {
471 const char *buf = g_variant_get_string(val, &len);
472 scan_info->bssid = g_strdup(buf);
473 MESH_LOGD(" BSSID : %s", scan_info->bssid);
475 else if (strcasecmp(key, "Frequency") == 0) {
476 scan_info->channel = __frequency_to_channel(g_variant_get_uint16(val));
477 MESH_LOGD(" Channel : %d", scan_info->channel);
479 else if (strcasecmp(key, "Strength") == 0) {
480 scan_info->rssi = (gint)g_variant_get_byte(val);
481 MESH_LOGD(" RSSI : %d", scan_info->rssi);
484 service->scanned_mesh_network =
485 g_list_prepend(service->scanned_mesh_network, scan_info);
488 g_variant_iter_free(property);
490 g_variant_iter_free(peer);
493 int mesh_ipc_get_mesh_peers(mesh_service *service)
495 GVariant *variant = NULL;
496 GError *error = NULL;
498 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
499 meshd_check_null_ret_error("connection", service->connection,
500 MESHD_ERROR_INVALID_PARAMETER);
501 meshd_check_null_ret_error("_gproxy_connman",
502 _gproxy_connman, MESHD_ERROR_IO_ERROR);
504 variant = g_dbus_proxy_call_sync(_gproxy_connman, "GetMeshPeers",
506 G_DBUS_CALL_FLAGS_NONE,
509 MESH_LOGD("Successfully requested. [GetMeshPeers]");
511 if (service->scanned_mesh_network) {
512 g_list_free_full(service->scanned_mesh_network, _on_scan_result_destroy);
513 service->scanned_mesh_network = NULL;
516 _get_mesh_peers(service, variant);
518 /* List item is saved with reversed order for efficiency. */
519 service->scanned_mesh_network =
520 g_list_reverse(service->scanned_mesh_network);
522 MESH_LOGE("Failed DBus call [%s]", error->message);
524 return MESHD_ERROR_IO_ERROR;
527 return MESHD_ERROR_NONE;
530 int mesh_ipc_connect_network(mesh_service *service, mesh_scan_result_s *info)
532 GVariant *variant = NULL;
533 GError *error = NULL;
535 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
536 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
538 variant = g_dbus_connection_call_sync(service->connection,
541 CONNMAN_INTERFACE_MESH,
544 G_DBUS_CALL_FLAGS_NONE,
547 MESH_LOGD("Successfully requested. [Connect]");
549 LOGE("Failed DBus call [%s]", error->message);
551 return MESHD_ERROR_IO_ERROR;
554 return MESHD_ERROR_NONE;
557 int mesh_ipc_disconnect_network(mesh_service *service, mesh_scan_result_s *info)
559 GVariant *variant = NULL;
560 GError *error = NULL;
562 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
563 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
565 variant = g_dbus_connection_call_sync(service->connection,
568 CONNMAN_INTERFACE_MESH,
571 G_DBUS_CALL_FLAGS_NONE,
574 MESH_LOGD("Successfully requested. [Disconnect]");
576 LOGE("Failed DBus call [%s]", error->message);
578 return MESHD_ERROR_IO_ERROR;
581 return MESHD_ERROR_NONE;
584 int mesh_ipc_remove_network(mesh_service *service, mesh_scan_result_s *info)
586 GVariant *variant = NULL;
587 GError *error = NULL;
589 meshd_check_null_ret_error("service", service, MESHD_ERROR_INVALID_PARAMETER);
590 meshd_check_null_ret_error("info", info, MESHD_ERROR_INVALID_PARAMETER);
592 variant = g_dbus_connection_call_sync(service->connection,
595 CONNMAN_INTERFACE_MESH,
598 G_DBUS_CALL_FLAGS_NONE,
601 MESH_LOGD("Successfully requested. [Remove]");
603 LOGE("Failed DBus call [%s]", error->message);
605 return MESHD_ERROR_IO_ERROR;
608 return MESHD_ERROR_NONE;