afe423213d152e35d3a362d572697c536788ae6c
[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 #define BT_INDICATION_TIMEOUT_MAX 30000 /* Timeout for Indication from OTP Server in msec */
45
46 /* OTP Notification Request structure */
47 typedef struct {
48         char *handle;
49         char *sender;
50         unsigned int notification_timeout_id;
51         int req_id;
52 } bt_otp_notification_info;
53
54 /* OTP transport specific data read Request info structure */
55 typedef struct {
56         char *handle;
57         char *sender;
58         int req_id;
59 } bt_otp_read_req_info;
60
61 static GSList *otp_read_req_info_list = NULL;
62
63 static GSList *otp_notification_info_list = NULL;
64
65 static GDBusProxy *otp_gproxy;
66
67 static GDBusProxy *_bt_core_gdbus_init_otp_proxy(void)
68 {
69         GDBusProxy *proxy;
70         GError *err = NULL;
71         GDBusConnection *conn;
72
73         BT_DBG(" ");
74
75         conn = _bt_gdbus_get_system_gconn();
76         if (!conn)
77                 return NULL;
78
79         proxy =  g_dbus_proxy_new_sync(conn,
80                         G_DBUS_PROXY_FLAGS_NONE, NULL,
81                         BT_OTP_SERVICE_NAME,
82                         BT_OTP_OBJECT_PATH,
83                         BT_OTP_INTERFACE_NAME,
84                         NULL, &err);
85         if (proxy == NULL) {
86                 if (err) {
87                          BT_ERR("Unable to create proxy: %s", err->message);
88                          g_clear_error(&err);
89                 }
90                 return NULL;
91         }
92         BT_DBG("1");
93         otp_gproxy = proxy;
94
95         return proxy;
96 }
97
98 GDBusProxy *_bt_core_gdbus_get_otp_proxy(void)
99 {
100         return (otp_gproxy) ? otp_gproxy : _bt_core_gdbus_init_otp_proxy();
101 }
102
103 void server_init_cb(GObject *object, GAsyncResult *res,
104                                 gpointer user_data)
105 {
106         BT_INFO("Server Init completed");
107         GError *error = NULL;
108         GVariant *result, *out_param, *param;
109         request_info_t *req_info = NULL;
110         int status = BLUETOOTH_ERROR_NONE;
111         bool server_state = false;
112
113         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
114
115         if (result == NULL) {
116                 BT_ERR("Dbus-RPC is failed\n");
117                 if (error != NULL) {
118                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
119                                 error->code, error->message);
120                         g_clear_error(&error);
121                         status = BLUETOOTH_ERROR_INTERNAL;
122                 }
123         }
124
125         if (result) {
126                 g_variant_get(result, "(i)", &status);
127         }
128
129         BT_DBG("Status [%d]", status);
130
131         if (status == BLUETOOTH_ERROR_NONE)
132                 server_state = true;
133
134         param = g_variant_new("(ib)", status, server_state);
135
136         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
137
138         /* Send the event to application */
139         _bt_send_event(BT_OTP_EVENT,
140                 BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
141                 param);
142
143         out_param = g_variant_new_from_data((const GVariantType*)"i",
144                                 result, sizeof(int), TRUE, NULL, NULL);
145
146         if (req_info) {
147                 g_dbus_method_invocation_return_value(req_info->context,
148                                 g_variant_new("(iv)", status, out_param));
149
150                 _bt_delete_request_list(req_info->req_id);
151         }
152
153         g_variant_unref(result);
154 }
155
156 int bt_otp_server_init(int request_id, const char *directory)
157 {
158         BT_INFO("relative_path: [%s]", directory);
159         char *base_dir = g_strconcat(BT_OTP_BASE_DIR_PATH, directory, NULL);
160
161         BT_DBG(" ");
162
163         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
164         if (!otp_gproxy) {
165                 BT_DBG("Couldn't get service proxy");
166                 g_free(base_dir);
167                 return BLUETOOTH_ERROR_INTERNAL;
168         }
169
170         g_dbus_proxy_call(otp_gproxy,
171                         "enable",
172                         g_variant_new("(s)",
173                                 base_dir),
174                         G_DBUS_CALL_FLAGS_NONE, -1,
175                         NULL,
176                         (GAsyncReadyCallback) server_init_cb,
177                         GINT_TO_POINTER(request_id));
178
179         g_free(base_dir);
180
181         return BLUETOOTH_ERROR_NONE;
182 }
183
184 void server_deinit_cb(GObject *object, GAsyncResult *res,
185                                 gpointer user_data)
186 {
187         BT_INFO("Server Deinit completed");
188         GError *error = NULL;
189         GVariant *result, *out_param, *param;
190         request_info_t *req_info = NULL;
191         int status = BLUETOOTH_ERROR_NONE;
192         bool server_state = false;
193
194         result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
195
196         if (result == NULL) {
197                 BT_ERR("Dbus-RPC is failed\n");
198                 if (error != NULL) {
199                         BT_ERR("D-Bus API failure: errCode[%x], message[%s]\n",
200                                 error->code, error->message);
201                         g_clear_error(&error);
202                         status = BLUETOOTH_ERROR_INTERNAL;
203                 }
204         }
205
206         if (result) {
207                 g_variant_get(result, "(i)", &status);
208         }
209
210         BT_DBG("Status [%d]", status);
211
212         param = g_variant_new("(ib)", status, server_state);
213
214         req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
215
216         /* Send the event to application */
217         _bt_send_event(BT_OTP_EVENT,
218                         BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
219                         param);
220
221         if (req_info) {
222                 out_param = g_variant_new_from_data((const GVariantType*)"i",
223                                 result, sizeof(int), TRUE, NULL, NULL);
224
225                 g_dbus_method_invocation_return_value(req_info->context,
226                                 g_variant_new("(iv)", status, out_param));
227
228                 _bt_delete_request_list(req_info->req_id);
229         }
230
231         g_variant_unref(result);
232
233         if (otp_gproxy) {
234                 g_object_unref(otp_gproxy);
235                 otp_gproxy = NULL;
236         }
237 }
238
239 int bt_otp_server_deinit(int request_id)
240 {
241         BT_DBG("+");
242
243         otp_gproxy = _bt_core_gdbus_get_otp_proxy();
244         if (!otp_gproxy) {
245                 BT_DBG("Couldn't get service proxy");
246                 return BLUETOOTH_ERROR_INTERNAL;
247         }
248
249         g_dbus_proxy_call(otp_gproxy,
250                         "disable",
251                         NULL, G_DBUS_CALL_FLAGS_NONE,
252                         -1, NULL,
253                         (GAsyncReadyCallback) server_deinit_cb,
254                         GINT_TO_POINTER(request_id));
255
256         BT_DBG("-");
257         return BLUETOOTH_ERROR_NONE;
258 }
259
260 int __get_handle_length(char *handle)
261 {
262         int i = 0;
263         while (handle && (handle[i] != '\0')) {
264                 i++;
265         }
266         return i;
267 }
268
269 static bt_otp_read_req_info *__bt_otp_get_read_info(char *handle)
270 {
271         GSList *l;
272         bt_otp_read_req_info *info = NULL;
273         BT_INFO("Found waiting for OTP Read from charc handle[%s]", handle);
274         for (l = otp_read_req_info_list; l != NULL; l = g_slist_next(l)) {
275                 info = (bt_otp_read_req_info *)l->data;
276                 if (info == NULL)
277                         continue;
278
279                 if (!g_strcmp0(info->handle, handle)) {
280                         BT_INFO("Found waiting for OTP Read from remote addr[%s]",
281                                         info->handle);
282                         return info;
283                 }
284         }
285         return NULL;
286 }
287
288 static void __bt_otp_remove_read_info(bt_otp_read_req_info *info)
289 {
290         BT_DBG("Removing Read Req Info [%s]", info->handle);
291
292         otp_read_req_info_list = g_slist_remove(otp_read_req_info_list, info);
293         if (info->handle)
294                 g_free(info->handle);
295         if (info->sender)
296                 g_free(info->sender);
297         g_free(info);
298 }
299
300 static int __bluetooth_get_att_error_code(GError *error)
301 {
302         int att_ecode = 0;
303         int len;
304         char *str = NULL;
305
306         BT_ERR("Error : %s", error->message);
307         str = g_strrstr(error->message, "ATT error: 0x");
308         if (str) {
309                 len = strlen(str);
310                 att_ecode =  g_ascii_xdigit_value(str[len-2]) << 4;
311                 att_ecode += g_ascii_xdigit_value(str[len-1]);
312         } else
313                 return BLUETOOTH_ATT_ERROR_INTERNAL;
314
315         return att_ecode;
316 }
317
318 static void __bt_otp_read_char_cb(GObject *source_object,
319                         GAsyncResult *res, gpointer user_data)
320 {
321         bt_gatt_char_descriptor_property_t att_value =  { 0, };
322         GDBusConnection *system_gconn = NULL;
323         GVariant *var_data, *param = NULL;
324         int result = BLUETOOTH_ATT_ERROR_NONE;
325         bt_otp_read_req_info *info = NULL;
326         GByteArray *gp_byte_array = NULL;
327         request_info_t *req_info = NULL;
328         GVariantIter *iter = NULL;
329         GVariant *value = NULL;
330         char *otp_data = NULL;
331         GVariant *out_param1;
332         GError *error = NULL;
333         guint8 g_byte;
334         char *handle;
335
336         BT_DBG("+");
337         system_gconn = _bt_gdbus_get_system_gconn();
338
339         handle = (char *)user_data;
340         info = __bt_otp_get_read_info(handle);
341
342         value = g_dbus_connection_call_finish(system_gconn, res, &error);
343
344         if (error) {
345                 result = __bluetooth_get_att_error_code(error);
346                 att_value.val_len = 0;
347                 goto dbus_return;
348         }
349
350         g_variant_get(value, "(ay)", &iter);
351
352         gp_byte_array = g_byte_array_new();
353
354         while (g_variant_iter_loop(iter, "y",  &g_byte))
355                 g_byte_array_append(gp_byte_array, &g_byte, 1);
356
357         if (gp_byte_array->len != 0) {
358                 att_value.val_len = (unsigned int)gp_byte_array->len;
359                 att_value.val = (unsigned char *)gp_byte_array->data;
360         }
361
362         otp_data = (char *)g_memdup(att_value.val, att_value.val_len);
363
364 dbus_return:
365         var_data = g_variant_new_from_data((const GVariantType*)"ay",
366                         otp_data, att_value.val_len, TRUE, NULL, NULL);
367
368         if (info) {
369                 param = g_variant_new("(isn@ay)", result, handle, att_value.val_len, var_data);
370                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
371                                 BLUETOOTH_EVENT_OTP_READ_CHAR_VAL,
372                                 param);
373         }
374
375         req_info = _bt_get_request_info(info->req_id);
376         __bt_otp_remove_read_info(info);
377
378         if (req_info == NULL) {
379                 BT_ERR("OTP data read Request not found!!");
380                 goto done;
381         }
382
383         if (req_info->context == NULL)
384                 goto done;
385
386         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
387                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
388         g_dbus_method_invocation_return_value(req_info->context,
389                         g_variant_new("(iv)", result, out_param1));
390
391         _bt_delete_request_list(req_info->req_id);
392
393 done:
394         /* Data free */
395         if (error)
396                 g_clear_error(&error);
397         if (gp_byte_array)
398                 g_byte_array_free(gp_byte_array, TRUE);
399         if (handle)
400                 g_free(handle);
401         if (value)
402                 g_variant_unref(value);
403         if (iter)
404                 g_variant_iter_free(iter);
405         if (otp_data)
406                 g_free(otp_data);
407         BT_DBG("-");
408 }
409
410 int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle)
411 {
412         GDBusConnection *conn;
413         bt_otp_read_req_info *info = NULL;
414         char *charc_handle = g_strdup(handle);
415         GVariantBuilder *builder = NULL;
416         guint16 offset = 0;
417
418         BT_CHECK_PARAMETER(handle, return);
419         BT_CHECK_PARAMETER(sender, return);
420
421         conn = _bt_gdbus_get_system_gconn();
422         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
423
424         BT_DBG("Read OTP Characteristic from server handle [%s]", handle);
425
426         /* If OTP data read already pending on same Server, then return In progress */
427         if (__bt_otp_get_read_info(handle) != NULL) {
428                 BT_ERR("Read Req is ongoing in remote server [%s]", charc_handle);
429                 g_free(charc_handle);
430                 return BLUETOOTH_ERROR_IN_PROGRESS;
431         }
432
433         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
434         /*offset*/
435         g_variant_builder_add(builder, "{sv}", "offset",
436                 g_variant_new("q", offset));
437
438         g_dbus_connection_call(conn,
439                         BT_BLUEZ_NAME,
440                         handle,
441                         GATT_CHAR_INTERFACE,
442                         "ReadValue",
443                         g_variant_new("(a{sv})", builder),
444                         G_VARIANT_TYPE("(ay)"),
445                         G_DBUS_CALL_FLAGS_NONE,
446                         -1,
447                         NULL,
448                         (GAsyncReadyCallback)__bt_otp_read_char_cb,
449                         (gpointer)charc_handle);
450
451         /* Save Info in pending list */
452         info = g_malloc0(sizeof(bt_otp_read_req_info));
453         info->handle = g_strdup(handle);
454         BT_INFO("Found waiting for OTP Read from charc handle[%s] [%s]", info->handle, handle);
455         info->sender = g_strdup(sender);
456         info->req_id = request_id;
457         otp_read_req_info_list = g_slist_append(otp_read_req_info_list, info);
458
459         BT_DBG("-");
460         return BLUETOOTH_ERROR_NONE;
461 }
462
463 static bt_otp_notification_info *__bt_otp_get_notification_info(char *handle)
464 {
465         GSList *l;
466         bt_otp_notification_info *info = NULL;
467
468         for (l = otp_notification_info_list; l != NULL; l = g_slist_next(l)) {
469                 info = (bt_otp_notification_info *)l->data;
470                 if (info == NULL)
471                         continue;
472
473                 if (!g_strcmp0(info->handle, handle)) {
474                         BT_INFO("Found waiting for Ind from Server addr[%s]",
475                                         info->handle);
476                                 return info;
477                 }
478         }
479         return NULL;
480 }
481
482 static void __bt_otp_remove_notification_info(bt_otp_notification_info *info)
483 {
484         BT_DBG("Removing Notification Info [%s]", info->handle);
485
486         otp_notification_info_list = g_slist_remove(otp_notification_info_list, info);
487         if (info->handle)
488                 g_free(info->handle);
489         if (info->sender)
490                 g_free(info->sender);
491         if (info->notification_timeout_id > 0) {
492                 g_source_remove(info->notification_timeout_id);
493                 info->notification_timeout_id = 0;
494         }
495         g_free(info);
496 }
497
498 static void __bt_otp_notification_enable_request_cb(GObject *source_object,
499                         GAsyncResult *res, gpointer user_data)
500 {
501         GError *error = NULL;
502         GDBusConnection *system_gconn = NULL;
503         GVariant *value = NULL;
504         GVariant *param = NULL;
505         GVariant *out_param1 = NULL;
506         int result = BLUETOOTH_ERROR_NONE;
507         char *handle = NULL;
508         bt_otp_notification_info *info = NULL;
509         request_info_t *req_info = NULL;
510         BT_DBG("+");
511
512         system_gconn = _bt_gdbus_get_system_gconn();
513         value = g_dbus_connection_call_finish(system_gconn, res, &error);
514
515         if (error) {
516                 BT_ERR("Error : %s \n", error->message);
517                 if (g_strrstr(error->message, "Already notifying"))
518                         result = BLUETOOTH_ERROR_NONE;
519                 else if (g_strrstr(error->message, "In Progress"))
520                         result = BLUETOOTH_ERROR_IN_PROGRESS;
521                 else if (g_strrstr(error->message, "Operation is not supported"))
522                         result = BLUETOOTH_ERROR_NOT_SUPPORT;
523                 else if (g_strrstr(error->message, "Write not permitted") ||
524                                 g_strrstr(error->message, "Operation Not Authorized"))
525                         result = BLUETOOTH_ERROR_PERMISSION_DEINED;
526                 else if (g_strrstr(error->message, "Not paired"))
527                         result = BLUETOOTH_ERROR_NOT_PAIRED;
528                 else
529                         result = BLUETOOTH_ERROR_INTERNAL;
530         } else {
531                 BT_DBG("OTP CCCD enable request successful, send event to BT App");
532         }
533
534         handle = (char *)user_data;
535         info = __bt_otp_get_notification_info(handle);
536
537         if (info)
538                 req_info = _bt_get_request_info(info->req_id);
539
540         /* If CCCD Enable request failed for any reason, reset timer */
541         if (result != BLUETOOTH_ERROR_NONE && info != NULL) {
542                 BT_ERR("Activation Request failed");
543                 /* Reset Timer */
544                 if (info->notification_timeout_id > 0) {
545                         g_source_remove(info->notification_timeout_id);
546                         info->notification_timeout_id = 0;
547                 }
548
549                 /* Remove Indication Info */
550                 __bt_otp_remove_notification_info(info);
551         } else {
552                 /* CCCD Enable Request successful */
553                 if (info) {
554                         param = g_variant_new("(is)", result, handle);
555                         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
556                                         BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED,
557                                         param);
558                 }
559         }
560
561         if (req_info == NULL) {
562                 BT_ERR("OTP Control Point CCCD Enable Request is not found!!");
563                 goto done;
564         }
565
566         if (req_info->context == NULL)
567                 goto done;
568
569         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
570                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
571         g_dbus_method_invocation_return_value(req_info->context,
572                         g_variant_new("(iv)", result, out_param1));
573
574         _bt_delete_request_list(req_info->req_id);
575
576 done:
577         if (value)
578                 g_variant_unref(value);
579         if (error)
580                 g_clear_error(&error);
581         if (handle)
582                 g_free(handle);
583
584         BT_DBG("-");
585         return;
586 }
587
588 int _bt_otp_enable_notification(int request_id, char *sender, char *handle)
589 {
590         bt_otp_notification_info *info = NULL;
591         char *charc_handle = g_strdup(handle);
592         GDBusConnection *conn;
593
594         BT_CHECK_PARAMETER(handle, return);
595         BT_CHECK_PARAMETER(sender, return);
596
597         conn = _bt_gdbus_get_system_gconn();
598         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
599
600         BT_DBG("OTP Control point CCCD Handle [%s]", handle);
601
602         if (__bt_otp_get_notification_info(handle) != NULL) {
603                 BT_ERR("Activation is already ongoing for same remote server");
604                 g_free(charc_handle);
605                 return BLUETOOTH_ERROR_IN_PROGRESS;
606         }
607
608         BT_INFO("Start Notify to Bluez");
609         g_dbus_connection_call(conn,
610                         BT_BLUEZ_NAME,
611                         handle,
612                         GATT_CHAR_INTERFACE,
613                         "StartNotify",
614                         NULL,
615                         NULL,
616                         G_DBUS_CALL_FLAGS_NONE,
617                         GATT_DEFAULT_TIMEOUT, NULL,
618                         (GAsyncReadyCallback)__bt_otp_notification_enable_request_cb,
619                         (gpointer)charc_handle);
620
621         info = g_malloc0(sizeof(bt_otp_notification_info));
622         info->handle = g_strdup(handle);
623         info->sender = g_strdup(sender);
624         info->req_id = request_id;
625         otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
626
627         BT_DBG("-");
628         return BLUETOOTH_ERROR_NONE;
629 }
630
631 static void __bt_otp_write_request_cb(GObject *source_object,
632                         GAsyncResult *res, gpointer user_data)
633 {
634         GError *error = NULL;
635         GDBusConnection *system_gconn = NULL;
636         GVariant *value = NULL;
637         GVariant *param = NULL;
638         GVariant *out_param1 = NULL;
639         int result = BLUETOOTH_ATT_ERROR_NONE;
640         char *handle = NULL;
641         bt_otp_notification_info *info = NULL;
642         request_info_t *req_info = NULL;
643         BT_DBG("+");
644
645         system_gconn = _bt_gdbus_get_system_gconn();
646         value = g_dbus_connection_call_finish(system_gconn, res, &error);
647
648         if (error)
649                 result = __bluetooth_get_att_error_code(error);
650
651         handle = (char *)user_data;
652         info = __bt_otp_get_notification_info(handle);
653         if (info)
654                 req_info = _bt_get_request_info(info->req_id);
655
656         /* Is Activation request failed for any reason, reset timer */
657         if (result != BLUETOOTH_ATT_ERROR_NONE && info != NULL) {
658                 BT_ERR("Activation Request failed");
659                 /* Remove Indication Info */
660                 __bt_otp_remove_notification_info(info);
661         }
662
663         /* Activation Request successful */
664         if (info) {
665                 param = g_variant_new("(is)", result, handle);
666                 _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
667                                 BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL,
668                                 param);
669         }
670
671         if (req_info == NULL) {
672                 BT_ERR("OTP Write Request is not found!!");
673                 goto done;
674         }
675
676         if (req_info->context == NULL)
677                 goto done;
678
679         out_param1 = g_variant_new_from_data((const GVariantType*)"ay",
680                         handle, __get_handle_length(handle), TRUE, NULL, NULL);
681         g_dbus_method_invocation_return_value(req_info->context,
682                         g_variant_new("(iv)", result, out_param1));
683
684         _bt_delete_request_list(req_info->req_id);
685
686 done:
687         if (value)
688                 g_variant_unref(value);
689         if (error)
690                 g_clear_error(&error);
691         if (handle)
692                 g_free(handle);
693
694         BT_DBG("-");
695         return;
696 }
697
698 static void __bt_otp_send_indication_event(bt_otp_notification_info *info,
699                                                 unsigned char *buffer, int len, int result)
700 {
701         GVariant *otp_data;
702         GVariant *param;
703
704         otp_data = g_variant_new_from_data((const GVariantType*)"ay",
705                         buffer, len, TRUE, NULL, NULL);
706
707         BT_DBG("Send Indication event to sender");
708         param = g_variant_new("(is@ay)", result, info->handle, otp_data);
709         _bt_send_event_to_dest(info->sender, BT_OTP_EVENT,
710                                         BLUETOOTH_EVENT_OTP_INDICATION,
711                                         param);
712
713         /* Remove info from list */
714         __bt_otp_remove_notification_info(info);
715 }
716
717 static bool __bt_otp_indication_timeout_cb(gpointer user_data)
718 {
719         char *handle = NULL;
720         handle = (char *) user_data;
721         bt_otp_notification_info *info = NULL;
722         /* Indication:Fail*/
723         info = __bt_otp_get_notification_info(handle);
724         if (info) {
725                 BT_DBG("Activation timer Expired [Server] [%s]", info->handle);
726                 __bt_otp_send_indication_event(info, NULL, 0, BLUETOOTH_ERROR_INTERNAL);
727         }
728
729         return FALSE;
730 }
731
732 int _bt_otp_write_characteristic_value(int request_id, char *sender, char *handle,
733                                                         unsigned char *param, int length)
734 {
735         GVariantBuilder *builder1;
736         GVariant *val;
737         GVariant *options;
738         GVariantBuilder *builder2;
739         guint16 offset = 0;
740         bt_otp_notification_info *info = NULL;
741         GDBusConnection *conn;
742         char *charc_handle = g_strdup(handle);
743         int i;
744
745         BT_DBG("+");
746
747         BT_CHECK_PARAMETER(handle, return);
748         BT_CHECK_PARAMETER(sender, return);
749         BT_CHECK_PARAMETER(param, return);
750
751         conn = _bt_gdbus_get_system_gconn();
752         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
753
754         BT_DBG("OTP Write Characteristic value handle [%s] data length [%d]", handle, length);
755         /* Check if activation is ongoing for the same Remote Server */
756
757         info = __bt_otp_get_notification_info(handle);
758         if (info && info->notification_timeout_id > 0) {
759                 BT_ERR("Write Request is already ongoing in remote server");
760                 g_free(charc_handle);
761                 return BLUETOOTH_ERROR_IN_PROGRESS;
762         }
763
764         builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
765
766         for (i = 0; i < length; i++) {
767                 g_variant_builder_add(builder1, "y", param[i]);
768         }
769
770         val = g_variant_new("ay", builder1);
771         builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
772         /*offset*/
773         g_variant_builder_add(builder2, "{sv}", "offset",
774                                 g_variant_new_uint16(offset));
775
776         options = g_variant_new("a{sv}", builder2);
777
778         /* Activate Control Point */
779         g_dbus_connection_call(conn,
780                         BT_BLUEZ_NAME,
781                         handle,
782                         GATT_CHAR_INTERFACE,
783                         "WriteValue",
784                         g_variant_new("(@ay@a{sv})",
785                         val, options),
786                         NULL,
787                         G_DBUS_CALL_FLAGS_NONE,
788                         -1, NULL,
789                         (GAsyncReadyCallback)__bt_otp_write_request_cb,
790                         (gpointer)charc_handle);
791
792         g_variant_builder_unref(builder1);
793         g_variant_builder_unref(builder2);
794
795         if (info == NULL) {
796                 info = g_malloc0(sizeof(bt_otp_notification_info));
797                 info->handle = g_strdup(handle);
798                 info->sender = g_strdup(sender);
799                 otp_notification_info_list = g_slist_append(otp_notification_info_list, info);
800         }
801         info->req_id = request_id;
802         /* Set timeout only for cp charc */
803         info->notification_timeout_id = g_timeout_add(BT_INDICATION_TIMEOUT_MAX,
804                         (GSourceFunc)__bt_otp_indication_timeout_cb, (gpointer)info->handle);
805
806         BT_DBG("-");
807         return BLUETOOTH_ERROR_NONE;
808 }
809
810 void _bt_otp_check_indication(const char *path, GVariant *msg)
811 {
812         bt_otp_notification_info *info = NULL;
813         unsigned char *buffer = NULL;
814         int len = 0;
815         int i;
816         GVariant *value = NULL;
817         BT_DBG("+");
818
819         info = __bt_otp_get_notification_info((char *)path);
820
821         if (info) {
822                 g_variant_get(msg, "(is@ay)", NULL, NULL, &value);
823                 len = g_variant_get_size(value);
824                 BT_DBG("Indication data from Server len[%d]", len);
825                 if (len > 0) {
826                         buffer = (unsigned char *)g_variant_get_data(value);
827                         /* DEBUG */
828                         for (i = 0; i < len; i++)
829                                 BT_DBG("%.2x", buffer[i]);
830                 }
831
832                 /* Reset Timer */
833                 if (info->notification_timeout_id > 0)
834                         g_source_remove(info->notification_timeout_id);
835
836                 /* Send Indication & info removed internally */
837                 __bt_otp_send_indication_event(info, buffer, len, BLUETOOTH_ERROR_NONE);
838
839                 if (value)
840                         g_variant_unref(value);
841         }
842         BT_DBG("-");
843 }
844
845 int _bt_otp_connect_otc(int req_id, const bluetooth_device_address_t *bd_addr)
846 {
847         char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
848         gchar *device_path = NULL;
849         GDBusProxy *device_proxy = NULL;
850         GDBusConnection *conn;
851         int ret = BLUETOOTH_ERROR_NONE;
852         GVariant *result = NULL;
853         GError *err = NULL;
854
855         BT_CHECK_PARAMETER(bd_addr, return);
856
857         _bt_convert_addr_type_to_string(device_address,
858                         (unsigned char *)bd_addr->addr);
859
860         conn = _bt_gdbus_get_system_gconn();
861         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
862
863         device_path = _bt_get_device_object_path(device_address);
864         if (device_path == NULL) {
865                 BT_DBG("device_path NULL");
866                 ret = BLUETOOTH_ERROR_INTERNAL;
867                 goto fail;
868         }
869
870         retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL);
871
872         device_proxy = g_dbus_proxy_new_sync(conn,
873                                         G_DBUS_PROXY_FLAGS_NONE,
874                                         NULL, BT_BLUEZ_NAME,
875                                         device_path, BT_DEVICE_INTERFACE,
876                                         NULL, NULL);
877         g_free(device_path);
878         retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
879
880         result = g_dbus_proxy_call_sync(device_proxy, "ConnectOtc",
881                                 NULL,
882                                 G_DBUS_CALL_FLAGS_NONE,
883                                 -1,
884                                 NULL,
885                                 &err);
886
887         if (result == NULL) {
888                 if (err != NULL) {
889                         g_dbus_error_strip_remote_error(err);
890                         BT_ERR("OTC Connect Error: %s\n", err->message);
891                         if (g_strcmp0(err->message, "Already Exists") == 0)
892                                 ret = BLUETOOTH_ERROR_ALREADY_INITIALIZED;
893                         else
894                                 ret = BLUETOOTH_ERROR_INTERNAL;
895                         g_error_free(err);
896                 }
897         }
898         g_variant_unref(result);
899
900 fail:
901         g_object_unref(device_proxy);
902         return ret;
903 }
904
905 int _bt_otp_disconnect_otc(const bluetooth_device_address_t *bd_addr)
906 {
907         char device_address[BT_ADDRESS_STRING_SIZE] = { 0 };
908         gchar *device_path = NULL;
909         GError *error = NULL;
910         GDBusProxy *device_proxy = NULL;
911         GDBusProxy *adapter_proxy;
912         GDBusConnection *conn;
913         int ret = BLUETOOTH_ERROR_NONE;
914
915         BT_CHECK_PARAMETER(bd_addr, return);
916
917         _bt_convert_addr_type_to_string(device_address,
918                         (unsigned char *)bd_addr->addr);
919
920         conn = _bt_gdbus_get_system_gconn();
921         retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
922
923         adapter_proxy = _bt_get_adapter_proxy();
924         retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
925
926         device_path = _bt_get_device_object_path(device_address);
927         if (device_path == NULL) {
928                 BT_DBG("device_path NULL");
929                 return BLUETOOTH_ERROR_INTERNAL;
930         }
931
932         retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL);
933
934         device_proxy = g_dbus_proxy_new_sync(conn,
935                                         G_DBUS_PROXY_FLAGS_NONE,
936                                         NULL, BT_BLUEZ_NAME,
937                                         device_path,
938                                         BT_DEVICE_INTERFACE,
939                                         NULL, NULL);
940         g_free(device_path);
941         retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL);
942
943         g_dbus_proxy_call_sync(device_proxy, "DisconnectOtc",
944                                 NULL,
945                                 G_DBUS_CALL_FLAGS_NONE,
946                                 -1,
947                                 NULL,
948                                 &error);
949
950         if (error) {
951                 BT_ERR("DisconnectOtc Call Error %s[%s]",
952                                 error->message, device_address);
953                 g_error_free(error);
954                 g_object_unref(device_proxy);
955                 return BLUETOOTH_ERROR_INTERNAL;
956         }
957
958         if (device_proxy)
959                 g_object_unref(device_proxy);
960
961         return ret;
962 }