• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *******************************************************************************/
gatt_act_discovery(tGATT_CLCB * p_clcb)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 *******************************************************************************/
gatt_act_read(tGATT_CLCB * p_clcb,UINT16 offset)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 *******************************************************************************/
gatt_act_write(tGATT_CLCB * p_clcb,UINT8 sec_act)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 *******************************************************************************/
gatt_send_queue_write_cancel(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,tGATT_EXEC_FLAG flag)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 *******************************************************************************/
gatt_check_write_long_terminate(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,tGATT_VALUE * p_rsp_value)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 *******************************************************************************/
gatt_send_prepare_write(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb)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 *******************************************************************************/
gatt_process_find_type_value_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_read_info_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_proc_disc_error_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 opcode,UINT16 handle,UINT8 reason)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 *******************************************************************************/
gatt_process_error_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_prep_write_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_notification(tGATT_TCB * p_tcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_read_by_type_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_read_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_handle_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_process_mtu_rsp(tGATT_TCB * p_tcb,tGATT_CLCB * p_clcb,UINT16 len,UINT8 * p_data)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 *******************************************************************************/
gatt_cmd_to_rsp_code(UINT8 cmd_code)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 *******************************************************************************/
gatt_cl_send_next_cmd_inq(tGATT_TCB * p_tcb)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 *******************************************************************************/
gatt_client_handle_server_rsp(tGATT_TCB * p_tcb,UINT8 op_code,UINT16 len,UINT8 * p_data)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