OSDN Git Service

Only initiate codec negotiation if feature is supported am: ecb3b8386f
[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     tGATT_VALUE  value = {0};
615     UINT8        *p= p_data;
616
617     GATT_TRACE_ERROR("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
618
619     if (len < GATT_PREP_WRITE_RSP_MIN_LEN)
620     {
621         GATT_TRACE_ERROR("illegal prepare write response length, discard");
622         gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
623         return;
624     }
625
626     STREAM_TO_UINT16 (value.handle, p);
627     STREAM_TO_UINT16 (value.offset, p);
628
629     value.len = len - 4;
630
631     memcpy (value.value, p, value.len);
632
633     if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
634     {
635         p_clcb->status = GATT_SUCCESS;
636         /* application should verify handle offset
637            and value are matched or not */
638
639         gatt_end_operation(p_clcb, p_clcb->status, &value);
640     }
641     else if (p_clcb->op_subtype == GATT_WRITE )
642     {
643         if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
644             gatt_send_prepare_write(p_tcb, p_clcb);
645     }
646
647 }
648 /*******************************************************************************
649 **
650 ** Function         gatt_process_notification
651 **
652 ** Description      This function is called to handle the handle value indication
653 **                  or handle value notification.
654 **
655 **
656 ** Returns          void
657 **
658 *******************************************************************************/
659 void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
660                                UINT16 len, UINT8 *p_data)
661 {
662     tGATT_VALUE     value = {0};
663     tGATT_REG       *p_reg;
664     UINT16          conn_id;
665     tGATT_STATUS    encrypt_status;
666     UINT8           *p= p_data, i,
667     event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
668
669     GATT_TRACE_DEBUG("gatt_process_notification ");
670
671     if (len < GATT_NOTIFICATION_MIN_LEN)
672     {
673         GATT_TRACE_ERROR("illegal notification PDU length, discard");
674         return;
675     }
676
677     STREAM_TO_UINT16 (value.handle, p);
678     value.len = len - 2;
679     memcpy (value.value, p, value.len);
680
681     if (!GATT_HANDLE_IS_VALID(value.handle))
682     {
683         /* illegal handle, send ack now */
684         if (op_code == GATT_HANDLE_VALUE_IND)
685             attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
686         return;
687     }
688
689     if (event == GATTC_OPTYPE_INDICATION)
690     {
691         if (p_tcb->ind_count)
692         {
693             /* this is an error case that receiving an indication but we
694                still has an indication not being acked yet.
695                For now, just log the error reset the counter.
696                Later we need to disconnect the link unconditionally.
697             */
698             GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)",  p_tcb->ind_count);
699         }
700         p_tcb->ind_count = 0;
701     }
702
703     /* should notify all registered client with the handle value notificaion/indication
704        Note: need to do the indication count and start timer first then do callback
705      */
706
707     for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
708     {
709         if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
710             p_tcb->ind_count++;
711     }
712
713     if (event == GATTC_OPTYPE_INDICATION)
714     {
715         /* start a timer for app confirmation */
716         if (p_tcb->ind_count > 0)
717             gatt_start_ind_ack_timer(p_tcb);
718         else /* no app to indicate, or invalid handle */
719             attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
720     }
721
722     encrypt_status = gatt_get_link_encrypt_status(p_tcb);
723     for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
724     {
725         if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
726         {
727             conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
728             (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
729         }
730     }
731
732 }
733
734 /*******************************************************************************
735 **
736 ** Function         gatt_process_read_by_type_rsp
737 **
738 ** Description      This function is called to handle the read by type response.
739 **                  read by type can be used for discovery, or read by type or
740 **                  read characteristic value.
741 **
742 ** Returns          void
743 **
744 *******************************************************************************/
745 void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
746                                     UINT16 len, UINT8 *p_data)
747 {
748     tGATT_DISC_RES      result;
749     tGATT_DISC_VALUE    record_value;
750     UINT8               *p = p_data, value_len, handle_len = 2;
751     UINT16              handle = 0;
752
753     /* discovery procedure and no callback function registered */
754     if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
755         return;
756
757     if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN)
758     {
759         GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard");
760         gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
761         return;
762     }
763
764     STREAM_TO_UINT8(value_len, p);
765
766     if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1))  )
767     {
768         /* this is an error case that server's response containing a value length which is larger than MTU-2
769            or value_len > message total length -1 */
770         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)",
771                           op_code, value_len, (p_tcb->payload_size - 2), (len-1));
772         gatt_end_operation(p_clcb, GATT_ERROR, NULL);
773         return;
774     }
775
776     if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
777         handle_len = 4;
778
779     value_len -= handle_len; /* substract the handle pairs bytes */
780     len -= 1;
781
782     while (len >= (handle_len + value_len))
783     {
784         STREAM_TO_UINT16(handle, p);
785
786         if (!GATT_HANDLE_IS_VALID(handle))
787         {
788             gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
789             return;
790         }
791
792         memset(&result, 0, sizeof(tGATT_DISC_RES));
793         memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
794
795         result.handle = handle;
796         result.type.len = 2;
797         result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
798
799         /* discover all services */
800         if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
801             p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
802             op_code == GATT_RSP_READ_BY_GRP_TYPE)
803         {
804             STREAM_TO_UINT16(handle, p);
805
806             if (!GATT_HANDLE_IS_VALID(handle))
807             {
808                 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
809                 return;
810             }
811             else
812             {
813                 record_value.group_value.e_handle = handle;
814                 if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
815                 {
816                     GATT_TRACE_ERROR("discover all service response parsing failure");
817                     break;
818                 }
819             }
820         }
821         /* discover included service */
822         else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
823         {
824             STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
825             STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
826
827             if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
828                 !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
829             {
830                 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
831                 return;
832             }
833
834             if(value_len == 6)
835             {
836                 STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
837                 record_value.incl_service.service_type.len = LEN_UUID_16;
838             }
839             else if (value_len == 4)
840             {
841                 p_clcb->s_handle = record_value.incl_service.s_handle;
842                 p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
843                 p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
844                 memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
845                 memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
846                 p_clcb->op_subtype |= 0x90;
847                 gatt_act_read(p_clcb, 0);
848                 return;
849             }
850             else
851             {
852                GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
853                gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
854                return;
855             }
856         }
857         /* read by type */
858         else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
859         {
860             p_clcb->counter = len - 2;
861             p_clcb->s_handle = handle;
862             if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
863             {
864                 p_clcb->op_subtype = GATT_READ_BY_HANDLE;
865                 if (!p_clcb->p_attr_buf)
866                     p_clcb->p_attr_buf = (UINT8 *)osi_getbuf(GATT_MAX_ATTR_LEN);
867                 if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN)
868                 {
869                     memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
870                     gatt_act_read(p_clcb, p_clcb->counter);
871                 }
872                 else
873                    gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
874             }
875             else
876             {
877                  gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
878             }
879             return;
880         }
881         else /* discover characterisitic */
882         {
883             STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
884             STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
885             if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
886             {
887                 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
888                 return;
889             }
890             if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p))
891             {
892                 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
893                 /* invalid format, and skip the result */
894                 return;
895             }
896
897             /* UUID not matching */
898             if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
899             {
900                 len -= (value_len + 2);
901                 continue; /* skip the result, and look for next one */
902             }
903             else if (p_clcb->operation == GATTC_OPTYPE_READ)
904             /* UUID match for read characteristic value */
905             {
906                 /* only read the first matching UUID characteristic value, and
907                   discard the rest results */
908                 p_clcb->s_handle = record_value.dclr_value.val_handle;
909                 p_clcb->op_subtype |= 0x80;
910                 gatt_act_read(p_clcb, 0);
911                 return;
912             }
913         }
914         len -= (value_len + handle_len);
915
916         /* result is (handle, 16bits UUID) pairs */
917         memcpy (&result.value, &record_value, sizeof (result.value));
918
919         /* send callback if is discover procedure */
920         if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
921             (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
922     }
923
924     p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
925
926     if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
927     {
928         /* initiate another request */
929         gatt_act_discovery(p_clcb) ;
930     }
931     else /* read characteristic value */
932     {
933         gatt_act_read(p_clcb, 0);
934     }
935 }
936
937 /*******************************************************************************
938 **
939 ** Function         gatt_process_read_rsp
940 **
941 ** Description      This function is called to handle the read BLOB response
942 **
943 **
944 ** Returns          void
945 **
946 *******************************************************************************/
947 void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,  UINT8 op_code,
948                            UINT16 len, UINT8 *p_data)
949 {
950     UINT16      offset = p_clcb->counter;
951     UINT8       * p= p_data;
952
953     UNUSED(op_code);
954
955     if (p_clcb->operation == GATTC_OPTYPE_READ)
956     {
957         if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
958         {
959             p_clcb->counter = len;
960             gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
961         }
962         else
963         {
964
965             /* allocate GKI buffer holding up long attribute value  */
966             if (!p_clcb->p_attr_buf)
967                 p_clcb->p_attr_buf = (UINT8 *)osi_getbuf(GATT_MAX_ATTR_LEN);
968
969             /* copy attrobute value into cb buffer  */
970             if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN)
971             {
972                 if ((len + offset) > GATT_MAX_ATTR_LEN)
973                     len = GATT_MAX_ATTR_LEN - offset;
974
975                 p_clcb->counter += len;
976
977                 memcpy(p_clcb->p_attr_buf + offset, p, len);
978
979                 /* send next request if needed  */
980
981                 if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
982                     len + offset < GATT_MAX_ATTR_LEN)
983                 {
984                     GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
985                                       offset, len, p_clcb->counter);
986                     gatt_act_read(p_clcb, p_clcb->counter);
987                 }
988                 else /* end of request, send callback */
989                 {
990                     gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
991                 }
992             }
993             else /* exception, should not happen */
994             {
995                 GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
996                 gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
997             }
998         }
999     }
1000     else
1001     {
1002         if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
1003             p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
1004             p_clcb->read_uuid128.wait_for_read_rsp )
1005         {
1006             p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
1007             p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
1008             if (len == LEN_UUID_128)
1009             {
1010
1011                 memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
1012                 p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
1013                 if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
1014                     (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
1015                 gatt_act_discovery(p_clcb) ;
1016             }
1017             else
1018             {
1019                 gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
1020             }
1021         }
1022     }
1023
1024 }
1025
1026
1027 /*******************************************************************************
1028 **
1029 ** Function         gatt_process_handle_rsp
1030 **
1031 ** Description      This function is called to handle the write response
1032 **
1033 **
1034 ** Returns          void
1035 **
1036 *******************************************************************************/
1037 void gatt_process_handle_rsp(tGATT_CLCB *p_clcb)
1038 {
1039     gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
1040 }
1041 /*******************************************************************************
1042 **
1043 ** Function         gatt_process_mtu_rsp
1044 **
1045 ** Description      This function is called to process the configure MTU response.
1046 **
1047 **
1048 ** Returns          void
1049 **
1050 *******************************************************************************/
1051 void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
1052 {
1053     UINT16 mtu;
1054     tGATT_STATUS    status = GATT_SUCCESS;
1055
1056     if (len < GATT_MTU_RSP_MIN_LEN)
1057     {
1058         GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
1059         status = GATT_INVALID_PDU;
1060     }
1061     else
1062     {
1063     STREAM_TO_UINT16(mtu, p_data);
1064
1065     if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
1066         p_tcb->payload_size = mtu;
1067     }
1068
1069     l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
1070     gatt_end_operation(p_clcb, status, NULL);
1071 }
1072 /*******************************************************************************
1073 **
1074 ** Function         gatt_cmd_to_rsp_code
1075 **
1076 ** Description      The function convert a ATT command op code into the corresponding
1077 **                  response code assume no error occurs.
1078 **
1079 ** Returns          response code.
1080 **
1081 *******************************************************************************/
1082 UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code)
1083 {
1084     UINT8   rsp_code  = 0;
1085
1086     if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
1087     {
1088         rsp_code = cmd_code + 1;
1089     }
1090     return rsp_code;
1091 }
1092 /*******************************************************************************
1093 **
1094 ** Function         gatt_cl_send_next_cmd_inq
1095 **
1096 ** Description      Find next command in queue and sent to server
1097 **
1098 ** Returns          TRUE if command sent, otherwise FALSE.
1099 **
1100 *******************************************************************************/
1101 BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
1102 {
1103     tGATT_CMD_Q  *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1104     BOOLEAN     sent = FALSE;
1105     UINT8       rsp_code;
1106     tGATT_CLCB   *p_clcb = NULL;
1107     tGATT_STATUS att_ret = GATT_SUCCESS;
1108
1109     while (!sent &&
1110            p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
1111            p_cmd->to_send && p_cmd->p_cmd != NULL)
1112     {
1113         att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
1114
1115         if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED)
1116         {
1117             sent = TRUE;
1118             p_cmd->to_send = FALSE;
1119             p_cmd->p_cmd = NULL;
1120
1121             /* dequeue the request if is write command or sign write */
1122             if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
1123             {
1124                 gatt_start_rsp_timer (p_cmd->clcb_idx);
1125             }
1126             else
1127             {
1128                 p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1129
1130                 /* if no ack needed, keep sending */
1131                 if (att_ret == GATT_SUCCESS)
1132                     sent = FALSE;
1133
1134                 p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1135                 /* send command complete callback here */
1136                 gatt_end_operation(p_clcb, att_ret, NULL);
1137             }
1138         }
1139         else
1140         {
1141             GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
1142
1143             memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
1144             p_tcb->pending_cl_req ++;
1145             p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1146         }
1147
1148     }
1149     return sent;
1150 }
1151
1152 /*******************************************************************************
1153 **
1154 ** Function         gatt_client_handle_server_rsp
1155 **
1156 ** Description      This function is called to handle the server response to
1157 **                  client.
1158 **
1159 **
1160 ** Returns          void
1161 **
1162 *******************************************************************************/
1163 void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
1164                                     UINT16 len, UINT8 *p_data)
1165 {
1166     tGATT_CLCB   *p_clcb = NULL;
1167     UINT8        rsp_code;
1168
1169     if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1170     {
1171         p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1172
1173         rsp_code = gatt_cmd_to_rsp_code(rsp_code);
1174
1175         if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
1176         {
1177             GATT_TRACE_WARNING ("ATT - Ignore wrong response. Receives (%02x) \
1178                                 Request(%02x) Ignored", op_code, rsp_code);
1179
1180             return;
1181         }
1182         else
1183         {
1184             alarm_cancel(p_clcb->gatt_rsp_timer_ent);
1185             p_clcb->retry_count = 0;
1186         }
1187     }
1188     /* the size of the message may not be bigger than the local max PDU size*/
1189     /* The message has to be smaller than the agreed MTU, len does not count op_code */
1190     if (len >= p_tcb->payload_size)
1191     {
1192         GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
1193         if (op_code != GATT_HANDLE_VALUE_NOTIF &&
1194             op_code != GATT_HANDLE_VALUE_IND)
1195             gatt_end_operation(p_clcb, GATT_ERROR, NULL);
1196     }
1197     else
1198     {
1199         switch (op_code)
1200         {
1201             case GATT_RSP_ERROR:
1202                 gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
1203                 break;
1204
1205             case GATT_RSP_MTU:       /* 2 bytes mtu */
1206                 gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
1207                 break;
1208
1209             case GATT_RSP_FIND_INFO:
1210                 gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
1211                 break;
1212
1213             case GATT_RSP_READ_BY_TYPE:
1214             case GATT_RSP_READ_BY_GRP_TYPE:
1215                 gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
1216                 break;
1217
1218             case GATT_RSP_READ:
1219             case GATT_RSP_READ_BLOB:
1220             case GATT_RSP_READ_MULTI:
1221                 gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
1222                 break;
1223
1224             case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
1225                 gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
1226                 break;
1227
1228             case GATT_RSP_WRITE:
1229                 gatt_process_handle_rsp(p_clcb);
1230                 break;
1231
1232             case GATT_RSP_PREPARE_WRITE:
1233                 gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
1234                 break;
1235
1236             case GATT_RSP_EXEC_WRITE:
1237                 gatt_end_operation(p_clcb, p_clcb->status, NULL);
1238                 break;
1239
1240             case GATT_HANDLE_VALUE_NOTIF:
1241             case GATT_HANDLE_VALUE_IND:
1242                 gatt_process_notification(p_tcb, op_code, len, p_data);
1243                 break;
1244
1245             default:
1246                 GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
1247                 break;
1248         }
1249     }
1250
1251     if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1252     {
1253         gatt_cl_send_next_cmd_inq(p_tcb);
1254     }
1255
1256     return;
1257 }
1258
1259 #endif  /* BLE_INCLUDED */