X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-otp%2Fbt-otpserver.c;h=8cc44939e1040d47239357793878e06e66a811a9;hb=0beafff38fb90ccd8086be57a80b8a8acd344230;hp=48fce4922eecc8386f93551f8072483306b7ce59;hpb=7aecce7eaeb56caf35f9479fa5000c1b7ac2b01b;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index 48fce49..8cc4493 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "bt-otpserver.h" #include "bluetooth-api.h" @@ -63,6 +65,7 @@ static int property_sub_id = -1; static int adapter_sub_id = -1; static int device_sub_id = -1; static guint g_owner_id = 0; +static guint server_watch_id = 0; struct otp_char_info { gchar *char_path; @@ -94,8 +97,16 @@ struct oacp_operation { uint32_t offset; uint32_t length; uint8_t opcode; + uint32_t length_sofar; uint8_t mode; int fd; + FILE *fp; +}; + +struct oacp_create_operation { + char *remote_address; + char *uuid; + uint32_t size; }; static struct object_metadata *selected_object = NULL; @@ -109,7 +120,9 @@ 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; +struct oacp_operation *oacp_op = NULL; +struct oacp_create_operation *oacp_create = NULL; +unsigned int timeout_id; static const gchar otp_introspection_xml[] = "" @@ -133,6 +146,7 @@ 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); static void delete_all_objects(void) { @@ -285,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) { @@ -321,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); @@ -382,8 +398,10 @@ int _bt_otp_prepare_ots(void) } /* 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); @@ -488,17 +506,13 @@ int _bt_otp_set_advertising_data(void) void _bt_otp_start_write_on_fd() { char buf[BT_L2CAP_BUFFER_LEN]; - int written = 0; - int read = 0; + int written; + int read; + int len; 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); @@ -506,43 +520,149 @@ void _bt_otp_start_write_on_fd() fp = fopen(file_path, "r"); if (!fp) { BT_DBG("fopen() failed : %s", strerror(errno)); - goto fail; + 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; + + 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("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; + BT_DBG("Received data length %d, 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, sizeof(file_path), "%s%s", + directory, selected_object->name); + + BT_DBG("file_path = [%s]", file_path); + fp = fopen(file_path, "w"); + if (!fp) { + BT_DBG("fopen() failed : %s", strerror(errno)); + goto fail; } - } else { - read = fread(buf, 1, length, fp); - written = write(oacp_read->fd, buf, oacp_read->length); - BT_DBG("read [%d], Written [%d]", read, written); + oacp_op->fp = fp; } - fclose(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 [%lu], received_buff_len [%d], size [%lu]", + 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(oacp_read->remote_address); - g_free(oacp_read); - oacp_read = NULL; + 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, @@ -564,7 +684,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; @@ -617,7 +737,8 @@ 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->props = OBJECT_READ | OBJECT_WRITE | + OBJECT_EXECUTE | OBJECT_DELETE; otp_object_list = g_slist_append(otp_object_list, object); @@ -683,16 +804,15 @@ fail: _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_op) { + oacp_op->fd = fd; - if (oacp_read->opcode == OACP_READ) - _bt_otp_start_write_on_fd(); -done: + 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(); + } g_dbus_method_invocation_return_value(invocation, NULL); } BT_DBG("-"); @@ -873,7 +993,7 @@ fail: return object_path; } -int _bt_otp_open_otc_and_listen(char *address) +int _bt_otp_open_otc_and_listen(char *address, char *method) { char *object_path; GDBusProxy *device_proxy = NULL; @@ -881,6 +1001,13 @@ int _bt_otp_open_otc_and_listen(char *address) 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; @@ -896,7 +1023,7 @@ int _bt_otp_open_otc_and_listen(char *address) } - result = g_dbus_proxy_call_sync(device_proxy, "ListenOtc", + result = g_dbus_proxy_call_sync(device_proxy, method, NULL, G_DBUS_CALL_FLAGS_NONE, -1, @@ -919,35 +1046,170 @@ fail: return ret; } +static bool __bt_oacp_create_timeout_cb(gpointer user_data) +{ + if (oacp_create) { + g_free(oacp_create->uuid); + g_free(oacp_create); + oacp_create = NULL; + } + return TRUE; +} + +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; + + /* 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; + } + + ret = fun(absolute_path); + dlclose(handle); + + 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 err = BLUETOOTH_ERROR_NONE; int opcode = value[0]; - uint32_t object_offset, length; + 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 (!otp_object_list) { + if (!selected_object) { + BT_DBG("Object not selected"); ret = OACP_INVALID_OBJ; goto fail; } switch (opcode) { case OACP_CREATE: - ret = OACP_OPCODE_NOT_SUPPORTED; + BT_INFO("OACP_CREATE"); + object_size = (uint32_t)(value[4] & 0xFF) << 24 | + (uint32_t)(value[3] & 0xFF) << 16 | + (uint32_t)(value[2] & 0xFF) << 8 | + (uint32_t)(value[1] & 0xFF); + + uuid = g_strndup(value + 5, len - 5); + BT_INFO("Size = %lu, UUID = %s", object_size, uuid); + + if (oacp_create) { + /* Create operation already going on. */ + ret = OACP_OPERATION_FAILED; + goto fail; + } + oacp_create = g_malloc0(sizeof(struct oacp_create_operation)); + oacp_create->size = object_size; + oacp_create->uuid = g_strdup(uuid); + if (timeout_id > 0) + g_source_remove(timeout_id); + timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT, + (GSourceFunc)__bt_oacp_create_timeout_cb, NULL); + g_free(uuid); break; case OACP_DELETE: - ret = OACP_OPCODE_NOT_SUPPORTED; + if (opcode == OACP_DELETE && + ~(selected_object->props & OBJECT_DELETE)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + snprintf(absolute_file_path, sizeof(absolute_file_path), + "%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: - ret = OACP_OPCODE_NOT_SUPPORTED; + if (opcode == OACP_EXECUTE && + ~(selected_object->props & OBJECT_EXECUTE)) { + ret = OACP_PROCEDURE_NOT_SUPPORTED; + goto fail; + } + snprintf(absolute_file_path, sizeof(absolute_file_path), + "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 | @@ -957,31 +1219,35 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, (uint32_t)(value[6] & 0xFF) << 8 | (uint32_t)(value[5] & 0xFF); - BT_INFO("Offset = %lu, Length = %lu", object_offset, length); + if (opcode == OACP_WRITE) + mode = (uint8_t)value[9] & 0xFF; - if (oacp_read && otc_connection_status) { - /* Read operation already going on. */ - ret = OACP_OBJECT_LOCKED; - goto fail; + BT_INFO("Offset = %lu, Length = %lu", object_offset, length, mode); + + 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_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; + + 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; } - ret = OACP_SUCCESS; - break; - case OACP_WRITE: - ret = OACP_OPCODE_NOT_SUPPORTED; break; case OACP_ABORT: ret = OACP_OPCODE_NOT_SUPPORTED; @@ -995,18 +1261,45 @@ fail: info->req_opcode = opcode; info->result_code = ret; info->resp_param = NULL; - return app_err; + return BLUETOOTH_ERROR_NONE; } -void convert_to_hex(struct object_metadata *object, char *type, char *value) +void convert_to_hex(struct object_metadata *object, char *metadata, char *value) { 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, "type")) { + /* Convert UUID string to 128 bit UUID */ + uint32_t data0, data4; + uint16_t data1, data2, data3, data5; + + if (!object->type || sscanf(object->type, + "%08x-%04hx-%04hx-%04hx-%08x%04hx", + &data0, &data1, &data2, + &data3, &data4, &data5) != 6) { + BT_ERR("Object Type UUID not updated"); + return; + } + + 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); + + } else if (!g_strcmp0(metadata, "size")) { value[3] = (object->curr_size >> 24) & 0xFF; value[2] = (object->curr_size >> 16) & 0xFF; @@ -1018,7 +1311,7 @@ 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), &fc_tm); @@ -1030,7 +1323,7 @@ void convert_to_hex(struct object_metadata *object, char *type, char *value) 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; @@ -1039,7 +1332,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; @@ -1049,13 +1342,14 @@ 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]; _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)); + + convert_to_hex(object, "type", value); + _bt_otp_set_char_value(otp_object_type_obj_path, value, 16); convert_to_hex(object, "size", value); _bt_otp_set_char_value(otp_object_size_obj_path, value, 8); @@ -1074,12 +1368,29 @@ void update_obj_metadata_charc_value(struct object_metadata *object) _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); @@ -1089,7 +1400,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; @@ -1098,8 +1409,8 @@ 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: { + 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) { @@ -1109,8 +1420,8 @@ 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: { + break; + case OLCP_PREVIOUS: if (obj_curr_index == 0) { ret = OLCP_OUT_OF_BOUNDS; goto fail; @@ -1123,8 +1434,8 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, update_obj_metadata_charc_value(object); selected_object = object; obj_curr_index -= 1; - } break; - case OLCP_NEXT: { + break; + case OLCP_NEXT: object = (struct object_metadata *) g_slist_nth_data(otp_object_list, obj_curr_index+1); if (!object) { ret = OLCP_OUT_OF_BOUNDS; @@ -1133,8 +1444,27 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, update_obj_metadata_charc_value(object); selected_object = object; obj_curr_index += 1; - } break; + 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]", 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; + obj_curr_index = index - 1; + break; case OLCP_ORDER: case OLCP_REQ_NO_OBJ: case OLCP_CLEAR_MARKING: @@ -1150,6 +1480,68 @@ fail: return BLUETOOTH_ERROR_NONE; } +int _bt_otp_obj_name_cb(char *value, int len) +{ + int ret = BLUETOOTH_ERROR_NONE; + + struct object_metadata *object = NULL; + struct stat st; + char *file_path; + char *filename; + int length; + FILE *fp = NULL; + + filename = g_strndup(value, len); + length = len + strlen(BT_OTP_BASE_DIR_PATH) + 1; + file_path = malloc(length); + + snprintf(file_path, length, "%s%s", + BT_OTP_BASE_DIR_PATH, filename); + BT_DBG("file_path = [%s]", file_path); + + fp = fopen(file_path, "a"); + if (!fp) { + BT_DBG("fopen() failed : %s", strerror(errno)); + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + if (stat(file_path, &st) == -1) { + BT_INFO("stat failed: (%d)\n", errno); + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + object = g_new0(struct object_metadata, 1); + + object->name = g_strdup(filename); + object->type = _otp_convert_uuid_to_uuid128(oacp_create->uuid); + object->first_created = st.st_ctime; + object->last_modified = st.st_ctime; + object->curr_size = (uint32_t)st.st_size; + object->alloc_size = oacp_create->size; + object->id = object_id; + object->props = OBJECT_READ | OBJECT_WRITE; + + otp_object_list = g_slist_append(otp_object_list, + object); + + update_obj_metadata_charc_value(object); + selected_object = object; + obj_curr_index = g_slist_length(otp_object_list) - 1; + object_id++; +fail: + if (fp) + fclose(fp); + g_free(filename); + free(file_path); + g_free(oacp_create->uuid); + g_free(oacp_create); + oacp_create = NULL; + + return ret; +} + static struct otp_char_info *otp_get_char_value(const char *path) { GSList *tmp = NULL; @@ -1219,6 +1611,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(""); @@ -1230,12 +1623,13 @@ static void _bt_otp_send_indication(const char *obj_path, value[5] = (info->resp_param[4] >> 16) & 0xFF; value[4] = (info->resp_param[5] >> 8) & 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); @@ -1243,7 +1637,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; @@ -1281,6 +1675,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); @@ -1294,9 +1689,29 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, if (len != 0) { if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - result = _bt_otp_oacp_write_cb(value, len, offset, addr, &info); + if (!OACP_indicate) + result = BLUETOOTH_ERROR_CCC_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_ERROR_CCC_IMPROPERLY_CONFIGURED; + else + result = _bt_otp_olcp_write_cb(value, len, offset, &info); + } else if (!g_strcmp0(char_path, otp_object_name_obj_path)) { + if (oacp_create) { + /* OACP_CREATE is ongoing */ + result = _bt_otp_obj_name_cb(value, len); + } else { + /* Dont permit writting object name except while creating object. + * As this is directly pointing local objects. + */ + result = BLUETOOTH_ERROR_WRITE_REQUEST_REJECTED; + } + } else if (!g_strcmp0(char_path, otp_object_first_created_obj_path)) { + _bt_otp_set_char_value(otp_object_first_created_obj_path, value, len); + } else if (!g_strcmp0(char_path, otp_object_last_modified_obj_path)) { + _bt_otp_set_char_value(otp_object_last_modified_obj_path, value, len); } else { BT_ERR("Wrong Object Path %s", char_path); result = BLUETOOTH_ERROR_INTERNAL; @@ -1431,12 +1846,9 @@ void _bt_otc_disconnected_cb(GDBusConnection *connection, 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); + object_path); otc_connection_status = FALSE; - if (oacp_read) { - g_free(oacp_read->remote_address); - g_free(oacp_read); - } + _bt_otp_free_oacp_op(); } } }