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