OSDN Git Service

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