From b36ccf5d2733bc46047259a836323df81915fa99 Mon Sep 17 00:00:00 2001 From: Gowtham Anandha Babu Date: Wed, 24 May 2017 13:41:42 +0530 Subject: [PATCH] [OTP] Add support for OACP Read Change-Id: Ic98585d0158b5d3a1cca756f50bfb0faba0f0fe3 Signed-off-by: Gowtham Anandha Babu --- bt-api/bt-common.c | 2 + bt-api/bt-event-handler.c | 22 ++ bt-api/bt-otp.c | 214 +++++++++++++++++- bt-otp/CMakeLists.txt | 1 + bt-otp/bt-otpserver.c | 402 +++++++++++++++++++++++++++++++-- bt-otp/bt-otpserver.h | 9 + bt-service/CMakeLists.txt | 1 + bt-service/bt-request-handler.c | 20 ++ bt-service/bt-service-event-receiver.c | 15 ++ bt-service/bt-service-event-sender.c | 3 + bt-service/bt-service-otp.c | 178 +++++++++++++-- bt-service/include/bt-service-otp.h | 4 + include/bluetooth-api.h | 44 ++++ include/bt-internal-types.h | 3 + 14 files changed, 874 insertions(+), 44 deletions(-) diff --git a/bt-api/bt-common.c b/bt-api/bt-common.c index 363f5a2..3e61585 100644 --- a/bt-api/bt-common.c +++ b/bt-api/bt-common.c @@ -605,6 +605,8 @@ const char *_bt_convert_service_function_to_string(int function) {BT_OTP_READ_VALUE, "BT_OTP_READ_VALUE"}, {BT_OTP_ENABLE_NOTIFICATION, "BT_OTP_ENABLE_NOTIFICATION"}, {BT_OTP_WRITE_VALUE, "BT_OTP_WRITE_VALUE"}, + {BT_LE_OTC_CONNECT, "BT_LE_OTC_CONNECT"}, + {BT_LE_OTC_DISCONNECT, "BT_LE_OTC_DISCONNECT"}, {-1, ""}, }; diff --git a/bt-api/bt-event-handler.c b/bt-api/bt-event-handler.c index 67ead44..8f6cc2b 100644 --- a/bt-api/bt-event-handler.c +++ b/bt-api/bt-event-handler.c @@ -3145,6 +3145,28 @@ static void __bt_otp_event_filter(GDBusConnection *connection, } if (byte_var) g_variant_unref(byte_var); + } else if (strcasecmp(signal_name, BT_OTC_STATE_CHANGED) == 0) { + BT_DBG("OTC State Changed"); + char *address = NULL; + int fd = -1; + gboolean connected = FALSE; + bluetooth_otc_info_t *otc_info = NULL; + + /* Extract data from DBUS params */ + g_variant_get(parameters, "(ib&sn)", &result, &connected, &address, &fd); + BT_DBG("Result [%d]", result); + BT_DBG("Address [%s]", address); + BT_DBG("Connected [%d]", connected); + BT_DBG("Fd [%d]", fd); + + otc_info = g_malloc0(sizeof(bluetooth_otc_info_t)); + otc_info->fd = fd; + otc_info->connected = connected; + otc_info->address = g_strdup(address); + + _bt_common_event_cb(BLUETOOTH_EVENT_OTC_STATE_CHANGED, + result, otc_info, + event_info->cb, event_info->user_data); } BT_DBG("-"); diff --git a/bt-api/bt-otp.c b/bt-api/bt-otp.c index 1d0a86c..7d7a7f0 100644 --- a/bt-api/bt-otp.c +++ b/bt-api/bt-otp.c @@ -14,6 +14,7 @@ * limitations under the License. * */ +#include #include "bluetooth-api.h" #include "bt-internal-types.h" @@ -155,7 +156,7 @@ BT_EXPORT_API int bluetooth_otp_enable_notification(const char *handle) } BT_EXPORT_API int bluetooth_otp_write_characteristics_value(const char *handle, - unsigned char *buf, int length) + unsigned char *buf, int length) { char *path; int path_len = 0; @@ -186,7 +187,8 @@ BT_EXPORT_API int bluetooth_otp_write_characteristics_value(const char *handle, /*Fill parameters*/ g_array_append_vals(in_param1, path, path_len); - g_array_append_vals(in_param2, &data, sizeof(bluetooth_otp_charc_data_t)); + g_array_append_vals(in_param2, &data, + sizeof(bluetooth_otp_charc_data_t)); int i; for (i = 0; i < length; i++) @@ -201,3 +203,211 @@ BT_EXPORT_API int bluetooth_otp_write_characteristics_value(const char *handle, BT_DBG("-"); return result; } + +#define BT_OTP_CLIENT_SERVICE_NAME "org.otp.client" +#define BT_OTP_CLIENT_OBJECT_PATH "/org/otp/client" + +static const gchar otc_connection_xml[] = +"" +" " +" " +" " +" " +" " +" " +""; + +GDBusNodeInfo *otp_node_info = NULL; +static GDBusConnection *g_conn; +static guint g_owner_id = 0; + +static void __new_connection_method(GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + BT_DBG("method %s", method_name); + if (g_strcmp0(method_name, "NewConnection") == 0) { + int index; + GDBusMessage *msg; + GUnixFDList *fd_list; + char *dev_path; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + int fd; + bluetooth_otc_info_t *otc_info = NULL; + bt_event_info_t *event_info; + int result = BLUETOOTH_ERROR_NONE; + + g_variant_get(parameters, "(oh)", &dev_path, &index); + + msg = g_dbus_method_invocation_get_message(invocation); + fd_list = g_dbus_message_get_unix_fd_list(msg); + if (fd_list == NULL) { + BT_ERR("fd_list is NULL"); + return; + } + + fd = g_unix_fd_list_get(fd_list, index, NULL); + if (fd == -1) { + BT_ERR("Invalid fd return"); + return; + } + + _bt_convert_device_path_to_address(dev_path, address); + + BT_INFO("OTC Connected fd: %d, address %s", fd, address); + + otc_info = g_malloc0(sizeof(bluetooth_otc_info_t)); + otc_info->fd = fd; + otc_info->connected = TRUE; + otc_info->address = g_strdup(address); + + event_info = _bt_event_get_cb_data(BT_OTP_EVENT); + + if (event_info) { + _bt_common_event_cb(BLUETOOTH_EVENT_OTC_STATE_CHANGED, + result, otc_info, event_info->cb, + event_info->user_data); + } + + g_dbus_method_invocation_return_value(invocation, NULL); + } +} + +static const GDBusInterfaceVTable method_table = { + __new_connection_method, + NULL, + NULL, +}; + +static void _bt_otp_on_bus_acquired(GDBusConnection *connection, + const gchar *name, gpointer user_data) +{ + guint object_id; + GError *error = NULL; + + BT_DBG("+"); + + g_conn = connection; + + object_id = g_dbus_connection_register_object(connection, + BT_OTP_CLIENT_OBJECT_PATH, + otp_node_info->interfaces[0], + &method_table, + NULL, NULL, &error); + if (object_id == 0) { + BT_ERR("Failed to register method table: %s", error->message); + g_error_free(error); + g_dbus_node_info_unref(otp_node_info); + } + + BT_DBG("-"); +} + +static void _bt_otp_on_name_acquired(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + BT_DBG(""); +} + +static void _bt_otp_on_name_lost(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + BT_DBG("+"); + + if (g_conn) { + g_object_unref(g_conn); + g_conn = NULL; + } + + g_dbus_node_info_unref(otp_node_info); + BT_DBG("-"); +} + +int _bt_otp_register_interface(void) +{ + BT_DBG("+"); + GError *error = NULL; + guint owner_id; + + otp_node_info = g_dbus_node_info_new_for_xml(otc_connection_xml, + &error); + if (!otp_node_info) { + BT_ERR("Failed to install: %s", error->message); + return BLUETOOTH_ERROR_INTERNAL; + } + + owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, + BT_OTP_CLIENT_SERVICE_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + _bt_otp_on_bus_acquired, + _bt_otp_on_name_acquired, + _bt_otp_on_name_lost, + NULL, NULL); + g_owner_id = owner_id; + BT_DBG("owner_id is [%d]\n", owner_id); + + BT_DBG("-"); + return BLUETOOTH_ERROR_NONE; +} + +void _bt_otp_unregister_interface(void) +{ + BT_DBG("+"); + + g_bus_unown_name(g_owner_id); + + BT_DBG("-"); +} + +BT_EXPORT_API int bluetooth_otp_connect_otc(const bluetooth_device_address_t *device_address) +{ + int ret = BLUETOOTH_ERROR_INTERNAL; + + BT_CHECK_PARAMETER(device_address, return); + BT_CHECK_ENABLED_LE(return); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, device_address, + sizeof(bluetooth_device_address_t)); + + _bt_otp_register_interface(); + + ret = _bt_send_request(BT_BLUEZ_SERVICE, BT_LE_OTC_CONNECT, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return ret; +} + +BT_EXPORT_API int bluetooth_otp_disconnect_otc(const bluetooth_device_address_t *device_address) +{ + int ret = BLUETOOTH_ERROR_INTERNAL; + + BT_CHECK_PARAMETER(device_address, return); + BT_CHECK_ENABLED_LE(return); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + /* TODO: Send fd as in_param2 */ + g_array_append_vals(in_param1, device_address, + sizeof(bluetooth_device_address_t)); + + ret = _bt_send_request(BT_BLUEZ_SERVICE, BT_LE_OTC_DISCONNECT, + in_param1, in_param2, in_param3, in_param4, &out_param); + + _bt_otp_unregister_interface(); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return ret; +} diff --git a/bt-otp/CMakeLists.txt b/bt-otp/CMakeLists.txt index eb3a814..1b72c55 100644 --- a/bt-otp/CMakeLists.txt +++ b/bt-otp/CMakeLists.txt @@ -17,6 +17,7 @@ SET(PKG_MODULES pkgmgr eventsystem dbus-1 + gio-unix-2.0 ) INCLUDE(FindPkgConfig) diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index 9501f3e..48fce49 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "bt-otpserver.h" #include "bluetooth-api.h" @@ -60,6 +61,7 @@ static GDBusConnection *g_conn; static int property_sub_id = -1; static int adapter_sub_id = -1; +static int device_sub_id = -1; static guint g_owner_id = 0; struct otp_char_info { @@ -87,15 +89,27 @@ struct object_metadata { uint32_t props; }; -static struct object_metadata *selected_object; +struct oacp_operation { + char *remote_address; + uint32_t offset; + uint32_t length; + uint8_t opcode; + uint8_t mode; + int fd; +}; + +static struct object_metadata *selected_object = NULL; static uint64_t object_id = OBJECT_START_ID; static GSList *otp_object_list = NULL; static GSList *otp_char_list = NULL; static guint obj_curr_index; static int adv_handle = 0; +static gboolean OACP_indicate = FALSE; static gboolean OLCP_indicate = FALSE; char *directory = NULL; gboolean mutiple_obj_support = false; +static gboolean otc_connection_status = FALSE; +struct oacp_operation *oacp_read = NULL; static const gchar otp_introspection_xml[] = "" @@ -107,12 +121,18 @@ static const gchar otp_introspection_xml[] = " " " " " " +" " +" " +" " +" " " " ""; void _bt_otp_deinit_event_receiver(void); void _bt_otp_unregister_interface(void); void update_obj_metadata_charc_value(struct object_metadata *object); +void _bt_convert_device_path_to_address(const char *device_path, + char *device_address); static void delete_all_objects(void) { @@ -465,6 +485,66 @@ int _bt_otp_set_advertising_data(void) return 0; } +void _bt_otp_start_write_on_fd() +{ + char buf[BT_L2CAP_BUFFER_LEN]; + int written = 0; + int read = 0; + FILE *fp; + char file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + int length; + + if (!selected_object) { + BT_DBG("Object not selected"); + goto fail; + } + + snprintf(file_path, sizeof(file_path), "%s%s", + directory, selected_object->name); + BT_DBG("file_path = [%s]", file_path); + + fp = fopen(file_path, "r"); + if (!fp) { + BT_DBG("fopen() failed : %s", strerror(errno)); + goto fail; + } + + BT_DBG("length [%d]", oacp_read->length); + length = oacp_read->length; + if (length > BT_L2CAP_BUFFER_LEN) { + int offset = oacp_read->offset; + int len = 0; + int written_len = 0; + + while (length > 0) { + if (length < BT_L2CAP_BUFFER_LEN) + len = length; + else + len = BT_L2CAP_BUFFER_LEN; + + fseek(fp, offset, SEEK_SET); + read = fread(buf, 1, len, fp); + + written = write(oacp_read->fd, buf, len); + BT_DBG("read [%d], Written [%d], len [%d], offset [%d], length [%d], written_len [%d]", + read, written, len, offset, length, written_len); + length -= len; + offset += len; + written_len += len; + } + } else { + read = fread(buf, 1, length, fp); + written = write(oacp_read->fd, buf, oacp_read->length); + BT_DBG("read [%d], Written [%d]", read, written); + } + + fclose(fp); +fail: + g_free(oacp_read->remote_address); + g_free(oacp_read); + oacp_read = NULL; +} + static void _bt_otp_method(GDBusConnection *connection, const gchar *sender, const gchar *object_path, @@ -537,7 +617,7 @@ static void _bt_otp_method(GDBusConnection *connection, object->curr_size = (uint32_t) st.st_size; object->alloc_size = (uint32_t) st.st_size; object->id = object_id; - object->props = OBJECT_READ | OBJECT_WRITE; + object->props = OBJECT_READ; otp_object_list = g_slist_append(otp_object_list, object); @@ -558,7 +638,8 @@ static void _bt_otp_method(GDBusConnection *connection, if (!mutiple_obj_support) { BT_INFO("Server supports single object"); selected_object = (struct object_metadata *) g_slist_nth_data(otp_object_list, 0); - update_obj_metadata_charc_value(selected_object); + if (selected_object) + update_obj_metadata_charc_value(selected_object); } BT_DBG("advertsing"); @@ -575,6 +656,44 @@ fail: g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", status)); _bt_otp_exit(); + + } else if (g_strcmp0(method_name, "NewConnection") == 0) { + int index; + GDBusMessage *msg; + GUnixFDList *fd_list; + char *dev_path; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + int fd; + + g_variant_get(parameters, "(oh)", &dev_path, &index); + + msg = g_dbus_method_invocation_get_message(invocation); + fd_list = g_dbus_message_get_unix_fd_list(msg); + if (fd_list == NULL) { + BT_ERR("fd_list is NULL"); + return; + } + + fd = g_unix_fd_list_get(fd_list, index, NULL); + if (fd == -1) { + BT_ERR("Invalid fd return"); + return; + } + + _bt_convert_device_path_to_address(dev_path, address); + + BT_INFO("OTC Connected fd: %d, address %s", fd, address); + if (!oacp_read) { + /* OTC Connected, but no on going request */ + goto done; + } + oacp_read->fd = fd; + otc_connection_status = TRUE; + + if (oacp_read->opcode == OACP_READ) + _bt_otp_start_write_on_fd(); +done: + g_dbus_method_invocation_return_value(invocation, NULL); } BT_DBG("-"); } @@ -666,10 +785,222 @@ void _bt_otp_unregister_interface(void) return; } +void _bt_convert_device_path_to_address(const char *device_path, + char *device_address) +{ + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + char *dev_addr; + + dev_addr = strstr(device_path, "dev_"); + if (dev_addr != NULL) { + char *pos = NULL; + dev_addr += 4; + g_strlcpy(address, dev_addr, sizeof(address)); + + while ((pos = strchr(address, '_')) != NULL) + *pos = ':'; + + g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE); + } +} + +static char *__bt_extract_device_path(GVariantIter *iter, char *address) +{ + char *object_path = NULL; + char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + + /* Parse the signature: oa{sa{sv}}} */ + while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path, + NULL)) { + if (!object_path) { + BT_ERR("Unable to get object path"); + return NULL; + } + _bt_convert_device_path_to_address(object_path, device_address); + if (g_strcmp0(address, device_address) == 0) + return g_strdup(object_path); + + } + + BT_ERR("Unable to get object path"); + return NULL; +} + +char *_bt_otp_get_device_object_path(char *address) +{ + GError *err = NULL; + GDBusProxy *proxy = NULL; + GVariant *result = NULL; + GVariantIter *iter = NULL; + char *object_path = NULL; + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, NULL, + BT_BLUEZ_NAME, + BT_MANAGER_PATH, + BT_MANAGER_INTERFACE, + NULL, &err); + + if (!proxy) { + BT_ERR("Unable to create proxy: %s", err->message); + goto fail; + } + + result = g_dbus_proxy_call_sync(proxy, "GetManagedObjects", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); + if (!result) { + if (err != NULL) + BT_ERR("Fail to get GetManagedObjects (Error: %s)", err->message); + else + BT_ERR("Fail to get GetManagedObjects"); + + goto fail; + } + + g_variant_get(result, "(a{oa{sa{sv}}})", &iter); + object_path = __bt_extract_device_path(iter, address); + + g_variant_unref(result); + g_variant_iter_free(iter); + +fail: + if (err) + g_clear_error(&err); + + if (proxy) + g_object_unref(proxy); + + return object_path; +} + +int _bt_otp_open_otc_and_listen(char *address) +{ + char *object_path; + GDBusProxy *device_proxy = NULL; + GVariant *result = NULL; + GError *error = NULL; + int ret = BLUETOOTH_ERROR_NONE; + + object_path = _bt_otp_get_device_object_path(address); + if (object_path == NULL) { + ret = BLUETOOTH_ERROR_NOT_PAIRED; + goto fail; + } + + device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_BLUEZ_NAME, object_path, + BT_DEVICE_INTERFACE, NULL, NULL); + if (device_proxy == NULL) { + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + + result = g_dbus_proxy_call_sync(device_proxy, "ListenOtc", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (result == NULL) { + if (error != NULL) { + BT_ERR("Error occured in Proxy call [%s]\n", error->message); + g_error_free(error); + } + ret = BLUETOOTH_ERROR_INTERNAL; + } +fail: + if (object_path) + g_free(object_path); + if (result) + g_variant_unref(result); + if (device_proxy) + g_object_unref(device_proxy); + return ret; +} + +int _bt_otp_oacp_write_cb(char *value, int len, int offset, + char *remote_addr, struct indicate_info *info) +{ + int ret = OACP_SUCCESS; + int app_err = BLUETOOTH_ERROR_NONE; + int opcode = value[0]; + uint32_t object_offset, length; + + BT_INFO("OACP Opcode 0x%d", opcode); + + if (!otp_object_list) { + ret = OACP_INVALID_OBJ; + goto fail; + } + + switch (opcode) { + case OACP_CREATE: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_DELETE: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_CALC_CHECKSUM: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_EXECUTE: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_READ: + object_offset = (uint32_t)(value[4] & 0xFF) << 24 | + (uint32_t)(value[3] & 0xFF) << 16 | + (uint32_t)(value[2] & 0xFF) << 8 | + (uint32_t)(value[1] & 0xFF); + length = (uint32_t)(value[8] & 0xFF) << 24 | + (uint32_t)(value[7] & 0xFF) << 16 | + (uint32_t)(value[6] & 0xFF) << 8 | + (uint32_t)(value[5] & 0xFF); + + BT_INFO("Offset = %lu, Length = %lu", object_offset, length); + + if (oacp_read && otc_connection_status) { + /* Read operation already going on. */ + ret = OACP_OBJECT_LOCKED; + goto fail; + } + oacp_read = g_malloc0(sizeof(struct oacp_operation)); + oacp_read->offset = object_offset; + oacp_read->length = length; + oacp_read->remote_address = g_strdup(remote_addr); + oacp_read->opcode = OACP_READ; + + app_err = _bt_otp_open_otc_and_listen(remote_addr); + if (app_err != BLUETOOTH_ERROR_NONE) { + ret = OACP_OPERATION_FAILED; + g_free(oacp_read->remote_address); + g_free(oacp_read); + oacp_read = NULL; + goto fail; + } + ret = OACP_SUCCESS; + break; + case OACP_WRITE: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_ABORT: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + default: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + } +fail: + info->resp_opcode = OACP_RESPONSE; + info->req_opcode = opcode; + info->result_code = ret; + info->resp_param = NULL; + return app_err; +} void convert_to_hex(struct object_metadata *object, char *type, char *value) { - struct tm *tm = NULL; + struct tm fc_tm; BT_DBG("type : %s", type); @@ -689,17 +1020,15 @@ void convert_to_hex(struct object_metadata *object, char *type, char *value) } else if (!g_strcmp0(type, "date")) { - localtime_r(&(object->first_created), tm); + localtime_r(&(object->first_created), &fc_tm); - if (tm) { - value[1] = ((tm->tm_year+1900) >> 8) & 0xFF; - value[0] = (tm->tm_year+1900) & 0xFF; - value[2] = (tm->tm_mon+1) & 0xFF; - value[3] = tm->tm_mday & 0xFF; - value[4] = tm->tm_hour & 0xFF; - value[5] = tm->tm_min & 0xFF; - value[6] = tm->tm_sec & 0xFF; - } + value[1] = ((fc_tm.tm_year+1900) >> 8) & 0xFF; + value[0] = (fc_tm.tm_year+1900) & 0xFF; + value[2] = (fc_tm.tm_mon+1) & 0xFF; + value[3] = fc_tm.tm_mday & 0xFF; + value[4] = fc_tm.tm_hour & 0xFF; + value[5] = fc_tm.tm_min & 0xFF; + value[6] = fc_tm.tm_sec & 0xFF; } else if (!g_strcmp0(type, "id")) { @@ -965,9 +1294,7 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, if (len != 0) { if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - /* TODO: Handle OACP Control - * Point requests - */ + result = _bt_otp_oacp_write_cb(value, len, offset, addr, &info); } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) { result = _bt_otp_olcp_write_cb(value, len, offset, &info); } else { @@ -980,7 +1307,9 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, /* Send indication for CPs */ if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - /* Handle OACP Indication */ + if (OACP_indicate) { + _bt_otp_send_indication(char_path, &info, &addr_hex); + } } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) { if (OLCP_indicate) { _bt_otp_send_indication(char_path, &info, &addr_hex); @@ -1031,7 +1360,7 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, BT_INFO("Type '%s'\n", g_variant_get_type_string(var)); if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - /* Handle OACP notification */ + OACP_indicate = indicate; } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) { OLCP_indicate = indicate; } @@ -1084,6 +1413,34 @@ void _bt_otp_adapter_event_filter(GDBusConnection *connection, } } +void _bt_otc_disconnected_cb(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + if (signal_name == NULL) { + BT_ERR("Wrong Signal"); + return; + } + + BT_INFO("Interface %s, Signal %s", interface_name, signal_name); + + if (g_strcmp0(interface_name, BT_DEVICE_INTERFACE) == 0) { + if (strcasecmp(signal_name, OTC_DISCONNECTED) == 0) { + BT_DBG("OTC Channel Disconnected dev_path[%s]", + object_path); + otc_connection_status = FALSE; + if (oacp_read) { + g_free(oacp_read->remote_address); + g_free(oacp_read); + } + } + } +} + int _bt_otp_init_event_receiver() { BT_DBG("+"); @@ -1114,6 +1471,12 @@ int _bt_otp_init_event_receiver() _bt_otp_adapter_event_filter, NULL, NULL); + device_sub_id = g_dbus_connection_signal_subscribe(conn, + NULL, BT_DEVICE_INTERFACE, + OTC_DISCONNECTED, NULL, NULL, 0, + _bt_otc_disconnected_cb, + NULL, NULL); + BT_DBG("-"); return 0; } @@ -1124,6 +1487,7 @@ void _bt_otp_deinit_event_receiver(void) g_dbus_connection_signal_unsubscribe(conn, property_sub_id); g_dbus_connection_signal_unsubscribe(conn, adapter_sub_id); + g_dbus_connection_signal_unsubscribe(conn, device_sub_id); conn = NULL; BT_DBG("-"); diff --git a/bt-otp/bt-otpserver.h b/bt-otp/bt-otpserver.h index 498419f..fa4aa1f 100755 --- a/bt-otp/bt-otpserver.h +++ b/bt-otp/bt-otpserver.h @@ -21,8 +21,17 @@ #define BLE_DISABLED "LeDisabled" #define PROPERTIES_CHANGED "PropertiesChanged" +#define OTC_DISCONNECTED "OtcDisconnected" +#define BT_MANAGER_PATH "/" +#define BT_MANAGER_INTERFACE "org.freedesktop.DBus.ObjectManager" #define BT_BLUEZ_NAME "org.bluez" +#define BT_DEVICE_INTERFACE "org.bluez.Device1" + +#define BT_OTC_INTERFACE_NAME "org.projectx.otc_channel" + +#define BT_FILE_PATH_MAX_LEN 262 +#define BT_L2CAP_BUFFER_LEN 672 #define BT_ADDRESS_STRING_SIZE 18 diff --git a/bt-service/CMakeLists.txt b/bt-service/CMakeLists.txt index a7290c6..913185b 100644 --- a/bt-service/CMakeLists.txt +++ b/bt-service/CMakeLists.txt @@ -59,6 +59,7 @@ SET(PKG_MODULES vconf vconf gio-2.0 + gio-unix-2.0 alarm-service capi-content-mime-type capi-network-connection diff --git a/bt-service/bt-request-handler.c b/bt-service/bt-request-handler.c index cf35d49..069adcf 100644 --- a/bt-service/bt-request-handler.c +++ b/bt-service/bt-request-handler.c @@ -2439,6 +2439,24 @@ int __bt_bluez_request(int function_name, g_free(handle); break; } + case BT_LE_OTC_CONNECT: { + BT_DBG("OTC Connect"); + bluetooth_device_address_t address = { {0} }; + __bt_service_get_parameters(in_param1, &address, + sizeof(bluetooth_device_address_t)); + + result = _bt_otp_connect_otc(request_id, &address); + break; + } + case BT_LE_OTC_DISCONNECT: { + BT_DBG("OTC Disconnect"); + bluetooth_device_address_t address = { {0} }; + + __bt_service_get_parameters(in_param1, &address, + sizeof(bluetooth_device_address_t)); + result = _bt_otp_disconnect_otc(&address); + break; + } default: result = BLUETOOTH_ERROR_INTERNAL; break; @@ -3288,6 +3306,8 @@ gboolean __bt_service_check_privilege(int function_name, case BT_OTP_READ_VALUE: case BT_OTP_ENABLE_NOTIFICATION: case BT_OTP_WRITE_VALUE: + case BT_LE_OTC_CONNECT: + case BT_LE_OTC_DISCONNECT: case BT_MAP_CREATE_SESSION: case BT_MAP_DESTROY_SESSION: diff --git a/bt-service/bt-service-event-receiver.c b/bt-service/bt-service-event-receiver.c index 153c6ad..b0b6043 100644 --- a/bt-service/bt-service-event-receiver.c +++ b/bt-service/bt-service-event-receiver.c @@ -2347,6 +2347,21 @@ void _bt_handle_device_event(GVariant *msg, const char *member, const char *path param); g_free(address); + } else if (strcasecmp(member, "OtcDisconnected") == 0) { + gboolean connected = FALSE; + GVariant *otc_param = NULL; + + address = g_malloc0(BT_ADDRESS_STRING_SIZE); + _bt_convert_device_path_to_address(path, address); + + BT_DBG("OTC Disconnected, address: %s", address); + otc_param = g_variant_new("(ibsn)", result, connected, address); + + /* Send event to application */ + _bt_send_event(BT_OTP_EVENT, + BLUETOOTH_EVENT_OTC_STATE_CHANGED, + otc_param); + g_free(address); } } diff --git a/bt-service/bt-service-event-sender.c b/bt-service/bt-service-event-sender.c index a5ccbe2..3584f09 100644 --- a/bt-service/bt-service-event-sender.c +++ b/bt-service/bt-service-event-sender.c @@ -461,6 +461,9 @@ int _bt_send_event(int event_type, int event, GVariant *param) case BLUETOOTH_EVENT_OTP_SERVER_STATE_CHANGED: signal = BT_OTP_SERVER_STATE_CHANGED; break; + case BLUETOOTH_EVENT_OTC_STATE_CHANGED: + signal = BT_OTC_STATE_CHANGED; + break; default: BT_ERR("Unknown event"); return BLUETOOTH_ERROR_INTERNAL; diff --git a/bt-service/bt-service-otp.c b/bt-service/bt-service-otp.c index e62e809..dc8716d 100644 --- a/bt-service/bt-service-otp.c +++ b/bt-service/bt-service-otp.c @@ -41,7 +41,7 @@ #define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1" #define GATT_DEFAULT_TIMEOUT (6 * 1000) /* Dependent on supervision timeout 6 sec */ -#define BT_INDICATION_TIMEOUT_MAX 15000 /* Timeout for Indication from OTP Server in msec */ +#define BT_INDICATION_TIMEOUT_MAX 30000 /* Timeout for Indication from OTP Server in msec */ /* OTP Notification Request structure */ typedef struct { @@ -312,7 +312,7 @@ static void __bt_otp_read_char_cb(GObject *source_object, char *otp_data = NULL; GVariant *out_param1; GError *error = NULL; - guint8 g_byte; + guint8 g_byte, att_error_code; char *handle; BT_DBG("+"); @@ -325,17 +325,21 @@ static void __bt_otp_read_char_cb(GObject *source_object, if (error) { BT_ERR("Error : %s \n", error->message); - g_free(handle); - if (info) { - req_info = _bt_get_request_info(info->req_id); - __bt_otp_remove_read_info(info); - } + att_value.val_len = 0; result = BLUETOOTH_ERROR_INTERNAL; goto dbus_return; } + g_variant_get(value, "(yay)", &att_error_code, &iter); + + if (att_error_code != 0) { + BT_ERR("ATT err code : [%d]", att_error_code); + att_value.val_len = 0; + result = att_error_code; + goto dbus_return; + } + gp_byte_array = g_byte_array_new(); - g_variant_get(value, "(ay)", &iter); while (g_variant_iter_loop(iter, "y", &g_byte)) g_byte_array_append(gp_byte_array, &g_byte, 1); @@ -347,6 +351,7 @@ static void __bt_otp_read_char_cb(GObject *source_object, otp_data = (char *)g_memdup(att_value.val, att_value.val_len); +dbus_return: var_data = g_variant_new_from_data((const GVariantType*)"ay", otp_data, att_value.val_len, TRUE, NULL, NULL); @@ -355,11 +360,11 @@ static void __bt_otp_read_char_cb(GObject *source_object, _bt_send_event_to_dest(info->sender, BT_OTP_EVENT, BLUETOOTH_EVENT_OTP_READ_CHAR_VAL, param); - req_info = _bt_get_request_info(info->req_id); - __bt_otp_remove_read_info(info); } -dbus_return: + req_info = _bt_get_request_info(info->req_id); + __bt_otp_remove_read_info(info); + if (req_info == NULL) { BT_ERR("OTP data read Request not found!!"); goto done; @@ -426,7 +431,7 @@ int _bt_otp_read_characteristic_value(int request_id, char *sender, char *handle GATT_CHAR_INTERFACE, "ReadValue", g_variant_new("(a{sv})", builder), - G_VARIANT_TYPE("(ay)"), + G_VARIANT_TYPE("(yay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, @@ -625,6 +630,7 @@ static void __bt_otp_write_request_cb(GObject *source_object, char *handle = NULL; bt_otp_notification_info *info = NULL; request_info_t *req_info = NULL; + guint8 att_ecode = 0; BT_DBG("+"); system_gconn = _bt_gdbus_get_system_gconn(); @@ -634,6 +640,12 @@ static void __bt_otp_write_request_cb(GObject *source_object, BT_ERR("Error : %s \n", error->message); /* Process error->message to narrow down the att_ecode */ result = BLUETOOTH_ERROR_INTERNAL; + } else { + g_variant_get(value, "(y)", &att_ecode); + if (att_ecode) { + result = att_ecode; + BT_ERR("ATT Error code: %d \n", att_ecode); + } } handle = (char *)user_data; @@ -646,14 +658,14 @@ static void __bt_otp_write_request_cb(GObject *source_object, BT_ERR("Activation Request failed"); /* Remove Indication Info */ __bt_otp_remove_notification_info(info); - } else { - /* Activation Request successful */ - if (info) { - param = g_variant_new("(is)", result, handle); - _bt_send_event_to_dest(info->sender, BT_OTP_EVENT, - BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL, - param); - } + } + + /* Activation Request successful */ + if (info) { + param = g_variant_new("(is)", result, handle); + _bt_send_event_to_dest(info->sender, BT_OTP_EVENT, + BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL, + param); } if (req_info == NULL) { @@ -709,9 +721,10 @@ static bool __bt_otp_indication_timeout_cb(gpointer user_data) bt_otp_notification_info *info = NULL; /* Indication:Fail*/ info = __bt_otp_get_notification_info(handle); - BT_DBG("Activation timer Expired [Server] [%s]", info->handle); - if (info) + if (info) { + BT_DBG("Activation timer Expired [Server] [%s]", info->handle); __bt_otp_send_indication_event(info, NULL, 0, BLUETOOTH_ERROR_INTERNAL); + } return FALSE; } @@ -754,7 +767,7 @@ int _bt_otp_write_characteristic_value(int request_id, char *sender, char *handl g_variant_builder_add(builder1, "y", param[i]); } - val = g_variant_new("(ay)", builder1); + val = g_variant_new("ay", builder1); builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); /*offset*/ g_variant_builder_add(builder2, "{sv}", "offset", @@ -827,3 +840,122 @@ void _bt_otp_check_indication(const char *path, GVariant *msg) } BT_DBG("-"); } + +int _bt_otp_connect_otc(int req_id, const bluetooth_device_address_t *bd_addr) +{ + char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + gchar *device_path = NULL; + GDBusProxy *device_proxy = NULL; + GDBusConnection *conn; + int ret = BLUETOOTH_ERROR_NONE; + GVariant *result = NULL; + GError *err = NULL; + + BT_CHECK_PARAMETER(bd_addr, return); + + _bt_convert_addr_type_to_string(device_address, + (unsigned char *)bd_addr->addr); + + conn = _bt_gdbus_get_system_gconn(); + retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + + device_path = _bt_get_device_object_path(device_address); + if (device_path == NULL) { + BT_DBG("device_path NULL"); + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL); + + device_proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_BLUEZ_NAME, + device_path, BT_DEVICE_INTERFACE, + NULL, NULL); + g_free(device_path); + retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + result = g_dbus_proxy_call_sync(device_proxy, "ConnectOtc", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err); + + if (result == NULL) { + if (err != NULL) { + g_dbus_error_strip_remote_error(err); + BT_ERR("OTC Connect Error: %s\n", err->message); + if (g_strcmp0(err->message, "Already Exists") == 0) + ret = BLUETOOTH_ERROR_ALREADY_INITIALIZED; + else + ret = BLUETOOTH_ERROR_INTERNAL; + g_error_free(err); + } + } + g_variant_unref(result); + +fail: + g_object_unref(device_proxy); + return ret; +} + +int _bt_otp_disconnect_otc(const bluetooth_device_address_t *bd_addr) +{ + char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + gchar *device_path = NULL; + GError *error = NULL; + GDBusProxy *device_proxy = NULL; + GDBusProxy *adapter_proxy; + GDBusConnection *conn; + int ret = BLUETOOTH_ERROR_NONE; + + BT_CHECK_PARAMETER(bd_addr, return); + + _bt_convert_addr_type_to_string(device_address, + (unsigned char *)bd_addr->addr); + + conn = _bt_gdbus_get_system_gconn(); + retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); + + adapter_proxy = _bt_get_adapter_proxy(); + retv_if(adapter_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + device_path = _bt_get_device_object_path(device_address); + if (device_path == NULL) { + BT_DBG("device_path NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } + + retv_if(device_path == NULL, BLUETOOTH_ERROR_INTERNAL); + + device_proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, BT_BLUEZ_NAME, + device_path, + BT_DEVICE_INTERFACE, + NULL, NULL); + g_free(device_path); + retv_if(device_proxy == NULL, BLUETOOTH_ERROR_INTERNAL); + + g_dbus_proxy_call_sync(device_proxy, "DisconnectOtc", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if (error) { + BT_ERR("DisconnectOtc Call Error %s[%s]", + error->message, device_address); + g_error_free(error); + g_object_unref(device_proxy); + return BLUETOOTH_ERROR_INTERNAL; + } + + if (device_proxy) + g_object_unref(device_proxy); + + return ret; +} diff --git a/bt-service/include/bt-service-otp.h b/bt-service/include/bt-service-otp.h index 64d4026..5b8b190 100644 --- a/bt-service/include/bt-service-otp.h +++ b/bt-service/include/bt-service-otp.h @@ -39,6 +39,10 @@ int _bt_otp_write_characteristic_value(int request_id, char *sender, char *handl void _bt_otp_check_indication(const char *path, GVariant *msg); +int _bt_otp_connect_otc(int req_id, const bluetooth_device_address_t *bd_addr); + +int _bt_otp_disconnect_otc(const bluetooth_device_address_t *bd_addr); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/bluetooth-api.h b/include/bluetooth-api.h index 153f324..94f8a89 100644 --- a/include/bluetooth-api.h +++ b/include/bluetooth-api.h @@ -525,6 +525,15 @@ typedef struct { } bluetooth_otp_resp_info_t; /** +* Structure to hold the OTC Channel Info +*/ +typedef struct { + gboolean connected; /**< Connection Status */ + int fd; /**< Fd */ + char *address; /**< Remote address */ +} bluetooth_otc_info_t; + +/** * Advertising parameters */ typedef struct { @@ -845,6 +854,7 @@ typedef enum { BLUETOOTH_EVENT_OTP_NOTIFICATION_ENABLED, /* OTP Notification Enabled Response */ BLUETOOTH_EVENT_OTP_WRITE_CHAR_VAL, /* OTP Write Value Response */ BLUETOOTH_EVENT_OTP_INDICATION, /* OTP Indication */ + BLUETOOTH_EVENT_OTC_STATE_CHANGED, /* OTC Connection State Changed Event */ } bluetooth_event_type_t; /** @@ -7646,6 +7656,40 @@ int bluetooth_otp_write_characteristics_value( const char *handle, int bluetooth_otp_read_characteristic_value(const char *handle); /** + * @fn int bluetooth_otp_connect_otc(const bluetooth_device_address_t *device_address); + * + * @brief Read value for remote characteristics. + * + * This function is a synchronous call. + * + * @return + * + * @exception None + * @param[in] None + * @param[out] None + * + * @remark None + */ +int bluetooth_otp_connect_otc(const bluetooth_device_address_t *device_address); + +/** + * @fn int bluetooth_otp_disconnect_otc(const bluetooth_device_address_t *device_address); + * + * @brief Read value for remote characteristics. + * + * This function is a synchronous call. + * + * @return + * + * @exception None + * @param[in] None + * @param[out] None + * + * @remark None + */ +int bluetooth_otp_disconnect_otc(const bluetooth_device_address_t *device_address); + +/** * @} */ diff --git a/include/bt-internal-types.h b/include/bt-internal-types.h index 23d8917..597384b 100644 --- a/include/bt-internal-types.h +++ b/include/bt-internal-types.h @@ -386,6 +386,8 @@ typedef enum { BT_OTP_READ_VALUE, BT_OTP_ENABLE_NOTIFICATION, BT_OTP_WRITE_VALUE, + BT_LE_OTC_CONNECT, + BT_LE_OTC_DISCONNECT, } bt_function_t; typedef struct { @@ -568,6 +570,7 @@ typedef struct { #define BT_OTP_NOTIFICATION_ENABLED "OtpNotificationEnabled" #define BT_OTP_WRITE_CHAR_VAL "OtpWriteCharVal" #define BT_OTP_INDICATION "OtpIndication" +#define BT_OTC_STATE_CHANGED "OtcStateChanged" typedef enum { _PROFILE_UNKNOWN = 0, -- 2.7.4