Add test scan request & async result receiver
[platform/core/connectivity/wifi-mesh-manager.git] / src / mesh-service-interface.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include <stdlib.h>
20
21 #include <glib.h>
22 #include <gio/gio.h>
23
24 #include "mesh.h"
25 #include "mesh-log.h"
26 #include "mesh-util.h"
27 #include "mesh-service-interface.h"
28 #include "mesh-generated-code.h"
29
30 #include "mesh-request.h"
31 #include "mesh-interface.h"
32
33 static NetMesh *meshd_dbus_object;
34
35 /* global list to care resource handle for each client */
36 static GList *meshd_dbus_client_list;
37 static GMutex meshd_dbus_client_list_mutex;
38
39 typedef struct _meshd_dbus_client_s {
40         gchar *bus_name;
41 } meshd_dbus_client_s;
42
43 NetMesh* meshd_dbus_get_object()
44 {
45         return meshd_dbus_object;
46 }
47
48 int64_t meshd_dbus_generate_signal_number()
49 {
50         static int64_t i = 0;
51
52         return i++;
53 }
54
55 static int _meshd_dbus_client_list_cleanup(GList *client_list)
56 {
57         meshd_dbus_client_s *client;
58
59         meshd_check_null_ret_error("client_list", client_list, FALSE);
60
61         client = client_list->data;
62
63         free(client->bus_name);
64         client->bus_name = NULL;
65         free(client);
66         g_list_free(client_list);
67
68         return MESHD_ERROR_NONE;
69 }
70
71 static int _meshd_dbus_client_list_compare_bus_name(const void *a, const void *b)
72 {
73         const meshd_dbus_client_s *client = a;
74
75         return g_strcmp0(client->bus_name, b);
76 }
77
78 static inline GList* _meshd_dbus_client_list_find_client(const gchar *owner)
79 {
80         return g_list_find_custom(meshd_dbus_client_list, owner,
81                         _meshd_dbus_client_list_compare_bus_name);
82 }
83
84 static void _meshd_dbus_name_owner_changed_cb(GDBusConnection *conn,
85                 const gchar *sender_name,
86                 const gchar *object_path,
87                 const gchar *interface_name,
88                 const gchar *signal_name,
89                 GVariant *parameters,
90                 gpointer user_data)
91 {
92         int ret;
93         GList *client = NULL;
94         gchar *name, *old_owner, *new_owner;
95
96         NOTUSED(conn);
97         NOTUSED(sender_name);
98         NOTUSED(object_path);
99         NOTUSED(interface_name);
100         NOTUSED(signal_name);
101         NOTUSED(user_data);
102
103         g_variant_get(parameters, "(&s&s&s)", &name, &old_owner, &new_owner);
104
105         if (0 == strlen(new_owner)) {
106                 g_mutex_lock(&meshd_dbus_client_list_mutex);
107                 client = _meshd_dbus_client_list_find_client(old_owner);
108                 if (client) { /* found bus name in our bus list */
109                         MESH_LOGD("bus(%s) stopped", old_owner);
110                         meshd_dbus_client_list = g_list_remove_link(meshd_dbus_client_list, client);
111                 }
112                 g_mutex_unlock(&meshd_dbus_client_list_mutex);
113
114                 if (client) {
115                         ret = _meshd_dbus_client_list_cleanup(client);
116                         if (MESHD_ERROR_NONE != ret)
117                                 MESH_LOGE("_meshd_dbus_client_list_cleanup() Fail(%d)", ret);
118                 }
119         }
120 }
121
122 static int _meshd_dbus_subscribe_name_owner_changed(GDBusConnection *conn)
123 {
124         unsigned int id;
125
126         id = g_dbus_connection_signal_subscribe(conn,
127                         "org.freedesktop.DBus", /* bus name */
128                         "org.freedesktop.DBus", /* interface */
129                         "NameOwnerChanged", /* member */
130                         "/org/freedesktop/DBus", /* path */
131                         NULL, /* arg0 */
132                         G_DBUS_SIGNAL_FLAGS_NONE,
133                         _meshd_dbus_name_owner_changed_cb,
134                         NULL,
135                         NULL);
136         if (0 == id) {
137                 MESH_LOGE("g_dbus_connection_signal_subscribe() Fail");
138                 return MESHD_ERROR_IO_ERROR;
139         }
140
141         return MESHD_ERROR_NONE;
142 }
143
144 static gboolean _meshd_dbus_handle_enable(NetMesh *object,
145                 GDBusMethodInvocation *invocation,
146                 gpointer user_data)
147 {
148         int ret = MESHD_ERROR_NONE;
149         mesh_service *service = (mesh_service *)user_data;
150         mesh_interface_s *info = service->interface_info;
151
152         if (service->mesh_activated) {
153                 /* Already activated */
154                 net_mesh_complete_enable(object, invocation,
155                                 MESHD_ERROR_OPERATION_FAILED);
156         } else {
157                 /* Do API response first */
158                 net_mesh_complete_enable(object, invocation, ret);
159                 service->mesh_activated = TRUE;
160         }
161
162         meshd_check_null_ret_error("info", info, FALSE);
163
164         ret = mesh_interface_initialize(service->interface_info);
165         if (MESHD_ERROR_NONE != ret) {
166                 MESH_LOGE("Failed to mesh_interface_initialize [%d]", ret);
167                 goto FINISH;
168         }
169
170         ret = mesh_request_enable_mesh_gate(info->base_interface,
171                         info->mesh_interface, info->mesh_id, info->mesh_channel);
172         if (MESHD_ERROR_NONE != ret) {
173                 MESH_LOGE("Failed to mesh_request_enable_mesh_gate [%d]", ret);
174                 goto FINISH;
175         }
176
177         ret = mesh_request_create_bridge(info->bridge_interface,
178                         info->mesh_interface, info->external_interface);
179         if (MESHD_ERROR_NONE != ret) {
180                 MESH_LOGE("Failed to mesh_request_create_bridge [%d]", ret);
181                 goto FINISH;
182         }
183 #if 0
184         ret = mesh_request_specific_scan(info->mesh_interface,
185                         info->mesh_id, info->mesh_channel);
186         if (MESHD_ERROR_NONE != ret) {
187                 MESH_LOGE("Failed to mesh_request_specific_scan [%d]", ret);
188         }
189
190         ret = mesh_request_dhcp(info->bridge_interface);
191         if (MESHD_ERROR_NONE != ret) {
192                 MESH_LOGE("Failed to mesh_request_dhcp [%d]", ret);
193         }
194 #endif
195
196 FINISH:
197         net_mesh_emit_mesh_enabled(object, ret);
198
199         return TRUE;
200 }
201
202 static gboolean _meshd_dbus_handle_disable(NetMesh *object,
203                 GDBusMethodInvocation *invocation,
204                 gpointer user_data)
205 {
206         int ret = MESHD_ERROR_NONE;
207         mesh_service *service = (mesh_service *)user_data;
208         mesh_interface_s *info = service->interface_info;
209
210         meshd_check_null_ret_error("info", info, FALSE);
211
212         if (FALSE == service->mesh_activated) {
213                 MESH_LOGD("Mesh network is not activated yet");
214                 ret = MESHD_ERROR_OPERATION_FAILED;
215                 goto FINISH;
216         }
217
218         ret = mesh_request_disable_mesh_gate(info->mesh_interface);
219         if (MESHD_ERROR_NONE != ret) {
220                 MESH_LOGE("Failed to mesh_request_disable_mesh_gate");
221                 goto FINISH;
222         }
223
224         ret = mesh_request_remove_bridge(info->bridge_interface);
225         if (MESHD_ERROR_NONE != ret) {
226                 MESH_LOGE("Failed to mesh_request_remove_bridge");
227         }
228
229 FINISH:
230         net_mesh_complete_disable(object, invocation, ret);
231
232         return TRUE;
233 }
234
235 static gboolean _meshd_dbus_handle_set_mesh_gate(NetMesh *object,
236                 GDBusMethodInvocation *invocation,
237                 gboolean state,
238                 gpointer user_data)
239 {
240         int ret = MESHD_ERROR_NONE;
241
242         MESH_LOGD("Not implemented yet !");
243         NOTUSED(state);
244         NOTUSED(user_data);
245
246         /* TODO: Check external interface and set it into bridge */
247
248         net_mesh_complete_set_mesh_gate(object, invocation, ret);
249
250         return TRUE;
251 }
252
253 static gboolean _meshd_dbus_handle_set_mesh_softap(NetMesh *object,
254                 GDBusMethodInvocation *invocation,
255                 gboolean state,
256                 gpointer user_data)
257 {
258         int ret = MESHD_ERROR_NONE;
259
260         MESH_LOGD("Not implemented yet !");
261         NOTUSED(state);
262         NOTUSED(user_data);
263
264         /* TODO: Check softAP interface and execute it */
265
266         net_mesh_complete_set_mesh_softap(object, invocation, ret);
267
268         return TRUE;
269 }
270
271 static gboolean _meshd_dbus_handle_scan(NetMesh *object,
272                 GDBusMethodInvocation *invocation,
273                 gpointer user_data)
274 {
275         int ret = MESHD_ERROR_NONE;
276         mesh_service *service = (mesh_service *)user_data;
277         mesh_interface_s *info = service->interface_info;
278
279         meshd_check_null_ret_error("info", info, FALSE);
280
281         ret = mesh_request_scan(info->mesh_interface);
282         if (MESHD_ERROR_NONE != ret) {
283                 MESH_LOGE("Failed to mesh_request_scan");
284         }
285
286         net_mesh_complete_scan(object, invocation, ret);
287
288         return TRUE;
289 }
290
291 static gboolean _meshd_dbus_handle_specific_scan(NetMesh *object,
292                 GDBusMethodInvocation *invocation,
293                 gchar *mesh_id,
294                 gint channel,
295                 gpointer user_data)
296 {
297         int ret = MESHD_ERROR_NONE;
298         mesh_service *service = (mesh_service *)user_data;
299         mesh_interface_s *info = service->interface_info;
300
301         meshd_check_null_ret_error("info", info, FALSE);
302
303         ret = mesh_request_specific_scan(info->mesh_interface, mesh_id, channel);
304         if (MESHD_ERROR_NONE != ret) {
305                 MESH_LOGE("Failed to mesh_request_specific_scan");
306         }
307
308         net_mesh_complete_specific_scan(object, invocation, ret);
309
310         return TRUE;
311 }
312
313 static gboolean _meshd_dbus_handle_cancel_scan(NetMesh *object,
314                 GDBusMethodInvocation *invocation,
315                 gpointer user_data)
316 {
317         int ret = MESHD_ERROR_NONE;
318         mesh_service *service = (mesh_service *)user_data;
319         mesh_interface_s *info = service->interface_info;
320
321         ret = mesh_request_cancel_scan(info->mesh_interface);
322         if (MESHD_ERROR_NONE != ret) {
323                 MESH_LOGE("Failed to mesh_request_cancel_scan");
324         }
325
326         net_mesh_complete_cancel_scan(object, invocation, ret);
327
328         return TRUE;
329 }
330
331 static gboolean _meshd_dbus_handle_get_station_info(NetMesh *object,
332                 GDBusMethodInvocation *invocation)
333 {
334         int ret = MESHD_ERROR_NONE;
335
336         NOTUSED(ret);
337         NOTUSED(object);
338         NOTUSED(invocation);
339
340         MESH_LOGD("Not implemented yet !");
341         //net_mesh_complete_get_station_info(object, invocation, ret);
342
343         return TRUE;
344 }
345
346 static gboolean _meshd_dbus_handle_get_mpath_info(NetMesh *object,
347                 GDBusMethodInvocation *invocation)
348 {
349         int ret = MESHD_ERROR_NONE;
350
351         NOTUSED(ret);
352         NOTUSED(object);
353         NOTUSED(invocation);
354
355         MESH_LOGD("Not implemented yet !");
356         //net_mesh_complete_get_mpath_info(object, invocation, ret);
357
358         return TRUE;
359 }
360
361 static gboolean _meshd_dbus_handle_join(NetMesh *object,
362                 GDBusMethodInvocation *invocation)
363 {
364         int ret = MESHD_ERROR_NONE;
365
366         MESH_LOGD("Not implemented yet !");
367         net_mesh_complete_join(object, invocation, ret);
368
369         return TRUE;
370 }
371
372 static gboolean _meshd_dbus_handle_is_joined(NetMesh *object,
373                 GDBusMethodInvocation *invocation)
374 {
375         int ret = MESHD_ERROR_NONE;
376
377         MESH_LOGD("Not implemented yet !");
378         net_mesh_complete_is_joined(object, invocation, ret);
379
380         return TRUE;
381 }
382
383 static gboolean _meshd_dbus_handle_disjoin(NetMesh *object,
384                 GDBusMethodInvocation *invocation)
385 {
386         int ret = MESHD_ERROR_NONE;
387
388         //MESH_LOGD("Not implemented yet !");
389
390         ret = mesh_request_test();
391         MESH_LOGD("TEST requested [%d]", ret);
392
393         net_mesh_complete_disjoin(object, invocation, ret);
394
395         return TRUE;
396 }
397
398 static gboolean _meshd_dbus_handle_load_softap_settings(NetMesh *object,
399                 GDBusMethodInvocation *invocation)
400 {
401         int ret = MESHD_ERROR_NONE;
402
403         MESH_LOGD("Not implemented yet !");
404         net_mesh_complete_load_softap_settings(object, invocation, ret);
405
406         return TRUE;
407 }
408
409 static gboolean _meshd_dbus_handle_start_bridge(NetMesh *object,
410                 GDBusMethodInvocation *invocation,
411                 gint mode,
412                 gchar *bridge_interface,
413                 gpointer user_data)
414 {
415         int ret = MESHD_ERROR_NONE;
416
417         NOTUSED(user_data);
418
419         MESH_LOGD("Mode : %d", mode);
420         MESH_LOGD("Interface : %s", bridge_interface);
421         ret = mesh_request_create_bridge(bridge_interface, NULL, NULL);
422
423         net_mesh_complete_start_bridge(object, invocation, ret);
424
425         return TRUE;
426 }
427
428 static gboolean _meshd_dbus_handle_stop_bridge(NetMesh *object,
429                 GDBusMethodInvocation *invocation,
430                 gchar *bridge_interface,
431                 gpointer user_data)
432 {
433         int ret = MESHD_ERROR_NONE;
434
435         NOTUSED(user_data);
436
437         MESH_LOGD("Interface : %s", bridge_interface);
438         ret = mesh_request_remove_bridge(bridge_interface);
439
440         net_mesh_complete_stop_bridge(object, invocation, ret);
441
442         return TRUE;
443 }
444
445
446 static void _meshd_dbus_on_bus_acquired(GDBusConnection *conn, const gchar *name,
447                 gpointer user_data)
448 {
449         gboolean ret;
450         GError *error = NULL;
451         mesh_service *service = (mesh_service *)user_data;
452
453         NOTUSED(name);
454
455         meshd_dbus_object = net_mesh_skeleton_new();
456         if (NULL == meshd_dbus_object) {
457                 MESH_LOGE("net_mesh_skeleton_new() Fail");
458                 return;
459         }
460
461         g_signal_connect(meshd_dbus_object, "handle-enable",
462                         G_CALLBACK(_meshd_dbus_handle_enable), service);
463         g_signal_connect(meshd_dbus_object, "handle-disable",
464                         G_CALLBACK(_meshd_dbus_handle_disable), service);
465         g_signal_connect(meshd_dbus_object, "handle-set-mesh-gate",
466                         G_CALLBACK(_meshd_dbus_handle_set_mesh_gate), service);
467         g_signal_connect(meshd_dbus_object, "handle-set-mesh-softap",
468                         G_CALLBACK(_meshd_dbus_handle_set_mesh_softap), service);
469         g_signal_connect(meshd_dbus_object, "handle-scan",
470                         G_CALLBACK(_meshd_dbus_handle_scan), service);
471         g_signal_connect(meshd_dbus_object, "handle-specific-scan",
472                         G_CALLBACK(_meshd_dbus_handle_specific_scan), service);
473         g_signal_connect(meshd_dbus_object, "handle-cancel-scan",
474                         G_CALLBACK(_meshd_dbus_handle_cancel_scan), service);
475         g_signal_connect(meshd_dbus_object, "handle-get-station-info",
476                         G_CALLBACK(_meshd_dbus_handle_get_station_info), service);
477         g_signal_connect(meshd_dbus_object, "handle-get-mpath-info",
478                         G_CALLBACK(_meshd_dbus_handle_get_mpath_info), service);
479         g_signal_connect(meshd_dbus_object, "handle-join",
480                         G_CALLBACK(_meshd_dbus_handle_join), service);
481         g_signal_connect(meshd_dbus_object, "handle-is-joined",
482                         G_CALLBACK(_meshd_dbus_handle_is_joined), service);
483         g_signal_connect(meshd_dbus_object, "handle-disjoin",
484                         G_CALLBACK(_meshd_dbus_handle_disjoin), service);
485         g_signal_connect(meshd_dbus_object, "handle-load-softap-settings",
486                         G_CALLBACK(_meshd_dbus_handle_load_softap_settings), service);
487         g_signal_connect(meshd_dbus_object, "handle-start-bridge",
488                         G_CALLBACK(_meshd_dbus_handle_start_bridge), service);
489         g_signal_connect(meshd_dbus_object, "handle-stop-bridge",
490                         G_CALLBACK(_meshd_dbus_handle_stop_bridge), service);
491
492         ret = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(meshd_dbus_object),
493                         conn, MESH_DBUS_OBJPATH, &error);
494         if (FALSE == ret) {
495                 MESH_LOGE("g_dbus_interface_skeleton_export() Fail(%s)", error->message);
496                 g_error_free(error);
497         }
498
499         ret = _meshd_dbus_subscribe_name_owner_changed(conn);
500         if (MESHD_ERROR_NONE != ret) {
501                 MESH_LOGE("_meshd_dbus_subscribe_name_owner_changed() Fail(%d)", ret);
502                 return;
503         }
504 }
505
506 static void _meshd_dbus_on_name_lost(GDBusConnection *conn, const gchar *name,
507                 gpointer user_data)
508 {
509         NOTUSED(conn);
510         NOTUSED(user_data);
511
512         MESH_LOGD("Lost the name %s", name);
513 }
514
515 static void _meshd_dbus_on_name_acquired(GDBusConnection *conn, const gchar *name,
516                 gpointer user_data)
517 {
518         NOTUSED(conn);
519         NOTUSED(user_data);
520
521         MESH_LOGD("Acquired the name %s", name);
522 }
523
524 static gboolean _meshd_dbus_interface_init(mesh_service *service)
525 {
526         guint id;
527         meshd_check_null_ret_error("service", service, FALSE);
528
529         id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
530                         MESH_DBUS_INTERFACE,
531                         G_BUS_NAME_OWNER_FLAGS_REPLACE,
532                         _meshd_dbus_on_bus_acquired,
533                         _meshd_dbus_on_name_acquired,
534                         _meshd_dbus_on_name_lost,
535                         service,
536                         NULL);
537         if (0 == id) {
538                 MESH_LOGE("g_bus_own_name() Fail");
539                 return FALSE;
540         }
541
542         service->dbus_id = id;
543         service->interface_info = g_new0(mesh_interface_s, 1);
544
545         return TRUE;
546 }
547
548 static void _meshd_dbus_deinit(mesh_service *service)
549 {
550         mesh_interface_s *info = NULL;
551         meshd_check_null_ret("service", service);
552
553         g_bus_unown_name(service->dbus_id);
554
555         info = service->interface_info;
556         meshd_check_null_ret("info", info);
557         if (info->bridge_interface)
558                 g_free(info->bridge_interface);
559         if (info->base_interface)
560                 g_free(info->base_interface);
561         if (info->mesh_interface)
562                 g_free(info->mesh_interface);
563         if (info->softap_interface)
564                 g_free(info->softap_interface);
565         if (info->external_interface)
566                 g_free(info->external_interface);
567
568         g_free(service->interface_info);
569         service->interface_info = NULL;
570 }
571
572  /**< mesh service interface initialization */
573 gboolean meshd_service_interface_init(mesh_service *service)
574 {
575         guint ret;
576         meshd_check_null_ret_error("service", service, FALSE);
577
578         /* Initialize dbus interface */
579         ret = _meshd_dbus_interface_init(service);
580         if (FALSE == ret) {
581                 MESH_LOGE("zigbee_service_dbus_interface_init failed!!!");
582                 return FALSE;
583         }
584
585         return TRUE;
586 }
587
588 /**< Zigbee service interface de-initialization */
589 void meshd_service_interface_deinit(mesh_service *service)
590 {
591         meshd_check_null_ret("service", service);
592
593         /* De-initialize dbus interface */
594         _meshd_dbus_deinit(service);
595 }