X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-otp%2Fbt-otpserver.c;h=c588be9f15e57aca4d05240ef010bce646260179;hb=8be593a40f32cf0245157f62c313ea02658204a7;hp=3eff442a810f1d437387e4e427771dcda3a907db;hpb=d9f33483f2498b7476080df530c8558dc5ddf8da;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index 3eff442..c588be9 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -26,10 +26,14 @@ #include #include #include +#include +#include +#include #include "bt-otpserver.h" #include "bluetooth-api.h" +#include #undef LOG_TAG #define LOG_TAG "BLUETOOTH_OTP" @@ -60,7 +64,10 @@ static GDBusConnection *g_conn; static int property_sub_id = -1; static int adapter_sub_id = -1; +static int device_sub_id = -1; +static int device_property_sub_id = -1; static guint g_owner_id = 0; +static guint server_watch_id = 0; struct otp_char_info { gchar *char_path; @@ -87,14 +94,33 @@ 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; + uint32_t length_sofar; + uint8_t mode; + int fd; + FILE *fp; +}; + +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 guint curr_obj_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_op = NULL; +unsigned int timeout_id; +unsigned int oacp_create_timeout_id; +uint64_t curr_obj_id, prev_obj_id; +static gboolean oacp_create = FALSE; static const gchar otp_introspection_xml[] = "" @@ -106,11 +132,22 @@ 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); +int _bt_otp_open_otc_and_listen(char *address, char *method); +void _bt_otp_restore_old_object(); +struct object_metadata *_bt_otp_client_find_object(GSList *list, + uint64_t id, guint *index); static void delete_all_objects(void) { @@ -174,9 +211,8 @@ void _bt_otp_exit(void) if (ret != BLUETOOTH_ERROR_NONE) BT_ERR("Failed to stop ADV %d", ret); - if (main_loop != NULL) { + if (main_loop != NULL) g_main_loop_quit(main_loop); - } } static void _bt_otp_set_char_value(const char *obj_path, @@ -263,8 +299,8 @@ int _bt_otp_prepare_ots(void) char *desc_uuid; bt_gatt_characteristic_property_t props; bt_gatt_permission_t perms; - char supp_feat[OTP_FEATURE_LENGTH] = { 0x08, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00 }; + char supp_feat[OTP_FEATURE_LENGTH] = { 0x3B, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00 }; ret = bluetooth_gatt_init(); if (ret != BLUETOOTH_ERROR_NONE) { @@ -299,8 +335,10 @@ int _bt_otp_prepare_ots(void) OTP_FEATURE_LENGTH); /* Characteristic Object Name */ - props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ; - perms = BLUETOOTH_GATT_PERMISSION_READ; + props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ | + BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE; + perms = BLUETOOTH_GATT_PERMISSION_READ | + BLUETOOTH_GATT_PERMISSION_WRITE; char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_NAME_UUID); ret = add_new_characteristic(char_uuid, perms, props, &otp_object_name_obj_path); @@ -347,18 +385,23 @@ int _bt_otp_prepare_ots(void) if (ret != BLUETOOTH_ERROR_NONE) goto fail; - /* Characteristic Object ID */ - props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ; - perms = BLUETOOTH_GATT_PERMISSION_READ; - char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_ID_UUID); - ret = add_new_characteristic(char_uuid, perms, props, - &otp_object_id_obj_path); - if (ret != BLUETOOTH_ERROR_NONE) - goto fail; + /* Object ID is mandatory for mutiple object server */ + if (mutiple_obj_support) { + /* Characteristic Object ID */ + props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ; + perms = BLUETOOTH_GATT_PERMISSION_READ; + char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_ID_UUID); + ret = add_new_characteristic(char_uuid, perms, props, + &otp_object_id_obj_path); + if (ret != BLUETOOTH_ERROR_NONE) + goto fail; + } /* Characteristic Object Properties */ - props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ; - perms = BLUETOOTH_GATT_PERMISSION_READ; + props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ | + BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE; + perms = BLUETOOTH_GATT_PERMISSION_READ | + BLUETOOTH_GATT_PERMISSION_WRITE; char_uuid = _otp_convert_uuid_to_uuid128(OTP_OBJECT_PROP_UUID); ret = add_new_characteristic(char_uuid, perms, props, &otp_object_prop_obj_path); @@ -386,25 +429,30 @@ int _bt_otp_prepare_ots(void) goto fail; } - /* Characteristic OLCP */ - props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE | - BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE; - perms = BLUETOOTH_GATT_PERMISSION_WRITE; - char_uuid = _otp_convert_uuid_to_uuid128(OTP_OLCP_UUID); - ret = add_new_characteristic(char_uuid, perms, props, - &otp_olcp_obj_path); - if (ret != BLUETOOTH_ERROR_NONE) - goto fail; + /* OLCP Characteristics is not required + * for single object server + */ + if (mutiple_obj_support) { + /* Characteristic OLCP */ + props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE | + BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE; + perms = BLUETOOTH_GATT_PERMISSION_WRITE; + char_uuid = _otp_convert_uuid_to_uuid128(OTP_OLCP_UUID); + ret = add_new_characteristic(char_uuid, perms, props, + &otp_olcp_obj_path); + if (ret != BLUETOOTH_ERROR_NONE) + goto fail; - /* CCCD for OLCP */ - desc_uuid = _otp_convert_uuid_to_uuid128(OTP_CP_CCC_DESC_UUID); - perms = BLUETOOTH_GATT_PERMISSION_READ | - BLUETOOTH_GATT_PERMISSION_WRITE; - ret = bluetooth_gatt_add_descriptor(otp_olcp_obj_path, desc_uuid, - perms, &otp_olcp_desc_obj_path); - if (ret != BLUETOOTH_ERROR_NONE) { - BT_ERR("Failed to add new char descriptor %d", ret); - goto fail; + /* CCCD for OLCP */ + desc_uuid = _otp_convert_uuid_to_uuid128(OTP_CP_CCC_DESC_UUID); + perms = BLUETOOTH_GATT_PERMISSION_READ | + BLUETOOTH_GATT_PERMISSION_WRITE; + ret = bluetooth_gatt_add_descriptor(otp_olcp_obj_path, desc_uuid, + perms, &otp_olcp_desc_obj_path); + if (ret != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to add new char descriptor %d", ret); + goto fail; + } } /* Register service */ @@ -455,6 +503,172 @@ int _bt_otp_set_advertising_data(void) return 0; } +void _bt_otp_start_write_on_fd() +{ + char buf[BT_L2CAP_BUFFER_LEN]; + int written; + int read; + int len; + FILE *fp; + char file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + int length; + char err_msg[256] = {0, }; + + snprintf(file_path, BT_FILE_PATH_MAX_LEN, "%s%s", + directory, selected_object->name); + BT_DBG("file_path = [%s]", file_path); + + fp = fopen(file_path, "r"); + if (!fp) { + cynara_strerror(errno, err_msg, sizeof(err_msg)); + BT_ERR("fopen() failed : %s", err_msg); + return; + } + + BT_DBG("length [%d]", oacp_op->length); + length = oacp_op->length; + + while (length > 0) { + if (length < BT_L2CAP_BUFFER_LEN) + len = length; + else + len = BT_L2CAP_BUFFER_LEN; + + read = fread(buf, 1, len, fp); + written = write(oacp_op->fd, buf, len); + + if (written < 0) + goto fail; + + length -= written; + + BT_DBG("read [%d], written [%d], rem_len [%d]", + read, written, length); + } +fail: + fclose(fp); +} + + +static bool __bt_otc_connection_timeout_cb(gpointer user_data) +{ + int err = BLUETOOTH_ERROR_NONE; + char *remote_addr = oacp_op->remote_address; + + err = _bt_otp_open_otc_and_listen(remote_addr, "DisconnectOtc"); + if (err != BLUETOOTH_ERROR_NONE) + BT_ERR("Disconnect OTC failed"); + + return TRUE; +} + +static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + char *remote_addr = oacp_op->remote_address; + GIOStatus status = G_IO_STATUS_NORMAL; + GError *err = NULL; + char *buffer = NULL; + gsize len = 0; + int written; + int fd; + char err_msg[256] = {0, }; + + BT_DBG(""); + + fd = g_io_channel_unix_get_fd(chan); + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + otc_connection_status = FALSE; + BT_ERR("OTC disconnected: %d", fd); + close(fd); + g_source_remove(server_watch_id); + return FALSE; + } + + buffer = g_malloc0(BT_L2CAP_BUFFER_LEN + 1); + + status = g_io_channel_read_chars(chan, buffer, + BT_L2CAP_BUFFER_LEN, + &len, &err); + if (status != G_IO_STATUS_NORMAL) { + BT_ERR("IO Channel read is failed with %d", status); + + g_free(buffer); + if (err) { + otc_connection_status = FALSE; + BT_ERR("IO Channel read error [%s]", err->message); + if (status == G_IO_STATUS_ERROR) { + BT_ERR("cond : %d", cond); + g_error_free(err); + close(fd); + g_source_remove(server_watch_id); + return FALSE; + } + g_error_free(err); + } + return TRUE; + } + + BT_DBG("Received data length %zu, remote_addr = %s", len, remote_addr); + + if (!oacp_op->fp) { + char file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + FILE *fp = NULL; + + if (!selected_object) { + BT_DBG("Object not selected"); + goto fail; + } + + snprintf(file_path, BT_FILE_PATH_MAX_LEN, "%s%s", + directory, selected_object->name); + + BT_DBG("file_path = [%s]", file_path); + fp = fopen(file_path, "w"); + if (!fp) { + cynara_strerror(errno, err_msg, sizeof(err_msg)); + BT_ERR("fopen() failed : %s", err_msg); + goto fail; + } + oacp_op->fp = fp; + } + + if (oacp_op->length_sofar <= oacp_op->length) { + written = fwrite(buffer, 1, len, oacp_op->fp); + oacp_op->length_sofar += written; + BT_DBG("written [%d], length_sofar [%u], received_buff_len [%zu], size [%u]", + written, oacp_op->length_sofar, len, oacp_op->length); + } + + if (timeout_id > 0) { + g_source_remove(timeout_id); + timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT, + (GSourceFunc)__bt_otc_connection_timeout_cb, NULL); + } +fail: + g_free(buffer); + return TRUE; +} + +static void _bt_otp_start_read_on_fd() +{ + GIOChannel *data_io; + data_io = g_io_channel_unix_new(oacp_op->fd); + + g_io_channel_set_encoding(data_io, NULL, NULL); + g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL); + + server_watch_id = g_io_add_watch(data_io, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + __server_data_received_cb, NULL); + + if (timeout_id > 0) + g_source_remove(timeout_id); + + timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT, + (GSourceFunc)__bt_otc_connection_timeout_cb, NULL); +} + static void _bt_otp_method(GDBusConnection *connection, const gchar *sender, const gchar *object_path, @@ -474,7 +688,7 @@ static void _bt_otp_method(GDBusConnection *connection, GDir *dir = NULL; GError *error = NULL; const gchar *filename = NULL; - char absolute_path[ABSOLUTE_PATH_MAX_LENGTH]; + char absolute_path[BT_FILE_PATH_MAX_LEN]; GSList *list = NULL, *l = NULL; struct stat st; struct object_metadata *object = NULL; @@ -490,9 +704,10 @@ static void _bt_otp_method(GDBusConnection *connection, goto fail; } - while ((filename = g_dir_read_name(dir))) { + while ((filename = g_dir_read_name(dir))) list = g_slist_append(list, (gpointer) filename); - } + + g_dir_close(dir); if (!list) { BT_DBG("No object found in given directory"); @@ -500,9 +715,12 @@ static void _bt_otp_method(GDBusConnection *connection, goto fail; } + if (g_slist_length(list) > 1) + mutiple_obj_support = true; + for (l = list; l != NULL; l = l->next) { if (!l->data) continue; - snprintf(absolute_path, sizeof(absolute_path), "%s%s", directory, + snprintf(absolute_path, BT_FILE_PATH_MAX_LEN, "%s%s", directory, (char *)l->data); BT_INFO("filename: %s, absoulte_path: %s", @@ -516,13 +734,14 @@ static void _bt_otp_method(GDBusConnection *connection, object = g_new0(struct object_metadata, 1); object->name = g_strdup((const gchar *)l->data); - object->type = _otp_convert_uuid_to_uuid128(UNSUPPORTED_OBJECT_TYPE_UUID); + object->type = g_strdup(UNSUPPORTED_OBJECT_TYPE_UUID); object->first_created = st.st_ctime; object->last_modified = st.st_ctime; 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 | OBJECT_WRITE | + OBJECT_EXECUTE | OBJECT_DELETE; otp_object_list = g_slist_append(otp_object_list, object); @@ -530,8 +749,6 @@ static void _bt_otp_method(GDBusConnection *connection, object_id++; } - g_dir_close(dir); - BT_DBG("preparing"); if (_bt_otp_prepare_ots() != BLUETOOTH_ERROR_NONE) { BT_ERR("Fail to prepare OTP Proxy"); @@ -539,6 +756,16 @@ static void _bt_otp_method(GDBusConnection *connection, goto fail; } + /* If single object is supported, make that as + * selected object and update the metadata for the same. + */ + if (!mutiple_obj_support) { + BT_INFO("Server supports single object"); + selected_object = (struct object_metadata *) g_slist_nth_data(otp_object_list, 0); + if (selected_object) + update_obj_metadata_charc_value(selected_object); + } + BT_DBG("advertsing"); if (_bt_otp_set_advertising_data() != BLUETOOTH_ERROR_NONE) { BT_ERR("Fail to set advertising data"); @@ -553,6 +780,46 @@ 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); + otc_connection_status = TRUE; + if (oacp_op) { + oacp_op->fd = fd; + + if (oacp_op->opcode == OACP_READ) + _bt_otp_start_write_on_fd(); + else if (oacp_op->opcode == OACP_WRITE) + _bt_otp_start_read_on_fd(); + } else { + /* Close fd if oacp_op is NULL */ + close(fd); + } + g_dbus_method_invocation_return_value(invocation, NULL); } BT_DBG("-"); } @@ -644,16 +911,536 @@ 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 *method) +{ + char *object_path; + GDBusProxy *device_proxy = NULL; + GVariant *result = NULL; + GError *error = NULL; + int ret = BLUETOOTH_ERROR_NONE; + + if (method == NULL) + return BLUETOOTH_ERROR_INTERNAL; + + if (g_strcmp0(method, "ListenOtc") && + g_strcmp0(method, "DisconnectOtc")) + return BLUETOOTH_ERROR_INTERNAL; + + 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, method, + 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; +} + +static bool __bt_oacp_create_timeout_cb(gpointer user_data) +{ + /* Delete the EMPTY object */ + BT_INFO("+"); + _bt_otp_restore_old_object(); + return FALSE; +} + +static void _bt_otp_free_oacp_op() +{ + if (timeout_id > 0) { + g_source_remove(timeout_id); + timeout_id = 0; + } + + if (oacp_op) { + g_free(oacp_op->remote_address); + if (oacp_op->fp) + fclose(oacp_op->fp); + g_free(oacp_op); + oacp_op = NULL; + } +} + +int _bt_otp_send_launch_request(char *absolute_path) +{ + void *handle; + char *error; + int ret = BLUETOOTH_ERROR_NONE; + + /* check ARCH 64 or 32*/ + if (!access(FILEPATH_ARCH_64, 0)) { + BT_INFO("plugin loading for ARCH 64"); + handle = dlopen(HEADED_PLUGIN_FILEPATH64, RTLD_NOW); + } else { + BT_INFO("plugin loading for ARCH 32"); + handle = dlopen(HEADED_PLUGIN_FILEPATH, RTLD_NOW); + } + + if (!handle) { + BT_ERR("Can not load plugin %s", dlerror()); + return BLUETOOTH_ERROR_INTERNAL; + } + + dlerror(); /* Clear any existing error */ + + int (*fun)(char *) = (int (*)(char *))dlsym(handle, + "bt_app_control_send_launch_request"); + + if ((error = dlerror()) != NULL) { + BT_ERR("Can not load symbol : %s", dlerror()); + dlclose(handle); + return BLUETOOTH_ERROR_INTERNAL; + } + + if (fun) + ret = fun(absolute_path); + dlclose(handle); + + return ret; +} + +char *_bt_otp_uuid_convert_hex_to_string(char *value, uint32_t length) +{ + char *uuid = NULL; + unsigned int data0; + unsigned short data1; + unsigned short data2; + unsigned short data3; + unsigned int data4; + unsigned short data5; + size_t n; + + uuid = (char *) g_malloc0(2 * length * sizeof(char)); + n = 2 * length + 1; + + switch (length) { + case 2: + memcpy(&data1, &value[0], 2); + snprintf(uuid, n, "%.4x", ntohs(data1)); + break; + case 4: + memcpy(&data0, &value[0], 4); + snprintf(uuid, n, "%.8x", ntohl(data0)); + break; + case 16: + memcpy(&data0, &value[0], 4); + memcpy(&data1, &value[4], 2); + memcpy(&data2, &value[6], 2); + memcpy(&data3, &value[8], 2); + memcpy(&data4, &value[10], 4); + memcpy(&data5, &value[14], 2); + + snprintf(uuid, n + 4, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", + ntohl(data0), ntohs(data1), + ntohs(data2), ntohs(data3), + ntohl(data4), ntohs(data5)); + break; + default: + g_free(uuid); + return NULL; + } + + return uuid; +} + +void _bt_otp_create_new_object(uint32_t size, char *uuid) +{ + struct object_metadata *object = NULL; + + /* Store current object id. + * Incase of OACP Create fail, need to restore + * it back. + */ + prev_obj_id = selected_object->id; + + object = g_new0(struct object_metadata, 1); + + object->name = NULL; + object->type = g_strdup(uuid); + object->first_created = 0; + object->last_modified = 0; + object->curr_size = 0; + object->alloc_size = size; + object->id = object_id; + object->props = OBJECT_READ | OBJECT_WRITE | + OBJECT_EXECUTE | OBJECT_DELETE; + + otp_object_list = g_slist_append(otp_object_list, + object); + + update_obj_metadata_charc_value(object); + selected_object = object; + curr_obj_index = g_slist_length(otp_object_list) - 1; + curr_obj_id = selected_object->id; + object_id++; + + free(uuid); +} + +void _bt_otp_restore_old_object() +{ + struct object_metadata *object = NULL; + guint index = 0; + + object = _bt_otp_client_find_object(otp_object_list, curr_obj_id, &index); + if (!object) + return; + + otp_object_list = g_slist_remove(otp_object_list, object); + + index = 0; + object = _bt_otp_client_find_object(otp_object_list, prev_obj_id, &index); + if (!object) { + BT_ERR("Object is NULL"); + return; + } + oacp_create = FALSE; + update_obj_metadata_charc_value(object); + selected_object = object; + curr_obj_index = index; + object_id--; +} + +int _bt_otp_oacp_write_cb(char *value, int len, int offset, + char *remote_addr, struct indicate_info *info) +{ + int ret = OACP_SUCCESS; + int err = BLUETOOTH_ERROR_NONE; + int opcode = value[0]; + uint32_t object_offset, length, object_size; + uint8_t mode = 0; + char *uuid; + char absolute_file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + + BT_INFO("OACP Opcode 0x%d", opcode); + + if (!selected_object) { + BT_DBG("Object not selected"); + ret = OACP_INVALID_OBJ; + goto fail; + } -void convert_to_hex(struct object_metadata *object, char *type, char *value) + switch (opcode) { + case OACP_CREATE: + BT_INFO("OACP_CREATE"); + if (len < 7) { + BT_DBG("Error: invalid param"); + ret = OACP_INVALID_PARAM; + goto fail; + } + /* UUIDs can be 2/4/16 bytes long. + * So based on remaining len, determine uuid len. + */ + length = len - 5; + + uuid = _bt_otp_uuid_convert_hex_to_string(value + 1, length); + object_size = (uint32_t)(value[length + 4] & 0xFF) << 24 | + (uint32_t)(value[length + 3] & 0xFF) << 16 | + (uint32_t)(value[length + 2] & 0xFF) << 8 | + (uint32_t)(value[length + 1] & 0xFF); + + BT_INFO("Size = %u, UUID = %s", object_size, uuid); + + oacp_create = TRUE; + _bt_otp_create_new_object(object_size, uuid); + + if (oacp_create_timeout_id > 0) + g_source_remove(oacp_create_timeout_id); + oacp_create_timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT, + (GSourceFunc)__bt_oacp_create_timeout_cb, NULL); + break; + case OACP_DELETE: + if (!(selected_object->props & OBJECT_DELETE)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + snprintf(absolute_file_path, BT_FILE_PATH_MAX_LEN, + "%s%s", directory, selected_object->name); + + BT_DBG("absolute_file_path = [%s]", absolute_file_path); + + if (remove(absolute_file_path) != 0) { + BT_DBG("Error: unable to delete the file"); + ret = OACP_OPERATION_FAILED; + goto fail; + } + + BT_DBG("File deleted successfully"); + selected_object = NULL; + break; + case OACP_CALC_CHECKSUM: + ret = OACP_OPCODE_NOT_SUPPORTED; + break; + case OACP_EXECUTE: + if (!(selected_object->props & OBJECT_EXECUTE)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + snprintf(absolute_file_path, BT_FILE_PATH_MAX_LEN, + "file://%s%s", directory, selected_object->name); + + BT_DBG("absolute_file_path = [%s]", absolute_file_path); + + err = _bt_otp_send_launch_request(absolute_file_path); + if (err != BLUETOOTH_ERROR_NONE) { + BT_DBG("Error: unable to launch the file"); + ret = OACP_OPERATION_FAILED; + goto fail; + } + + BT_DBG("Successfully launched the file"); + break; + case OACP_READ: + case OACP_WRITE: + if (opcode == OACP_WRITE && + !(selected_object->props & OBJECT_WRITE)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + + if (opcode == OACP_READ && + !(selected_object->props & OBJECT_READ)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + + 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); + + if (opcode == OACP_WRITE) + mode = (uint8_t)value[9] & 0xFF; + + BT_INFO("Offset = %u, Length = %u", object_offset, length); + + if (oacp_op) { + if (otc_connection_status) { + /* Read/Write operation already going on. */ + ret = OACP_OBJECT_LOCKED; + goto fail; + } + _bt_otp_free_oacp_op(); + } + + oacp_op = g_malloc0(sizeof(struct oacp_operation)); + oacp_op->offset = object_offset; + oacp_op->length = length; + oacp_op->remote_address = g_strdup(remote_addr); + oacp_op->mode = mode; + oacp_op->opcode = opcode; + oacp_op->length_sofar = 0; + oacp_op->fp = NULL; + + err = _bt_otp_open_otc_and_listen(remote_addr, "ListenOtc"); + if (err != BLUETOOTH_ERROR_NONE) { + ret = OACP_CHANNEL_UNAVAILABLE; + _bt_otp_free_oacp_op(); + goto fail; + } + 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 BLUETOOTH_ERROR_NONE; +} + +int _bt_otp_uuid_convert_string_to_hex(char *uuid, char *value) +{ + int len, uuid_len; + uint32_t data0, data4; + uint16_t data1, data2, data3, data5; + + if (!uuid) { + BT_ERR("Object Type UUID NULL"); + return 0; + } + + len = strlen(uuid); + + switch (len) { + case 4: + /* UUID 16bits */ + sscanf(uuid, "%04hx", &data1); + data1 = htons(data1); + memcpy(value, &data1, 2); + uuid_len = 2; + break; + + case 8: + /* UUID 32bits */ + sscanf(uuid, "%08x", &data0); + data0 = htonl(data0); + memcpy(value, &data0, 4); + uuid_len = 4; + break; + + case 36: + /* UUID 128bits */ + sscanf(uuid, "%08x-%04hx-%04hx-%04hx-%08x%04hx", + &data0, &data1, &data2, + &data3, &data4, &data5); + + data0 = htonl(data0); + data1 = htons(data1); + data2 = htons(data2); + data3 = htons(data3); + data4 = htonl(data4); + data5 = htons(data5); + + memcpy(value, &data0, 4); + memcpy(value+4, &data1, 2); + memcpy(value+6, &data2, 2); + memcpy(value+8, &data3, 2); + memcpy(value+10, &data4, 4); + memcpy(value+14, &data5, 2); + uuid_len = 16; + break; + + default: + uuid_len = 0; + } + + return uuid_len; +} + +void convert_to_hex(struct object_metadata *object, char *metadata, char *value) { - struct tm *tm = NULL; + struct tm fc_tm; - BT_DBG("type : %s", type); + BT_DBG("Metadata : %s", metadata); - memset(value, 0, 8); + memset(value, 0, 16); - if (!g_strcmp0(type, "size")) { + if (!g_strcmp0(metadata, "size")) { value[3] = (object->curr_size >> 24) & 0xFF; value[2] = (object->curr_size >> 16) & 0xFF; @@ -665,19 +1452,21 @@ void convert_to_hex(struct object_metadata *object, char *type, char *value) value[5] = (object->alloc_size >> 8) & 0xFF; value[4] = object->alloc_size & 0xFF; - } else if (!g_strcmp0(type, "date")) { + } else if (!g_strcmp0(metadata, "date")) { - localtime_r(&(object->first_created), tm); + if (object->first_created) { + localtime_r(&(object->first_created), &fc_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")) { + } else if (!g_strcmp0(metadata, "id")) { value[5] = (object->id >> 48) & 0xFF; value[4] = (object->id >> 32) & 0xFF; @@ -686,7 +1475,7 @@ void convert_to_hex(struct object_metadata *object, char *type, char *value) value[1] = (object->id >> 8) & 0xFF; value[0] = object->id & 0xFF; - } else if (!g_strcmp0(type, "props")) { + } else if (!g_strcmp0(metadata, "props")) { value[3] = (object->props >> 24) & 0xFF; value[2] = (object->props >> 16) & 0xFF; value[1] = (object->props >> 8) & 0xFF; @@ -696,13 +1485,17 @@ void convert_to_hex(struct object_metadata *object, char *type, char *value) void update_obj_metadata_charc_value(struct object_metadata *object) { - /* Value can be of maximum eight bytes */ - char value[8]; + /* Value can be of maximum 16 bytes */ + char value[16]; + int uuid_len; - _bt_otp_set_char_value(otp_object_name_obj_path, object->name, - strlen(object->name)); - _bt_otp_set_char_value(otp_object_type_obj_path, object->type, - strlen(object->type)); + if (!oacp_create) { + _bt_otp_set_char_value(otp_object_name_obj_path, object->name, + strlen(object->name)); + } + + uuid_len = _bt_otp_uuid_convert_string_to_hex(object->type, value); + _bt_otp_set_char_value(otp_object_type_obj_path, value, uuid_len); convert_to_hex(object, "size", value); _bt_otp_set_char_value(otp_object_size_obj_path, value, 8); @@ -711,19 +1504,39 @@ void update_obj_metadata_charc_value(struct object_metadata *object) _bt_otp_set_char_value(otp_object_first_created_obj_path, value, 7); _bt_otp_set_char_value(otp_object_last_modified_obj_path, value, 7); - convert_to_hex(object, "id", value); - _bt_otp_set_char_value(otp_object_id_obj_path, value, 6); + /* Object ID is optonal for single object server */ + if (mutiple_obj_support) { + convert_to_hex(object, "id", value); + _bt_otp_set_char_value(otp_object_id_obj_path, value, 6); + } convert_to_hex(object, "props", value); _bt_otp_set_char_value(otp_object_prop_obj_path, value, 4); } +struct object_metadata *_bt_otp_client_find_object(GSList *list, uint64_t id, guint *index) +{ + GSList *l; + struct object_metadata *info; + + for (l = list; l; l = g_slist_next(l)) { + (*index)++; + info = l->data; + + if (info && (info->id == id)) + return info; + } + return NULL; +} + int _bt_otp_olcp_write_cb(char *value, int len, int offset, struct indicate_info *info) { int ret = OLCP_SUCCESS; int opcode = value[0]; struct object_metadata *object; + uint64_t object_id; + guint index = 0; BT_INFO("OLCP Opcode 0x%d", opcode); @@ -733,7 +1546,7 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, } switch (opcode) { - case OLCP_FIRST: { + case OLCP_FIRST: object = (struct object_metadata *) g_slist_nth_data(otp_object_list, 0); if (!object) { ret = OLCP_OUT_OF_BOUNDS; @@ -741,9 +1554,9 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, } update_obj_metadata_charc_value(object); selected_object = object; - obj_curr_index = 0; - } break; - case OLCP_LAST: { + curr_obj_index = 0; + break; + case OLCP_LAST: len = g_slist_length(otp_object_list); object = (struct object_metadata *) g_slist_nth_data(otp_object_list, len-1); if (!object) { @@ -752,33 +1565,52 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, } update_obj_metadata_charc_value(object); selected_object = object; - obj_curr_index = len-1; - } break; - case OLCP_PREVIOUS: { - if (obj_curr_index == 0) { + curr_obj_index = len-1; + break; + case OLCP_PREVIOUS: + if (curr_obj_index == 0) { ret = OLCP_OUT_OF_BOUNDS; goto fail; } - object = (struct object_metadata *) g_slist_nth_data(otp_object_list, obj_curr_index-1); + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index-1); if (!object) { ret = OLCP_OUT_OF_BOUNDS; goto fail; } update_obj_metadata_charc_value(object); selected_object = object; - obj_curr_index -= 1; - } break; - case OLCP_NEXT: { - object = (struct object_metadata *) g_slist_nth_data(otp_object_list, obj_curr_index+1); + curr_obj_index -= 1; + break; + case OLCP_NEXT: + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index+1); if (!object) { ret = OLCP_OUT_OF_BOUNDS; goto fail; } update_obj_metadata_charc_value(object); selected_object = object; - obj_curr_index += 1; - } break; + curr_obj_index += 1; + break; case OLCP_GOTO: + object_id = (uint64_t)(value[6] & 0xFF) << 40 | + (uint64_t)(value[5] & 0xFF) << 32 | + (uint64_t)(value[4] & 0xFF) << 24 | + (uint64_t)(value[3] & 0xFF) << 16 | + (uint64_t)(value[2] & 0xFF) << 8 | + (uint64_t)(value[1] & 0xFF); + BT_INFO("Object ID [%llu]", (unsigned long long int)object_id); + if (selected_object && selected_object->id == object_id) + goto fail; + + object = _bt_otp_client_find_object(otp_object_list, object_id, &index); + if (!object) { + ret = OLCP_OJECT_ID_NOT_FOUND; + goto fail; + } + update_obj_metadata_charc_value(object); + selected_object = object; + curr_obj_index = index - 1; + break; case OLCP_ORDER: case OLCP_REQ_NO_OBJ: case OLCP_CLEAR_MARKING: @@ -794,6 +1626,157 @@ fail: return BLUETOOTH_ERROR_NONE; } +int _bt_otp_obj_name_write_cb(char *value, int len) +{ + struct object_metadata *object; + char *filename; + char new_abs_filepath[BT_FILE_PATH_MAX_LEN] = {0, }; + int ret = BLUETOOTH_ERROR_NONE; + FILE *fp = NULL; + char err_msg[256] = {0, }; + + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; + + filename = g_strndup(value, len); + snprintf(new_abs_filepath, BT_FILE_PATH_MAX_LEN, "%s%s", + directory, filename); + BT_DBG("file_path = [%s]", new_abs_filepath); + + fp = fopen(new_abs_filepath, "r"); + /* fopen succeed means file already exists */ + if (fp) { + ret = BLUETOOTH_OTP_ERROR_OBJECT_NAME_EXISTS; + goto fail; + } + + if (oacp_create) { + struct stat st; + + fp = fopen(new_abs_filepath, "a"); + if (!fp) { + cynara_strerror(errno, err_msg, sizeof(err_msg)); + BT_ERR("fopen() failed : %s", err_msg); + ret = BLUETOOTH_ATT_ERROR_INTERNAL; + goto fail; + } + + if (stat(new_abs_filepath, &st) == -1) { + BT_INFO("stat failed: (%d)\n", errno); + ret = BLUETOOTH_ATT_ERROR_INTERNAL; + goto fail; + } + + object->name = g_strdup(filename); + object->first_created = st.st_ctime; + object->last_modified = st.st_ctime; + object->curr_size = (uint32_t) st.st_size; + oacp_create = FALSE; + } else { + char old_abs_filepath[BT_FILE_PATH_MAX_LEN] = {0, }; + snprintf(old_abs_filepath, BT_FILE_PATH_MAX_LEN, "%s%s", + directory, object->name); + + if (rename(old_abs_filepath, new_abs_filepath)) { + ret = BLUETOOTH_ATT_ERROR_INTERNAL; + goto fail; + } + } + + memcpy(object->name, value, len); + _bt_otp_set_char_value(otp_object_name_obj_path, value, len); + +fail: + if (oacp_create) + _bt_otp_restore_old_object(); + + if (oacp_create_timeout_id > 0) + g_source_remove(oacp_create_timeout_id); + + if (fp) + fclose(fp); + + g_free(filename); + return ret; +} + +int _bt_otp_obj_first_created_write_cb(char *value, int len) +{ + struct object_metadata *object; + struct tm tm = {0}; + uint16_t year; + + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; + + year = (uint16_t)(value[1] & 0xFF) << 8 | + (uint16_t)(value[0] & 0xFF); + tm.tm_year = year-1900; + tm.tm_mon = value[2] & 0xFF; + tm.tm_mon = tm.tm_mon-1; + tm.tm_mday = value[3] & 0xFF; + tm.tm_hour = value[4] & 0xFF; + tm.tm_min = value[5] & 0xFF; + tm.tm_sec = value[6] & 0xFF; + + object->first_created = mktime(&tm); + _bt_otp_set_char_value(otp_object_first_created_obj_path, value, len); + + return BLUETOOTH_ERROR_NONE; +} + +int _bt_otp_obj_last_modified_write_cb(char *value, int len) +{ + struct object_metadata *object; + struct tm tm = {0}; + uint16_t year; + + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; + + year = (uint16_t)(value[1] & 0xFF) << 8 | + (uint16_t)(value[0] & 0xFF); + tm.tm_year = year-1900; + tm.tm_mon = value[2] & 0xFF; + tm.tm_mon = tm.tm_mon-1; + tm.tm_mday = value[3] & 0xFF; + tm.tm_hour = value[4] & 0xFF; + tm.tm_min = value[5] & 0xFF; + tm.tm_sec = value[6] & 0xFF; + + object->last_modified = mktime(&tm); + _bt_otp_set_char_value(otp_object_last_modified_obj_path, value, len); + + return BLUETOOTH_ERROR_NONE; +} + +int _bt_otp_obj_props_write_cb(char *value, int len) +{ + struct object_metadata *object; + uint32_t props; + + /* Any attempt to write RFU bits is error */ + if (value[1] || value[2] || value[3]) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; + + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; + + props = (uint32_t)(value[3] & 0xFF) << 24 | + (uint32_t)(value[2] & 0xFF) << 16 | + (uint32_t)(value[1] & 0xFF) << 8 | + (uint32_t)(value[0] & 0xFF); + + object->props = props; + _bt_otp_set_char_value(otp_object_prop_obj_path, value, len); + + return BLUETOOTH_ERROR_NONE; +} + static struct otp_char_info *otp_get_char_value(const char *path) { GSList *tmp = NULL; @@ -809,33 +1792,45 @@ static struct otp_char_info *otp_get_char_value(const char *path) return NULL; } -int _bt_otp_read_cb(const char *obj_path, char **value, int *len) +int _bt_otp_read_cb(const char *obj_path, char **value, int *len, uint16_t offset) { struct otp_char_info *info = NULL; if (!obj_path) { BT_ERR("Wrong Obj path"); - return BLUETOOTH_ERROR_INTERNAL; + return BLUETOOTH_ATT_ERROR_INTERNAL; } if (g_strcmp0(obj_path, otp_feature_obj_path)) { - if (!selected_object) { - return BLUETOOTH_ERROR_OBJECT_NOT_SELECTED; - } + if (!selected_object) + return BLUETOOTH_OTP_ERROR_OBJECT_NOT_SELECTED; } info = otp_get_char_value(obj_path); if (info) { + if (oacp_create && !g_strcmp0(obj_path, otp_object_name_obj_path)) { + /* char_value is NULL, value_length is zero */ + *value = NULL; + *len = 0; + return BLUETOOTH_ATT_ERROR_NONE; + } + if (info->char_value == NULL || info->value_length == 0) - return BLUETOOTH_ERROR_INTERNAL; + return BLUETOOTH_ATT_ERROR_INTERNAL; + + if (offset > info->value_length) + return BLUETOOTH_ATT_ERROR_INVALID_OFFSET; - *len = info->value_length; + *len = info->value_length - offset; *value = (char *)malloc(sizeof(char)*(*len)); + if (*value == NULL) + return BLUETOOTH_ATT_ERROR_INTERNAL; + memcpy(*value, info->char_value, *len); - return BLUETOOTH_ERROR_NONE; + return BLUETOOTH_ATT_ERROR_NONE; } else { - return BLUETOOTH_ERROR_INTERNAL; + return BLUETOOTH_ATT_ERROR_INTERNAL; } } @@ -863,6 +1858,7 @@ static void _bt_otp_send_indication(const char *obj_path, { int ret = BLUETOOTH_ERROR_NONE; char value[7] = {0x00}; + int length = OTP_INDICATION_LEN_WITHOUT_RESP; BT_DBG(""); @@ -870,16 +1866,17 @@ static void _bt_otp_send_indication(const char *obj_path, value[1] = info->req_opcode & 0xFF; value[2] = info->result_code & 0xFF; if (info->resp_param) { - value[6] = (info->resp_param[3] >> 24) & 0xFF; - value[5] = (info->resp_param[4] >> 16) & 0xFF; - value[4] = (info->resp_param[5] >> 8) & 0xFF; + value[6] = info->resp_param[3] & 0xFF; + value[5] = info->resp_param[4] & 0xFF; + value[4] = info->resp_param[5] & 0xFF; value[3] = info->resp_param[6] & 0xFF; + length = OTP_INDICATION_LEN_WITH_RESP; } BT_DBG("Opcode: %d", value[1]); /* Store the status value */ - _bt_otp_set_char_value(obj_path, value, 7); + _bt_otp_set_char_value(obj_path, value, length); /* Send indication */ ret = bluetooth_gatt_server_set_notification(obj_path, remote_address); @@ -887,7 +1884,7 @@ static void _bt_otp_send_indication(const char *obj_path, BT_ERR("_bt_otp_send_control_point_indication failed"); return; } - ret = bluetooth_gatt_update_characteristic(obj_path, value, 7); + ret = bluetooth_gatt_update_characteristic(obj_path, value, length); if (ret != BLUETOOTH_ERROR_NONE) { BT_ERR("_bt_otp_send_control_point_indication failed"); return; @@ -925,6 +1922,7 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, guint16 offset = 0; char *value = NULL; struct indicate_info info; + g_variant_get(var, "(&s&s&syq@ay)", &char_path, &svc_handle, &addr, &req_id, &offset, &val); @@ -938,11 +1936,23 @@ 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 - */ + if (!OACP_indicate) + result = BLUETOOTH_ATT_ERROR_CCCD_IMPROPERLY_CONFIGURED; + else + 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); + if (!OLCP_indicate) + result = BLUETOOTH_ATT_ERROR_CCCD_IMPROPERLY_CONFIGURED; + else + result = _bt_otp_olcp_write_cb(value, len, offset, &info); + } else if (!g_strcmp0(char_path, otp_object_name_obj_path)) { + result = _bt_otp_obj_name_write_cb(value, len); + } else if (!g_strcmp0(char_path, otp_object_first_created_obj_path)) { + result = _bt_otp_obj_first_created_write_cb(value, len); + } else if (!g_strcmp0(char_path, otp_object_last_modified_obj_path)) { + result = _bt_otp_obj_last_modified_write_cb(value, len); + } else if (!g_strcmp0(char_path, otp_object_prop_obj_path)) { + result = _bt_otp_obj_props_write_cb(value, len); } else { BT_ERR("Wrong Object Path %s", char_path); result = BLUETOOTH_ERROR_INTERNAL; @@ -953,11 +1963,11 @@ 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) { + if (OLCP_indicate) _bt_otp_send_indication(char_path, &info, &addr_hex); - } } } else { BT_ERR("Array Len 0"); @@ -971,7 +1981,7 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, guint16 offset = 0; char *value = NULL; int len = 0; - result = BLUETOOTH_ERROR_NONE; + result = BLUETOOTH_ATT_ERROR_NONE; BT_INFO("ReadValue"); BT_INFO("Type '%s'\n", g_variant_get_type_string(var)); @@ -979,9 +1989,9 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, g_variant_get(var, "(&s&s&syq)", &char_path, &svc_handle, &addr, &req_id, &offset); - result = _bt_otp_read_cb(char_path, &value, &len); + result = _bt_otp_read_cb(char_path, &value, &len, offset); - if (result != BLUETOOTH_ERROR_NONE) { + if (result != BLUETOOTH_ATT_ERROR_NONE) { BT_ERR("ReadValue failed %s", char_path); bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ, @@ -1003,11 +2013,10 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, indicate ? "StartNotify" : "StopNotify"); BT_INFO("Type '%s'\n", g_variant_get_type_string(var)); - if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - /* Handle OACP notification */ - } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) { + if (!g_strcmp0(char_path, otp_oacp_obj_path)) + OACP_indicate = indicate; + else if (!g_strcmp0(char_path, otp_olcp_obj_path)) OLCP_indicate = indicate; - } } } return; @@ -1051,8 +2060,77 @@ void _bt_otp_adapter_event_filter(GDBusConnection *connection, BT_INFO("Interface %s, Signal %s", interface_name, signal_name); if (g_strcmp0(interface_name, BT_OTP_INTERFACE_NAME) == 0) { - if (strcasecmp(signal_name, BLE_DISABLED) == 0) { + if (strcasecmp(signal_name, BLE_DISABLED) == 0) _bt_otp_exit(); + } +} + +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; + _bt_otp_free_oacp_op(); + } + } +} + +void _bt_otp_device_property_event_filter(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + char *interfacename = NULL; + GVariant *val = NULL; + + g_variant_get(parameters, "(&s@a{sv}@as)", &interfacename, &val, NULL); + + if (strcasecmp(interfacename, BT_DEVICE_INTERFACE) == 0) { + GVariantIter value_iter; + GVariant *val1; + char *property = NULL; + + g_variant_iter_init(&value_iter, val); + while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &val1))) { + if (strcasecmp(property, "GattConnected") == 0) { + gboolean gatt_connected = FALSE; + char *address = NULL; + + g_variant_get(val1, "b", &gatt_connected); + + address = g_malloc0(BT_ADDRESS_STRING_SIZE); + + _bt_convert_device_path_to_address(object_path, address); + + BT_DBG("gatt_connected: %d", gatt_connected); + BT_DBG("address: %s", address); + if (!gatt_connected) { + if (oacp_create) + _bt_otp_restore_old_object(); + + if (oacp_create_timeout_id > 0) + g_source_remove(oacp_create_timeout_id); + } + g_free(address); + } } } } @@ -1087,6 +2165,18 @@ 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); + + device_property_sub_id = g_dbus_connection_signal_subscribe(conn, + NULL, BT_PROPERTIES_INTERFACE, + PROPERTIES_CHANGED, NULL, NULL, 0, + _bt_otp_device_property_event_filter, + NULL, NULL); + BT_DBG("-"); return 0; } @@ -1097,6 +2187,8 @@ 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); + g_dbus_connection_signal_unsubscribe(conn, device_property_sub_id); conn = NULL; BT_DBG("-"); @@ -1151,9 +2243,8 @@ int main(void) BT_DBG("g_main_loop_quit called!"); - if (main_loop != NULL) { + if (main_loop != NULL) g_main_loop_unref(main_loop); - } return 0; }