[Bluetooth][OTP-Client] Handle GATT operations for OTP
[platform/core/connectivity/bluetooth-frwk.git] / bt-service / bt-service-otp.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <glib.h>
19 #include <gio/gio.h>
20 #include <dlog.h>
21 #include <string.h>
22 #include <syspopup_caller.h>
23 #include <vconf.h>
24 #include <bundle_internal.h>
25
26 #include "bluetooth-api.h"
27 #include "bt-internal-types.h"
28
29 #include "bt-service-common.h"
30 #include "bt-service-device.h"
31 #include "bt-service-util.h"
32 #include "bt-service-event.h"
33 #include "bt-service-otp.h"
34
35 #define BT_OTP_SERVICE_NAME "org.projectx.otp"
36 #define BT_OTP_OBJECT_PATH "/org/projectx/otp"
37 #define BT_OTP_INTERFACE_NAME "org.projectx.otp_service"
38
39 #define BT_OTP_BASE_DIR_PATH "/home/owner/media/otp/"
40
41 #define GATT_CHAR_INTERFACE             "org.bluez.GattCharacteristic1"
42
43 #define GATT_DEFAULT_TIMEOUT  (6 * 1000) /* Dependent on supervision timeout 6 sec */
44
45 /* OTP Notification Request structure */
46 typedef struct {
47         char *handle;
48         char *sender;
49         int req_id;
50 } bt_otp_notification_info;
51
52 /* OTP transport specific data read Request info structure */
53 typedef struct {
54         char *handle;
55         char *sender;
56         int req_id;
57 } bt_otp_read_req_info;
58
59 static GSList *otp_read_req_info_list = NULL;
60
61 static GSList *otp_notification_info_list = NULL;
62
63 static GDBusProxy *otp_gproxy;
64
65 static GDBusProxy *_bt_core_gdbus_init_otp_proxy(void)
66 {
67         GDBusProxy *proxy;
68         GError *err = NULL;
69         GDBusConnection *conn;
70
71         BT_DBG(" ");
72
73         conn = _bt_gdbus_get_system_gconn();
74         if (!conn)
75                 return NULL;
76
77         proxy =  g_dbus_proxy_new_sync(conn,
78                         G_DBUS_PROXY_FLAGS_NONE, NULL,
79                         BT_OTP_SERVICE_NAME,
80                         BT_OTP_OBJECT_PATH,
81                         BT_OTP_INTERFACE_NAME,
82                         NULL, &err);
83         if (proxy == NULL) {
84                 if (err) {
85                          BT_ERR("Unable to create proxy: %s", err->message);
86                          g_clear_error(&err);
87                 }
88                 return NULL;
89         }
90         BT_DBG("1");
91         otp_gproxy = proxy;
92
93         return proxy;
94 }
95
96 GDBusProxy *_bt_core_gdbus_get_otp_proxy(void)
97 {
98         return (otp_gproxy) ? otp_gproxy : _bt_core_gdbus_init_otp_proxy();
99 }
100
101 void server_init_cb(GObject *object, GAsyncResult *res,
102                                 gpointer user_data)
103 {
104         BT_INFO("Server Init completed");
105         GError *error = NULL;
106         GVariant *result, *out_param, *param;
107         request_info_t *req_info = NULL;
108         int status = BLUETOOTH_ERROR_NONE;
109         bool server_state = false;
110
111         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
112
113         if (result == NULL) {
114                 BT_ERR("Dbus-RPC is failed\n");
115                 if (error != NULL) {
116                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
117                                 error->code, error->message);
118                         g_clear_error(&error);
119                         status = BLUETOOTH_ERROR_INTERNAL;
120                 }
121         }
122
123         if (result) {
124                 g_variant_get(result, "(i)", &status);
125         }
126
127         BT_DBG("Status [%d]", status);
128
129         if (status == BLUETOOTH_ERROR_NONE)
130                 server_state = true;
131
132         param = g_variant_new("(ib)", status, server_state);
133
134         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
135
136         /* Send the event to application */
137         _bt_send_event(BT_OTP_EVENT,
138                 BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
139                 param);
140
141         out_param = g_variant_new_from_data((const GVariantType*)"i",
142                                 result, sizeof(int), TRUE, NULL, NULL);
143
144         if (req_info) {
145                 g_dbus_method_invocation_return_value(req_info->context,
146                                 g_variant_new("(iv)", status, out_param));
147
148                 _bt_delete_request_list(req_info->req_id);
149         }
150
151         g_variant_unref(result);
152 }
153
154 int bt_otp_server_init(int request_id, const char *directory)
155 {
156         BT_INFO("relative_path: [%s]", directory);
157         char *base_dir = g_strconcat(BT_OTP_BASE_DIR_PATH, directory, NULL);
158
159         BT_DBG(" ");
160
161         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
162         if (!otp_gproxy) {
163                 BT_DBG("Couldn't get service proxy");
164                 g_free(base_dir);
165                 return BLUETOOTH_ERROR_INTERNAL;
166         }
167
168         g_dbus_proxy_call(otp_gproxy,
169                         "enable",
170                         g_variant_new("(s)",
171                                 base_dir),
172                         G_DBUS_CALL_FLAGS_NONE, -1,
173                         NULL,
174                         (GAsyncReadyCallback) server_init_cb,
175                         GINT_TO_POINTER(request_id));
176
177         g_free(base_dir);
178
179         return BLUETOOTH_ERROR_NONE;
180 }
181
182 void server_deinit_cb(GObject *object, GAsyncResult *res,
183                                 gpointer user_data)
184 {
185         BT_INFO("Server Deinit completed");
186         GError *error = NULL;
187         GVariant *result, *out_param, *param;
188         request_info_t *req_info = NULL;
189         int status = BLUETOOTH_ERROR_NONE;
190         bool server_state = false;
191
192         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
193
194         if (result == NULL) {
195                 BT_ERR("Dbus-RPC is failed\n");
196                 if (error != NULL) {
197                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
198                                 error->code, error->message);
199                         g_clear_error(&error);
200                         status = BLUETOOTH_ERROR_INTERNAL;
201                 }
202         }
203
204         if (result) {
205                 g_variant_get(result, "(i)", &status);
206         }
207
208         BT_DBG("Status [%d]", status);
209
210         param = g_variant_new("(ib)", status, server_state);
211
212         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
213
214         /* Send the event to application */
215         _bt_send_event(BT_OTP_EVENT,
216                         BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
217                         param);
218
219         if (req_info) {
220                 out_param = g_variant_new_from_data((const GVariantType*)"i",
221                                 result, sizeof(int), TRUE, NULL, NULL);
222
223                 g_dbus_method_invocation_return_value(req_info->context,
224                                 g_variant_new("(iv)", status, out_param));
225
226                 _bt_delete_request_list(req_info->req_id);
227         }
228
229         g_variant_unref(result);
230
231         if (otp_gproxy) {
232                 g_object_unref(otp_gproxy);
233                 otp_gproxy = NULL;
234         }
235 }
236
237 int bt_otp_server_deinit(int request_id)
238 {
239         BT_DBG("+");
240
241         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
242         if (!otp_gproxy) {
243                 BT_DBG("Couldn't get service proxy");
244                 return BLUETOOTH_ERROR_INTERNAL;
245         }
246
247         g_dbus_proxy_call(otp_gproxy,
248                         "disable",
249                         NULL, G_DBUS_CALL_FLAGS_NONE,
250                         -1, NULL,
251                         (GAsyncReadyCallback) server_deinit_cb,
252                         GINT_TO_POINTER(request_id));
253
254         BT_DBG("-");
255         return BLUETOOTH_ERROR_NONE;
256 }
257
258 int __get_handle_length(char *handle)
259 {
260         int i = 0;
261         while (handle && (handle[i] != '\0')) {
262                 i++;
263         }
264         return i;
265 }
266
267 static bt_otp_read_req_info *__bt_otp_get_read_info(char *handle)
268 {
269         GSList *l;
270         bt_otp_read_req_info *info = NULL;
271         BT_INFO("Found waiting for OTP Read from charc handle[%s]", handle);
272         for (l = otp_read_req_info_list; l != NULL; l = g_slist_next(l)) {
273                 info = (bt_otp_read_req_info *)l->data;
274                 if (info == NULL)
275                         continue;
276
277                 if (!g_strcmp0(info->handle, handle)) {
278                         BT_INFO("Found waiting for OTP Read from remote addr[%s]",
279                                         info->handle);
280                         return info;
281                 }
282         }
283         return NULL;
284 }
285
286 static void __bt_otp_remove_read_info(bt_otp_read_req_info *info)
287 {
288         BT_DBG("Removing Read Req Info [%s]", info->handle);
289
290         otp_read_req_info_list = g_slist_remove(otp_read_req_info_list, info);
291         if (info->handle)
292                 g_free(info->handle);
293         if (info->sender)
294                 g_free(info->sender);
295         g_free(info);
296 }
297
298 static void __bt_otp_read_char_cb(GObject *source_object,
299                         GAsyncResult *res, gpointer user_data)
300 {
301         bt_gatt_char_descriptor_property_t att_value =  { 0, };
302         GDBusConnection *system_gconn = NULL;
303         GVariant *var_data, *param = NULL;
304         int result = BLUETOOTH_ERROR_NONE;
305         bt_otp_read_req_info *info = NULL;
306         GByteArray *gp_byte_array = NULL;
307         request_info_t *req_info = NULL;
308         GVariantIter *iter = NULL;
309         GVariant *value = NULL;
310         char *otp_data = NULL;
311         GVariant *out_param1;
312         GError *error = NULL;
313         guint8 g_byte;
314         char *handle;
315
316         BT_DBG("+");
317         system_gconn = _bt_gdbus_get_system_gconn();
318
319         handle = (char *)user_data;
320         info = __bt_otp_get_read_info(handle);
321
322         value = g_dbus_connection_call_finish(system_gconn, res, &error);
323
324         if (error) {
325                 BT_ERR("Error : %s \n", error->message);
326                 g_free(handle);
327                 if (info) {
328                         req_info = _bt_get_request_info(info->req_id);
329                         __bt_otp_remove_read_info(info);
330                 }
331                 result = BLUETOOTH_ERROR_INTERNAL;
332                 goto dbus_return;
333         }
334
335         gp_byte_array = g_byte_array_new();
336         g_variant_get(value, "(ay)", &iter);
337
338         while (g_variant_iter_loop(iter, "y",  &g_byte))
339                 g_byte_array_append(gp_byte_array, &g_byte, 1);
340
341         if (gp_byte_array->len != 0) {
342                 att_value.val_len = (unsigned int)gp_byte_array->len;
343                 att_value.val = (unsigned char *)gp_byte_array->data;
344         }
345
346         otp_data = (char *)g_memdup(att_value.val, att_value.val_len);
347
348         var_data = g_variant_new_from_data((const GVariantType*)"ay",
349                         otp_data, att_value.val_len, TRUE, NULL, NULL);
350
351         if (info) {
352                 param = g_variant_new("(isn@ay)", result, handle, att_value.val_len, var_data);
353                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
354                                 BLUETOOTH_EVENT_OTP_READ_CHAR_VAL,
355                                 param);
356                 req_info = _bt_get_request_info(info->req_id);
357                 __bt_otp_remove_read_info(info);
358         }
359
360 dbus_return:
361         if (req_info == NULL) {
362                 BT_ERR("OTP data read Request not found!!");
363                 goto done;
364         }
365
366         if (req_info->context == NULL)
367                 goto done;
368
369         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
370                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
371         g_dbus_method_invocation_return_value(req_info->context,
372                         g_variant_new("(iv)", result, out_param1));
373
374         _bt_delete_request_list(req_info->req_id);
375
376 done:
377         /* Data free */
378         if (error)
379                 g_clear_error(&error);
380         if (gp_byte_array)
381                 g_byte_array_free(gp_byte_array, TRUE);
382         if (handle)
383                 g_free(handle);
384         if (value)
385                 g_variant_unref(value);
386         if (iter)
387                 g_variant_iter_free(iter);
388         if (otp_data)
389                 g_free(otp_data);
390         BT_DBG("-");
391 }
392
393 int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle)
394 {
395         GDBusConnection *conn;
396         bt_otp_read_req_info *info = NULL;
397         GVariantBuilder *builder = NULL;
398         char *charc_handle = g_strdup(handle);
399         guint16 offset = 0;
400
401         BT_CHECK_PARAMETER(handle, return);
402         BT_CHECK_PARAMETER(sender, return);
403
404         conn = _bt_gdbus_get_system_gconn();
405         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
406
407         BT_DBG("Read OTP Characteristic from server handle [%s]", handle);
408
409         /* If OTP data read already pending on same Server, then return In progress */
410         if (__bt_otp_get_read_info(handle) != NULL) {
411                 BT_ERR("Read Req is ongoing in remote server [%s]", charc_handle);
412                 g_free(charc_handle);
413                 return BLUETOOTH_ERROR_IN_PROGRESS;
414         }
415
416         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
417         /*offset*/
418         g_variant_builder_add(builder, "{sv}", "offset",
419                 g_variant_new("q", offset));
420
421         g_dbus_connection_call(conn,
422                         BT_BLUEZ_NAME,
423                         handle,
424                         GATT_CHAR_INTERFACE,
425                         "ReadValue",
426                         g_variant_new("(a{sv})", builder),
427                         G_VARIANT_TYPE("(ay)"),
428                         G_DBUS_CALL_FLAGS_NONE,
429                         -1,
430                         NULL,
431                         (GAsyncReadyCallback)__bt_otp_read_char_cb,
432                         (gpointer)charc_handle);
433
434         /* Save Info in pending list */
435         info = g_malloc0(sizeof(bt_otp_read_req_info));
436         info->handle = g_strdup(handle);
437         BT_INFO("Found waiting for OTP Read from charc handle[%s] [%s]", info->handle, handle);
438         info->sender = g_strdup(sender);
439         info->req_id = request_id;
440         otp_read_req_info_list = g_slist_append(otp_read_req_info_list, info);
441
442         BT_DBG("-");
443         return BLUETOOTH_ERROR_NONE;
444 }
445
446 static bt_otp_notification_info *__bt_otp_get_notification_info(char *handle)
447 {
448         GSList *l;
449         bt_otp_notification_info *info = NULL;
450
451         for (l = otp_notification_info_list; l != NULL; l = g_slist_next(l)) {
452                 info = (bt_otp_notification_info *)l->data;
453                 if (info == NULL)
454                         continue;
455
456                 if (!g_strcmp0(info->handle, handle)) {
457                         BT_INFO("Found waiting for Ind from Server addr[%s]",
458                                         info->handle);
459                                 return info;
460                 }
461         }
462         return NULL;
463 }
464
465 static void __bt_otp_remove_notification_info(bt_otp_notification_info *info)
466 {
467         BT_DBG("Removing Notification Info [%s]", info->handle);
468
469         otp_notification_info_list = g_slist_remove(otp_notification_info_list, info);
470         if (info->handle)
471                 g_free(info->handle);
472         if (info->sender)
473                 g_free(info->sender);
474         g_free(info);
475 }
476
477 static void __bt_otp_notification_enable_request_cb(GObject *source_object,
478                         GAsyncResult *res, gpointer user_data)
479 {
480         GError *error = NULL;
481         GDBusConnection *system_gconn = NULL;
482         GVariant *value = NULL;
483         GVariant *param = NULL;
484         GVariant *out_param1 = NULL;
485         int result = BLUETOOTH_ERROR_NONE;
486         char *handle = NULL;
487         bt_otp_notification_info *info = NULL;
488         request_info_t *req_info = NULL;
489         BT_DBG("+");
490
491         system_gconn = _bt_gdbus_get_system_gconn();
492         value = g_dbus_connection_call_finish(system_gconn, res, &error);
493
494         if (error) {
495                 BT_ERR("Error : %s \n", error->message);
496                 if (g_strrstr(error->message, "Already notifying"))
497                         result = BLUETOOTH_ERROR_NONE;
498                 else if (g_strrstr(error->message, "In Progress"))
499                         result = BLUETOOTH_ERROR_IN_PROGRESS;
500                 else if (g_strrstr(error->message, "Operation is not supported"))
501                         result = BLUETOOTH_ERROR_NOT_SUPPORT;
502                 else if (g_strrstr(error->message, "Write not permitted") ||
503                                 g_strrstr(error->message, "Operation Not Authorized"))
504                         result = BLUETOOTH_ERROR_PERMISSION_DEINED;
505                 else if (g_strrstr(error->message, "Not paired"))
506                         result = BLUETOOTH_ERROR_NOT_PAIRED;
507                 else
508                         result = BLUETOOTH_ERROR_INTERNAL;
509         } else {
510                 BT_DBG("OTP CCCD enable request successful, send event to BT App");
511         }
512
513         handle = (char *)user_data;
514         info = __bt_otp_get_notification_info(handle);
515
516         if (info)
517                 req_info = _bt_get_request_info(info->req_id);
518
519         /* CCCD Enable request failed */
520         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
521                 BT_ERR("Activation Request failed");
522                 /* Remove Indication Info */
523                 __bt_otp_remove_notification_info(info);
524         } else {
525                 /* CCCD Enable Request successful */
526                 if (info) {
527                         param = g_variant_new("(is)", result, handle);
528                         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
529                                         BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED,
530                                         param);
531                 }
532         }
533
534         if (req_info == NULL) {
535                 BT_ERR("OTP Control Point CCCD Enable Request is not found!!");
536                 goto done;
537         }
538
539         if (req_info->context == NULL)
540                 goto done;
541
542         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
543                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
544         g_dbus_method_invocation_return_value(req_info->context,
545                         g_variant_new("(iv)", result, out_param1));
546
547         _bt_delete_request_list(req_info->req_id);
548
549 done:
550         if (value)
551                 g_variant_unref(value);
552         if (error)
553                 g_clear_error(&error);
554         if (handle)
555                 g_free(handle);
556
557         BT_DBG("-");
558         return;
559 }
560
561 int _bt_otp_enable_notification(int request_id, char *sender, char *handle)
562 {
563         bt_otp_notification_info *info = NULL;
564         char *charc_handle = g_strdup(handle);
565         GDBusConnection *conn;
566
567         BT_CHECK_PARAMETER(handle, return);
568         BT_CHECK_PARAMETER(sender, return);
569
570         conn = _bt_gdbus_get_system_gconn();
571         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
572
573         BT_DBG("OTP Control point CCCD Handle [%s]", handle);
574
575         if (__bt_otp_get_notification_info(handle) != NULL) {
576                 BT_ERR("Activation is already ongoing for same remote server");
577                 g_free(charc_handle);
578                 return BLUETOOTH_ERROR_IN_PROGRESS;
579         }
580
581         BT_INFO("Start Notify to Bluez");
582         g_dbus_connection_call(conn,
583                         BT_BLUEZ_NAME,
584                         handle,
585                         GATT_CHAR_INTERFACE,
586                         "StartNotify",
587                         NULL,
588                         NULL,
589                         G_DBUS_CALL_FLAGS_NONE,
590                         GATT_DEFAULT_TIMEOUT, NULL,
591                         (GAsyncReadyCallback)__bt_otp_notification_enable_request_cb,
592                         (gpointer)charc_handle);
593
594         info = g_malloc0(sizeof(bt_otp_notification_info));
595         info->handle = g_strdup(handle);
596         info->sender = g_strdup(sender);
597         info->req_id = request_id;
598         otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
599
600         BT_DBG("-");
601         return BLUETOOTH_ERROR_NONE;
602 }