Home | History | Annotate | Download | only in gatt
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 1999-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /******************************************************************************
     20  *
     21  *  this file contains the main GATT client functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include "bt_target.h"
     26 
     27 #include <string.h>
     28 #include "bt_common.h"
     29 #include "bt_utils.h"
     30 #include "gatt_int.h"
     31 #include "l2c_int.h"
     32 #include "osi/include/osi.h"
     33 
     34 #define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
     35 #define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
     36 #define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90)
     37 
     38 #define GATT_PREP_WRITE_RSP_MIN_LEN 4
     39 #define GATT_NOTIFICATION_MIN_LEN 2
     40 #define GATT_WRITE_RSP_MIN_LEN 2
     41 #define GATT_INFO_RSP_MIN_LEN 1
     42 #define GATT_MTU_RSP_MIN_LEN 2
     43 #define GATT_READ_BY_TYPE_RSP_MIN_LEN 1
     44 
     45 /*******************************************************************************
     46  *                      G L O B A L      G A T T       D A T A                 *
     47  ******************************************************************************/
     48 void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb);
     49 
     50 uint8_t disc_type_to_att_opcode[GATT_DISC_MAX] = {
     51     0,
     52     GATT_REQ_READ_BY_GRP_TYPE, /*  GATT_DISC_SRVC_ALL = 1, */
     53     GATT_REQ_FIND_TYPE_VALUE,  /*  GATT_DISC_SRVC_BY_UUID,  */
     54     GATT_REQ_READ_BY_TYPE,     /*  GATT_DISC_INC_SRVC,      */
     55     GATT_REQ_READ_BY_TYPE,     /*  GATT_DISC_CHAR,          */
     56     GATT_REQ_FIND_INFO         /*  GATT_DISC_CHAR_DSCPT,    */
     57 };
     58 
     59 uint16_t disc_type_to_uuid[GATT_DISC_MAX] = {
     60     0,                         /* reserved */
     61     GATT_UUID_PRI_SERVICE,     /* <service> DISC_SRVC_ALL */
     62     GATT_UUID_PRI_SERVICE,     /* <service> for DISC_SERVC_BY_UUID */
     63     GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
     64     GATT_UUID_CHAR_DECLARE,    /* <characteristic> for DISC_CHAR */
     65     0                          /* no type filtering for DISC_CHAR_DSCPT */
     66 };
     67 
     68 /*******************************************************************************
     69  *
     70  * Function         gatt_act_discovery
     71  *
     72  * Description      GATT discovery operation.
     73  *
     74  * Returns          void.
     75  *
     76  ******************************************************************************/
     77 void gatt_act_discovery(tGATT_CLCB* p_clcb) {
     78   uint8_t op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
     79   tGATT_CL_MSG cl_req;
     80   tGATT_STATUS st;
     81 
     82   if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) {
     83     memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
     84 
     85     cl_req.browse.s_handle = p_clcb->s_handle;
     86     cl_req.browse.e_handle = p_clcb->e_handle;
     87 
     88     if (disc_type_to_uuid[p_clcb->op_subtype] != 0) {
     89       cl_req.browse.uuid.len = 2;
     90       cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
     91     }
     92 
     93     if (p_clcb->op_subtype ==
     94         GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
     95     {
     96       cl_req.find_type_value.uuid.len = 2;
     97       cl_req.find_type_value.uuid.uu.uuid16 =
     98           disc_type_to_uuid[p_clcb->op_subtype];
     99       cl_req.find_type_value.s_handle = p_clcb->s_handle;
    100       cl_req.find_type_value.e_handle = p_clcb->e_handle;
    101       cl_req.find_type_value.value_len = p_clcb->uuid.len;
    102       /* if service type is 32 bits UUID, convert it now */
    103       if (p_clcb->uuid.len == LEN_UUID_32) {
    104         cl_req.find_type_value.value_len = LEN_UUID_128;
    105         gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value,
    106                                        p_clcb->uuid.uu.uuid32);
    107       } else
    108         memcpy(cl_req.find_type_value.value, &p_clcb->uuid.uu,
    109                p_clcb->uuid.len);
    110     }
    111 
    112     st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
    113 
    114     if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
    115       gatt_end_operation(p_clcb, GATT_ERROR, NULL);
    116     }
    117   } else /* end of handle range */
    118     gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
    119 }
    120 
    121 /*******************************************************************************
    122  *
    123  * Function         gatt_act_read
    124  *
    125  * Description      GATT read operation.
    126  *
    127  * Returns          void.
    128  *
    129  ******************************************************************************/
    130 void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset) {
    131   tGATT_TCB* p_tcb = p_clcb->p_tcb;
    132   uint8_t rt = GATT_INTERNAL_ERROR;
    133   tGATT_CL_MSG msg;
    134   uint8_t op_code = 0;
    135 
    136   memset(&msg, 0, sizeof(tGATT_CL_MSG));
    137 
    138   switch (p_clcb->op_subtype) {
    139     case GATT_READ_CHAR_VALUE:
    140     case GATT_READ_BY_TYPE:
    141       op_code = GATT_REQ_READ_BY_TYPE;
    142       msg.browse.s_handle = p_clcb->s_handle;
    143       msg.browse.e_handle = p_clcb->e_handle;
    144       if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
    145         memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
    146       else {
    147         msg.browse.uuid.len = LEN_UUID_16;
    148         msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
    149       }
    150       break;
    151 
    152     case GATT_READ_CHAR_VALUE_HDL:
    153     case GATT_READ_BY_HANDLE:
    154       if (!p_clcb->counter) {
    155         op_code = GATT_REQ_READ;
    156         msg.handle = p_clcb->s_handle;
    157       } else {
    158         if (!p_clcb->first_read_blob_after_read)
    159           p_clcb->first_read_blob_after_read = true;
    160         else
    161           p_clcb->first_read_blob_after_read = false;
    162 
    163         GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d",
    164                          p_clcb->first_read_blob_after_read);
    165         op_code = GATT_REQ_READ_BLOB;
    166         msg.read_blob.offset = offset;
    167         msg.read_blob.handle = p_clcb->s_handle;
    168       }
    169       p_clcb->op_subtype &= ~0x80;
    170       break;
    171 
    172     case GATT_READ_PARTIAL:
    173       op_code = GATT_REQ_READ_BLOB;
    174       msg.read_blob.handle = p_clcb->s_handle;
    175       msg.read_blob.offset = offset;
    176       break;
    177 
    178     case GATT_READ_MULTIPLE:
    179       op_code = GATT_REQ_READ_MULTI;
    180       memcpy(&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
    181       break;
    182 
    183     case GATT_READ_INC_SRV_UUID128:
    184       op_code = GATT_REQ_READ;
    185       msg.handle = p_clcb->s_handle;
    186       p_clcb->op_subtype &= ~0x90;
    187       break;
    188 
    189     default:
    190       GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype);
    191       break;
    192   }
    193 
    194   if (op_code != 0)
    195     rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
    196 
    197   if (op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)) {
    198     gatt_end_operation(p_clcb, rt, NULL);
    199   }
    200 }
    201 
    202 /*******************************************************************************
    203  *
    204  * Function         gatt_act_write
    205  *
    206  * Description      GATT write operation.
    207  *
    208  * Returns          void.
    209  *
    210  ******************************************************************************/
    211 void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) {
    212   tGATT_TCB* p_tcb = p_clcb->p_tcb;
    213   uint8_t rt = GATT_SUCCESS, op_code = 0;
    214   tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
    215 
    216   if (p_attr) {
    217     switch (p_clcb->op_subtype) {
    218       case GATT_WRITE_NO_RSP:
    219         p_clcb->s_handle = p_attr->handle;
    220         op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE
    221                                                   : GATT_CMD_WRITE;
    222         rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, op_code,
    223                                  p_attr->handle, p_attr->len, 0, p_attr->value);
    224         break;
    225 
    226       case GATT_WRITE:
    227         if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE)) {
    228           p_clcb->s_handle = p_attr->handle;
    229 
    230           rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_WRITE,
    231                                    p_attr->handle, p_attr->len, 0,
    232                                    p_attr->value);
    233         } else /* prepare write for long attribute */
    234         {
    235           gatt_send_prepare_write(p_tcb, p_clcb);
    236         }
    237         break;
    238 
    239       case GATT_WRITE_PREPARE:
    240         gatt_send_prepare_write(p_tcb, p_clcb);
    241         break;
    242 
    243       default:
    244         rt = GATT_INTERNAL_ERROR;
    245         GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
    246         break;
    247     }
    248   } else
    249     rt = GATT_INTERNAL_ERROR;
    250 
    251   if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED) ||
    252       (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
    253     if (rt != GATT_SUCCESS) {
    254       GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code,
    255                        rt);
    256     }
    257     gatt_end_operation(p_clcb, rt, NULL);
    258   }
    259 }
    260 /*******************************************************************************
    261  *
    262  * Function         gatt_send_queue_write_cancel
    263  *
    264  * Description      send queue write cancel
    265  *
    266  * Returns          void.
    267  *
    268  ******************************************************************************/
    269 void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    270                                   tGATT_EXEC_FLAG flag) {
    271   uint8_t rt;
    272 
    273   GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
    274 
    275   rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE,
    276                         (tGATT_CL_MSG*)&flag);
    277 
    278   if (rt != GATT_SUCCESS) {
    279     gatt_end_operation(p_clcb, rt, NULL);
    280   }
    281 }
    282 /*******************************************************************************
    283  *
    284  * Function         gatt_check_write_long_terminate
    285  *
    286  * Description      To terminate write long or not.
    287  *
    288  * Returns          true: write long is terminated; false keep sending.
    289  *
    290  ******************************************************************************/
    291 bool gatt_check_write_long_terminate(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    292                                      tGATT_VALUE* p_rsp_value) {
    293   tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
    294   bool exec = false;
    295   tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
    296 
    297   GATT_TRACE_DEBUG("gatt_check_write_long_terminate ");
    298   /* check the first write response status */
    299   if (p_rsp_value != NULL) {
    300     if (p_rsp_value->handle != p_attr->handle ||
    301         p_rsp_value->len != p_clcb->counter ||
    302         memcmp(p_rsp_value->value, p_attr->value + p_attr->offset,
    303                p_rsp_value->len)) {
    304       /* data does not match    */
    305       p_clcb->status = GATT_ERROR;
    306       flag = GATT_PREP_WRITE_CANCEL;
    307       exec = true;
    308     } else /* response checking is good */
    309     {
    310       p_clcb->status = GATT_SUCCESS;
    311       /* update write offset and check if end of attribute value */
    312       if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) exec = true;
    313     }
    314   }
    315   if (exec) {
    316     gatt_send_queue_write_cancel(p_tcb, p_clcb, flag);
    317     return true;
    318   }
    319   return false;
    320 }
    321 /*******************************************************************************
    322  *
    323  * Function         gatt_send_prepare_write
    324  *
    325  * Description      Send prepare write.
    326  *
    327  * Returns          void.
    328  *
    329  ******************************************************************************/
    330 void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
    331   tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
    332   uint16_t to_send, offset;
    333   uint8_t rt = GATT_SUCCESS;
    334   uint8_t type = p_clcb->op_subtype;
    335 
    336   GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type);
    337   to_send = p_attr->len - p_attr->offset;
    338 
    339   if (to_send > (p_tcb->payload_size -
    340                  GATT_WRITE_LONG_HDR_SIZE)) /* 2 = uint16_t offset bytes  */
    341     to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
    342 
    343   p_clcb->s_handle = p_attr->handle;
    344 
    345   offset = p_attr->offset;
    346   if (type == GATT_WRITE_PREPARE) {
    347     offset += p_clcb->start_offset;
    348   }
    349 
    350   GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send);
    351 
    352   rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_PREPARE_WRITE,
    353                            p_attr->handle, to_send,         /* length */
    354                            offset,                          /* used as offset */
    355                            p_attr->value + p_attr->offset); /* data */
    356 
    357   /* remember the write long attribute length */
    358   p_clcb->counter = to_send;
    359 
    360   if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED) {
    361     gatt_end_operation(p_clcb, rt, NULL);
    362   }
    363 }
    364 
    365 /*******************************************************************************
    366  *
    367  * Function         gatt_process_find_type_value_rsp
    368  *
    369  * Description      This function handles the find by type value response.
    370  *
    371  *
    372  * Returns          void
    373  *
    374  ******************************************************************************/
    375 void gatt_process_find_type_value_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
    376                                       tGATT_CLCB* p_clcb, uint16_t len,
    377                                       uint8_t* p_data) {
    378   tGATT_DISC_RES result;
    379   uint8_t* p = p_data;
    380 
    381   GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
    382   /* unexpected response */
    383   if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY ||
    384       p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
    385     return;
    386 
    387   memset(&result, 0, sizeof(tGATT_DISC_RES));
    388   result.type.len = 2;
    389   result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
    390 
    391   /* returns a series of handle ranges */
    392   while (len >= 4) {
    393     STREAM_TO_UINT16(result.handle, p);
    394     STREAM_TO_UINT16(result.value.group_value.e_handle, p);
    395     memcpy(&result.value.group_value.service_type, &p_clcb->uuid,
    396            sizeof(tBT_UUID));
    397 
    398     len -= 4;
    399 
    400     if (p_clcb->p_reg->app_cb.p_disc_res_cb)
    401       (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
    402                                              p_clcb->op_subtype, &result);
    403   }
    404 
    405   /* last handle  + 1 */
    406   p_clcb->s_handle = (result.value.group_value.e_handle == 0)
    407                          ? 0
    408                          : (result.value.group_value.e_handle + 1);
    409   /* initiate another request */
    410   gatt_act_discovery(p_clcb);
    411 }
    412 /*******************************************************************************
    413  *
    414  * Function         gatt_process_read_info_rsp
    415  *
    416  * Description      This function is called to handle the read information
    417  *                  response.
    418  *
    419  *
    420  * Returns          void
    421  *
    422  ******************************************************************************/
    423 void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
    424                                 tGATT_CLCB* p_clcb, UNUSED_ATTR uint8_t op_code,
    425                                 uint16_t len, uint8_t* p_data) {
    426   tGATT_DISC_RES result;
    427   uint8_t *p = p_data, uuid_len = 0, type;
    428 
    429   if (len < GATT_INFO_RSP_MIN_LEN) {
    430     GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
    431     gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
    432     return;
    433   }
    434   /* unexpected response */
    435   if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY ||
    436       p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
    437     return;
    438 
    439   STREAM_TO_UINT8(type, p);
    440   len -= 1;
    441 
    442   if (type == GATT_INFO_TYPE_PAIR_16)
    443     uuid_len = LEN_UUID_16;
    444   else if (type == GATT_INFO_TYPE_PAIR_128)
    445     uuid_len = LEN_UUID_128;
    446 
    447   while (len >= uuid_len + 2) {
    448     STREAM_TO_UINT16(result.handle, p);
    449 
    450     if (uuid_len > 0) {
    451       if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p)) break;
    452     } else
    453       memcpy(&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
    454 
    455     len -= (uuid_len + 2);
    456 
    457     if (p_clcb->p_reg->app_cb.p_disc_res_cb)
    458       (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
    459                                              p_clcb->op_subtype, &result);
    460   }
    461 
    462   p_clcb->s_handle = (result.handle == 0) ? 0 : (result.handle + 1);
    463   /* initiate another request */
    464   gatt_act_discovery(p_clcb);
    465 }
    466 /*******************************************************************************
    467  *
    468  * Function         gatt_proc_disc_error_rsp
    469  *
    470  * Description      Process the read by type response and send another request
    471  *                  if needed.
    472  *
    473  * Returns          void.
    474  *
    475  ******************************************************************************/
    476 void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    477                               uint8_t opcode, UNUSED_ATTR uint16_t handle,
    478                               uint8_t reason) {
    479   tGATT_STATUS status = (tGATT_STATUS)reason;
    480 
    481   GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x",
    482                    reason, opcode);
    483 
    484   switch (opcode) {
    485     case GATT_REQ_READ_BY_GRP_TYPE:
    486     case GATT_REQ_FIND_TYPE_VALUE:
    487     case GATT_REQ_READ_BY_TYPE:
    488     case GATT_REQ_FIND_INFO:
    489       if (reason == GATT_NOT_FOUND) {
    490         status = GATT_SUCCESS;
    491         GATT_TRACE_DEBUG("Discovery completed");
    492       }
    493       break;
    494     default:
    495       GATT_TRACE_ERROR("Incorrect discovery opcode %04x", opcode);
    496       break;
    497   }
    498 
    499   gatt_end_operation(p_clcb, status, NULL);
    500 }
    501 
    502 /*******************************************************************************
    503  *
    504  * Function         gatt_process_error_rsp
    505  *
    506  * Description      This function is called to handle the error response
    507  *
    508  *
    509  * Returns          void
    510  *
    511  ******************************************************************************/
    512 void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    513                             UNUSED_ATTR uint8_t op_code,
    514                             UNUSED_ATTR uint16_t len, uint8_t* p_data) {
    515   uint8_t opcode, reason, *p = p_data;
    516   uint16_t handle;
    517   tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
    518 
    519   GATT_TRACE_DEBUG("gatt_process_error_rsp ");
    520   STREAM_TO_UINT8(opcode, p);
    521   STREAM_TO_UINT16(handle, p);
    522   STREAM_TO_UINT8(reason, p);
    523 
    524   if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
    525     gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
    526   } else {
    527     if ((p_clcb->operation == GATTC_OPTYPE_WRITE) &&
    528         (p_clcb->op_subtype == GATT_WRITE) &&
    529         (opcode == GATT_REQ_PREPARE_WRITE) && (p_attr) &&
    530         (handle == p_attr->handle)) {
    531       p_clcb->status = reason;
    532       gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
    533     } else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
    534                ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
    535                 (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
    536                (opcode == GATT_REQ_READ_BLOB) &&
    537                p_clcb->first_read_blob_after_read &&
    538                (reason == GATT_NOT_LONG)) {
    539       gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p_clcb->p_attr_buf);
    540     } else
    541       gatt_end_operation(p_clcb, reason, NULL);
    542   }
    543 }
    544 /*******************************************************************************
    545  *
    546  * Function         gatt_process_prep_write_rsp
    547  *
    548  * Description      This function is called to handle the read response
    549  *
    550  *
    551  * Returns          void
    552  *
    553  ******************************************************************************/
    554 void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    555                                  uint8_t op_code, uint16_t len,
    556                                  uint8_t* p_data) {
    557   uint8_t* p = p_data;
    558 
    559   tGATT_VALUE value = {
    560       .conn_id = p_clcb->conn_id, .auth_req = GATT_AUTH_REQ_NONE,
    561   };
    562 
    563   GATT_TRACE_ERROR("value resp op_code = %s len = %d",
    564                    gatt_dbg_op_name(op_code), len);
    565 
    566   if (len < GATT_PREP_WRITE_RSP_MIN_LEN) {
    567     GATT_TRACE_ERROR("illegal prepare write response length, discard");
    568     gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
    569     return;
    570   }
    571 
    572   STREAM_TO_UINT16(value.handle, p);
    573   STREAM_TO_UINT16(value.offset, p);
    574 
    575   value.len = len - 4;
    576 
    577   memcpy(value.value, p, value.len);
    578 
    579   if (p_clcb->op_subtype == GATT_WRITE_PREPARE) {
    580     p_clcb->status = GATT_SUCCESS;
    581     /* application should verify handle offset
    582        and value are matched or not */
    583 
    584     gatt_end_operation(p_clcb, p_clcb->status, &value);
    585   } else if (p_clcb->op_subtype == GATT_WRITE) {
    586     if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
    587       gatt_send_prepare_write(p_tcb, p_clcb);
    588   }
    589 }
    590 /*******************************************************************************
    591  *
    592  * Function         gatt_process_notification
    593  *
    594  * Description      Handle the handle value indication/notification.
    595  *
    596  * Returns          void
    597  *
    598  ******************************************************************************/
    599 void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
    600                                uint8_t* p_data) {
    601   tGATT_VALUE value;
    602   tGATT_REG* p_reg;
    603   uint16_t conn_id;
    604   tGATT_STATUS encrypt_status;
    605   uint8_t *p = p_data, i, event = (op_code == GATT_HANDLE_VALUE_NOTIF)
    606                                       ? GATTC_OPTYPE_NOTIFICATION
    607                                       : GATTC_OPTYPE_INDICATION;
    608 
    609   GATT_TRACE_DEBUG("gatt_process_notification ");
    610 
    611   if (len < GATT_NOTIFICATION_MIN_LEN) {
    612     GATT_TRACE_ERROR("illegal notification PDU length, discard");
    613     return;
    614   }
    615 
    616   memset(&value, 0, sizeof(value));
    617   STREAM_TO_UINT16(value.handle, p);
    618   value.len = len - 2;
    619   memcpy(value.value, p, value.len);
    620 
    621   if (!GATT_HANDLE_IS_VALID(value.handle)) {
    622     /* illegal handle, send ack now */
    623     if (op_code == GATT_HANDLE_VALUE_IND)
    624       attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
    625     return;
    626   }
    627 
    628   if (event == GATTC_OPTYPE_INDICATION) {
    629     if (p_tcb->ind_count) {
    630       /* this is an error case that receiving an indication but we
    631          still has an indication not being acked yet.
    632          For now, just log the error reset the counter.
    633          Later we need to disconnect the link unconditionally.
    634       */
    635       GATT_TRACE_ERROR(
    636           "gatt_process_notification rcv Ind. but ind_count=%d (will reset "
    637           "ind_count)",
    638           p_tcb->ind_count);
    639     }
    640     p_tcb->ind_count = 0;
    641   }
    642 
    643   /* should notify all registered client with the handle value
    644      notificaion/indication
    645      Note: need to do the indication count and start timer first then do
    646      callback
    647    */
    648 
    649   for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
    650     if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb &&
    651         (event == GATTC_OPTYPE_INDICATION))
    652       p_tcb->ind_count++;
    653   }
    654 
    655   if (event == GATTC_OPTYPE_INDICATION) {
    656     /* start a timer for app confirmation */
    657     if (p_tcb->ind_count > 0)
    658       gatt_start_ind_ack_timer(p_tcb);
    659     else /* no app to indicate, or invalid handle */
    660       attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
    661   }
    662 
    663   encrypt_status = gatt_get_link_encrypt_status(p_tcb);
    664   for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
    665     if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) {
    666       conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
    667       (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status,
    668                                  (tGATT_CL_COMPLETE*)&value);
    669     }
    670   }
    671 }
    672 
    673 /*******************************************************************************
    674  *
    675  * Function         gatt_process_read_by_type_rsp
    676  *
    677  * Description      This function is called to handle the read by type response.
    678  *                  read by type can be used for discovery, or read by type or
    679  *                  read characteristic value.
    680  *
    681  * Returns          void
    682  *
    683  ******************************************************************************/
    684 void gatt_process_read_by_type_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    685                                    uint8_t op_code, uint16_t len,
    686                                    uint8_t* p_data) {
    687   tGATT_DISC_RES result;
    688   tGATT_DISC_VALUE record_value;
    689   uint8_t *p = p_data, value_len, handle_len = 2;
    690   uint16_t handle = 0;
    691 
    692   /* discovery procedure and no callback function registered */
    693   if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) &&
    694       (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
    695     return;
    696 
    697   if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN) {
    698     GATT_TRACE_ERROR(
    699         "Illegal ReadByType/ReadByGroupType Response length, discard");
    700     gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
    701     return;
    702   }
    703 
    704   STREAM_TO_UINT8(value_len, p);
    705 
    706   if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len - 1))) {
    707     /* this is an error case that server's response containing a value length
    708        which is larger than MTU-2
    709        or value_len > message total length -1 */
    710     GATT_TRACE_ERROR(
    711         "gatt_process_read_by_type_rsp: Discard response op_code=%d "
    712         "vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
    713         op_code, value_len, (p_tcb->payload_size - 2), (len - 1));
    714     gatt_end_operation(p_clcb, GATT_ERROR, NULL);
    715     return;
    716   }
    717 
    718   if (op_code == GATT_RSP_READ_BY_GRP_TYPE) handle_len = 4;
    719 
    720   value_len -= handle_len; /* substract the handle pairs bytes */
    721   len -= 1;
    722 
    723   while (len >= (handle_len + value_len)) {
    724     STREAM_TO_UINT16(handle, p);
    725 
    726     if (!GATT_HANDLE_IS_VALID(handle)) {
    727       gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
    728       return;
    729     }
    730 
    731     memset(&result, 0, sizeof(tGATT_DISC_RES));
    732     memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
    733 
    734     result.handle = handle;
    735     result.type.len = 2;
    736     result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
    737 
    738     /* discover all services */
    739     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
    740         p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
    741         op_code == GATT_RSP_READ_BY_GRP_TYPE) {
    742       STREAM_TO_UINT16(handle, p);
    743 
    744       if (!GATT_HANDLE_IS_VALID(handle)) {
    745         gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
    746         return;
    747       } else {
    748         record_value.group_value.e_handle = handle;
    749         if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type,
    750                                       value_len, &p)) {
    751           GATT_TRACE_ERROR("discover all service response parsing failure");
    752           break;
    753         }
    754       }
    755     }
    756     /* discover included service */
    757     else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
    758              p_clcb->op_subtype == GATT_DISC_INC_SRVC) {
    759       STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
    760       STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
    761 
    762       if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
    763           !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle)) {
    764         gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
    765         return;
    766       }
    767 
    768       if (value_len == 6) {
    769         STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
    770         record_value.incl_service.service_type.len = LEN_UUID_16;
    771       } else if (value_len == 4) {
    772         p_clcb->s_handle = record_value.incl_service.s_handle;
    773         p_clcb->read_uuid128.wait_for_read_rsp = true;
    774         p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
    775         memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
    776         memcpy(&p_clcb->read_uuid128.result.value, &record_value,
    777                sizeof(result.value));
    778         p_clcb->op_subtype |= 0x90;
    779         gatt_act_read(p_clcb, 0);
    780         return;
    781       } else {
    782         GATT_TRACE_ERROR(
    783             "gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data "
    784             "value_len=%d",
    785             value_len);
    786         gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void*)p);
    787         return;
    788       }
    789     }
    790     /* read by type */
    791     else if (p_clcb->operation == GATTC_OPTYPE_READ &&
    792              p_clcb->op_subtype == GATT_READ_BY_TYPE) {
    793       p_clcb->counter = len - 2;
    794       p_clcb->s_handle = handle;
    795       if (p_clcb->counter == (p_clcb->p_tcb->payload_size - 4)) {
    796         p_clcb->op_subtype = GATT_READ_BY_HANDLE;
    797         if (!p_clcb->p_attr_buf)
    798           p_clcb->p_attr_buf = (uint8_t*)osi_malloc(GATT_MAX_ATTR_LEN);
    799         if (p_clcb->counter <= GATT_MAX_ATTR_LEN) {
    800           memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
    801           gatt_act_read(p_clcb, p_clcb->counter);
    802         } else {
    803           gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void*)p);
    804         }
    805       } else {
    806         gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p);
    807       }
    808       return;
    809     } else /* discover characterisitic */
    810     {
    811       STREAM_TO_UINT8(record_value.dclr_value.char_prop, p);
    812       STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
    813       if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) {
    814         gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
    815         return;
    816       }
    817       if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid,
    818                                     (uint16_t)(value_len - 3), &p)) {
    819         gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
    820         /* invalid format, and skip the result */
    821         return;
    822       }
    823 
    824       /* UUID not matching */
    825       if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) {
    826         len -= (value_len + 2);
    827         continue; /* skip the result, and look for next one */
    828       } else if (p_clcb->operation == GATTC_OPTYPE_READ)
    829       /* UUID match for read characteristic value */
    830       {
    831         /* only read the first matching UUID characteristic value, and
    832           discard the rest results */
    833         p_clcb->s_handle = record_value.dclr_value.val_handle;
    834         p_clcb->op_subtype |= 0x80;
    835         gatt_act_read(p_clcb, 0);
    836         return;
    837       }
    838     }
    839     len -= (value_len + handle_len);
    840 
    841     /* result is (handle, 16bits UUID) pairs */
    842     memcpy(&result.value, &record_value, sizeof(result.value));
    843 
    844     /* send callback if is discover procedure */
    845     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
    846         p_clcb->p_reg->app_cb.p_disc_res_cb)
    847       (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
    848                                              p_clcb->op_subtype, &result);
    849   }
    850 
    851   p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
    852 
    853   if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
    854     /* initiate another request */
    855     gatt_act_discovery(p_clcb);
    856   } else /* read characteristic value */
    857   {
    858     gatt_act_read(p_clcb, 0);
    859   }
    860 }
    861 
    862 /*******************************************************************************
    863  *
    864  * Function         gatt_process_read_rsp
    865  *
    866  * Description      This function is called to handle the read BLOB response
    867  *
    868  *
    869  * Returns          void
    870  *
    871  ******************************************************************************/
    872 void gatt_process_read_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
    873                            UNUSED_ATTR uint8_t op_code, uint16_t len,
    874                            uint8_t* p_data) {
    875   uint16_t offset = p_clcb->counter;
    876   uint8_t* p = p_data;
    877 
    878   if (p_clcb->operation == GATTC_OPTYPE_READ) {
    879     if (p_clcb->op_subtype != GATT_READ_BY_HANDLE) {
    880       p_clcb->counter = len;
    881       gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p);
    882     } else {
    883       /* allocate GKI buffer holding up long attribute value  */
    884       if (!p_clcb->p_attr_buf)
    885         p_clcb->p_attr_buf = (uint8_t*)osi_malloc(GATT_MAX_ATTR_LEN);
    886 
    887       /* copy attrobute value into cb buffer  */
    888       if (offset < GATT_MAX_ATTR_LEN) {
    889         if ((len + offset) > GATT_MAX_ATTR_LEN)
    890           len = GATT_MAX_ATTR_LEN - offset;
    891 
    892         p_clcb->counter += len;
    893 
    894         memcpy(p_clcb->p_attr_buf + offset, p, len);
    895 
    896         /* send next request if needed  */
    897 
    898         if (len == (p_tcb->payload_size -
    899                     1) && /* full packet for read or read blob rsp */
    900             len + offset < GATT_MAX_ATTR_LEN) {
    901           GATT_TRACE_DEBUG(
    902               "full pkt issue read blob for remianing bytes old offset=%d "
    903               "len=%d new offset=%d",
    904               offset, len, p_clcb->counter);
    905           gatt_act_read(p_clcb, p_clcb->counter);
    906         } else /* end of request, send callback */
    907         {
    908           gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p_clcb->p_attr_buf);
    909         }
    910       } else /* exception, should not happen */
    911       {
    912         GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset,
    913                          p_clcb->p_attr_buf);
    914         gatt_end_operation(p_clcb, GATT_NO_RESOURCES,
    915                            (void*)p_clcb->p_attr_buf);
    916       }
    917     }
    918   } else {
    919     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
    920         p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
    921         p_clcb->read_uuid128.wait_for_read_rsp) {
    922       p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
    923       p_clcb->read_uuid128.wait_for_read_rsp = false;
    924       if (len == LEN_UUID_128) {
    925         memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu
    926                    .uuid128,
    927                p, len);
    928         p_clcb->read_uuid128.result.value.incl_service.service_type.len =
    929             LEN_UUID_128;
    930         if (p_clcb->p_reg->app_cb.p_disc_res_cb)
    931           (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
    932                                                  p_clcb->op_subtype,
    933                                                  &p_clcb->read_uuid128.result);
    934         gatt_act_discovery(p_clcb);
    935       } else {
    936         gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void*)p);
    937       }
    938     }
    939   }
    940 }
    941 
    942 /*******************************************************************************
    943  *
    944  * Function         gatt_process_handle_rsp
    945  *
    946  * Description      This function is called to handle the write response
    947  *
    948  *
    949  * Returns          void
    950  *
    951  ******************************************************************************/
    952 void gatt_process_handle_rsp(tGATT_CLCB* p_clcb) {
    953   gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
    954 }
    955 /*******************************************************************************
    956  *
    957  * Function         gatt_process_mtu_rsp
    958  *
    959  * Description      Process the configure MTU response.
    960  *
    961  *
    962  * Returns          void
    963  *
    964  ******************************************************************************/
    965 void gatt_process_mtu_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb, uint16_t len,
    966                           uint8_t* p_data) {
    967   uint16_t mtu;
    968   tGATT_STATUS status = GATT_SUCCESS;
    969 
    970   if (len < GATT_MTU_RSP_MIN_LEN) {
    971     GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
    972     status = GATT_INVALID_PDU;
    973   } else {
    974     STREAM_TO_UINT16(mtu, p_data);
    975 
    976     if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
    977       p_tcb->payload_size = mtu;
    978   }
    979 
    980   l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID,
    981                                           p_tcb->payload_size);
    982   gatt_end_operation(p_clcb, status, NULL);
    983 }
    984 /*******************************************************************************
    985  *
    986  * Function         gatt_cmd_to_rsp_code
    987  *
    988  * Description      Convert an ATT command op code into the corresponding
    989  *                  response code assume no error occurs.
    990  *
    991  * Returns          response code.
    992  *
    993  ******************************************************************************/
    994 uint8_t gatt_cmd_to_rsp_code(uint8_t cmd_code) {
    995   uint8_t rsp_code = 0;
    996 
    997   if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE) {
    998     rsp_code = cmd_code + 1;
    999   }
   1000   return rsp_code;
   1001 }
   1002 /*******************************************************************************
   1003  *
   1004  * Function         gatt_cl_send_next_cmd_inq
   1005  *
   1006  * Description      Find next command in queue and sent to server
   1007  *
   1008  * Returns          true if command sent, otherwise false.
   1009  *
   1010  ******************************************************************************/
   1011 bool gatt_cl_send_next_cmd_inq(tGATT_TCB* p_tcb) {
   1012   tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
   1013   bool sent = false;
   1014   uint8_t rsp_code;
   1015   tGATT_CLCB* p_clcb = NULL;
   1016   tGATT_STATUS att_ret = GATT_SUCCESS;
   1017 
   1018   while (!sent && p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
   1019          p_cmd->to_send && p_cmd->p_cmd != NULL) {
   1020     att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
   1021 
   1022     if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
   1023       sent = true;
   1024       p_cmd->to_send = false;
   1025       p_cmd->p_cmd = NULL;
   1026 
   1027       /* dequeue the request if is write command or sign write */
   1028       if (p_cmd->op_code != GATT_CMD_WRITE &&
   1029           p_cmd->op_code != GATT_SIGN_CMD_WRITE) {
   1030         gatt_start_rsp_timer(p_cmd->clcb_idx);
   1031       } else {
   1032         p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
   1033 
   1034         /* if no ack needed, keep sending */
   1035         if (att_ret == GATT_SUCCESS) sent = false;
   1036 
   1037         p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
   1038         /* send command complete callback here */
   1039         gatt_end_operation(p_clcb, att_ret, NULL);
   1040       }
   1041     } else {
   1042       GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
   1043 
   1044       memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
   1045       p_tcb->pending_cl_req++;
   1046       p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
   1047     }
   1048   }
   1049   return sent;
   1050 }
   1051 
   1052 /*******************************************************************************
   1053  *
   1054  * Function         gatt_client_handle_server_rsp
   1055  *
   1056  * Description      This function is called to handle the server response to
   1057  *                  client.
   1058  *
   1059  *
   1060  * Returns          void
   1061  *
   1062  ******************************************************************************/
   1063 void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
   1064                                    uint16_t len, uint8_t* p_data) {
   1065   tGATT_CLCB* p_clcb = NULL;
   1066   uint8_t rsp_code;
   1067 
   1068   if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
   1069     p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
   1070 
   1071     rsp_code = gatt_cmd_to_rsp_code(rsp_code);
   1072 
   1073     if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR)) {
   1074       GATT_TRACE_WARNING(
   1075           "ATT - Ignore wrong response. Receives (%02x) \
   1076                                 Request(%02x) Ignored",
   1077           op_code, rsp_code);
   1078 
   1079       return;
   1080     } else {
   1081       alarm_cancel(p_clcb->gatt_rsp_timer_ent);
   1082       p_clcb->retry_count = 0;
   1083     }
   1084   }
   1085   /* the size of the message may not be bigger than the local max PDU size*/
   1086   /* The message has to be smaller than the agreed MTU, len does not count
   1087    * op_code */
   1088   if (len >= p_tcb->payload_size) {
   1089     GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d",
   1090                      len + 1, p_tcb->payload_size);
   1091     if (op_code != GATT_HANDLE_VALUE_NOTIF && op_code != GATT_HANDLE_VALUE_IND)
   1092       gatt_end_operation(p_clcb, GATT_ERROR, NULL);
   1093   } else {
   1094     switch (op_code) {
   1095       case GATT_RSP_ERROR:
   1096         gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
   1097         break;
   1098 
   1099       case GATT_RSP_MTU: /* 2 bytes mtu */
   1100         gatt_process_mtu_rsp(p_tcb, p_clcb, len, p_data);
   1101         break;
   1102 
   1103       case GATT_RSP_FIND_INFO:
   1104         gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
   1105         break;
   1106 
   1107       case GATT_RSP_READ_BY_TYPE:
   1108       case GATT_RSP_READ_BY_GRP_TYPE:
   1109         gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
   1110         break;
   1111 
   1112       case GATT_RSP_READ:
   1113       case GATT_RSP_READ_BLOB:
   1114       case GATT_RSP_READ_MULTI:
   1115         gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
   1116         break;
   1117 
   1118       case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
   1119         gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
   1120         break;
   1121 
   1122       case GATT_RSP_WRITE:
   1123         gatt_process_handle_rsp(p_clcb);
   1124         break;
   1125 
   1126       case GATT_RSP_PREPARE_WRITE:
   1127         gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
   1128         break;
   1129 
   1130       case GATT_RSP_EXEC_WRITE:
   1131         gatt_end_operation(p_clcb, p_clcb->status, NULL);
   1132         break;
   1133 
   1134       case GATT_HANDLE_VALUE_NOTIF:
   1135       case GATT_HANDLE_VALUE_IND:
   1136         gatt_process_notification(p_tcb, op_code, len, p_data);
   1137         break;
   1138 
   1139       default:
   1140         GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
   1141         break;
   1142     }
   1143   }
   1144 
   1145   if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
   1146     gatt_cl_send_next_cmd_inq(p_tcb);
   1147   }
   1148 
   1149   return;
   1150 }
   1151