X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-otp%2Fbt-otpserver.c;h=76a8d9e9d23b23989e70a62048d54e9ce5b6c871;hb=c8fc45b330e281480d0be9bc6adba19e84ddb4b4;hp=4948a8c5f0f1effcd1b337a639ee7f0d77be13b8;hpb=2577dd15729dbed8e2dd652251536a777b06cc95;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index 4948a8c..76a8d9e 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -28,10 +28,12 @@ #include #include #include +#include #include "bt-otpserver.h" #include "bluetooth-api.h" +#include #undef LOG_TAG #define LOG_TAG "BLUETOOTH_OTP" @@ -63,6 +65,7 @@ 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; @@ -102,17 +105,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; @@ -120,8 +117,10 @@ 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 gboolean oacp_create = FALSE; static const gchar otp_introspection_xml[] = "" @@ -146,6 +145,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_restore_old_object(); +struct object_metadata *_bt_otp_client_find_object(GSList *list, + uint64_t id, guint *index); static void delete_all_objects(void) { @@ -209,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, @@ -298,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] = { 0xDC, 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) { @@ -397,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); @@ -509,14 +512,16 @@ void _bt_otp_start_write_on_fd() FILE *fp; char file_path[BT_FILE_PATH_MAX_LEN] = {0, }; int length; + char err_msg[256] = {0, }; - snprintf(file_path, sizeof(file_path), "%s%s", + 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) { - BT_DBG("fopen() failed : %s", strerror(errno)); + cynara_strerror(errno, err_msg, sizeof(err_msg)); + BT_ERR("fopen() failed : %s", err_msg); return; } @@ -567,6 +572,7 @@ static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond, gsize len = 0; int written; int fd; + char err_msg[256] = {0, }; BT_DBG(""); @@ -603,7 +609,7 @@ static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond, return TRUE; } - BT_DBG("Received data length %d, remote_addr = %s", len, remote_addr); + 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, }; @@ -614,13 +620,14 @@ static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond, goto fail; } - snprintf(file_path, sizeof(file_path), "%s%s", + 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) { - BT_DBG("fopen() failed : %s", strerror(errno)); + cynara_strerror(errno, err_msg, sizeof(err_msg)); + BT_ERR("fopen() failed : %s", err_msg); goto fail; } oacp_op->fp = fp; @@ -629,7 +636,7 @@ static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond, 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]", + BT_DBG("written [%d], length_sofar [%u], received_buff_len [%zu], size [%u]", written, oacp_op->length_sofar, len, oacp_op->length); } @@ -686,7 +693,7 @@ static void _bt_otp_method(GDBusConnection *connection, struct stat st; struct object_metadata *object = NULL; - g_variant_get(parameters, "(s)", &directory); + g_variant_get(parameters, "(&s)", &directory); BT_DBG("Directory = [%s]", directory); dir = g_dir_open(directory, 0, &error); @@ -697,9 +704,8 @@ 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); @@ -714,7 +720,7 @@ static void _bt_otp_method(GDBusConnection *connection, 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", @@ -728,7 +734,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; @@ -783,7 +789,7 @@ fail: char address[BT_ADDRESS_STRING_SIZE] = { 0 }; int fd; - g_variant_get(parameters, "(oh)", &dev_path, &index); + 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); @@ -809,6 +815,9 @@ fail: _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); } @@ -1045,12 +1054,10 @@ 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; - } - return TRUE; + /* Delete the EMPTY object */ + BT_INFO("+"); + _bt_otp_restore_old_object(); + return FALSE; } static void _bt_otp_free_oacp_op() @@ -1073,7 +1080,7 @@ int _bt_otp_send_launch_request(char *absolute_path) { void *handle; char *error; - int ret; + int ret = BLUETOOTH_ERROR_NONE; /* check ARCH 64 or 32*/ if (!access(FILEPATH_ARCH_64, 0)) { @@ -1092,7 +1099,7 @@ int _bt_otp_send_launch_request(char *absolute_path) dlerror(); /* Clear any existing error */ int (*fun)(char *) = (int (*)(char *))dlsym(handle, - "bt_app_control_send_launch_request"); + "bt_app_control_send_launch_request"); if ((error = dlerror()) != NULL) { BT_ERR("Can not load symbol : %s", dlerror()); @@ -1100,12 +1107,113 @@ int _bt_otp_send_launch_request(char *absolute_path) return BLUETOOTH_ERROR_INTERNAL; } - ret = fun(absolute_path); + 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++; +} + +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) { @@ -1114,7 +1222,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, int opcode = value[0]; uint32_t object_offset, length, object_size; uint8_t mode = 0; - char *uuid; + char *uuid = NULL; char absolute_file_path[BT_FILE_PATH_MAX_LEN] = {0, }; BT_INFO("OACP Opcode 0x%d", opcode); @@ -1128,30 +1236,39 @@ 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); - - 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; + if (len < 7) { + BT_DBG("Error: invalid param"); + ret = OACP_INVALID_PARAM; 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); + /* 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); g_free(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: - snprintf(absolute_file_path, sizeof(absolute_file_path), + 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); @@ -1169,7 +1286,11 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, ret = OACP_OPCODE_NOT_SUPPORTED; break; case OACP_EXECUTE: - snprintf(absolute_file_path, sizeof(absolute_file_path), + 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); @@ -1185,6 +1306,18 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, 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 | @@ -1197,7 +1330,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, if (opcode == OACP_WRITE) mode = (uint8_t)value[9] & 0xFF; - BT_INFO("Offset = %lu, Length = %lu", object_offset, length, mode); + BT_INFO("Offset = %u, Length = %u", object_offset, length); if (oacp_op) { if (otc_connection_status) { @@ -1219,7 +1352,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset, err = _bt_otp_open_otc_and_listen(remote_addr, "ListenOtc"); if (err != BLUETOOTH_ERROR_NONE) { - ret = OACP_OPERATION_FAILED; + ret = OACP_CHANNEL_UNAVAILABLE; _bt_otp_free_oacp_op(); goto fail; } @@ -1239,15 +1372,74 @@ fail: return BLUETOOTH_ERROR_NONE; } -void convert_to_hex(struct object_metadata *object, char *type, char *value) +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 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; @@ -1259,19 +1451,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), &fc_tm); + if (object->first_created) { + localtime_r(&(object->first_created), &fc_tm); - 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; + 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; @@ -1280,7 +1474,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; @@ -1290,13 +1484,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); @@ -1355,7 +1553,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); @@ -1366,31 +1564,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 | @@ -1399,7 +1597,7 @@ int _bt_otp_olcp_write_cb(char *value, int len, int offset, (uint64_t)(value[3] & 0xFF) << 16 | (uint64_t)(value[2] & 0xFF) << 8 | (uint64_t)(value[1] & 0xFF); - BT_INFO("Object ID [%llu]", object_id); + BT_INFO("Object ID [%llu]", (unsigned long long int)object_id); if (selected_object && selected_object->id == object_id) goto fail; @@ -1410,7 +1608,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: @@ -1427,68 +1625,157 @@ 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) { - int ret = BLUETOOTH_ERROR_NONE; - - struct object_metadata *object = NULL; - struct stat st; - char *file_path; + struct object_metadata *object; char *filename; - int length; + char new_abs_filepath[BT_FILE_PATH_MAX_LEN] = {0, }; + int ret = BLUETOOTH_ERROR_NONE; FILE *fp = NULL; + char err_msg[256] = {0, }; - 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); + object = (struct object_metadata *) g_slist_nth_data(otp_object_list, curr_obj_index); + if (!object) + return BLUETOOTH_OTP_ERROR_WRITE_REQUEST_REJECTED; - fp = fopen(file_path, "a"); - if (!fp) { - BT_DBG("fopen() failed : %s", strerror(errno)); - ret = BLUETOOTH_ERROR_INTERNAL; + 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 (stat(file_path, &st) == -1) { - BT_INFO("stat failed: (%d)\n", errno); - ret = BLUETOOTH_ERROR_INTERNAL; - goto fail; - } + if (oacp_create) { + struct stat st; - object = g_new0(struct object_metadata, 1); + 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; + } - 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; + if (stat(new_abs_filepath, &st) == -1) { + BT_INFO("stat failed: (%d)\n", errno); + ret = BLUETOOTH_ATT_ERROR_INTERNAL; + goto fail; + } - otp_object_list = g_slist_append(otp_object_list, - object); + 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); - update_obj_metadata_charc_value(object); - selected_object = object; - obj_curr_index = g_slist_length(otp_object_list) - 1; - object_id++; 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); - free(file_path); - g_free(oacp_create->uuid); - g_free(oacp_create); - oacp_create = NULL; + 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; @@ -1504,33 +1791,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; } } @@ -1558,6 +1857,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(""); @@ -1565,16 +1865,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); @@ -1582,7 +1883,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; @@ -1620,6 +1921,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); @@ -1633,23 +1935,23 @@ 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_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)) { - 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; @@ -1660,17 +1962,16 @@ void _bt_otp_gatt_char_property_changed_event(GVariant *msg, /* Send indication for CPs */ if (!g_strcmp0(char_path, otp_oacp_obj_path)) { - if (OACP_indicate) { + 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"); } + g_variant_unref(val); } else { BT_ERR("var==NULL"); } @@ -1680,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)); @@ -1688,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, @@ -1712,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)) { + if (!g_strcmp0(char_path, otp_oacp_obj_path)) OACP_indicate = indicate; - } else if (!g_strcmp0(char_path, otp_olcp_obj_path)) { + else if (!g_strcmp0(char_path, otp_olcp_obj_path)) OLCP_indicate = indicate; - } } } return; @@ -1760,9 +2060,8 @@ 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(); - } } } @@ -1791,6 +2090,52 @@ void _bt_otc_disconnected_cb(GDBusConnection *connection, } } +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); + } + } + } + g_variant_unref(val); +} + int _bt_otp_init_event_receiver() { BT_DBG("+"); @@ -1827,6 +2172,12 @@ int _bt_otp_init_event_receiver() _bt_otc_disconnected_cb, NULL, NULL); + device_property_sub_id = g_dbus_connection_signal_subscribe(conn, + BT_BLUEZ_NAME, BT_PROPERTIES_INTERFACE, + PROPERTIES_CHANGED, NULL, NULL, 0, + _bt_otp_device_property_event_filter, + NULL, NULL); + BT_DBG("-"); return 0; } @@ -1838,6 +2189,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); + g_dbus_connection_signal_unsubscribe(conn, device_property_sub_id); conn = NULL; BT_DBG("-"); @@ -1892,9 +2244,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; }