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