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