2 * Copyright (c) 2011 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.
22 #include <syspopup_caller.h>
24 #include <bundle_internal.h>
26 #include "bluetooth-api.h"
27 #include "bt-internal-types.h"
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"
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"
39 #define BT_OTP_BASE_DIR_PATH "/home/owner/media/otp/"
41 #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1"
43 #define GATT_DEFAULT_TIMEOUT (6 * 1000) /* Dependent on supervision timeout 6 sec */
45 /* OTP Notification Request structure */
50 } bt_otp_notification_info;
52 /* OTP transport specific data read Request info structure */
57 } bt_otp_read_req_info;
59 static GSList *otp_read_req_info_list = NULL;
61 static GSList *otp_notification_info_list = NULL;
63 static GDBusProxy *otp_gproxy;
65 static GDBusProxy *_bt_core_gdbus_init_otp_proxy(void)
69 GDBusConnection *conn;
73 conn = _bt_gdbus_get_system_gconn();
77 proxy = g_dbus_proxy_new_sync(conn,
78 G_DBUS_PROXY_FLAGS_NONE, NULL,
81 BT_OTP_INTERFACE_NAME,
85 BT_ERR("Unable to create proxy: %s", err->message);
96 GDBusProxy *_bt_core_gdbus_get_otp_proxy(void)
98 return (otp_gproxy) ? otp_gproxy : _bt_core_gdbus_init_otp_proxy();
101 void server_init_cb(GObject *object, GAsyncResult *res,
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;
111 result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
113 if (result == NULL) {
114 BT_ERR("Dbus-RPC is failed\n");
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;
124 g_variant_get(result, "(i)", &status);
127 BT_DBG("Status [%d]", status);
129 if (status == BLUETOOTH_ERROR_NONE)
132 param = g_variant_new("(ib)", status, server_state);
134 req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
136 /* Send the event to application */
137 _bt_send_event(BT_OTP_EVENT,
138 BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
141 out_param = g_variant_new_from_data((const GVariantType*)"i",
142 result, sizeof(int), TRUE, NULL, NULL);
145 g_dbus_method_invocation_return_value(req_info->context,
146 g_variant_new("(iv)", status, out_param));
148 _bt_delete_request_list(req_info->req_id);
151 g_variant_unref(result);
154 int bt_otp_server_init(int request_id, const char *directory)
156 BT_INFO("relative_path: [%s]", directory);
157 char *base_dir = g_strconcat(BT_OTP_BASE_DIR_PATH, directory, NULL);
161 otp_gproxy = _bt_core_gdbus_get_otp_proxy();
163 BT_DBG("Couldn't get service proxy");
165 return BLUETOOTH_ERROR_INTERNAL;
168 g_dbus_proxy_call(otp_gproxy,
172 G_DBUS_CALL_FLAGS_NONE, -1,
174 (GAsyncReadyCallback) server_init_cb,
175 GINT_TO_POINTER(request_id));
179 return BLUETOOTH_ERROR_NONE;
182 void server_deinit_cb(GObject *object, GAsyncResult *res,
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;
192 result = g_dbus_proxy_call_finish(otp_gproxy, res, &error);
194 if (result == NULL) {
195 BT_ERR("Dbus-RPC is failed\n");
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;
205 g_variant_get(result, "(i)", &status);
208 BT_DBG("Status [%d]", status);
210 param = g_variant_new("(ib)", status, server_state);
212 req_info = _bt_get_request_info(GPOINTER_TO_INT(user_data));
214 /* Send the event to application */
215 _bt_send_event(BT_OTP_EVENT,
216 BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED,
220 out_param = g_variant_new_from_data((const GVariantType*)"i",
221 result, sizeof(int), TRUE, NULL, NULL);
223 g_dbus_method_invocation_return_value(req_info->context,
224 g_variant_new("(iv)", status, out_param));
226 _bt_delete_request_list(req_info->req_id);
229 g_variant_unref(result);
232 g_object_unref(otp_gproxy);
237 int bt_otp_server_deinit(int request_id)
241 otp_gproxy = _bt_core_gdbus_get_otp_proxy();
243 BT_DBG("Couldn't get service proxy");
244 return BLUETOOTH_ERROR_INTERNAL;
247 g_dbus_proxy_call(otp_gproxy,
249 NULL, G_DBUS_CALL_FLAGS_NONE,
251 (GAsyncReadyCallback) server_deinit_cb,
252 GINT_TO_POINTER(request_id));
255 return BLUETOOTH_ERROR_NONE;
258 int __get_handle_length(char *handle)
261 while (handle && (handle[i] != '\0')) {
267 static bt_otp_read_req_info *__bt_otp_get_read_info(char *handle)
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;
277 if (!g_strcmp0(info->handle, handle)) {
278 BT_INFO("Found waiting for OTP Read from remote addr[%s]",
286 static void __bt_otp_remove_read_info(bt_otp_read_req_info *info)
288 BT_DBG("Removing Read Req Info [%s]", info->handle);
290 otp_read_req_info_list = g_slist_remove(otp_read_req_info_list, info);
292 g_free(info->handle);
294 g_free(info->sender);
298 static void __bt_otp_read_char_cb(GObject *source_object,
299 GAsyncResult *res, gpointer user_data)
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;
317 system_gconn = _bt_gdbus_get_system_gconn();
319 handle = (char *)user_data;
320 info = __bt_otp_get_read_info(handle);
322 value = g_dbus_connection_call_finish(system_gconn, res, &error);
325 BT_ERR("Error : %s \n", error->message);
328 req_info = _bt_get_request_info(info->req_id);
329 __bt_otp_remove_read_info(info);
331 result = BLUETOOTH_ERROR_INTERNAL;
335 gp_byte_array = g_byte_array_new();
336 g_variant_get(value, "(ay)", &iter);
338 while (g_variant_iter_loop(iter, "y", &g_byte))
339 g_byte_array_append(gp_byte_array, &g_byte, 1);
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;
346 otp_data = (char *)g_memdup(att_value.val, att_value.val_len);
348 var_data = g_variant_new_from_data((const GVariantType*)"ay",
349 otp_data, att_value.val_len, TRUE, NULL, NULL);
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,
356 req_info = _bt_get_request_info(info->req_id);
357 __bt_otp_remove_read_info(info);
361 if (req_info == NULL) {
362 BT_ERR("OTP data read Request not found!!");
366 if (req_info->context == NULL)
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));
374 _bt_delete_request_list(req_info->req_id);
379 g_clear_error(&error);
381 g_byte_array_free(gp_byte_array, TRUE);
385 g_variant_unref(value);
387 g_variant_iter_free(iter);
393 int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle)
395 GDBusConnection *conn;
396 bt_otp_read_req_info *info = NULL;
397 GVariantBuilder *builder = NULL;
398 char *charc_handle = g_strdup(handle);
401 BT_CHECK_PARAMETER(handle, return);
402 BT_CHECK_PARAMETER(sender, return);
404 conn = _bt_gdbus_get_system_gconn();
405 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
407 BT_DBG("Read OTP Characteristic from server handle [%s]", handle);
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;
416 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
418 g_variant_builder_add(builder, "{sv}", "offset",
419 g_variant_new("q", offset));
421 g_dbus_connection_call(conn,
426 g_variant_new("(a{sv})", builder),
427 G_VARIANT_TYPE("(ay)"),
428 G_DBUS_CALL_FLAGS_NONE,
431 (GAsyncReadyCallback)__bt_otp_read_char_cb,
432 (gpointer)charc_handle);
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);
443 return BLUETOOTH_ERROR_NONE;
446 static bt_otp_notification_info *__bt_otp_get_notification_info(char *handle)
449 bt_otp_notification_info *info = NULL;
451 for (l = otp_notification_info_list; l != NULL; l = g_slist_next(l)) {
452 info = (bt_otp_notification_info *)l->data;
456 if (!g_strcmp0(info->handle, handle)) {
457 BT_INFO("Found waiting for Ind from Server addr[%s]",
465 static void __bt_otp_remove_notification_info(bt_otp_notification_info *info)
467 BT_DBG("Removing Notification Info [%s]", info->handle);
469 otp_notification_info_list = g_slist_remove(otp_notification_info_list, info);
471 g_free(info->handle);
473 g_free(info->sender);
477 static void __bt_otp_notification_enable_request_cb(GObject *source_object,
478 GAsyncResult *res, gpointer user_data)
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;
487 bt_otp_notification_info *info = NULL;
488 request_info_t *req_info = NULL;
491 system_gconn = _bt_gdbus_get_system_gconn();
492 value = g_dbus_connection_call_finish(system_gconn, res, &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;
508 result = BLUETOOTH_ERROR_INTERNAL;
510 BT_DBG("OTP CCCD enable request successful, send event to BT App");
513 handle = (char *)user_data;
514 info = __bt_otp_get_notification_info(handle);
517 req_info = _bt_get_request_info(info->req_id);
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);
525 /* CCCD Enable Request successful */
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,
534 if (req_info == NULL) {
535 BT_ERR("OTP Control Point CCCD Enable Request is not found!!");
539 if (req_info->context == NULL)
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));
547 _bt_delete_request_list(req_info->req_id);
551 g_variant_unref(value);
553 g_clear_error(&error);
561 int _bt_otp_enable_notification(int request_id, char *sender, char *handle)
563 bt_otp_notification_info *info = NULL;
564 char *charc_handle = g_strdup(handle);
565 GDBusConnection *conn;
567 BT_CHECK_PARAMETER(handle, return);
568 BT_CHECK_PARAMETER(sender, return);
570 conn = _bt_gdbus_get_system_gconn();
571 retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL);
573 BT_DBG("OTP Control point CCCD Handle [%s]", handle);
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;
581 BT_INFO("Start Notify to Bluez");
582 g_dbus_connection_call(conn,
589 G_DBUS_CALL_FLAGS_NONE,
590 GATT_DEFAULT_TIMEOUT, NULL,
591 (GAsyncReadyCallback)__bt_otp_notification_enable_request_cb,
592 (gpointer)charc_handle);
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);
601 return BLUETOOTH_ERROR_NONE;