1 /****************************************************************************** 2 * 3 * Copyright (C) 2008-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 GATT server functions 22 * 23 ******************************************************************************/ 24 25 #include "bt_target.h" 26 #include "bt_utils.h" 27 #include "osi/include/osi.h" 28 29 #include <string.h> 30 #include "gatt_int.h" 31 #include "l2c_api.h" 32 #include "l2c_int.h" 33 #define GATT_MTU_REQ_MIN_LEN 2 34 35 using base::StringPrintf; 36 /******************************************************************************* 37 * 38 * Function gatt_sr_enqueue_cmd 39 * 40 * Description This function enqueue the request from client which needs a 41 * application response, and update the transaction ID. 42 * 43 * Returns void 44 * 45 ******************************************************************************/ 46 uint32_t gatt_sr_enqueue_cmd(tGATT_TCB& tcb, uint8_t op_code, uint16_t handle) { 47 tGATT_SR_CMD* p_cmd = &tcb.sr_cmd; 48 uint32_t trans_id = 0; 49 50 if ((p_cmd->op_code == 0) || 51 (op_code == GATT_HANDLE_VALUE_CONF)) /* no pending request */ 52 { 53 if (op_code == GATT_CMD_WRITE || op_code == GATT_SIGN_CMD_WRITE || 54 op_code == GATT_REQ_MTU || op_code == GATT_HANDLE_VALUE_CONF) { 55 trans_id = ++tcb.trans_id; 56 } else { 57 p_cmd->trans_id = ++tcb.trans_id; 58 p_cmd->op_code = op_code; 59 p_cmd->handle = handle; 60 p_cmd->status = GATT_NOT_FOUND; 61 tcb.trans_id %= GATT_TRANS_ID_MAX; 62 trans_id = p_cmd->trans_id; 63 } 64 } 65 66 return trans_id; 67 } 68 69 /******************************************************************************* 70 * 71 * Function gatt_sr_cmd_empty 72 * 73 * Description This function checks if the server command queue is empty. 74 * 75 * Returns true if empty, false if there is pending command. 76 * 77 ******************************************************************************/ 78 bool gatt_sr_cmd_empty(tGATT_TCB& tcb) { return (tcb.sr_cmd.op_code == 0); } 79 80 /******************************************************************************* 81 * 82 * Function gatt_dequeue_sr_cmd 83 * 84 * Description This function dequeue the request from command queue. 85 * 86 * Returns void 87 * 88 ******************************************************************************/ 89 void gatt_dequeue_sr_cmd(tGATT_TCB& tcb) { 90 /* Double check in case any buffers are queued */ 91 VLOG(1) << "gatt_dequeue_sr_cmd"; 92 if (tcb.sr_cmd.p_rsp_msg) 93 LOG(ERROR) << "free tcb.sr_cmd.p_rsp_msg = " << tcb.sr_cmd.p_rsp_msg; 94 osi_free_and_reset((void**)&tcb.sr_cmd.p_rsp_msg); 95 96 while (!fixed_queue_is_empty(tcb.sr_cmd.multi_rsp_q)) 97 osi_free(fixed_queue_try_dequeue(tcb.sr_cmd.multi_rsp_q)); 98 fixed_queue_free(tcb.sr_cmd.multi_rsp_q, NULL); 99 memset(&tcb.sr_cmd, 0, sizeof(tGATT_SR_CMD)); 100 } 101 102 /******************************************************************************* 103 * 104 * Function process_read_multi_rsp 105 * 106 * Description This function check the read multiple response. 107 * 108 * Returns bool if all replies have been received 109 * 110 ******************************************************************************/ 111 static bool process_read_multi_rsp(tGATT_SR_CMD* p_cmd, tGATT_STATUS status, 112 tGATTS_RSP* p_msg, uint16_t mtu) { 113 uint16_t ii, total_len, len; 114 uint8_t* p; 115 bool is_overflow = false; 116 117 VLOG(1) << StringPrintf("%s status=%d mtu=%d", __func__, status, mtu); 118 119 if (p_cmd->multi_rsp_q == NULL) 120 p_cmd->multi_rsp_q = fixed_queue_new(SIZE_MAX); 121 122 /* Enqueue the response */ 123 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(tGATTS_RSP)); 124 memcpy((void*)p_buf, (const void*)p_msg, sizeof(tGATTS_RSP)); 125 fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf); 126 127 p_cmd->status = status; 128 if (status == GATT_SUCCESS) { 129 VLOG(1) << "Multi read count=" << fixed_queue_length(p_cmd->multi_rsp_q) 130 << " num_hdls=" << p_cmd->multi_req.num_handles; 131 /* Wait till we get all the responses */ 132 if (fixed_queue_length(p_cmd->multi_rsp_q) == 133 p_cmd->multi_req.num_handles) { 134 len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu; 135 p_buf = (BT_HDR*)osi_calloc(len); 136 p_buf->offset = L2CAP_MIN_OFFSET; 137 p = (uint8_t*)(p_buf + 1) + p_buf->offset; 138 139 /* First byte in the response is the opcode */ 140 *p++ = GATT_RSP_READ_MULTI; 141 p_buf->len = 1; 142 143 /* Now walk through the buffers puting the data into the response in order 144 */ 145 list_t* list = NULL; 146 const list_node_t* node = NULL; 147 if (!fixed_queue_is_empty(p_cmd->multi_rsp_q)) 148 list = fixed_queue_get_list(p_cmd->multi_rsp_q); 149 for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) { 150 tGATTS_RSP* p_rsp = NULL; 151 152 if (list != NULL) { 153 if (ii == 0) 154 node = list_begin(list); 155 else 156 node = list_next(node); 157 if (node != list_end(list)) p_rsp = (tGATTS_RSP*)list_node(node); 158 } 159 160 if (p_rsp != NULL) { 161 total_len = (p_buf->len + p_rsp->attr_value.len); 162 163 if (total_len > mtu) { 164 /* just send the partial response for the overflow case */ 165 len = p_rsp->attr_value.len - (total_len - mtu); 166 is_overflow = true; 167 VLOG(1) << StringPrintf( 168 "multi read overflow available len=%d val_len=%d", len, 169 p_rsp->attr_value.len); 170 } else { 171 len = p_rsp->attr_value.len; 172 } 173 174 if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) { 175 memcpy(p, p_rsp->attr_value.value, len); 176 if (!is_overflow) p += len; 177 p_buf->len += len; 178 } else { 179 p_cmd->status = GATT_NOT_FOUND; 180 break; 181 } 182 183 if (is_overflow) break; 184 185 } else { 186 p_cmd->status = GATT_NOT_FOUND; 187 break; 188 } 189 190 } /* loop through all handles*/ 191 192 /* Sanity check on the buffer length */ 193 if (p_buf->len == 0) { 194 LOG(ERROR) << __func__ << " nothing found!!"; 195 p_cmd->status = GATT_NOT_FOUND; 196 osi_free(p_buf); 197 VLOG(1) << __func__ << "osi_free(p_buf)"; 198 } else if (p_cmd->p_rsp_msg != NULL) { 199 osi_free(p_buf); 200 } else { 201 p_cmd->p_rsp_msg = p_buf; 202 } 203 204 return (true); 205 } 206 } else /* any handle read exception occurs, return error */ 207 { 208 return (true); 209 } 210 211 /* If here, still waiting */ 212 return (false); 213 } 214 215 /******************************************************************************* 216 * 217 * Function gatt_sr_process_app_rsp 218 * 219 * Description This function checks whether the response message from 220 * application matches any pending request. 221 * 222 * Returns void 223 * 224 ******************************************************************************/ 225 tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB& tcb, tGATT_IF gatt_if, 226 UNUSED_ATTR uint32_t trans_id, 227 uint8_t op_code, tGATT_STATUS status, 228 tGATTS_RSP* p_msg) { 229 tGATT_STATUS ret_code = GATT_SUCCESS; 230 231 VLOG(1) << __func__ << " gatt_if=" << +gatt_if; 232 233 gatt_sr_update_cback_cnt(tcb, gatt_if, false, false); 234 235 if (op_code == GATT_REQ_READ_MULTI) { 236 /* If no error and still waiting, just return */ 237 if (!process_read_multi_rsp(&tcb.sr_cmd, status, p_msg, tcb.payload_size)) 238 return (GATT_SUCCESS); 239 } else { 240 if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS) 241 gatt_sr_update_prep_cnt(tcb, gatt_if, true, false); 242 243 if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS) 244 gatt_sr_reset_cback_cnt(tcb); 245 246 tcb.sr_cmd.status = status; 247 248 if (gatt_sr_is_cback_cnt_zero(tcb) && status == GATT_SUCCESS) { 249 if (tcb.sr_cmd.p_rsp_msg == NULL) { 250 tcb.sr_cmd.p_rsp_msg = attp_build_sr_msg(tcb, (uint8_t)(op_code + 1), 251 (tGATT_SR_MSG*)p_msg); 252 } else { 253 LOG(ERROR) << "Exception!!! already has respond message"; 254 } 255 } 256 } 257 if (gatt_sr_is_cback_cnt_zero(tcb)) { 258 if ((tcb.sr_cmd.status == GATT_SUCCESS) && (tcb.sr_cmd.p_rsp_msg)) { 259 ret_code = attp_send_sr_msg(tcb, tcb.sr_cmd.p_rsp_msg); 260 tcb.sr_cmd.p_rsp_msg = NULL; 261 } else { 262 ret_code = 263 gatt_send_error_rsp(tcb, status, op_code, tcb.sr_cmd.handle, false); 264 } 265 266 gatt_dequeue_sr_cmd(tcb); 267 } 268 269 VLOG(1) << __func__ << " ret_code=" << +ret_code; 270 271 return ret_code; 272 } 273 274 /******************************************************************************* 275 * 276 * Function gatt_process_exec_write_req 277 * 278 * Description This function is called to process the execute write request 279 * from client. 280 * 281 * Returns void 282 * 283 ******************************************************************************/ 284 void gatt_process_exec_write_req(tGATT_TCB& tcb, uint8_t op_code, 285 UNUSED_ATTR uint16_t len, uint8_t* p_data) { 286 uint8_t *p = p_data, flag, i = 0; 287 uint32_t trans_id = 0; 288 tGATT_IF gatt_if; 289 uint16_t conn_id; 290 291 #if (GATT_CONFORMANCE_TESTING == TRUE) 292 if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) { 293 VLOG(1) 294 << "Conformance tst: forced err rspv for Execute Write: error status=" 295 << +gatt_cb.err_status; 296 297 gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, 298 gatt_cb.handle, false); 299 300 return; 301 } 302 #endif 303 304 STREAM_TO_UINT8(flag, p); 305 306 /* mask the flag */ 307 flag &= GATT_PREP_WRITE_EXEC; 308 309 /* no prep write is queued */ 310 if (!gatt_sr_is_prep_cnt_zero(tcb)) { 311 trans_id = gatt_sr_enqueue_cmd(tcb, op_code, 0); 312 gatt_sr_copy_prep_cnt_to_cback_cnt(tcb); 313 314 for (i = 0; i < GATT_MAX_APPS; i++) { 315 if (tcb.prep_cnt[i]) { 316 gatt_if = (tGATT_IF)(i + 1); 317 conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_if); 318 tGATTS_DATA gatts_data; 319 gatts_data.exec_write = flag; 320 gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC, 321 &gatts_data); 322 tcb.prep_cnt[i] = 0; 323 } 324 } 325 } else /* nothing needs to be executed , send response now */ 326 { 327 LOG(ERROR) << "gatt_process_exec_write_req: no prepare write pending"; 328 gatt_send_error_rsp(tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false); 329 } 330 } 331 332 /******************************************************************************* 333 * 334 * Function gatt_process_read_multi_req 335 * 336 * Description This function is called to process the read multiple request 337 * from client. 338 * 339 * Returns void 340 * 341 ******************************************************************************/ 342 void gatt_process_read_multi_req(tGATT_TCB& tcb, uint8_t op_code, uint16_t len, 343 uint8_t* p_data) { 344 uint32_t trans_id; 345 uint16_t handle = 0, ll = len; 346 uint8_t* p = p_data; 347 tGATT_STATUS err = GATT_SUCCESS; 348 uint8_t sec_flag, key_size; 349 350 VLOG(1) << __func__; 351 tcb.sr_cmd.multi_req.num_handles = 0; 352 353 gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size); 354 355 #if (GATT_CONFORMANCE_TESTING == TRUE) 356 if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) { 357 VLOG(1) << "Conformance tst: forced err rspvofr ReadMultiple: error status=" 358 << +gatt_cb.err_status; 359 360 STREAM_TO_UINT16(handle, p); 361 362 gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, 363 false); 364 365 return; 366 } 367 #endif 368 369 while (ll >= 2 && 370 tcb.sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) { 371 STREAM_TO_UINT16(handle, p); 372 373 auto it = gatt_sr_find_i_rcb_by_handle(handle); 374 if (it != gatt_cb.srv_list_info->end()) { 375 tcb.sr_cmd.multi_req.handles[tcb.sr_cmd.multi_req.num_handles++] = handle; 376 377 /* check read permission */ 378 err = gatts_read_attr_perm_check(it->p_db, false, handle, sec_flag, 379 key_size); 380 if (err != GATT_SUCCESS) { 381 VLOG(1) << StringPrintf("read permission denied : 0x%02x", err); 382 break; 383 } 384 } else { 385 /* invalid handle */ 386 err = GATT_INVALID_HANDLE; 387 break; 388 } 389 ll -= 2; 390 } 391 392 if (ll != 0) { 393 LOG(ERROR) << "max attribute handle reached in ReadMultiple Request."; 394 } 395 396 if (tcb.sr_cmd.multi_req.num_handles == 0) err = GATT_INVALID_HANDLE; 397 398 if (err == GATT_SUCCESS) { 399 trans_id = 400 gatt_sr_enqueue_cmd(tcb, op_code, tcb.sr_cmd.multi_req.handles[0]); 401 if (trans_id != 0) { 402 gatt_sr_reset_cback_cnt(tcb); /* read multiple use multi_rsp_q's count*/ 403 404 for (ll = 0; ll < tcb.sr_cmd.multi_req.num_handles; ll++) { 405 tGATTS_RSP* p_msg = (tGATTS_RSP*)osi_calloc(sizeof(tGATTS_RSP)); 406 handle = tcb.sr_cmd.multi_req.handles[ll]; 407 auto it = gatt_sr_find_i_rcb_by_handle(handle); 408 409 p_msg->attr_value.handle = handle; 410 err = gatts_read_attr_value_by_handle( 411 tcb, it->p_db, op_code, handle, 0, p_msg->attr_value.value, 412 &p_msg->attr_value.len, GATT_MAX_ATTR_LEN, sec_flag, key_size, 413 trans_id); 414 415 if (err == GATT_SUCCESS) { 416 gatt_sr_process_app_rsp(tcb, it->gatt_if, trans_id, op_code, 417 GATT_SUCCESS, p_msg); 418 } 419 /* either not using or done using the buffer, release it now */ 420 osi_free(p_msg); 421 } 422 } else 423 err = GATT_NO_RESOURCES; 424 } 425 426 /* in theroy BUSY is not possible(should already been checked), protected 427 * check */ 428 if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY) 429 gatt_send_error_rsp(tcb, err, op_code, handle, false); 430 } 431 432 /******************************************************************************* 433 * 434 * Function gatt_build_primary_service_rsp 435 * 436 * Description Primamry service request processed internally. Theretically 437 * only deal with ReadByTypeVAlue and ReadByGroupType. 438 * 439 * Returns void 440 * 441 ******************************************************************************/ 442 static tGATT_STATUS gatt_build_primary_service_rsp( 443 BT_HDR* p_msg, tGATT_TCB& tcb, uint8_t op_code, uint16_t s_hdl, 444 uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, tBT_UUID value) { 445 tGATT_STATUS status = GATT_NOT_FOUND; 446 uint8_t handle_len = 4, *p; 447 tBT_UUID* p_uuid; 448 449 p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 450 451 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) { 452 if (el.s_hdl >= s_hdl && el.s_hdl <= e_hdl && 453 el.type == GATT_UUID_PRI_SERVICE) { 454 p_uuid = gatts_get_service_uuid(el.p_db); 455 if (p_uuid != NULL) { 456 if (op_code == GATT_REQ_READ_BY_GRP_TYPE) handle_len = 4 + p_uuid->len; 457 458 /* get the length byte in the repsonse */ 459 if (p_msg->offset == 0) { 460 *p++ = op_code + 1; 461 p_msg->len++; 462 p_msg->offset = handle_len; 463 464 if (op_code == GATT_REQ_READ_BY_GRP_TYPE) { 465 *p++ = (uint8_t)p_msg->offset; /* length byte */ 466 p_msg->len++; 467 } 468 } 469 470 if (p_msg->len + p_msg->offset <= tcb.payload_size && 471 handle_len == p_msg->offset) { 472 if (op_code != GATT_REQ_FIND_TYPE_VALUE || 473 gatt_uuid_compare(value, *p_uuid)) { 474 UINT16_TO_STREAM(p, el.s_hdl); 475 476 if (gatt_cb.last_primary_s_handle && 477 gatt_cb.last_primary_s_handle == el.s_hdl) { 478 VLOG(1) << "Use 0xFFFF for the last primary attribute"; 479 /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */ 480 UINT16_TO_STREAM(p, 0xFFFF); 481 } else { 482 UINT16_TO_STREAM(p, el.e_hdl); 483 } 484 485 if (op_code == GATT_REQ_READ_BY_GRP_TYPE) 486 gatt_build_uuid_to_stream(&p, *p_uuid); 487 488 status = GATT_SUCCESS; 489 p_msg->len += p_msg->offset; 490 } 491 } else 492 break; 493 } 494 } 495 } 496 p_msg->offset = L2CAP_MIN_OFFSET; 497 498 return status; 499 } 500 501 /** 502 * fill the find information response information in the given buffer. 503 * 504 * Returns true: if data filled sucessfully. 505 * false: packet full, or format mismatch. 506 */ 507 static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SRV_LIST_ELEM& el, 508 BT_HDR* p_msg, uint16_t& len, 509 uint16_t s_hdl, uint16_t e_hdl) { 510 uint8_t info_pair_len[2] = {4, 18}; 511 512 if (!el.p_db) return GATT_NOT_FOUND; 513 514 /* check the attribute database */ 515 516 uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len; 517 518 for (auto& attr : el.p_db->attr_list) { 519 if (attr.handle > e_hdl) break; 520 521 if (attr.handle < s_hdl) continue; 522 523 if (p_msg->offset == 0) 524 p_msg->offset = (attr.uuid.len == LEN_UUID_16) ? GATT_INFO_TYPE_PAIR_16 525 : GATT_INFO_TYPE_PAIR_128; 526 527 if (len < info_pair_len[p_msg->offset - 1]) return GATT_NO_RESOURCES; 528 529 if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 && 530 attr.uuid.len == LEN_UUID_16) { 531 UINT16_TO_STREAM(p, attr.handle); 532 UINT16_TO_STREAM(p, attr.uuid.uu.uuid16); 533 } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && 534 attr.uuid.len == LEN_UUID_128) { 535 UINT16_TO_STREAM(p, attr.handle); 536 ARRAY_TO_STREAM(p, attr.uuid.uu.uuid128, LEN_UUID_128); 537 } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 && 538 attr.uuid.len == LEN_UUID_32) { 539 UINT16_TO_STREAM(p, attr.handle); 540 gatt_convert_uuid32_to_uuid128(p, attr.uuid.uu.uuid32); 541 p += LEN_UUID_128; 542 } else { 543 LOG(ERROR) << "format mismatch"; 544 return GATT_NO_RESOURCES; 545 /* format mismatch */ 546 } 547 p_msg->len += info_pair_len[p_msg->offset - 1]; 548 len -= info_pair_len[p_msg->offset - 1]; 549 return GATT_SUCCESS; 550 } 551 552 return GATT_NOT_FOUND; 553 } 554 555 static tGATT_STATUS read_handles(uint16_t& len, uint8_t*& p, uint16_t& s_hdl, 556 uint16_t& e_hdl) { 557 if (len < 4) return GATT_INVALID_PDU; 558 559 /* obtain starting handle, and ending handle */ 560 STREAM_TO_UINT16(s_hdl, p); 561 STREAM_TO_UINT16(e_hdl, p); 562 len -= 4; 563 564 if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) || 565 !GATT_HANDLE_IS_VALID(e_hdl)) { 566 return GATT_INVALID_PDU; 567 } 568 569 return GATT_SUCCESS; 570 } 571 572 static tGATT_STATUS gatts_validate_packet_format(uint8_t op_code, uint16_t& len, 573 uint8_t*& p, tBT_UUID* p_uuid, 574 uint16_t& s_hdl, 575 uint16_t& e_hdl) { 576 tGATT_STATUS ret = read_handles(len, p, s_hdl, e_hdl); 577 if (ret != GATT_SUCCESS) return ret; 578 579 if (len < 2) return GATT_INVALID_PDU; 580 581 /* parse uuid now */ 582 CHECK(p_uuid); 583 uint16_t uuid_len = (op_code == GATT_REQ_FIND_TYPE_VALUE) ? 2 : len; 584 if (!gatt_parse_uuid_from_cmd(p_uuid, uuid_len, &p)) { 585 VLOG(1) << "Bad UUID"; 586 return GATT_INVALID_PDU; 587 } 588 589 len -= uuid_len; 590 return GATT_SUCCESS; 591 } 592 593 /******************************************************************************* 594 * 595 * Function gatts_process_primary_service_req 596 * 597 * Description Process ReadByGroupType/ReadByTypeValue request, for 598 * discovering all primary services or discover primary service 599 * by UUID request. 600 * 601 * Returns void 602 * 603 ******************************************************************************/ 604 void gatts_process_primary_service_req(tGATT_TCB& tcb, uint8_t op_code, 605 uint16_t len, uint8_t* p_data) { 606 uint16_t s_hdl = 0, e_hdl = 0; 607 tBT_UUID uuid; 608 609 uint8_t reason = 610 gatts_validate_packet_format(op_code, len, p_data, &uuid, s_hdl, e_hdl); 611 if (reason != GATT_SUCCESS) { 612 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 613 return; 614 } 615 616 tBT_UUID primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}}; 617 if (!gatt_uuid_compare(uuid, primary_service)) { 618 if (op_code == GATT_REQ_READ_BY_GRP_TYPE) { 619 gatt_send_error_rsp(tcb, GATT_UNSUPPORT_GRP_TYPE, op_code, s_hdl, false); 620 VLOG(1) << StringPrintf("unexpected ReadByGrpType Group: 0x%04x", 621 uuid.uu.uuid16); 622 return; 623 } 624 625 // we do not support ReadByTypeValue with any non-primamry_service type 626 gatt_send_error_rsp(tcb, GATT_NOT_FOUND, op_code, s_hdl, false); 627 VLOG(1) << StringPrintf("unexpected ReadByTypeValue type: 0x%04x", 628 uuid.uu.uuid16); 629 return; 630 } 631 632 // TODO: we assume theh value is UUID, there is no such requirement in spec 633 tBT_UUID value; 634 memset(&value, 0, sizeof(tBT_UUID)); 635 if (op_code == GATT_REQ_FIND_TYPE_VALUE) { 636 if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == false) { 637 gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, s_hdl, false); 638 } 639 } 640 641 uint16_t msg_len = 642 (uint16_t)(sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET); 643 BT_HDR* p_msg = (BT_HDR*)osi_calloc(msg_len); 644 reason = gatt_build_primary_service_rsp(p_msg, tcb, op_code, s_hdl, e_hdl, 645 p_data, value); 646 if (reason != GATT_SUCCESS) { 647 osi_free(p_msg); 648 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 649 return; 650 } 651 652 attp_send_sr_msg(tcb, p_msg); 653 } 654 655 /******************************************************************************* 656 * 657 * Function gatts_process_find_info 658 * 659 * Description process find information request, for discover character 660 * descriptors. 661 * 662 * Returns void 663 * 664 ******************************************************************************/ 665 static void gatts_process_find_info(tGATT_TCB& tcb, uint8_t op_code, 666 uint16_t len, uint8_t* p_data) { 667 uint16_t s_hdl = 0, e_hdl = 0; 668 uint8_t reason = read_handles(len, p_data, s_hdl, e_hdl); 669 if (reason != GATT_SUCCESS) { 670 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 671 return; 672 } 673 674 uint16_t buf_len = 675 (uint16_t)(sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET); 676 677 BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len); 678 reason = GATT_NOT_FOUND; 679 680 uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 681 *p++ = op_code + 1; 682 p_msg->len = 2; 683 684 buf_len = tcb.payload_size - 2; 685 686 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) { 687 if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) { 688 reason = gatt_build_find_info_rsp(el, p_msg, buf_len, s_hdl, e_hdl); 689 if (reason == GATT_NO_RESOURCES) { 690 reason = GATT_SUCCESS; 691 break; 692 } 693 } 694 } 695 696 *p = (uint8_t)p_msg->offset; 697 698 p_msg->offset = L2CAP_MIN_OFFSET; 699 700 if (reason != GATT_SUCCESS) { 701 osi_free(p_msg); 702 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 703 } else 704 attp_send_sr_msg(tcb, p_msg); 705 } 706 707 /******************************************************************************* 708 * 709 * Function gatts_process_mtu_req 710 * 711 * Description This function is called to process excahnge MTU request. 712 * Only used on LE. 713 * 714 * Returns void 715 * 716 ******************************************************************************/ 717 static void gatts_process_mtu_req(tGATT_TCB& tcb, uint16_t len, 718 uint8_t* p_data) { 719 /* BR/EDR conenction, send error response */ 720 if (tcb.att_lcid != L2CAP_ATT_CID) { 721 gatt_send_error_rsp(tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, false); 722 return; 723 } 724 725 if (len < GATT_MTU_REQ_MIN_LEN) { 726 LOG(ERROR) << "invalid MTU request PDU received."; 727 gatt_send_error_rsp(tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, false); 728 return; 729 } 730 731 uint16_t mtu = 0; 732 uint8_t* p = p_data; 733 STREAM_TO_UINT16(mtu, p); 734 /* mtu must be greater than default MTU which is 23/48 */ 735 if (mtu < GATT_DEF_BLE_MTU_SIZE) 736 tcb.payload_size = GATT_DEF_BLE_MTU_SIZE; 737 else if (mtu > GATT_MAX_MTU_SIZE) 738 tcb.payload_size = GATT_MAX_MTU_SIZE; 739 else 740 tcb.payload_size = mtu; 741 742 LOG(ERROR) << "MTU request PDU with MTU size " << +tcb.payload_size; 743 744 l2cble_set_fixed_channel_tx_data_length(tcb.peer_bda, L2CAP_ATT_CID, 745 tcb.payload_size); 746 747 tGATT_SR_MSG gatt_sr_msg; 748 gatt_sr_msg.mtu = tcb.payload_size; 749 BT_HDR* p_buf = attp_build_sr_msg(tcb, GATT_RSP_MTU, &gatt_sr_msg); 750 attp_send_sr_msg(tcb, p_buf); 751 752 tGATTS_DATA gatts_data; 753 gatts_data.mtu = tcb.payload_size; 754 /* Notify all registered applicaiton with new MTU size. Us a transaction ID */ 755 /* of 0, as no response is allowed from applcations */ 756 for (int i = 0; i < GATT_MAX_APPS; i++) { 757 if (gatt_cb.cl_rcb[i].in_use) { 758 uint16_t conn_id = 759 GATT_CREATE_CONN_ID(tcb.tcb_idx, gatt_cb.cl_rcb[i].gatt_if); 760 gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU, &gatts_data); 761 } 762 } 763 } 764 765 /******************************************************************************* 766 * 767 * Function gatts_process_read_by_type_req 768 * 769 * Description process Read By type request. 770 * This PDU can be used to perform: 771 * - read characteristic value 772 * - read characteristic descriptor value 773 * - discover characteristic 774 * - discover characteristic by UUID 775 * - relationship discovery 776 * 777 * Returns void 778 * 779 ******************************************************************************/ 780 void gatts_process_read_by_type_req(tGATT_TCB& tcb, uint8_t op_code, 781 uint16_t len, uint8_t* p_data) { 782 tBT_UUID uuid; 783 uint16_t s_hdl, e_hdl, err_hdl = 0; 784 tGATT_STATUS reason = 785 gatts_validate_packet_format(op_code, len, p_data, &uuid, s_hdl, e_hdl); 786 787 #if (GATT_CONFORMANCE_TESTING == TRUE) 788 if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) { 789 VLOG(1) << "Conformance tst: forced err rsp for ReadByType: error status=" 790 << +gatt_cb.err_status; 791 792 gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl, 793 false); 794 795 return; 796 } 797 #endif 798 799 if (reason != GATT_SUCCESS) { 800 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 801 return; 802 } 803 804 size_t msg_len = sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET; 805 BT_HDR* p_msg = (BT_HDR*)osi_calloc(msg_len); 806 uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 807 808 *p++ = op_code + 1; 809 /* reserve length byte */ 810 p_msg->len = 2; 811 uint16_t buf_len = tcb.payload_size - 2; 812 813 reason = GATT_NOT_FOUND; 814 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) { 815 if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) { 816 uint8_t sec_flag, key_size; 817 gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size); 818 819 tGATT_STATUS ret = gatts_db_read_attr_value_by_type( 820 tcb, el.p_db, op_code, p_msg, s_hdl, e_hdl, uuid, &buf_len, sec_flag, 821 key_size, 0, &err_hdl); 822 if (ret != GATT_NOT_FOUND) { 823 reason = ret; 824 if (ret == GATT_NO_RESOURCES) reason = GATT_SUCCESS; 825 } 826 827 if (ret != GATT_SUCCESS && ret != GATT_NOT_FOUND) { 828 s_hdl = err_hdl; 829 break; 830 } 831 } 832 } 833 *p = (uint8_t)p_msg->offset; 834 p_msg->offset = L2CAP_MIN_OFFSET; 835 836 if (reason != GATT_SUCCESS) { 837 osi_free(p_msg); 838 839 /* in theroy BUSY is not possible(should already been checked), protected 840 * check */ 841 if (reason != GATT_PENDING && reason != GATT_BUSY) 842 gatt_send_error_rsp(tcb, reason, op_code, s_hdl, false); 843 844 return; 845 } 846 847 attp_send_sr_msg(tcb, p_msg); 848 } 849 850 /** 851 * This function is called to process the write request from client. 852 */ 853 void gatts_process_write_req(tGATT_TCB& tcb, tGATT_SRV_LIST_ELEM& el, 854 uint16_t handle, uint8_t op_code, uint16_t len, 855 uint8_t* p_data, 856 bt_gatt_db_attribute_type_t gatt_type) { 857 tGATTS_DATA sr_data; 858 uint32_t trans_id; 859 tGATT_STATUS status; 860 uint8_t sec_flag, key_size, *p = p_data; 861 uint16_t conn_id; 862 863 memset(&sr_data, 0, sizeof(tGATTS_DATA)); 864 865 switch (op_code) { 866 case GATT_REQ_PREPARE_WRITE: 867 if (len < 2) { 868 LOG(ERROR) << __func__ 869 << ": Prepare write request was invalid - missing offset, " 870 "sending error response"; 871 gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, handle, false); 872 return; 873 } 874 sr_data.write_req.is_prep = true; 875 STREAM_TO_UINT16(sr_data.write_req.offset, p); 876 len -= 2; 877 /* fall through */ 878 case GATT_SIGN_CMD_WRITE: 879 if (op_code == GATT_SIGN_CMD_WRITE) { 880 VLOG(1) << "Write CMD with data sigining"; 881 len -= GATT_AUTH_SIGN_LEN; 882 } 883 /* fall through */ 884 case GATT_CMD_WRITE: 885 case GATT_REQ_WRITE: 886 if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE) 887 sr_data.write_req.need_rsp = true; 888 sr_data.write_req.handle = handle; 889 sr_data.write_req.len = len; 890 if (len != 0 && p != NULL) { 891 memcpy(sr_data.write_req.value, p, len); 892 } 893 break; 894 } 895 896 gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size); 897 898 status = gatts_write_attr_perm_check(el.p_db, op_code, handle, 899 sr_data.write_req.offset, p, len, 900 sec_flag, key_size); 901 902 if (status == GATT_SUCCESS) { 903 trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle); 904 if (trans_id != 0) { 905 conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if); 906 907 uint8_t opcode = 0; 908 if (gatt_type == BTGATT_DB_DESCRIPTOR) { 909 opcode = GATTS_REQ_TYPE_WRITE_DESCRIPTOR; 910 } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) { 911 opcode = GATTS_REQ_TYPE_WRITE_CHARACTERISTIC; 912 } else { 913 LOG(ERROR) << __func__ 914 << "%s: Attempt to write attribute that's not tied with" 915 " characteristic or descriptor value."; 916 status = GATT_ERROR; 917 } 918 919 if (opcode) { 920 gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data); 921 status = GATT_PENDING; 922 } 923 } else { 924 LOG(ERROR) << "max pending command, send error"; 925 status = GATT_BUSY; /* max pending command, application error */ 926 } 927 } 928 929 /* in theroy BUSY is not possible(should already been checked), protected 930 * check */ 931 if (status != GATT_PENDING && status != GATT_BUSY && 932 (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) { 933 gatt_send_error_rsp(tcb, status, op_code, handle, false); 934 } 935 return; 936 } 937 938 /** 939 * This function is called to process the read request from client. 940 */ 941 static void gatts_process_read_req(tGATT_TCB& tcb, tGATT_SRV_LIST_ELEM& el, 942 uint8_t op_code, uint16_t handle, 943 UNUSED_ATTR uint16_t len, uint8_t* p_data) { 944 size_t buf_len = sizeof(BT_HDR) + tcb.payload_size + L2CAP_MIN_OFFSET; 945 uint16_t offset = 0; 946 BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len); 947 948 if (op_code == GATT_REQ_READ_BLOB) STREAM_TO_UINT16(offset, p_data); 949 950 uint8_t* p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 951 *p++ = op_code + 1; 952 p_msg->len = 1; 953 buf_len = tcb.payload_size - 1; 954 955 uint8_t sec_flag, key_size; 956 gatt_sr_get_sec_info(tcb.peer_bda, tcb.transport, &sec_flag, &key_size); 957 958 uint16_t value_len = 0; 959 tGATT_STATUS reason = gatts_read_attr_value_by_handle( 960 tcb, el.p_db, op_code, handle, offset, p, &value_len, (uint16_t)buf_len, 961 sec_flag, key_size, 0); 962 p_msg->len += value_len; 963 964 if (reason != GATT_SUCCESS) { 965 osi_free(p_msg); 966 967 /* in theroy BUSY is not possible(should already been checked), protected 968 * check */ 969 if (reason != GATT_PENDING && reason != GATT_BUSY) 970 gatt_send_error_rsp(tcb, reason, op_code, handle, false); 971 972 return; 973 } 974 975 attp_send_sr_msg(tcb, p_msg); 976 } 977 978 /******************************************************************************* 979 * 980 * Function gatts_process_attribute_req 981 * 982 * Description This function is called to process the per attribute handle 983 * request from client. 984 * 985 * Returns void 986 * 987 ******************************************************************************/ 988 void gatts_process_attribute_req(tGATT_TCB& tcb, uint8_t op_code, uint16_t len, 989 uint8_t* p_data) { 990 uint16_t handle = 0; 991 uint8_t* p = p_data; 992 tGATT_STATUS status = GATT_INVALID_HANDLE; 993 994 if (len < 2) { 995 LOG(ERROR) << "Illegal PDU length, discard request"; 996 status = GATT_INVALID_PDU; 997 } else { 998 STREAM_TO_UINT16(handle, p); 999 len -= 2; 1000 } 1001 1002 #if (GATT_CONFORMANCE_TESTING == TRUE) 1003 gatt_cb.handle = handle; 1004 if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) { 1005 VLOG(1) << "Conformance tst: forced err rsp: error status=" 1006 << +gatt_cb.err_status; 1007 1008 gatt_send_error_rsp(tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle, 1009 false); 1010 1011 return; 1012 } 1013 #endif 1014 1015 if (GATT_HANDLE_IS_VALID(handle)) { 1016 for (auto& el : *gatt_cb.srv_list_info) { 1017 if (el.s_hdl <= handle && el.e_hdl >= handle) { 1018 for (const auto& attr : el.p_db->attr_list) { 1019 if (attr.handle == handle) { 1020 switch (op_code) { 1021 case GATT_REQ_READ: /* read char/char descriptor value */ 1022 case GATT_REQ_READ_BLOB: 1023 gatts_process_read_req(tcb, el, op_code, handle, len, p); 1024 break; 1025 1026 case GATT_REQ_WRITE: /* write char/char descriptor value */ 1027 case GATT_CMD_WRITE: 1028 case GATT_SIGN_CMD_WRITE: 1029 case GATT_REQ_PREPARE_WRITE: 1030 gatts_process_write_req(tcb, el, handle, op_code, len, p, 1031 attr.gatt_type); 1032 break; 1033 default: 1034 break; 1035 } 1036 status = GATT_SUCCESS; 1037 break; 1038 } 1039 } 1040 break; 1041 } 1042 } 1043 } 1044 1045 if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE && 1046 op_code != GATT_SIGN_CMD_WRITE) 1047 gatt_send_error_rsp(tcb, status, op_code, handle, false); 1048 } 1049 1050 /******************************************************************************* 1051 * 1052 * Function gatts_proc_srv_chg_ind_ack 1053 * 1054 * Description This function process the service changed indicaiton ACK 1055 * 1056 * Returns void 1057 * 1058 ******************************************************************************/ 1059 static void gatts_proc_srv_chg_ind_ack(tGATT_TCB tcb) { 1060 tGATTS_SRV_CHG_REQ req; 1061 tGATTS_SRV_CHG* p_buf = NULL; 1062 1063 VLOG(1) << __func__; 1064 1065 p_buf = gatt_is_bda_in_the_srv_chg_clt_list(tcb.peer_bda); 1066 if (p_buf != NULL) { 1067 VLOG(1) << "NV update set srv chg = false"; 1068 p_buf->srv_changed = false; 1069 memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG)); 1070 if (gatt_cb.cb_info.p_srv_chg_callback) 1071 (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT, 1072 &req, NULL); 1073 } 1074 } 1075 1076 /******************************************************************************* 1077 * 1078 * Function gatts_chk_pending_ind 1079 * 1080 * Description This function check any pending indication needs to be sent 1081 * if there is a pending indication then sent the indication 1082 * 1083 * Returns void 1084 * 1085 ******************************************************************************/ 1086 static void gatts_chk_pending_ind(tGATT_TCB& tcb) { 1087 VLOG(1) << __func__; 1088 1089 tGATT_VALUE* p_buf = 1090 (tGATT_VALUE*)fixed_queue_try_peek_first(tcb.pending_ind_q); 1091 if (p_buf != NULL) { 1092 GATTS_HandleValueIndication(p_buf->conn_id, p_buf->handle, p_buf->len, 1093 p_buf->value); 1094 osi_free(fixed_queue_try_remove_from_queue(tcb.pending_ind_q, p_buf)); 1095 } 1096 } 1097 1098 /******************************************************************************* 1099 * 1100 * Function gatts_proc_ind_ack 1101 * 1102 * Description This function processes the Indication ack 1103 * 1104 * Returns true continue to process the indication ack by the 1105 * application if the ACK is not a Service Changed Indication 1106 * 1107 ******************************************************************************/ 1108 static bool gatts_proc_ind_ack(tGATT_TCB& tcb, uint16_t ack_handle) { 1109 bool continue_processing = true; 1110 1111 VLOG(1) << __func__ << " ack handle=%d" << ack_handle; 1112 1113 if (ack_handle == gatt_cb.handle_of_h_r) { 1114 gatts_proc_srv_chg_ind_ack(tcb); 1115 /* there is no need to inform the application since srv chg is handled 1116 * internally by GATT */ 1117 continue_processing = false; 1118 } 1119 1120 gatts_chk_pending_ind(tcb); 1121 return continue_processing; 1122 } 1123 1124 /******************************************************************************* 1125 * 1126 * Function gatts_process_value_conf 1127 * 1128 * Description This function is called to process the handle value 1129 * confirmation. 1130 * 1131 * Returns void 1132 * 1133 ******************************************************************************/ 1134 void gatts_process_value_conf(tGATT_TCB& tcb, uint8_t op_code) { 1135 uint16_t handle = tcb.indicate_handle; 1136 1137 alarm_cancel(tcb.conf_timer); 1138 if (!GATT_HANDLE_IS_VALID(handle)) { 1139 LOG(ERROR) << "unexpected handle value confirmation"; 1140 return; 1141 } 1142 1143 tcb.indicate_handle = 0; 1144 bool continue_processing = gatts_proc_ind_ack(tcb, handle); 1145 1146 if (continue_processing) { 1147 tGATTS_DATA gatts_data; 1148 gatts_data.handle = handle; 1149 for (auto& el : *gatt_cb.srv_list_info) { 1150 if (el.s_hdl <= handle && el.e_hdl >= handle) { 1151 uint32_t trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle); 1152 uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if); 1153 gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_CONF, 1154 &gatts_data); 1155 } 1156 } 1157 } 1158 } 1159 1160 /** This function is called to handle the client requests to server */ 1161 void gatt_server_handle_client_req(tGATT_TCB& tcb, uint8_t op_code, 1162 uint16_t len, uint8_t* p_data) { 1163 /* there is pending command, discard this one */ 1164 if (!gatt_sr_cmd_empty(tcb) && op_code != GATT_HANDLE_VALUE_CONF) return; 1165 1166 /* the size of the message may not be bigger than the local max PDU size*/ 1167 /* The message has to be smaller than the agreed MTU, len does not include op 1168 * code */ 1169 if (len >= tcb.payload_size) { 1170 LOG(ERROR) << StringPrintf("server receive invalid PDU size:%d pdu size:%d", 1171 len + 1, tcb.payload_size); 1172 /* for invalid request expecting response, send it now */ 1173 if (op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE && 1174 op_code != GATT_HANDLE_VALUE_CONF) { 1175 gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, 0, false); 1176 } 1177 /* otherwise, ignore the pkt */ 1178 } else { 1179 switch (op_code) { 1180 case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */ 1181 case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */ 1182 gatts_process_primary_service_req(tcb, op_code, len, p_data); 1183 break; 1184 1185 case GATT_REQ_FIND_INFO: /* discover char descrptor */ 1186 gatts_process_find_info(tcb, op_code, len, p_data); 1187 break; 1188 1189 case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor 1190 value */ 1191 /* discover characteristic, discover char by UUID */ 1192 gatts_process_read_by_type_req(tcb, op_code, len, p_data); 1193 break; 1194 1195 case GATT_REQ_READ: /* read char/char descriptor value */ 1196 case GATT_REQ_READ_BLOB: 1197 case GATT_REQ_WRITE: /* write char/char descriptor value */ 1198 case GATT_CMD_WRITE: 1199 case GATT_SIGN_CMD_WRITE: 1200 case GATT_REQ_PREPARE_WRITE: 1201 gatts_process_attribute_req(tcb, op_code, len, p_data); 1202 break; 1203 1204 case GATT_HANDLE_VALUE_CONF: 1205 gatts_process_value_conf(tcb, op_code); 1206 break; 1207 1208 case GATT_REQ_MTU: 1209 gatts_process_mtu_req(tcb, len, p_data); 1210 break; 1211 1212 case GATT_REQ_EXEC_WRITE: 1213 gatt_process_exec_write_req(tcb, op_code, len, p_data); 1214 break; 1215 1216 case GATT_REQ_READ_MULTI: 1217 gatt_process_read_multi_req(tcb, op_code, len, p_data); 1218 break; 1219 1220 default: 1221 break; 1222 } 1223 } 1224 } 1225