bt component: fix bluetooth gatt packets process bugs

1. Add process of prepare write request packets
2. Add process of execute write request packets
3. Add process of reliable write request packets
4. Fix bug of processing read blob request packets
5. Fix bug of processing write request packets
6. Optimize error check and process in stack
This commit is contained in:
island 2017-03-06 17:20:45 +08:00
parent c06cc31d85
commit 2955b20f2e
6 changed files with 511 additions and 114 deletions

View file

@ -142,6 +142,28 @@ esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_
return ESP_ERR_INVALID_STATE;
}
/* parameter validation check */
if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){
if (char_val == NULL){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_val should not be NULL here\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
else if (char_val->attr_max_len == 0){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
}
if (char_val != NULL){
if (char_val->attr_len > char_val->attr_max_len){
LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
}
memset(&arg, 0, sizeof(btc_ble_gatts_args_t));
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_GATTS;
@ -175,6 +197,29 @@ esp_err_t esp_ble_gatts_add_char_descr (uint16_t service_handle,
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
/* parameter validation check */
if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){
if (char_descr_val == NULL){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, char_descr_val should not be NULL here\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
else if (char_descr_val->attr_max_len == 0){
LOG_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
}
if (char_descr_val != NULL){
if (char_descr_val->attr_len > char_descr_val->attr_max_len){
LOG_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\
__func__, __LINE__);
return ESP_ERR_INVALID_ARG;
}
}
memset(&arg, 0, sizeof(btc_ble_gatts_args_t));
msg.sig = BTC_SIG_API_CALL;

View file

@ -268,14 +268,22 @@ static tGATT_STATUS read_attr_value (void *p_attr,
status = GATT_SUCCESS;
}
} else { /* characteristic description or characteristic value */
if (p_attr16->control.auto_rsp == GATT_RSP_BY_STACK) {
if (p_attr16->p_value != NULL && p_attr16->p_value->attr_val.attr_val != NULL) {
uint8_t *value = p_attr16->p_value->attr_val.attr_val + offset;
len = (mtu >= p_attr16->p_value->attr_val.attr_len) ? (p_attr16->p_value->attr_val.attr_len) : mtu;
ARRAY_TO_STREAM(p, value, len);
if (p_attr16->p_value == NULL || p_attr16->p_value->attr_val.attr_val == NULL) {
status = GATT_ESP_ERROR;
}
/*if offset equal to max_len, should respond with zero byte value
//if offset is greater than max_len, should respond with an error*/
else if (offset > p_attr16->p_value->attr_val.attr_len){
status = GATT_INVALID_OFFSET;
}
else {
UINT8 *value = (UINT8 *)(p_attr16->p_value->attr_val.attr_val) + offset;
UINT16 len_left = p_attr16->p_value->attr_val.attr_len - offset;
len = (mtu >= len_left) ? (len_left) : mtu;
ARRAY_TO_STREAM(p, value, len);
status = GATT_STACK_RSP;
}
status = GATT_STACK_RSP;
} else {
status = GATT_PENDING;
@ -463,6 +471,28 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
GATT_TRACE_DEBUG("gatts_add_characteristic perm=0x%0x property=0x%0x\n", perm, property);
/* parameter validation check */
if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){
if (attr_val == NULL){
GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\
__func__, __LINE__);
return 0;
}
else if (attr_val->attr_max_len == 0){
GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\
__func__, __LINE__);
return 0;
}
}
if (attr_val != NULL){
if (attr_val->attr_len > attr_val->attr_max_len){
GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\
__func__, __LINE__);
return 0;
}
}
if ((p_char_decl = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, &uuid, GATT_PERM_READ)) != NULL) {
if (!copy_extra_byte_in_db(p_db, (void **)&p_char_decl->p_value, sizeof(tGATT_CHAR_DECL))) {
@ -483,10 +513,9 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
p_char_val->control.auto_rsp = control->auto_rsp;
} else {
p_char_val->control.auto_rsp = GATT_RSP_DEFAULT;
}
if (attr_val != NULL) {
if (attr_val != NULL) {
if (!copy_extra_byte_in_db(p_db, (void **)&p_char_val->p_value, sizeof(tGATT_ATTR_VAL))) {
deallocate_attr_in_db(p_db, p_char_val);
return 0;
@ -496,12 +525,23 @@ UINT16 gatts_add_characteristic (tGATT_SVC_DB *p_db, tGATT_PERM perm,
p_char_val->p_value->attr_val.attr_len = attr_val->attr_len;
p_char_val->p_value->attr_val.attr_max_len = attr_val->attr_max_len;
p_char_val->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len);
if (p_char_val->p_value->attr_val.attr_val != NULL) {
GATT_TRACE_DEBUG("attribute value not NULL");
memcpy(p_char_val->p_value->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len);
if (p_char_val->p_value->attr_val.attr_val == NULL) {
deallocate_attr_in_db(p_db, p_char_decl);
deallocate_attr_in_db(p_db, p_char_val);
GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for attribute value\n", __func__, __LINE__);
return 0;
}
//initiate characteristic attribute value part
memset(p_char_val->p_value->attr_val.attr_val, 0, attr_val->attr_max_len);
if (attr_val->attr_val != NULL) {
if (attr_val->attr_max_len < attr_val->attr_len){
GATT_TRACE_ERROR("Error in %s, Line=%d, attribute actual length(%d) should not larger than max size(%d)\n",
__func__, __LINE__, attr_val->attr_len, attr_val->attr_max_len);
}
UINT16 actual_len = (attr_val->attr_max_len < attr_val->attr_len) ? (attr_val->attr_max_len) : (attr_val->attr_len);
memcpy(p_char_val->p_value->attr_val.attr_val, attr_val->attr_val, actual_len);
}
} else {
p_char_val->p_value = NULL;
}
return p_char_val->handle;
@ -582,14 +622,37 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x\n", p_descr_uuid->uu.uuid16);
/* parameter validation check */
if ((control != NULL) && (control->auto_rsp == GATT_STACK_RSP)){
if (attr_val == NULL){
GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attr_val should not be NULL here\n",\
__func__, __LINE__);
return 0;
}
else if (attr_val->attr_max_len == 0){
GATT_TRACE_ERROR("Error in %s, line=%d, for stack respond attribute, attribute max length should not be 0\n",\
__func__, __LINE__);
return 0;
}
}
if (attr_val != NULL){
if (attr_val->attr_len > attr_val->attr_max_len){
GATT_TRACE_ERROR("Error in %s, line=%d,attribute actual length should not be larger than max length\n",\
__func__, __LINE__);
return 0;
}
}
/* Add characteristic descriptors */
if ((p_char_dscptr = (tGATT_ATTR16 *)allocate_attr_in_db(p_db, p_descr_uuid, perm)) == NULL) {
deallocate_attr_in_db(p_db, p_char_dscptr);
GATT_TRACE_DEBUG("gatts_add_char_descr Fail for adding char descriptors.");
return 0;
} else {
if (control != NULL) {
p_char_dscptr->control.auto_rsp = control->auto_rsp;
}
}
else {
p_char_dscptr->control.auto_rsp = (control == NULL) ? GATT_RSP_DEFAULT : (control->auto_rsp);
if (attr_val != NULL) {
if (!copy_extra_byte_in_db(p_db, (void **)&p_char_dscptr->p_value, sizeof(tGATT_ATTR_VAL))) {
deallocate_attr_in_db(p_db, p_char_dscptr);
@ -599,12 +662,16 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
p_char_dscptr->p_value->attr_val.attr_max_len = attr_val->attr_max_len;
if (attr_val->attr_max_len != 0) {
p_char_dscptr->p_value->attr_val.attr_val = GKI_getbuf(attr_val->attr_max_len);
if (p_char_dscptr->p_value->attr_val.attr_val != NULL) {
memset(p_char_dscptr->p_value->attr_val.attr_val, 0, attr_val->attr_max_len);
if(attr_val->attr_val != NULL) {
memcpy(p_char_dscptr->p_value->attr_val.attr_val,
attr_val->attr_val, attr_val->attr_len);
}
if (p_char_dscptr->p_value->attr_val.attr_val == NULL) {
deallocate_attr_in_db(p_db, p_char_dscptr);
GATT_TRACE_ERROR("Warning in %s, line=%d, insufficient resource to allocate for descriptor value\n", __func__, __LINE__);
return 0;
}
//initiate characteristic attribute value part
memset(p_char_dscptr->p_value->attr_val.attr_val, 0, attr_val->attr_max_len);
if(attr_val->attr_val != NULL) {
memcpy(p_char_dscptr->p_value->attr_val.attr_val, attr_val->attr_val, attr_val->attr_len);
}
}
}
@ -628,7 +695,7 @@ UINT16 gatts_add_char_descr (tGATT_SVC_DB *p_db, tGATT_PERM perm,
**
*******************************************************************************/
tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
UINT16 length, UINT8 *value)
UINT16 length, UINT8 *value)
{
tGATT_ATTR16 *p_cur;
@ -640,51 +707,48 @@ tGATT_STATUS gatts_set_attribute_value(tGATT_SVC_DB *p_db, UINT16 attr_handle,
GATT_TRACE_DEBUG("gatts_set_attribute_value Fail:p_db->p_attr_list is NULL.\n");
return GATT_INVALID_PDU;
}
if ((length > 0) && (value == NULL)){
GATT_TRACE_ERROR("Error in %s, line=%d, value should not be NULL here\n",__func__, __LINE__);
return GATT_INVALID_PDU;
}
p_cur = (tGATT_ATTR16 *) p_db->p_attr_list;
while (p_cur != NULL) {
if (p_cur->handle == attr_handle) {
/* for characteristic should not be set, return GATT_NOT_FOUND */
if (p_cur->uuid_type == GATT_ATTR_UUID_TYPE_16) {
switch (p_cur->uuid) {
case GATT_UUID_PRI_SERVICE:
case GATT_UUID_SEC_SERVICE:
case GATT_UUID_CHAR_DECLARE:
case GATT_UUID_INCLUDE_SERVICE:
return GATT_NOT_FOUND;
default:
if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) {
GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length");
return GATT_INVALID_ATTR_LEN;
} else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) {
memcpy(p_cur->p_value->attr_val.attr_val, value, length);
p_cur->p_value->attr_val.attr_len = length;
} else {
return GATT_INVALID_ATTR_LEN;
}
break;
}
} else {
if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len < length) {
GATT_TRACE_ERROR("gatts_set_attribute_vaule failt:Invalid value length");
} else if (p_cur->p_value != NULL && p_cur->p_value->attr_val.attr_max_len > 0) {
memcpy(p_cur->p_value->attr_val.attr_val, value, length);
p_cur->p_value->attr_val.attr_len = length;
} else {
return GATT_INVALID_ATTR_LEN;
case GATT_UUID_PRI_SERVICE:
case GATT_UUID_SEC_SERVICE:
case GATT_UUID_CHAR_DECLARE:
return GATT_NOT_FOUND;
break;
}
}
/* in other cases, value can be set*/
if ((p_cur->p_value == NULL) || (p_cur->p_value->attr_val.attr_val == NULL) \
|| (p_cur->p_value->attr_val.attr_max_len == 0)){
GATT_TRACE_ERROR("Error in %s, line=%d, attribute value should not be NULL here\n", __func__, __LINE__);
return GATT_NOT_FOUND;
}
else if (p_cur->p_value->attr_val.attr_max_len < length) {
GATT_TRACE_ERROR("gatts_set_attribute_value failed:Invalid value length");
return GATT_INVALID_ATTR_LEN;
}
else{
memcpy(p_cur->p_value->attr_val.attr_val, value, length);
p_cur->p_value->attr_val.attr_len = length;
}
break;
}
p_cur = p_cur->p_next;
}
return GATT_SUCCESS;
}
/*******************************************************************************
**
** Function gatts_get_attribute_value
@ -875,20 +939,27 @@ tGATT_STATUS gatts_write_attr_value_by_handle(tGATT_SVC_DB *p_db,
return GATT_APP_RSP;
}
if (p_attr->p_value != NULL && (p_attr->p_value->attr_val.attr_max_len >=
offset + len) && p_attr->p_value->attr_val.attr_val != NULL) {
if ((p_attr->p_value != NULL) &&
(p_attr->p_value->attr_val.attr_max_len >= offset + len) &&
p_attr->p_value->attr_val.attr_val != NULL) {
memcpy(p_attr->p_value->attr_val.attr_val + offset, p_value, len);
p_attr->p_value->attr_val.attr_len = len + offset;
return GATT_SUCCESS;
} else {
return GATT_NOT_LONG;
}
else if (p_attr->p_value->attr_val.attr_max_len < offset + len){
GATT_TRACE_DEBUG("Remote device try to write with a length larger then attribute's max length\n");
return GATT_INVALID_ATTR_LEN;
}
else if ((p_attr->p_value == NULL) || (p_attr->p_value->attr_val.attr_val == NULL)){
GATT_TRACE_ERROR("Error in %s, line=%d, %s should not be NULL here\n", __func__, __LINE__, \
(p_attr->p_value == NULL) ? "p_value" : "attr_val.attr_val");
return GATT_ESP_ERROR;
}
}
p_attr = (tGATT_ATTR16 *)p_attr->p_next;
}
}
return status;

View file

@ -33,6 +33,42 @@
#define GATT_MTU_REQ_MIN_LEN 2
/*******************************************************************************
**
** Function gatt_send_packet
**
** Description This function is called to send gatt packets directly
**
** Returns status
**
*******************************************************************************/
tGATT_STATUS gatt_send_packet (tGATT_TCB *p_tcb, UINT8 *p_data, UINT16 len)
{
BT_HDR *p_msg = NULL;
UINT8 *p_m = NULL;
UINT16 buf_len;
tGATT_STATUS status;
if (len > p_tcb->payload_size){
return GATT_ILLEGAL_PARAMETER;
}
buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) {
return GATT_NO_RESOURCES;
}
memset(p_msg, 0, buf_len);
p_msg->len = len;
p_m = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
memcpy(p_m, p_data, len);
status = attp_send_sr_msg(p_tcb, p_msg);
return status;
}
/*******************************************************************************
**
** Function gatt_sr_enqueue_cmd
@ -300,7 +336,11 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
UINT32 trans_id = 0;
tGATT_IF gatt_if;
UINT16 conn_id;
UINT16 queue_num = 0;
BOOLEAN is_prepare_write_valid = FALSE;
BOOLEAN is_need_dequeue_sr_cmd = FALSE;
tGATT_PREPARE_WRITE_RECORD *prepare_record = NULL;
tGATT_PREPARE_WRITE_QUEUE_DATA * queue_data = NULL;
UNUSED(len);
#if GATT_CONFORMANCE_TESTING == TRUE
@ -319,11 +359,63 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
/* mask the flag */
flag &= GATT_PREP_WRITE_EXEC;
prepare_record = &(p_tcb->prepare_write_record);
queue_num = prepare_record->queue._count;
/* no prep write is queued */
//if received prepare_write packets include stack_rsp and app_rsp,
//stack respond to execute_write only when stack_rsp handle has invalid_offset
//or invalid_length error;
//app need to respond to execute_write if it has received app_rsp handle packets
if (((prepare_record->error_code_app == GATT_SUCCESS) &&
(prepare_record->total_num == queue_num))
|| (flag == GATT_PREP_WRITE_CANCEL)){
tGATT_EXEC_WRITE_RSP gatt_exec_write_rsp;
gatt_exec_write_rsp.op_code = GATT_RSP_EXEC_WRITE;
gatt_send_packet(p_tcb, (UINT8 *)(&gatt_exec_write_rsp), sizeof(gatt_exec_write_rsp));
gatt_dequeue_sr_cmd(p_tcb);
if (flag != GATT_PREP_WRITE_CANCEL){
is_prepare_write_valid = TRUE;
}
GATT_TRACE_DEBUG("Send execute_write_rsp\n");
}
else if ((prepare_record->error_code_app == GATT_SUCCESS) &&
(prepare_record->total_num > queue_num)){
//No error for stack_rsp's handles and there exist some app_rsp's handles,
//so exec_write_rsp depends to app's response; but stack_rsp's data is valid
//TODO: there exist problem if stack_rsp's data is valid but app_rsp's data is not valid.
is_prepare_write_valid = TRUE;
}
else if(prepare_record->total_num < queue_num) {
GATT_TRACE_ERROR("Error in %s, line=%d, prepare write total number(=%d) \
should not smaller than prepare queue number(=%d)\n", \
__func__, __LINE__,prepare_record->total_num, queue_num);
}
else if (prepare_record->error_code_app != GATT_SUCCESS){
GATT_TRACE_DEBUG("Send error code for execute_write, code=0x%x\n", prepare_record->error_code_app);
is_need_dequeue_sr_cmd = (prepare_record->total_num == queue_num) ? TRUE : FALSE;
gatt_send_error_rsp(p_tcb, prepare_record->error_code_app, GATT_REQ_EXEC_WRITE, 0, is_need_dequeue_sr_cmd);
}
//dequeue prepare write data
while(GKI_getfirst(&(prepare_record->queue))) {
queue_data = GKI_dequeue(&(prepare_record->queue));
if (is_prepare_write_valid){
if((queue_data->p_attr->p_value != NULL) && (queue_data->p_attr->p_value->attr_val.attr_val != NULL)){
memcpy(queue_data->p_attr->p_value->attr_val.attr_val+queue_data->offset, queue_data->value, queue_data->len);
}
}
GKI_freebuf(queue_data);
}
/* according to ble spec, even if there is no prep write queued,
* need to respond execute_write_response
* Note: exec_write_rsp callback should be called after all data has been written*/
if (!gatt_sr_is_prep_cnt_zero(p_tcb)) {
trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
if (prepare_record->total_num > queue_num){
trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
}
for (i = 0; i < GATT_MAX_APPS; i++) {
if (p_tcb->prep_cnt[i]) {
@ -336,10 +428,10 @@ void gatt_process_exec_write_req (tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, U
p_tcb->prep_cnt[i] = 0;
}
}
} else { /* nothing needs to be executed , send response now */
GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending");
gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, FALSE);
}
prepare_record->total_num = 0;
prepare_record->error_code_app = GATT_SUCCESS;
}
/*******************************************************************************
@ -987,54 +1079,29 @@ void gatts_process_read_by_type_req(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len,
void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
UINT8 op_code, UINT16 len, UINT8 *p_data)
{
UINT16 buf_len = (UINT16)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
tGATTS_DATA sr_data;
UINT32 trans_id;
tGATT_STATUS status;
UINT8 sec_flag, key_size, *p = p_data, *p_m;
UINT8 sec_flag, key_size, *p = p_data;
tGATT_SR_REG *p_sreg;
UINT16 conn_id, offset = 0;
BT_HDR *p_msg = NULL;
memset(&sr_data, 0, sizeof(tGATTS_DATA));
sr_data.write_req.need_rsp = FALSE;
if ((p_msg = (BT_HDR *)GKI_getbuf(buf_len)) == NULL) {
GATT_TRACE_ERROR("gatts_process_write_req failed. no resources.\n");
}
memset(p_msg, 0, buf_len);
p_m = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
*p_m ++ = op_code + 1;
p_msg->len = 1;
buf_len = p_tcb->payload_size - 1;
switch (op_code) {
case GATT_REQ_PREPARE_WRITE:
sr_data.write_req.is_prep = TRUE;
STREAM_TO_UINT16(sr_data.write_req.offset, p);
UINT16_TO_STREAM(p_m, sr_data.write_req.is_prep);
offset = sr_data.write_req.offset;
len -= 2;
/* fall through */
case GATT_SIGN_CMD_WRITE:
if (op_code == GATT_SIGN_CMD_WRITE) {
GATT_TRACE_DEBUG("Write CMD with data sigining" );
GATT_TRACE_DEBUG("Write CMD with data signing" );
len -= GATT_AUTH_SIGN_LEN;
}
/* fall through */
case GATT_CMD_WRITE:
case GATT_REQ_WRITE:
if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE) {
sr_data.write_req.need_rsp = TRUE;
if(op_code == GATT_REQ_PREPARE_WRITE){
memcpy(p_m, p, len);
p_msg->len += len;
}
}
sr_data.write_req.handle = handle;
sr_data.write_req.len = len;
if (len != 0 && p != NULL) {
memcpy (sr_data.write_req.value, p, len);
}
break;
}
@ -1059,42 +1126,194 @@ void gatts_process_write_req (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
status = gatts_write_attr_value_by_handle(gatt_cb.sr_reg[i_rcb].p_db,
handle, offset, p, len);
if((sr_data.write_req.need_rsp == TRUE) && (status == GATT_APP_RSP)){
if((op_code == GATT_REQ_WRITE) && (status == GATT_APP_RSP)){
sr_data.write_req.need_rsp = TRUE;
status = GATT_PENDING;
}
else{
sr_data.write_req.need_rsp = FALSE;
}
gatt_sr_send_req_callback(conn_id,
trans_id,
GATTS_REQ_TYPE_WRITE,
&sr_data);
if (status == GATT_SUCCESS) {
attp_send_sr_msg(p_tcb, p_msg);
gatt_dequeue_sr_cmd(p_tcb);
} else {
GKI_freebuf(p_msg);
}
} else {
GATT_TRACE_ERROR("max pending command, send error\n");
}
else {
GATT_TRACE_ERROR("Error in %s, line=%d, max pending command, send error\n", __func__, __LINE__);
status = GATT_BUSY; /* max pending command, application error */
}
}
//test isl
GATT_TRACE_ERROR("!!!write opcode=0x%x, need_rsp=0x%x, status=0x%x\n",op_code, sr_data.write_req.need_rsp, status);
/* in theroy BUSY is not possible(should already been checked), protected check */
if (status != GATT_PENDING && status != GATT_BUSY && status != GATT_SUCCESS &&
(op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) {
gatt_send_error_rsp (p_tcb, status, op_code, handle, FALSE);
gatt_dequeue_sr_cmd(p_tcb);
/* response should be sent only for write_request */
if ((op_code == GATT_REQ_WRITE) && (sr_data.write_req.need_rsp == FALSE)){
if (status == GATT_SUCCESS){
tGATT_WRITE_REQ_RSP gatt_write_req_rsp;
gatt_write_req_rsp.op_code = GATT_RSP_WRITE;
gatt_send_packet(p_tcb, (UINT8 *)(&gatt_write_req_rsp), sizeof(gatt_write_req_rsp));
gatt_dequeue_sr_cmd(p_tcb);
}
else if (status != GATT_PENDING){
/* note: in case of GATT_BUSY, will respond this application error to remote device */
gatt_send_error_rsp (p_tcb, status, op_code, handle, TRUE);
}
}
return;
}
/*******************************************************************************
**
** Function gatts_attr_process_preapre_write
**
** Description This function is called to process the prepare write request
** from client.
**
** Returns void
**
*******************************************************************************/
void gatt_attr_process_prepare_write (tGATT_TCB *p_tcb, UINT8 i_rcb, UINT16 handle,
UINT8 op_code, UINT16 len, UINT8 *p_data)
{
tGATT_STATUS status;
tGATT_PREPARE_WRITE_QUEUE_DATA * queue_data = NULL;
tGATT_ATTR16 *p_attr;
tGATT_ATTR16 *p_attr_temp;
tGATTS_DATA sr_data;
UINT32 trans_id = 0;
UINT8 sec_flag, key_size, *p = p_data;
tGATT_SR_REG *p_sreg;
UINT16 conn_id, offset = 0;
tGATT_SVC_DB *p_db;
BOOLEAN is_need_prepare_write_rsp = FALSE;
BOOLEAN is_need_queue_data = FALSE;
tGATT_PREPARE_WRITE_RECORD *prepare_record = NULL;
memset(&sr_data, 0, sizeof(tGATTS_DATA));
//get offset from p_data
STREAM_TO_UINT16(offset, p);
len -= 2;
p_sreg = &gatt_cb.sr_reg[i_rcb];
conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_sreg->gatt_if);
//prepare_record = &(prepare_write_record);
prepare_record = &(p_tcb->prepare_write_record);
gatt_sr_get_sec_info(p_tcb->peer_bda,
p_tcb->transport,
&sec_flag,
&key_size);
status = gatts_write_attr_perm_check (gatt_cb.sr_reg[i_rcb].p_db,
op_code,
handle,
sr_data.write_req.offset,
p,
len,
sec_flag,
key_size);
if (status == GATT_SUCCESS){
if ((trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle)) != 0) {
p_db = gatt_cb.sr_reg[i_rcb].p_db;
if (p_db && p_db->p_attr_list) {
p_attr = (tGATT_ATTR16 *)p_db->p_attr_list;
while (p_attr && handle >= p_attr->handle) {
if (p_attr->handle == handle ) {
p_attr_temp = p_attr;
if (p_attr->control.auto_rsp == GATT_RSP_BY_APP) {
status = GATT_APP_RSP;
}
else if (p_attr->p_value != NULL &&
offset > p_attr->p_value->attr_val.attr_max_len) {
status = GATT_INVALID_OFFSET;
is_need_prepare_write_rsp = TRUE;
is_need_queue_data = TRUE;
}
else if (p_attr->p_value != NULL &&
((offset + len) > p_attr->p_value->attr_val.attr_max_len)){
status = GATT_INVALID_ATTR_LEN;
is_need_prepare_write_rsp = TRUE;
is_need_queue_data = TRUE;
}
else if (p_attr->p_value == NULL) {
LOG_ERROR("Error in %s, attribute of handle 0x%x not allocate value buffer\n",
__func__, handle);
status = GATT_ESP_ERROR;
}
else {
//valid prepare write request, need to send response and queue the data
//status: GATT_SUCCESS
is_need_prepare_write_rsp = TRUE;
is_need_queue_data = TRUE;
}
}
p_attr = (tGATT_ATTR16 *)p_attr->p_next;
}
}
}
else{
status = GATT_ESP_ERROR;
GATT_TRACE_ERROR("Error in %s, Line %d: GATT BUSY\n", __func__, __LINE__);
}
}
if (is_need_queue_data){
queue_data = (tGATT_PREPARE_WRITE_QUEUE_DATA *)GKI_getbuf(len + sizeof(tGATT_PREPARE_WRITE_QUEUE_DATA));
if (queue_data == NULL){
status = GATT_PREPARE_Q_FULL;
}
else {
queue_data->p_attr = p_attr_temp;
queue_data->len = len;
queue_data->handle = handle;
queue_data->offset = offset;
memcpy(queue_data->value, p, len);
GKI_enqueue(&(prepare_record->queue), queue_data);
}
}
if (is_need_prepare_write_rsp){
//send prepare write response
if (queue_data != NULL){
queue_data->op_code = op_code + 1;
//5: op_code 1 + handle 2 + offset 2
tGATT_STATUS rsp_send_status = gatt_send_packet(p_tcb, &(queue_data->op_code), queue_data->len + 5);
gatt_sr_update_prep_cnt(p_tcb, p_sreg->gatt_if, TRUE, FALSE);
gatt_dequeue_sr_cmd(p_tcb);
if (rsp_send_status != GATT_SUCCESS){
LOG_ERROR("Error in %s, line=%d, fail to send prepare_write_rsp, status=0x%x\n",
__func__, __LINE__, rsp_send_status);
}
}
else{
LOG_ERROR("Error in %s, line=%d, queue_data should not be NULL here, fail to send prepare_write_rsp\n",
__func__, __LINE__);
}
}
if ((status == GATT_APP_RSP) || (is_need_prepare_write_rsp)){
prepare_record->total_num++;
memset(&sr_data, 0, sizeof(sr_data));
sr_data.write_req.is_prep = TRUE;
sr_data.write_req.handle = handle;
sr_data.write_req.offset = offset;
sr_data.write_req.len = len;
sr_data.write_req.need_rsp = (status == GATT_APP_RSP) ? TRUE : FALSE;
memcpy(sr_data.write_req.value, p, len);
gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE, &sr_data);
}
else{
gatt_send_error_rsp(p_tcb, status, GATT_REQ_PREPARE_WRITE, handle, TRUE);
}
if ((prepare_record->error_code_app == GATT_SUCCESS)
&& ((status == GATT_INVALID_OFFSET) || (status == GATT_INVALID_ATTR_LEN))){
prepare_record->error_code_app = status;
}
}
/*******************************************************************************
**
** Function gatts_process_read_req
@ -1226,9 +1445,11 @@ void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code,
case GATT_REQ_WRITE: /* write char/char descriptor value */
case GATT_CMD_WRITE:
case GATT_SIGN_CMD_WRITE:
case GATT_REQ_PREPARE_WRITE:
gatts_process_write_req(p_tcb, i, handle, op_code, len, p);
break;
case GATT_REQ_PREPARE_WRITE:
gatt_attr_process_prepare_write (p_tcb, i, handle, op_code, len, p);
default:
break;
}

