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