From: Ayush Garg Date: Sat, 23 Jan 2021 09:20:06 +0000 (+0530) Subject: Implement Long Write Operations for Tizen TV X-Git-Tag: accepted/tizen/unified/20210128.132338~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3432ebdccf1001aa2d1b07b91d7c6d29e241adb5;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git Implement Long Write Operations for Tizen TV In Tizen Platform, For long write operations, bluez handles all the ATT_Prepare_Write_Req packets and sends the complete data to the BT-Service when ATT_EXEC_WRITE_REQ is received. Where as in Tizen TV, Bluedroid works in a different manner. It sends every ATT_Prepare_Write_Req packet to bt-service using OAL_EVENT_GATTS_REQUEST_WRITE event with flag is_prep=1 and thus, allows upper layers to handle long write operation on its own. This change will perform all the below operations(in case of bluedroid) at bt-service level which bluez performs for GATT long write: 1. Appending all the Prepare_Write_Req data in a list and send prepare_write_resp. 2. Passing the complete data to the capi when OAL_EVENT_GATTS_EXEC_REQUEST_WRITE event comes. Thus this change will help in maintaining uniformity at CAPI level irrespective of Bluez or Bluedroid. Change-Id: Iae005dc3643d54783dbd3ddd8c1dc70a1684be99 Signed-off-by: Ayush Garg --- diff --git a/bt-oal/include/oal-event.h b/bt-oal/include/oal-event.h index 87ca441..672d7fd 100644 --- a/bt-oal/include/oal-event.h +++ b/bt-oal/include/oal-event.h @@ -160,6 +160,7 @@ extern "C" { EVENT(OAL_EVENT_GATTS_DISCONNECTION_COMPLETED) /* gatts DisConnection completed */\ EVENT(OAL_EVENT_GATTS_REQUEST_READ) /* gatts Request Read from client */\ EVENT(OAL_EVENT_GATTS_REQUEST_WRITE) /* gatts Request Write from client */\ + EVENT(OAL_EVENT_GATTS_EXEC_REQUEST_WRITE) /* gatts Exec Request Write from client */\ EVENT(OAL_EVENT_GATTS_RESPONSE_CONFIRMED) /* gatts Response confirmation */\ EVENT(OAL_EVENT_GATTS_IND_CONFIRM) /* gatts Indiction confirmation from remote client */\ EVENT(OAL_EVENT_GATTS_NOTIFICATION) /* gatts Notification from remote client */\ @@ -431,6 +432,15 @@ typedef struct { uint8_t is_prep; } event_gatts_srvc_write_attr_t; +#ifdef TIZEN_BLUEDROID_PORTING +typedef struct { + bt_address_t address; + int conn_id; + int trans_id; + int exec_write; +} event_gatts_srvc_exec_write_attr_t; +#endif + typedef struct { int hndl; oal_status_t status; diff --git a/bt-service/services/bt-service-event-receiver.c b/bt-service/services/bt-service-event-receiver.c index 78334d7..3ddd545 100644 --- a/bt-service/services/bt-service-event-receiver.c +++ b/bt-service/services/bt-service-event-receiver.c @@ -369,6 +369,7 @@ static gboolean __bt_handle_oal_events(gpointer data) case OAL_EVENT_GATTS_DISCONNECTION_COMPLETED: /* gatts Disconnection completed */\ case OAL_EVENT_GATTS_REQUEST_READ: /* gatts Request Read from client */\ case OAL_EVENT_GATTS_REQUEST_WRITE: /* gatts Request Write from client */\ + case OAL_EVENT_GATTS_EXEC_REQUEST_WRITE: /* gatts Exec Request Write from client */\ case OAL_EVENT_GATTS_IND_CONFIRM: /* gatts Indicate confirmation from remote client */\ case OAL_EVENT_GATTS_REQUEST_ACQUIRE_WRITE: case OAL_EVENT_GATTS_REQUEST_ACQUIRE_NOTIFY: diff --git a/bt-service/services/gatt/bt-service-gatt.c b/bt-service/services/gatt/bt-service-gatt.c index 9944e26..5b834cb 100644 --- a/bt-service/services/gatt/bt-service-gatt.c +++ b/bt-service/services/gatt/bt-service-gatt.c @@ -56,6 +56,22 @@ #define NUM_UUID 20 #define UUID_MAX_LEN 50 +#ifdef TIZEN_BLUEDROID_PORTING +typedef struct { + int connection_id; + int request_id; + char *device_address; + char *value; + int handle; + int offset; + int length; + bluetooth_gatt_att_request_type_e request_type; + int prep_request_count; +} bt_gatt_prep_write_data_t; + +static GSList *g_pending_write_list = NULL; +#endif + #define BDADDR_ANY (&(bluetooth_device_address_t) {{0, 0, 0, 0, 0, 0} }) static char uuid_list[NUM_UUID][BT_UUID_STRING_MAX] = {"0000b00b-0000-0000-f065-080080fa49b5", /* Used by BLEAPP */ @@ -1703,6 +1719,282 @@ static void __bt_handle_gatt_server_acquire_notify_requested(event_gatts_srvc_ac param); } +#ifdef TIZEN_BLUEDROID_PORTING +static bt_gatt_prep_write_data_t* __bt_create_prep_write_data(event_gatts_srvc_write_attr_t *event) +{ + bluetooth_device_address_t dev_addr; + char *addr; + bt_gatt_prep_write_data_t *prep_data = NULL; + + prep_data = g_malloc0(sizeof(bt_gatt_prep_write_data_t)); + prep_data->connection_id = event->attr_trans.conn_id; + prep_data->request_id = event->attr_trans.trans_id; + prep_data->handle = event->attr_trans.attr_handle; + prep_data->request_type = BLUETOOTH_GATT_REQUEST_TYPE_WRITE; + memcpy(dev_addr.addr, event->address.addr, 6); + addr = g_malloc0(BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(addr, + (unsigned char *)dev_addr.addr); + prep_data->device_address = addr; + prep_data->offset = event->attr_trans.offset; + prep_data->length = event->length; + prep_data->value = g_memdup(&event->value[0], event->length); + + return prep_data; +} + +static int __bt_gatt_server_send_long_write_response(bt_gatt_prep_write_data_t *prep_data, int resp_status, int auth_req) +{ + int ret = OAL_STATUS_SUCCESS; + oal_gatt_response_t response; + + memset(&response, 0x00, sizeof(oal_gatt_response_t)); + + BT_INFO("GATT Server Write Res Connection ID: [%d]", prep_data->connection_id); + BT_INFO("GATT Server Write Res Transaction ID:[%d]", prep_data->request_id); + BT_INFO("GATT Server Write Res Attribute Handle: [%d]", prep_data->handle); + BT_INFO("GATT Server Write Res Attribute Offset: [%d]", prep_data->offset); + BT_INFO("GATT Server Write Res value length [%d]", prep_data->length); + + response.handle = prep_data->handle; + response.attr_value.auth_req = auth_req; + response.attr_value.handle = prep_data->handle; + response.attr_value.offset = prep_data->offset; + response.attr_value.len = prep_data->length; + memcpy(&response.attr_value.value, &prep_data->value[0], prep_data->length); + + ret = gatts_send_response(prep_data->connection_id, prep_data->request_id, + resp_status, &response); + return ret; +} + +static bt_gatt_prep_write_data_t* __bt_find_prep_write_data_from_request_id(int request_id) +{ + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + + for (l = g_pending_write_list; l != NULL; l = g_slist_next(l)) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + if (prep_data && (prep_data->request_id == request_id) && + (prep_data->request_type == BLUETOOTH_GATT_REQUEST_TYPE_WRITE)) { + BT_INFO("prep_data found for request id [%d]", request_id); + return prep_data; + } + } + BT_INFO("prep_data not found for request [%d]", request_id); + return NULL; +} + +static bt_gatt_prep_write_data_t* __bt_find_exec_write_req(int conn_id) +{ + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + + for (l = g_pending_write_list; l != NULL; l = g_slist_next(l)) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + if (prep_data && (prep_data->request_type == BLUETOOTH_GATT_REQUEST_TYPE_EXEC_WRITE) + && (prep_data->connection_id == conn_id)) { + BT_INFO("Exec request found"); + return prep_data; + } + } + BT_INFO("Exec request not found"); + return NULL; +} + +static int __bt_get_prep_request_count(int conn_id) +{ + int count = 0; + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + + for (l = g_pending_write_list; l != NULL; l = g_slist_next(l)) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + if (prep_data && (prep_data->connection_id == conn_id) && + (prep_data->request_type == BLUETOOTH_GATT_REQUEST_TYPE_WRITE)) + count++; + } + return count; +} + +static bt_gatt_prep_write_data_t* __bt_find_prep_write_data_from_handle(int conn_id, int handle) +{ + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + bt_gatt_prep_write_data_t *last_prep_data = NULL; + + for (l = g_pending_write_list; l != NULL; l = g_slist_next(l)) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + if (prep_data && (prep_data->connection_id == conn_id) && (prep_data->handle == handle)) { + BT_INFO("prep_data entry found for handle [%d]", handle); + last_prep_data = prep_data; + } + } + + if (!last_prep_data) + BT_INFO("prep_data entry not found for handle [%d]", handle); + + return last_prep_data; +} + +static void __bt_gatt_server_send_prep_write_req(int conn_id) +{ + int result = BLUETOOTH_ERROR_NONE; + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + + for (l = g_pending_write_list; l != NULL; l = g_slist_next(l)) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + if (prep_data && (prep_data->connection_id == conn_id) && + (prep_data->request_type == BLUETOOTH_GATT_REQUEST_TYPE_WRITE)) { + BT_INFO("sending prep_req, req_id=%d", prep_data->request_id); + GVariant *data = NULL; + GVariant *param = NULL; + data = g_variant_new_from_data( + G_VARIANT_TYPE_BYTESTRING, + prep_data->value, + prep_data->length, + TRUE, NULL, NULL); + + param = g_variant_new("(iiiiiibbsn@ay)", result, + prep_data->connection_id, + prep_data->request_id, + prep_data->handle, + prep_data->offset, + prep_data->length, + 1, + 0, + prep_data->device_address, + prep_data->length, + data); + + _bt_send_event(BT_GATT_SERVER_EVENT, + BLUETOOTH_EVENT_GATT_SERVER_VALUE_CHANGED, + param); + } + } +} + +static void __bt_remove_all_prep_write_req(int conn_id) +{ + GSList *l; + bt_gatt_prep_write_data_t *prep_data = NULL; + + BT_INFO("Removing all req for conn_id %d", conn_id); + for (l = g_pending_write_list; l != NULL;) { + prep_data = (bt_gatt_prep_write_data_t*)l->data; + l = g_slist_next(l); + if (prep_data && (prep_data->connection_id == conn_id)) { + BT_INFO("Removing req for req_id %d", prep_data->request_id); + g_pending_write_list = g_slist_remove(g_pending_write_list, prep_data); + g_free(prep_data->value); + g_free(prep_data->device_address); + g_free(prep_data); + prep_data = NULL; + } + } +} + +static bool __bt_update_prep_write_data(bt_gatt_prep_write_data_t *prep_data, int offset, + int length, char *value) +{ + char *val; + int len; + + if (!length) + return true; + + len = prep_data->length + length; + val = g_realloc(prep_data->value, len); + if (!val) + return false; + + memcpy(val + prep_data->length, value, length); + prep_data->value = val; + prep_data->length = len; + + BT_INFO("updated prep_data->length %d, prep_data->req_id %d", prep_data->length, prep_data->request_id); + return true; +} + +static bool __bt_handle_gatt_server_prepare_write_response(int *res, + bluetooth_gatt_server_response_params_t *param) +{ + bt_gatt_prep_write_data_t *prep_data = NULL; + bt_gatt_prep_write_data_t *exec_data = NULL; + int conn_id = -1; + + /* Search for matching Request in prepare write List */ + prep_data = __bt_find_prep_write_data_from_request_id(param->request_id); + + if (!prep_data) + return false; + + conn_id = prep_data->connection_id; + exec_data = __bt_find_exec_write_req(conn_id); + + if (!exec_data) { + BT_ERR("Oops, Something weird has happened!!!"); + *res = BLUETOOTH_ERROR_INTERNAL; + __bt_remove_all_prep_write_req(conn_id); + } else { + // remove pending write request from the list + BT_INFO("Removing prending write request, request id = %d", prep_data->request_id); + g_pending_write_list = g_slist_remove(g_pending_write_list, prep_data); + g_free(prep_data->value); + g_free(prep_data->device_address); + g_free(prep_data); + + exec_data->prep_request_count--; + if (param->response_status || !exec_data->prep_request_count) { + BT_INFO("Sending exec response with status = %d", param->response_status); + ret = __bt_gatt_server_send_long_write_response(exec_data, param->response_status, param->auth_req); + if (ret != OAL_STATUS_SUCCESS) { + BT_ERR("ret: %d", ret); + *res = BLUETOOTH_ERROR_INTERNAL; + } + __bt_remove_all_prep_write_req(conn_id); + } + } + return true; +} + +static void __bt_handle_gatt_server_prepare_write_requested(event_gatts_srvc_write_attr_t *event) +{ + bt_gatt_prep_write_data_t *pdata = NULL; + bt_gatt_prep_write_data_t *prep_data = NULL; + int ret; + int resp_status = BLUETOOTH_ATT_ERROR_NONE; + + prep_data = __bt_create_prep_write_data(event); + + /* Find if the req node for that attribute already exists */ + pdata = __bt_find_prep_write_data_from_handle(prep_data->connection_id, prep_data->handle); + + if (!pdata || (prep_data->offset != (pdata->length + pdata->offset))) { + BT_INFO("prep_write_req node doestn't exist or data is not in continuation, offset=%d", prep_data->offset); + pdata = prep_data; + g_pending_write_list = g_slist_append(g_pending_write_list, (gpointer)pdata); + BT_INFO("Send prep_write_response"); + ret = __bt_gatt_server_send_long_write_response(prep_data, resp_status, 0); + } else { + /* Update the data and offset in attribute node */ + if (!(__bt_update_prep_write_data(pdata, prep_data->offset, prep_data->length, prep_data->value))) { + BT_ERR("prep_data couldnot be updated"); + resp_status = BLUETOOTH_ATT_ERROR_INSUFFICIENT_RESOURCES; + } + BT_INFO("Send prep_write_response"); + ret = __bt_gatt_server_send_long_write_response(prep_data, resp_status, 0); + g_free(prep_data->device_address); + g_free(prep_data->value); + g_free(prep_data); + } + + if (ret != OAL_STATUS_SUCCESS) + BT_ERR("ret: %d", ret); +} +#endif + static void __bt_handle_gatt_server_write_requested(event_gatts_srvc_write_attr_t *event) { char *address; @@ -1732,6 +2024,13 @@ static void __bt_handle_gatt_server_write_requested(event_gatts_srvc_write_attr_ return; } +#ifdef TIZEN_BLUEDROID_PORTING + if (event->is_prep) { + BT_INFO("receive prepare_write request"); + return __bt_handle_gatt_server_prepare_write_requested(event); + } +#endif + need_resp = event->need_rsp; is_prepare_write = event->is_prep; @@ -1782,6 +2081,64 @@ static void __bt_handle_gatt_server_write_requested(event_gatts_srvc_write_attr_ g_free(write_val); } +#ifdef TIZEN_BLUEDROID_PORTING +static void __bt_handle_gatt_server_exec_write_requested(event_gatts_srvc_exec_write_attr_t *event) +{ + char *address; + bluetooth_device_address_t dev_addr; + int ret; + bt_gatt_prep_write_data_t *exec_data = NULL; + int resp_status = BLUETOOTH_ATT_ERROR_NONE; + BT_INFO("GATT Server Execute Write Requested"); + + memcpy(dev_addr.addr, event->address.addr, 6); + address = g_malloc0(BT_ADDRESS_STRING_SIZE); + _bt_convert_addr_type_to_string(address, + (unsigned char *)dev_addr.addr); + + BT_INFO("GATT Server Exec Write Req Connection ID: [%d]", event->conn_id); + BT_INFO("GATT Server Exec Write Req Transaction ID:[%d]", event->trans_id); + BT_INFO("GATT Server Exec Write Req Exec Write: [%d]", event->exec_write); + + // prepare exec response data + exec_data = g_malloc0(sizeof(bt_gatt_prep_write_data_t)); + exec_data->connection_id = event->conn_id; + exec_data->request_id = event->trans_id; + exec_data->device_address = address; + exec_data->request_type = BLUETOOTH_GATT_REQUEST_TYPE_EXEC_WRITE; + exec_data->prep_request_count = __bt_get_prep_request_count(exec_data->connection_id); + + if ((exec_data->prep_request_count != 1) || !event->exec_write) { + if (!event->exec_write) { + BT_INFO("Cancelling all prepared writes, removing all pending entries"); + __bt_remove_all_prep_write_req(event->conn_id); + } else if (exec_data->prep_request_count > 1) { + /* TODO: Handle reliable-write session */ + BT_INFO("This may be reliable write session. Not yet supported!!!, prep_request_count =%d", + exec_data->prep_request_count); + resp_status = BLUETOOTH_ATT_ERROR_REQUEST_NOT_SUPPORTED; + __bt_remove_all_prep_write_req(event->conn_id); + } + + BT_INFO("Send exec response"); + // Made response and send it. + ret = __bt_gatt_server_send_long_write_response(exec_data, resp_status, 0); + if (ret != OAL_STATUS_SUCCESS) + BT_ERR("ret: %d", ret); + + g_free(exec_data->device_address); + g_free(exec_data); + return; + } + + BT_INFO("Write all pending prepared values"); + __bt_gatt_server_send_prep_write_req(exec_data->connection_id); + + // Add exec request in the queue. + g_pending_write_list = g_slist_append(g_pending_write_list, (gpointer)exec_data); +} +#endif + static void __bt_handle_gatt_server_read_requested(event_gatts_srvc_read_attr_t *event) { char *address = g_malloc0(BT_ADDRESS_STRING_SIZE); @@ -1998,6 +2355,13 @@ static void __bt_gatt_event_handler(int event_type, gpointer event_data) __bt_handle_gatt_server_write_requested((event_gatts_srvc_write_attr_t *)event_data); break; } +#ifdef TIZEN_BLUEDROID_PORTING + case OAL_EVENT_GATTS_EXEC_REQUEST_WRITE: { + BT_INFO("OAL Event: GATT Server Exec Write Request"); + __bt_handle_gatt_server_exec_write_requested((event_gatts_srvc_exec_write_attr_t *)event_data); + break; + } +#endif case OAL_EVENT_GATTS_REQUEST_ACQUIRE_WRITE: { BT_INFO("OAL Event: GATT Server Acquire Write Request"); __bt_handle_gatt_server_acquire_write_requested((event_gatts_srvc_acquire_attr_t*)event_data); @@ -2272,14 +2636,21 @@ int _bt_gatt_server_send_response(char *sender, bluetooth_gatt_att_data_t *data, BT_CHECK_PARAMETER(param, return); struct gatt_server_req_info *req_info = NULL; int ret = OAL_STATUS_SUCCESS; - +#ifdef TIZEN_BLUEDROID_PORTING + int res = BLUETOOTH_ERROR_NONE; +#endif oal_gatt_response_t response; - BT_DBG("GATT Server Response: Req Type [%d] req_id [%d] status [%d] auth_req [%d] offset[%d] data len[%d]", + BT_INFO("GATT Server Response: Req Type [%d] req_id [%d] status [%d] auth_req [%d] offset[%d] data len[%d]", param->req_type, param->request_id, param->response_status, param->auth_req, data->offset, data->length); +#ifdef TIZEN_BLUEDROID_PORTING + if (__bt_handle_gatt_server_prepare_write_response(&res, param)) + return res; +#endif + /* Search for matching Request in List */ req_info = __bt_gatt_server_find_request_info(param->request_id, param->req_type); if (!req_info) {