View file

@ -116,6 +116,26 @@ void gatt_free_pending_enc_queue(tGATT_TCB *p_tcb)
}
}
/*******************************************************************************
**
** Function gatt_free_pending_prepare_write_queue
**
** Description Free all buffers in pending prepare write packets queue
**
** Returns None
**
*******************************************************************************/
void gatt_free_pending_prepare_write_queue(tGATT_TCB *p_tcb)
{
GATT_TRACE_DEBUG("gatt_free_pending_prepare_write_queue");
/* release all queued prepare write packets */
while (!GKI_queue_is_empty(&(p_tcb->prepare_write_record.queue))) {
GKI_freebuf (GKI_dequeue (&(p_tcb->prepare_write_record.queue)));
}
p_tcb->prepare_write_record.total_num = 0;
p_tcb->prepare_write_record.error_code_app = GATT_SUCCESS;
}
/*******************************************************************************
**
** Function gatt_delete_dev_from_srv_chg_clt_list
@ -2108,6 +2128,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
btu_stop_timer (&p_tcb->conf_timer_ent);
gatt_free_pending_ind(p_tcb);
gatt_free_pending_enc_queue(p_tcb);
gatt_free_pending_prepare_write_queue(p_tcb);
for (i = 0; i < GATT_MAX_APPS; i ++) {
p_reg = &gatt_cb.cl_rcb[i];

View file

@ -133,6 +133,16 @@ typedef struct {
UINT8 reason;
} tGATT_ERROR;
/* Execute write response structure */
typedef struct {
UINT8 op_code;
}__attribute__((packed)) tGATT_EXEC_WRITE_RSP;
/* Write request response structure */
typedef struct {
UINT8 op_code;
}__attribute__((packed)) tGATT_WRITE_REQ_RSP;
/* server response message to ATT protocol
*/
typedef union {
@ -329,6 +339,32 @@ typedef struct {
UINT16 count;
} tGATT_SRV_LIST_INFO;
/* prepare write queue data */
typedef struct{
//len: length of value
tGATT_ATTR16 *p_attr;
UINT16 len;
UINT8 op_code;
UINT16 handle;
UINT16 offset;
UINT8 value[2];
}__attribute__((packed)) tGATT_PREPARE_WRITE_QUEUE_DATA;
/* structure to store prepare write packts information */
typedef struct{
//only store prepare write packets which need
//to be responded by stack (not by application)
BUFFER_Q queue;
//store the total number of prepare write packets
//including that should be responded by stack or by application
UINT16 total_num;
//store application error code for prepare write,
//invalid offset && invalid length
UINT8 error_code_app;
}tGATT_PREPARE_WRITE_RECORD;
typedef struct {
BUFFER_Q pending_enc_clcb; /* pending encryption channel q */
tGATT_SEC_ACTION sec_act;
@ -362,6 +398,7 @@ typedef struct {
BOOLEAN in_use;
UINT8 tcb_idx;
tGATT_PREPARE_WRITE_RECORD prepare_write_record; /* prepare write packets record */
} tGATT_TCB;

View file

@ -65,6 +65,8 @@
#define GATT_CONGESTED 0x8f
#define GATT_STACK_RSP 0x90
#define GATT_APP_RSP 0x91
//Error caused by customer application or stack bug
#define GATT_ESP_ERROR 0X9f
/* 0xE0 ~ 0xFC reserved for future use */
#define GATT_CCC_CFG_ERR 0xFD /* Client Characteristic Configuration Descriptor Improperly Configured */