From: Gowtham Anandha Babu Date: Thu, 13 Jul 2017 15:22:50 +0000 (+0530) Subject: [OTP] Fix OACP Create request X-Git-Tag: accepted/tizen/unified/20170718.174144~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git;a=commitdiff_plain;h=645df23b2ffb0266288192222a3e23d41d117f3c [OTP] Fix OACP Create request 1) Changed Object type UUID implementation to support all types(16/32/128 bits) of UUIDs. 2) Fixed Object Metadata Write logic, so that changes reflect in object list. 3) Modified OACP Create logic to align with PTS. Change-Id: If652a0a32be6334c30d4302ad4caa9fb5a7cf92f Signed-off-by: Gowtham Anandha Babu --- diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index 8cc4493..1b62b0e 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -103,17 +103,11 @@ struct oacp_operation { FILE *fp; }; -struct oacp_create_operation { - char *remote_address; - char *uuid; - uint32_t size; -}; - 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; @@ -121,8 +115,9 @@ char *directory = NULL; gboolean mutiple_obj_support = false; static gboolean otc_connection_status = FALSE; struct oacp_operation *oacp_op = NULL; -struct oacp_create_operation *oacp_create = NULL; unsigned int timeout_id; +unsigned int oacp_create_timeout_id; +uint64_t curr_obj_id, prev_obj_id; static const gchar otp_introspection_xml[] = "" @@ -147,6 +142,9 @@ 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_delete_empty_file(); +struct object_metadata *_bt_otp_client_find_object(GSList *list, + uint64_t id, guint *index); static void delete_all_objects(void) { @@ -731,7 +729,7 @@ 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; @@ -1048,11 +1046,8 @@ fail: 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; - } + /* Delete the EMPTY object */ + _bt_otp_delete_empty_file(); return TRUE; } @@ -1109,6 +1104,134 @@ int _bt_otp_send_launch_request(char *absolute_path) 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; +} + +int _bt_otp_create_empty_file(uint32_t size, char *uuid) +{ + int ret = BLUETOOTH_ERROR_NONE; + struct object_metadata *object = NULL; + struct stat st; + char absolute_file_path[BT_FILE_PATH_MAX_LEN] = {0, }; + FILE *fp = NULL; + + snprintf(absolute_file_path, sizeof(absolute_file_path), + "%s%s", directory, BT_OTP_EMPTY_FILENAME); + BT_DBG("file_path = [%s]", absolute_file_path); + + fp = fopen(absolute_file_path, "a"); + if (!fp) { + BT_DBG("fopen() failed : %s", strerror(errno)); + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + if (stat(absolute_file_path, &st) == -1) { + BT_INFO("stat failed: (%d)\n", errno); + ret = BLUETOOTH_ERROR_INTERNAL; + goto fail; + } + + /* 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 = g_strdup(BT_OTP_EMPTY_FILENAME); + object->type = g_strdup(uuid); + object->first_created = st.st_ctime; + object->last_modified = st.st_ctime; + object->curr_size = (uint32_t)st.st_size; + object->alloc_size = 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; + curr_obj_index = g_slist_length(otp_object_list) - 1; + curr_obj_id = selected_object->id; + object_id++; +fail: + if (fp) + fclose(fp); + free(uuid); + return ret; +} + +void _bt_otp_delete_empty_file() +{ + struct object_metadata *object = NULL; + guint index = 0; + char absolute_file_path[BT_FILE_PATH_MAX_LEN] = {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); + + snprintf(absolute_file_path, sizeof(absolute_file_path), + "%s%s", directory, object->name); + + if (remove(absolute_file_path) != 0) { + BT_DBG("Error: unable to delete the file"); + } + + index = 0; + object = _bt_otp_client_find_object(otp_object_list, prev_obj_id, &index); + 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) { @@ -1131,27 +1254,35 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, switch (opcode) { case OACP_CREATE: 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); + 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); - uuid = g_strndup(value + 5, len - 5); - BT_INFO("Size = %lu, UUID = %s", object_size, uuid); + BT_INFO("Size = %u, UUID = %s", object_size, uuid); - if (oacp_create) { - /* Create operation already going on. */ + err = _bt_otp_create_empty_file(object_size, uuid); + if (err != BLUETOOTH_ERROR_NONE) { + BT_ERR("Failed to create empty file"); 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, + + 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); - g_free(uuid); break; case OACP_DELETE: if (opcode == OACP_DELETE && @@ -1264,26 +1395,41 @@ fail: return BLUETOOTH_ERROR_NONE; } -void convert_to_hex(struct object_metadata *object, char *metadata, char *value) +int _bt_otp_uuid_convert_string_to_hex(char *uuid, char *value) { - struct tm fc_tm; + int len, uuid_len; + uint32_t data0, data4; + uint16_t data1, data2, data3, data5; - BT_DBG("Metadata : %s", metadata); + if (!uuid) { + BT_ERR("Object Type UUID NULL"); + return 0; + } - memset(value, 0, 16); + len = strlen(uuid); - if (!g_strcmp0(metadata, "type")) { - /* Convert UUID string to 128 bit UUID */ - uint32_t data0, data4; - uint16_t data1, data2, data3, data5; + switch (len) { + case 4: + /* UUID 16bits */ + sscanf(uuid, "%04hx", &data1); + data1 = htons(data1); + memcpy(value, &data1, 2); + uuid_len = 2; + break; - 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; - } + 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); @@ -1298,8 +1444,25 @@ void convert_to_hex(struct object_metadata *object, char *metadata, char *value) memcpy(value+8, &data3, 2); memcpy(value+10, &data4, 4); memcpy(value+14, &data5, 2); + uuid_len = 16; + break; + + default: + uuid_len = 0; + } - } else if (!g_strcmp0(metadata, "size")) { + return uuid_len; +} + +void convert_to_hex(struct object_metadata *object, char *metadata, char *value) +{ + struct tm fc_tm; + + BT_DBG("Metadata : %s", metadata); + + memset(value, 0, 16); + + if (!g_strcmp0(metadata, "size")) { value[3] = (object->curr_size >> 24) & 0xFF; value[2] = (object->curr_size >> 16) & 0xFF; @@ -1344,12 +1507,13 @@ void update_obj_metadata_charc_value(struct object_metadata *object) { /* 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)); - convert_to_hex(object, "type", value); - _bt_otp_set_char_value(otp_object_type_obj_path, value, 16); + 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); @@ -1408,7 +1572,7 @@ 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; + curr_obj_index = 0; break; case OLCP_LAST: len = g_slist_length(otp_object_list); @@ -1419,31 +1583,31 @@ 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; + curr_obj_index = len-1; break; case OLCP_PREVIOUS: - if (obj_curr_index == 0) { + 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; + curr_obj_index -= 1; break; case OLCP_NEXT: - 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; + curr_obj_index += 1; break; case OLCP_GOTO: object_id = (uint64_t)(value[6] & 0xFF) << 40 | @@ -1463,7 +1627,7 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, } update_obj_metadata_charc_value(object); selected_object = object; - obj_curr_index = index - 1; + curr_obj_index = index - 1; break; case OLCP_ORDER: case OLCP_REQ_NO_OBJ: @@ -1480,68 +1644,117 @@ fail: return BLUETOOTH_ERROR_NONE; } -int _bt_otp_obj_name_cb(char *value, int len) +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, }; + char old_abs_filepath[BT_FILE_PATH_MAX_LEN] = {0, }; int ret = BLUETOOTH_ERROR_NONE; - struct object_metadata *object = NULL; - struct stat st; - char *file_path; - char *filename; - int length; - FILE *fp = NULL; + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_ERROR_WRITE_REQUEST_REJECTED; filename = g_strndup(value, len); - length = len + strlen(BT_OTP_BASE_DIR_PATH) + 1; - file_path = malloc(length); + snprintf(new_abs_filepath, strlen(new_abs_filepath), "%s%s", + directory, filename); - snprintf(file_path, length, "%s%s", - BT_OTP_BASE_DIR_PATH, filename); - BT_DBG("file_path = [%s]", file_path); + snprintf(old_abs_filepath, strlen(old_abs_filepath), "%s%s", + directory, object->name); - fp = fopen(file_path, "a"); - if (!fp) { - BT_DBG("fopen() failed : %s", strerror(errno)); - ret = BLUETOOTH_ERROR_INTERNAL; + if (rename(old_abs_filepath, new_abs_filepath)) { + ret = OBJECT_NAME_ALREADY_EXISTS; 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; + memcpy(object->name, value, len); + _bt_otp_set_char_value(otp_object_name_obj_path, value, len); - otp_object_list = g_slist_append(otp_object_list, - object); + if (oacp_create_timeout_id > 0) + g_source_remove(oacp_create_timeout_id); - 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; } +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_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_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_ERROR_WRITE_REQUEST_REJECTED; + + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_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; @@ -1699,19 +1912,13 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, 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; - } + result = _bt_otp_obj_name_write_cb(value, len); } 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); + result = _bt_otp_obj_first_created_write_cb(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); + 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; diff --git a/bt-otp/bt-otpserver.h b/bt-otp/bt-otpserver.h index 358a849..f8ce296 100755 --- a/bt-otp/bt-otpserver.h +++ b/bt-otp/bt-otpserver.h @@ -40,6 +40,7 @@ #define BT_ADDRESS_STRING_SIZE 18 #define BT_OTP_BASE_DIR_PATH "/home/owner/media/otp/" +#define BT_OTP_EMPTY_FILENAME " " #define BT_OACP_MAX_TIMEOUT 10000 /* Timeout for OACP operation in msec */