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