1/****************************************************************************** 2 * 3 * Copyright 2009-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 GATT database building and query functions 22 * 23 ******************************************************************************/ 24 25#include "bt_target.h" 26 27#include "bt_trace.h" 28#include "bt_utils.h" 29 30#include <stdio.h> 31#include <string.h> 32#include "btm_int.h" 33#include "gatt_int.h" 34#include "l2c_api.h" 35#include "osi/include/osi.h" 36 37using base::StringPrintf; 38using bluetooth::Uuid; 39 40/******************************************************************************* 41 * L O C A L F U N C T I O N P R O T O T Y P E S * 42 ******************************************************************************/ 43static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid, 44 tGATT_PERM perm); 45static tGATT_STATUS gatts_send_app_read_request( 46 tGATT_TCB& tcb, uint8_t op_code, uint16_t handle, uint16_t offset, 47 uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type); 48 49/** 50 * Initialize a memory space to be a service database. 51 */ 52void gatts_init_service_db(tGATT_SVC_DB& db, const Uuid& service_uuid, 53 bool is_pri, uint16_t s_hdl, uint16_t num_handle) { 54 db.attr_list.reserve(num_handle); 55 56 VLOG(1) << StringPrintf("%s: s_hdl= %d num_handle= %d", __func__, s_hdl, 57 num_handle); 58 59 /* update service database information */ 60 db.next_handle = s_hdl; 61 db.end_handle = s_hdl + num_handle; 62 63 /* add service declration record */ 64 Uuid uuid = 65 Uuid::From16Bit(is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE); 66 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ); 67 attr.p_value.reset((tGATT_ATTR_VALUE*)(new Uuid)); 68 attr.p_value->uuid = service_uuid; 69} 70 71Uuid* gatts_get_service_uuid(tGATT_SVC_DB* p_db) { 72 if (!p_db || p_db->attr_list.empty()) { 73 LOG(ERROR) << "service DB empty"; 74 return NULL; 75 } else { 76 return &p_db->attr_list[0].p_value->uuid; 77 } 78} 79 80/** Check attribute readability. Returns status of operation. */ 81static tGATT_STATUS gatts_check_attr_readability(const tGATT_ATTR& attr, 82 UNUSED_ATTR uint16_t offset, 83 bool read_long, 84 tGATT_SEC_FLAG sec_flag, 85 uint8_t key_size) { 86 uint16_t min_key_size; 87 tGATT_PERM perm = attr.permission; 88 89 min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); 90 if (min_key_size != 0) { 91 min_key_size += 6; 92 } 93 94 if (!(perm & GATT_READ_ALLOWED)) { 95 LOG(ERROR) << __func__ << ": GATT_READ_NOT_PERMIT"; 96 return GATT_READ_NOT_PERMIT; 97 } 98 99 if ((perm & GATT_READ_AUTH_REQUIRED) && 100 !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) && 101 !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) { 102 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION"; 103 return GATT_INSUF_AUTHENTICATION; 104 } 105 106 if ((perm & GATT_READ_MITM_REQUIRED) && 107 !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) { 108 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION: MITM Required"; 109 return GATT_INSUF_AUTHENTICATION; 110 } 111 112 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) && 113 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) { 114 LOG(ERROR) << __func__ << ": GATT_INSUF_ENCRYPTION"; 115 return GATT_INSUF_ENCRYPTION; 116 } 117 118 if ((perm & GATT_READ_ENCRYPTED_REQUIRED) && 119 (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) { 120 LOG(ERROR) << __func__ << ": GATT_INSUF_KEY_SIZE"; 121 return GATT_INSUF_KEY_SIZE; 122 } 123 124 if (read_long && attr.uuid.Is16Bit()) { 125 switch (attr.uuid.As16Bit()) { 126 case GATT_UUID_PRI_SERVICE: 127 case GATT_UUID_SEC_SERVICE: 128 case GATT_UUID_CHAR_DECLARE: 129 case GATT_UUID_INCLUDE_SERVICE: 130 case GATT_UUID_CHAR_EXT_PROP: 131 case GATT_UUID_CHAR_CLIENT_CONFIG: 132 case GATT_UUID_CHAR_SRVR_CONFIG: 133 case GATT_UUID_CHAR_PRESENT_FORMAT: 134 LOG(ERROR) << __func__ << ": GATT_NOT_LONG"; 135 return GATT_NOT_LONG; 136 137 default: 138 break; 139 } 140 } 141 142 return GATT_SUCCESS; 143} 144 145/******************************************************************************* 146 * 147 * Function read_attr_value 148 * 149 * Description Utility function to read an attribute value. 150 * 151 * Parameter attr16: pointer to the attribute to read. 152 * offset: read offset. 153 * p_data: output parameter to carry out the attribute value. 154 * read_long: this is a read blob request. 155 * mtu: MTU 156 * p_len: output parameter to carry out the attribute length. 157 * sec_flag: current link security status. 158 * key_size: encryption key size. 159 * 160 * Returns status of operation. 161 * 162 ******************************************************************************/ 163static tGATT_STATUS read_attr_value(tGATT_ATTR& attr16, uint16_t offset, 164 uint8_t** p_data, bool read_long, 165 uint16_t mtu, uint16_t* p_len, 166 tGATT_SEC_FLAG sec_flag, uint8_t key_size) { 167 uint8_t* p = *p_data; 168 169 VLOG(1) << __func__ << " uuid=" << attr16.uuid 170 << StringPrintf(" perm=0x%02x sec_flag=0x%x offset=%d read_long=%d", 171 attr16.permission, sec_flag, offset, read_long); 172 173 tGATT_STATUS status = gatts_check_attr_readability(attr16, offset, read_long, 174 sec_flag, key_size); 175 if (status != GATT_SUCCESS) return status; 176 177 if (!attr16.uuid.Is16Bit()) { 178 /* characteristic description or characteristic value */ 179 return GATT_PENDING; 180 } 181 182 uint16_t uuid16 = attr16.uuid.As16Bit(); 183 184 if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) { 185 *p_len = gatt_build_uuid_to_stream_len(attr16.p_value->uuid); 186 if (mtu < *p_len) return GATT_NO_RESOURCES; 187 188 gatt_build_uuid_to_stream(&p, attr16.p_value->uuid); 189 *p_data = p; 190 return GATT_SUCCESS; 191 } 192 193 if (uuid16 == GATT_UUID_CHAR_DECLARE) { 194 tGATT_ATTR* val_attr = &attr16 + 1; 195 uint8_t val_len = val_attr->uuid.GetShortestRepresentationSize(); 196 *p_len = (val_len == Uuid::kNumBytes16) ? 5 : 19; 197 198 if (mtu < *p_len) return GATT_NO_RESOURCES; 199 200 UINT8_TO_STREAM(p, attr16.p_value->char_decl.property); 201 UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle); 202 203 if (val_len == Uuid::kNumBytes16) { 204 UINT16_TO_STREAM(p, val_attr->uuid.As16Bit()); 205 } else { 206 /* if 32 bit UUID, convert to 128 bit */ 207 ARRAY_TO_STREAM(p, val_attr->uuid.To128BitLE(), (int)Uuid::kNumBytes128); 208 } 209 *p_data = p; 210 return GATT_SUCCESS; 211 } 212 213 if (uuid16 == GATT_UUID_INCLUDE_SERVICE) { 214 tGATT_INCL_SRVC& incl_handle = attr16.p_value->incl_handle; 215 if (incl_handle.service_type.Is16Bit()) 216 *p_len = 6; 217 else 218 *p_len = 4; 219 220 if (mtu < *p_len) return GATT_NO_RESOURCES; 221 222 UINT16_TO_STREAM(p, incl_handle.s_handle); 223 UINT16_TO_STREAM(p, incl_handle.e_handle); 224 225 if (incl_handle.service_type.Is16Bit()) { 226 UINT16_TO_STREAM(p, incl_handle.service_type.As16Bit()); 227 } 228 *p_data = p; 229 return GATT_SUCCESS; 230 } 231 232 /* characteristic description or characteristic value (again) */ 233 return GATT_PENDING; 234} 235 236/******************************************************************************* 237 * 238 * Function gatts_db_read_attr_value_by_type 239 * 240 * Description Query attribute value by attribute type. 241 * 242 * Parameter p_db: pointer to the attribute database. 243 * p_rsp: Read By type response data. 244 * s_handle: starting handle of the range we are looking for. 245 * e_handle: ending handle of the range we are looking for. 246 * type: Attribute type. 247 * mtu: MTU. 248 * sec_flag: current link security status. 249 * key_size: encryption key size. 250 * 251 * Returns Status of the operation. 252 * 253 ******************************************************************************/ 254tGATT_STATUS gatts_db_read_attr_value_by_type( 255 tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp, 256 uint16_t s_handle, uint16_t e_handle, const Uuid& type, uint16_t* p_len, 257 tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id, 258 uint16_t* p_cur_handle) { 259 tGATT_STATUS status = GATT_NOT_FOUND; 260 uint16_t len = 0; 261 uint8_t* p = (uint8_t*)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET; 262 263 if (p_db) { 264 for (tGATT_ATTR& attr : p_db->attr_list) { 265 if (attr.handle >= s_handle && type == attr.uuid) { 266 if (*p_len <= 2) { 267 status = GATT_NO_RESOURCES; 268 break; 269 } 270 271 UINT16_TO_STREAM(p, attr.handle); 272 273 status = read_attr_value(attr, 0, &p, false, (uint16_t)(*p_len - 2), 274 &len, sec_flag, key_size); 275 276 if (status == GATT_PENDING) { 277 status = gatts_send_app_read_request(tcb, op_code, attr.handle, 0, 278 trans_id, attr.gatt_type); 279 280 /* one callback at a time */ 281 break; 282 } else if (status == GATT_SUCCESS) { 283 if (p_rsp->offset == 0) p_rsp->offset = len + 2; 284 285 if (p_rsp->offset == len + 2) { 286 p_rsp->len += (len + 2); 287 *p_len -= (len + 2); 288 } else { 289 LOG(ERROR) << "format mismatch"; 290 status = GATT_NO_RESOURCES; 291 break; 292 } 293 } else { 294 *p_cur_handle = attr.handle; 295 break; 296 } 297 } 298 } 299 } 300 301#if (BLE_DELAY_REQUEST_ENC == TRUE) 302 uint8_t flag = 0; 303 if (BTM_GetSecurityFlags(tcb.peer_bda, &flag)) { 304 if ((tcb.att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) && 305 (type.As16Bit() == GATT_UUID_GAP_DEVICE_NAME)) { 306 if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) == 307 BTM_SEC_LINK_KEY_KNOWN) { 308 tACL_CONN* p = btm_bda_to_acl(tcb.peer_bda, BT_TRANSPORT_LE); 309 if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER)) 310 btm_ble_set_encryption(tcb.peer_bda, BTM_BLE_SEC_ENCRYPT, 311 p->link_role); 312 } 313 } 314 } 315#endif 316 return status; 317} 318 319/** 320 * This function adds an included service into a database. 321 * 322 * Parameter db: database pointer. 323 * inc_srvc_type: included service type. 324 * 325 * Returns Status of the operation. 326 * 327 */ 328uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle, 329 uint16_t e_handle, const Uuid& service) { 330 Uuid uuid = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE); 331 332 VLOG(1) << __func__ 333 << StringPrintf(": s_hdl=0x%04x e_hdl=0x%04x ", s_handle, e_handle) 334 << "service uuid = " << service; 335 336 if (service.IsEmpty() || s_handle == 0 || e_handle == 0) { 337 LOG(ERROR) << __func__ << ": Illegal Params."; 338 return 0; 339 } 340 341 tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ); 342 343 attr.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_INCL_SRVC)); 344 attr.p_value->incl_handle.s_handle = s_handle; 345 attr.p_value->incl_handle.e_handle = e_handle; 346 attr.p_value->incl_handle.service_type = service; 347 348 return attr.handle; 349} 350 351/******************************************************************************* 352 * 353 * Function gatts_add_characteristic 354 * 355 * Description This function add a characteristics and its descriptor into 356 * a servce identified by the service database pointer. 357 * 358 * Parameter db: database. 359 * perm: permission (authentication and key size requirements) 360 * property: property of the characteristic. 361 * p_char: characteristic value information. 362 * 363 * Returns Status of te operation. 364 * 365 ******************************************************************************/ 366uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm, 367 tGATT_CHAR_PROP property, 368 const Uuid& char_uuid) { 369 Uuid uuid = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE); 370 371 VLOG(1) << StringPrintf("%s: perm=0x%0x property=0x%0x", __func__, perm, 372 property); 373 374 tGATT_ATTR& char_decl = allocate_attr_in_db(db, uuid, GATT_PERM_READ); 375 tGATT_ATTR& char_val = allocate_attr_in_db(db, char_uuid, perm); 376 377 char_decl.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_CHAR_DECL)); 378 char_decl.p_value->char_decl.property = property; 379 char_decl.p_value->char_decl.char_val_handle = char_val.handle; 380 char_val.gatt_type = BTGATT_DB_CHARACTERISTIC; 381 return char_val.handle; 382} 383 384/******************************************************************************* 385 * 386 * Function gatts_add_char_descr 387 * 388 * Description This function add a characteristics descriptor. 389 * 390 * Parameter p_db: database pointer. 391 * perm: characteristic descriptor permission type. 392 * char_dscp_tpye: the characteristic descriptor masks. 393 * p_dscp_params: characteristic descriptors values. 394 * 395 * Returns Status of the operation. 396 * 397 ******************************************************************************/ 398uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm, 399 const Uuid& descr_uuid) { 400 VLOG(1) << StringPrintf("gatts_add_char_descr uuid=%s", 401 descr_uuid.ToString().c_str()); 402 403 /* Add characteristic descriptors */ 404 tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm); 405 char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR; 406 return char_dscptr.handle; 407} 408 409/******************************************************************************/ 410/* Service Attribute Database Query Utility Functions */ 411/******************************************************************************/ 412tGATT_ATTR* find_attr_by_handle(tGATT_SVC_DB* p_db, uint16_t handle) { 413 if (!p_db) return nullptr; 414 415 for (auto& attr : p_db->attr_list) { 416 if (attr.handle == handle) return &attr; 417 if (attr.handle > handle) return nullptr; 418 } 419 420 return nullptr; 421} 422 423/******************************************************************************* 424 * 425 * Function gatts_read_attr_value_by_handle 426 * 427 * Description Query attribute value by attribute handle. 428 * 429 * Parameter p_db: pointer to the attribute database. 430 * handle: Attribute handle to read. 431 * offset: Read offset. 432 * p_value: output parameter to carry out the attribute value. 433 * p_len: output parameter as attribute length read. 434 * read_long: this is a read blob request. 435 * mtu: MTU. 436 * sec_flag: current link security status. 437 * key_size: encryption key size 438 * 439 * Returns Status of operation. 440 * 441 ******************************************************************************/ 442tGATT_STATUS gatts_read_attr_value_by_handle( 443 tGATT_TCB& tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle, 444 uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu, 445 tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id) { 446 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle); 447 if (!p_attr) return GATT_NOT_FOUND; 448 449 uint8_t* pp = p_value; 450 tGATT_STATUS status = read_attr_value(*p_attr, offset, &pp, 451 (bool)(op_code == GATT_REQ_READ_BLOB), 452 mtu, p_len, sec_flag, key_size); 453 454 if (status == GATT_PENDING) { 455 status = gatts_send_app_read_request(tcb, op_code, p_attr->handle, offset, 456 trans_id, p_attr->gatt_type); 457 } 458 return status; 459} 460 461/******************************************************************************* 462 * 463 * Function gatts_read_attr_perm_check 464 * 465 * Description Check attribute readability. 466 * 467 * Parameter p_db: pointer to the attribute database. 468 * handle: Attribute handle to read. 469 * offset: Read offset. 470 * p_value: output parameter to carry out the attribute value. 471 * p_len: output parameter as attribute length read. 472 * read_long: this is a read blob request. 473 * mtu: MTU. 474 * sec_flag: current link security status. 475 * key_size: encryption key size 476 * 477 * Returns Status of operation. 478 * 479 ******************************************************************************/ 480tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long, 481 uint16_t handle, 482 tGATT_SEC_FLAG sec_flag, 483 uint8_t key_size) { 484 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle); 485 if (!p_attr) return GATT_NOT_FOUND; 486 487 return gatts_check_attr_readability(*p_attr, 0, is_long, sec_flag, key_size); 488} 489 490/******************************************************************************* 491 * 492 * Function gatts_write_attr_perm_check 493 * 494 * Description Write attribute value into database. 495 * 496 * Parameter p_db: pointer to the attribute database. 497 * op_code:op code of this write. 498 * handle: handle of the attribute to write. 499 * offset: Write offset if write op code is write blob. 500 * p_data: Attribute value to write. 501 * len: attribute data length. 502 * sec_flag: current link security status. 503 * key_size: encryption key size 504 * 505 * Returns Status of the operation. 506 * 507 ******************************************************************************/ 508tGATT_STATUS gatts_write_attr_perm_check(tGATT_SVC_DB* p_db, uint8_t op_code, 509 uint16_t handle, uint16_t offset, 510 uint8_t* p_data, uint16_t len, 511 tGATT_SEC_FLAG sec_flag, 512 uint8_t key_size) { 513 VLOG(1) << StringPrintf( 514 "%s: op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x " 515 "key_size=%d", 516 __func__, op_code, handle, offset, len, sec_flag, key_size); 517 518 tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle); 519 if (!p_attr) return GATT_NOT_FOUND; 520 521 tGATT_PERM perm = p_attr->permission; 522 uint16_t min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12)); 523 if (min_key_size != 0) { 524 min_key_size += 6; 525 } 526 VLOG(1) << StringPrintf("%s: p_attr->permission =0x%04x min_key_size==0x%04x", 527 __func__, p_attr->permission, min_key_size); 528 529 if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) && 530 (perm & GATT_WRITE_SIGNED_PERM)) { 531 /* use the rules for the mixed security see section 10.2.3*/ 532 /* use security mode 1 level 2 when the following condition follows */ 533 /* LE security mode 2 level 1 and LE security mode 1 level 2 */ 534 if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) { 535 perm = GATT_PERM_WRITE_ENCRYPTED; 536 } 537 /* use security mode 1 level 3 when the following condition follows */ 538 /* LE security mode 2 level 2 and security mode 1 and LE */ 539 else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) && 540 (perm & GATT_PERM_WRITE_ENCRYPTED)) || 541 /* LE security mode 2 and security mode 1 level 3 */ 542 ((perm & GATT_WRITE_SIGNED_PERM) && 543 (perm & GATT_PERM_WRITE_ENC_MITM))) { 544 perm = GATT_PERM_WRITE_ENC_MITM; 545 } 546 } 547 548 tGATT_STATUS status = GATT_NOT_FOUND; 549 if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) { 550 status = GATT_WRITE_NOT_PERMIT; 551 VLOG(1) << __func__ << ": sign cmd write not allowed"; 552 } 553 if ((op_code == GATT_SIGN_CMD_WRITE) && 554 (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) { 555 status = GATT_INVALID_PDU; 556 LOG(ERROR) << __func__ 557 << ": Error!! sign cmd write sent on a encypted link"; 558 } else if (!(perm & GATT_WRITE_ALLOWED)) { 559 status = GATT_WRITE_NOT_PERMIT; 560 LOG(ERROR) << __func__ << ": GATT_WRITE_NOT_PERMIT"; 561 } 562 /* require authentication, but not been authenticated */ 563 else if ((perm & GATT_WRITE_AUTH_REQUIRED) && 564 !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) { 565 status = GATT_INSUF_AUTHENTICATION; 566 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION"; 567 } else if ((perm & GATT_WRITE_MITM_REQUIRED) && 568 !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) { 569 status = GATT_INSUF_AUTHENTICATION; 570 LOG(ERROR) << __func__ << ": GATT_INSUF_AUTHENTICATION: MITM required"; 571 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) && 572 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) { 573 status = GATT_INSUF_ENCRYPTION; 574 LOG(ERROR) << __func__ << ": GATT_INSUF_ENCRYPTION"; 575 } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) && 576 (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && 577 (key_size < min_key_size)) { 578 status = GATT_INSUF_KEY_SIZE; 579 LOG(ERROR) << __func__ << ": GATT_INSUF_KEY_SIZE"; 580 } 581 /* LE security mode 2 attribute */ 582 else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE && 583 !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) && 584 (perm & GATT_WRITE_ALLOWED) == 0) { 585 status = GATT_INSUF_AUTHENTICATION; 586 LOG(ERROR) << __func__ 587 << ": GATT_INSUF_AUTHENTICATION: LE security mode 2 required"; 588 } else /* writable: must be char value declaration or char descritpors */ 589 { 590 uint16_t max_size = 0; 591 592 if (p_attr->uuid.IsEmpty()) { 593 status = GATT_INVALID_PDU; 594 } else if (p_attr->uuid.Is16Bit()) { 595 switch (p_attr->uuid.As16Bit()) { 596 case GATT_UUID_CHAR_PRESENT_FORMAT: /* should be readable only */ 597 case GATT_UUID_CHAR_EXT_PROP: /* should be readable only */ 598 case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */ 599 case GATT_UUID_CHAR_VALID_RANGE: 600 status = GATT_WRITE_NOT_PERMIT; 601 break; 602 603 case GATT_UUID_CHAR_CLIENT_CONFIG: 604 /* fall through */ 605 case GATT_UUID_CHAR_SRVR_CONFIG: 606 max_size = 2; 607 /* fall through */ 608 case GATT_UUID_CHAR_DESCRIPTION: 609 default: /* any other must be character value declaration */ 610 status = GATT_SUCCESS; 611 break; 612 } 613 } else { // 32 or 128 bit UUID 614 status = GATT_SUCCESS; 615 } 616 617 if (p_data == NULL && len > 0) { 618 return GATT_INVALID_PDU; 619 } 620 621 /* these attribute does not allow write blob */ 622 if (p_attr->uuid.Is16Bit() && 623 (p_attr->uuid.As16Bit() == GATT_UUID_CHAR_CLIENT_CONFIG || 624 p_attr->uuid.As16Bit() == GATT_UUID_CHAR_SRVR_CONFIG)) { 625 if (op_code == GATT_REQ_PREPARE_WRITE && offset != 0) { 626 /* does not allow write blob */ 627 status = GATT_NOT_LONG; 628 LOG(ERROR) << __func__ << ": GATT_NOT_LONG"; 629 } else if (len != max_size) { 630 /* data does not match the required format */ 631 status = GATT_INVALID_ATTR_LEN; 632 LOG(ERROR) << __func__ << ": GATT_INVALID_PDU"; 633 } else { 634 return GATT_SUCCESS; 635 } 636 } 637 } 638 639 return status; 640} 641 642/** 643 * Description Allocate a memory space for a new attribute, and link this 644 * attribute into the database attribute list. 645 * 646 * 647 * Parameter p_db : database pointer. 648 * uuid: attribute UUID 649 * 650 * Returns pointer to the newly allocated attribute. 651 * 652 */ 653static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid, 654 tGATT_PERM perm) { 655 if (db.next_handle >= db.end_handle) { 656 LOG(FATAL) << __func__ 657 << " wrong number of handles! handle_max = " << +db.end_handle 658 << ", next_handle = " << +db.next_handle; 659 } 660 661 db.attr_list.emplace_back(); 662 tGATT_ATTR& attr = db.attr_list.back(); 663 attr.handle = db.next_handle++; 664 attr.uuid = uuid; 665 attr.permission = perm; 666 return attr; 667} 668 669/******************************************************************************* 670 * 671 * Function gatts_send_app_read_request 672 * 673 * Description Send application read request callback 674 * 675 * Returns status of operation. 676 * 677 ******************************************************************************/ 678static tGATT_STATUS gatts_send_app_read_request( 679 tGATT_TCB& tcb, uint8_t op_code, uint16_t handle, uint16_t offset, 680 uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type) { 681 tGATT_SRV_LIST_ELEM& el = *gatt_sr_find_i_rcb_by_handle(handle); 682 uint16_t conn_id = GATT_CREATE_CONN_ID(tcb.tcb_idx, el.gatt_if); 683 684 if (trans_id == 0) { 685 trans_id = gatt_sr_enqueue_cmd(tcb, op_code, handle); 686 gatt_sr_update_cback_cnt(tcb, el.gatt_if, true, true); 687 } 688 689 if (trans_id != 0) { 690 tGATTS_DATA sr_data; 691 memset(&sr_data, 0, sizeof(tGATTS_DATA)); 692 693 sr_data.read_req.handle = handle; 694 sr_data.read_req.is_long = (bool)(op_code == GATT_REQ_READ_BLOB); 695 sr_data.read_req.offset = offset; 696 697 uint8_t opcode; 698 if (gatt_type == BTGATT_DB_DESCRIPTOR) { 699 opcode = GATTS_REQ_TYPE_READ_DESCRIPTOR; 700 } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) { 701 opcode = GATTS_REQ_TYPE_READ_CHARACTERISTIC; 702 } else { 703 LOG(ERROR) << __func__ 704 << ": Attempt to read attribute that's not tied with " 705 "characteristic or descriptor value."; 706 return GATT_ERROR; 707 } 708 709 gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data); 710 return (tGATT_STATUS)GATT_PENDING; 711 } else 712 return (tGATT_STATUS)GATT_BUSY; /* max pending command, application error */ 713} 714