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