1 /****************************************************************************** 2 * 3 * Copyright (C) 2008-2014 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 ATT protocol functions 22 * 23 ******************************************************************************/ 24 25 #include "bt_target.h" 26 27 #if BLE_INCLUDED == TRUE 28 29 #include "gatt_int.h" 30 #include "l2c_api.h" 31 32 #define GATT_HDR_FIND_TYPE_VALUE_LEN 21 33 #define GATT_OP_CODE_SIZE 1 34 /********************************************************************** 35 ** ATT protocl message building utility * 36 ***********************************************************************/ 37 /******************************************************************************* 38 ** 39 ** Function attp_build_mtu_exec_cmd 40 ** 41 ** Description Build a exchange MTU request 42 ** 43 ** Returns None. 44 ** 45 *******************************************************************************/ 46 BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu) 47 { 48 BT_HDR *p_buf = NULL; 49 UINT8 *p; 50 51 if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) 52 { 53 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 54 55 UINT8_TO_STREAM (p, op_code); 56 UINT16_TO_STREAM (p, rx_mtu); 57 58 p_buf->offset = L2CAP_MIN_OFFSET; 59 p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */ 60 } 61 return p_buf; 62 } 63 /******************************************************************************* 64 ** 65 ** Function attp_build_exec_write_cmd 66 ** 67 ** Description Build a execute write request or response. 68 ** 69 ** Returns None. 70 ** 71 *******************************************************************************/ 72 BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag) 73 { 74 BT_HDR *p_buf = NULL; 75 UINT8 *p; 76 77 if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_BUF_POOL_ID)) != NULL) 78 { 79 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 80 81 p_buf->offset = L2CAP_MIN_OFFSET; 82 p_buf->len = GATT_OP_CODE_SIZE; 83 84 UINT8_TO_STREAM (p, op_code); 85 86 if (op_code == GATT_REQ_EXEC_WRITE) 87 { 88 flag &= GATT_PREP_WRITE_EXEC; 89 UINT8_TO_STREAM (p, flag); 90 p_buf->len += 1; 91 } 92 93 } 94 95 return p_buf; 96 } 97 98 /******************************************************************************* 99 ** 100 ** Function attp_build_err_cmd 101 ** 102 ** Description Build a exchange MTU request 103 ** 104 ** Returns None. 105 ** 106 *******************************************************************************/ 107 BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason) 108 { 109 BT_HDR *p_buf = NULL; 110 UINT8 *p; 111 112 if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL) 113 { 114 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 115 116 UINT8_TO_STREAM (p, GATT_RSP_ERROR); 117 UINT8_TO_STREAM (p, cmd_code); 118 UINT16_TO_STREAM(p, err_handle); 119 UINT8_TO_STREAM (p, reason); 120 121 p_buf->offset = L2CAP_MIN_OFFSET; 122 /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */ 123 p_buf->len = GATT_HDR_SIZE + 1 + 1; 124 } 125 return p_buf; 126 } 127 /******************************************************************************* 128 ** 129 ** Function attp_build_browse_cmd 130 ** 131 ** Description Build a read information request or read by type request 132 ** 133 ** Returns None. 134 ** 135 *******************************************************************************/ 136 BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid) 137 { 138 BT_HDR *p_buf = NULL; 139 UINT8 *p; 140 141 if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 8 + L2CAP_MIN_OFFSET)) != NULL) 142 { 143 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 144 /* Describe the built message location and size */ 145 p_buf->offset = L2CAP_MIN_OFFSET; 146 p_buf->len = GATT_OP_CODE_SIZE + 4; 147 148 UINT8_TO_STREAM (p, op_code); 149 UINT16_TO_STREAM (p, s_hdl); 150 UINT16_TO_STREAM (p, e_hdl); 151 p_buf->len += gatt_build_uuid_to_stream(&p, uuid); 152 } 153 154 return p_buf; 155 } 156 /******************************************************************************* 157 ** 158 ** Function attp_build_read_handles_cmd 159 ** 160 ** Description Build a read by type and value request. 161 ** 162 ** Returns pointer to the command buffer. 163 ** 164 *******************************************************************************/ 165 BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type) 166 { 167 BT_HDR *p_buf = NULL; 168 UINT8 *p; 169 UINT16 len = p_value_type->value_len; 170 171 if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) 172 { 173 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 174 175 p_buf->offset = L2CAP_MIN_OFFSET; 176 p_buf->len = 5; /* opcode + s_handle + e_handle */ 177 178 UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE); 179 UINT16_TO_STREAM (p, p_value_type->s_handle); 180 UINT16_TO_STREAM (p, p_value_type->e_handle); 181 182 p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid); 183 184 if (p_value_type->value_len + p_buf->len > payload_size ) 185 len = payload_size - p_buf->len; 186 187 memcpy (p, p_value_type->value, len); 188 p_buf->len += len; 189 } 190 191 return p_buf; 192 } 193 /******************************************************************************* 194 ** 195 ** Function attp_build_read_multi_cmd 196 ** 197 ** Description Build a read multiple request 198 ** 199 ** Returns None. 200 ** 201 *******************************************************************************/ 202 BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) 203 { 204 BT_HDR *p_buf = NULL; 205 UINT8 *p, i = 0; 206 207 if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) 208 { 209 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 210 211 p_buf->offset = L2CAP_MIN_OFFSET; 212 p_buf->len = 1; 213 214 UINT8_TO_STREAM (p, GATT_REQ_READ_MULTI); 215 216 for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) 217 { 218 UINT16_TO_STREAM (p, *(p_handle + i)); 219 p_buf->len += 2; 220 } 221 } 222 223 return p_buf; 224 } 225 /******************************************************************************* 226 ** 227 ** Function attp_build_handle_cmd 228 ** 229 ** Description Build a read /read blob request 230 ** 231 ** Returns None. 232 ** 233 *******************************************************************************/ 234 BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset) 235 { 236 BT_HDR *p_buf = NULL; 237 UINT8 *p; 238 239 if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL) 240 { 241 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 242 243 p_buf->offset = L2CAP_MIN_OFFSET; 244 245 UINT8_TO_STREAM (p, op_code); 246 p_buf->len = 1; 247 248 UINT16_TO_STREAM (p, handle); 249 p_buf->len += 2; 250 251 if (op_code == GATT_REQ_READ_BLOB) 252 { 253 UINT16_TO_STREAM (p, offset); 254 p_buf->len += 2; 255 } 256 257 } 258 259 return p_buf; 260 } 261 /******************************************************************************* 262 ** 263 ** Function attp_build_opcode_cmd 264 ** 265 ** Description Build a request/response with opcode only. 266 ** 267 ** Returns None. 268 ** 269 *******************************************************************************/ 270 BT_HDR *attp_build_opcode_cmd(UINT8 op_code) 271 { 272 BT_HDR *p_buf = NULL; 273 UINT8 *p; 274 275 if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL) 276 { 277 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 278 p_buf->offset = L2CAP_MIN_OFFSET; 279 280 UINT8_TO_STREAM (p, op_code); 281 p_buf->len = 1; 282 } 283 284 return p_buf; 285 } 286 /******************************************************************************* 287 ** 288 ** Function attp_build_value_cmd 289 ** 290 ** Description Build a attribute value request 291 ** 292 ** Returns None. 293 ** 294 *******************************************************************************/ 295 BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle, 296 UINT16 offset, UINT16 len, UINT8 *p_data) 297 { 298 BT_HDR *p_buf = NULL; 299 UINT8 *p, *pp, pair_len, *p_pair_len; 300 301 if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) 302 { 303 p = pp =(UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; 304 305 UINT8_TO_STREAM (p, op_code); 306 p_buf->offset = L2CAP_MIN_OFFSET; 307 p_buf->len = 1; 308 309 if (op_code == GATT_RSP_READ_BY_TYPE) 310 { 311 p_pair_len = p; 312 pair_len = len + 2; 313 UINT8_TO_STREAM (p, pair_len); 314 p_buf->len += 1; 315 } 316 if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) 317 { 318 UINT16_TO_STREAM (p, handle); 319 p_buf->len += 2; 320 } 321 322 if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE ) 323 { 324 UINT16_TO_STREAM (p, offset); 325 p_buf->len += 2; 326 } 327 328 if (len > 0 && p_data != NULL) 329 { 330 /* ensure data not exceed MTU size */ 331 if (payload_size - p_buf->len < len) 332 { 333 len = payload_size - p_buf->len; 334 /* update handle value pair length */ 335 if (op_code == GATT_RSP_READ_BY_TYPE) 336 *p_pair_len = (len + 2); 337 338 GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len); 339 } 340 341 ARRAY_TO_STREAM (p, p_data, len); 342 p_buf->len += len; 343 } 344 } 345 return p_buf; 346 } 347 348 /******************************************************************************* 349 ** 350 ** Function attp_send_msg_to_l2cap 351 ** 352 ** Description Send message to L2CAP. 353 ** 354 *******************************************************************************/ 355 tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP) 356 { 357 UINT16 l2cap_ret; 358 359 360 if (p_tcb->att_lcid == L2CAP_ATT_CID) 361 l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP); 362 else 363 l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP); 364 365 if (l2cap_ret == L2CAP_DW_FAILED) 366 { 367 GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP", 368 *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset)); 369 return GATT_INTERNAL_ERROR; 370 } 371 else if (l2cap_ret == L2CAP_DW_CONGESTED) 372 { 373 GATT_TRACE_DEBUG("ATT congested, message accepted"); 374 return GATT_CONGESTED; 375 } 376 return GATT_SUCCESS; 377 } 378 379 /******************************************************************************* 380 ** 381 ** Function attp_build_sr_msg 382 ** 383 ** Description Build ATT Server PDUs. 384 ** 385 *******************************************************************************/ 386 BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg) 387 { 388 BT_HDR *p_cmd = NULL; 389 UINT16 offset = 0; 390 391 switch (op_code) 392 { 393 case GATT_RSP_READ_BLOB: 394 case GATT_RSP_PREPARE_WRITE: 395 GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d", 396 p_msg->attr_value.len, p_msg->attr_value.offset); 397 offset = p_msg->attr_value.offset; 398 /* Coverity: [FALSE-POSITIVE error] intended fall through */ 399 /* Missing break statement between cases in switch statement */ 400 /* fall through */ 401 case GATT_RSP_READ_BY_TYPE: 402 case GATT_RSP_READ: 403 case GATT_HANDLE_VALUE_NOTIF: 404 case GATT_HANDLE_VALUE_IND: 405 p_cmd = attp_build_value_cmd(p_tcb->payload_size, 406 op_code, 407 p_msg->attr_value.handle, 408 offset, 409 p_msg->attr_value.len, 410 p_msg->attr_value.value); 411 break; 412 413 case GATT_RSP_WRITE: 414 p_cmd = attp_build_opcode_cmd(op_code); 415 break; 416 417 case GATT_RSP_ERROR: 418 p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason); 419 break; 420 421 case GATT_RSP_EXEC_WRITE: 422 p_cmd = attp_build_exec_write_cmd(op_code, 0); 423 break; 424 425 case GATT_RSP_MTU: 426 p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu); 427 break; 428 429 default: 430 GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code); 431 break; 432 } 433 434 if (!p_cmd) 435 GATT_TRACE_ERROR("No resources"); 436 437 return p_cmd; 438 } 439 440 /******************************************************************************* 441 ** 442 ** Function attp_send_sr_msg 443 ** 444 ** Description This function sends the server response or indication message 445 ** to client. 446 ** 447 ** Parameter p_tcb: pointer to the connecton control block. 448 ** p_msg: pointer to message parameters structure. 449 ** 450 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 451 ** 452 ** 453 *******************************************************************************/ 454 tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg) 455 { 456 tGATT_STATUS cmd_sent = GATT_NO_RESOURCES; 457 458 if (p_tcb != NULL) 459 { 460 if (p_msg != NULL) 461 { 462 p_msg->offset = L2CAP_MIN_OFFSET; 463 cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg); 464 } 465 } 466 return cmd_sent; 467 } 468 469 /******************************************************************************* 470 ** 471 ** Function attp_cl_send_cmd 472 ** 473 ** Description Send a ATT command or enqueue it. 474 ** 475 ** Returns GATT_SUCCESS if command sent 476 ** GATT_CONGESTED if command sent but channel congested 477 ** GATT_CMD_STARTED if command queue up in GATT 478 ** GATT_ERROR if command sending failure 479 ** 480 *******************************************************************************/ 481 tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd) 482 { 483 tGATT_STATUS att_ret = GATT_SUCCESS; 484 485 if (p_tcb != NULL) 486 { 487 cmd_code &= ~GATT_AUTH_SIGN_MASK; 488 489 /* no pending request or value confirmation */ 490 if (p_tcb->pending_cl_req == p_tcb->next_slot_inq || 491 cmd_code == GATT_HANDLE_VALUE_CONF) 492 { 493 att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd); 494 if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) 495 { 496 /* do not enq cmd if handle value confirmation or set request */ 497 if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) 498 { 499 gatt_start_rsp_timer (clcb_idx); 500 gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL); 501 } 502 } 503 else 504 att_ret = GATT_INTERNAL_ERROR; 505 } 506 else 507 { 508 att_ret = GATT_CMD_STARTED; 509 gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd); 510 } 511 } 512 else 513 att_ret = GATT_ERROR; 514 515 return att_ret; 516 } 517 /******************************************************************************* 518 ** 519 ** Function attp_send_cl_msg 520 ** 521 ** Description This function sends the client request or confirmation message 522 ** to server. 523 ** 524 ** Parameter p_tcb: pointer to the connectino control block. 525 ** clcb_idx: clcb index 526 ** op_code: message op code. 527 ** p_msg: pointer to message parameters structure. 528 ** 529 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 530 ** 531 ** 532 *******************************************************************************/ 533 tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg) 534 { 535 tGATT_STATUS status = GATT_NO_RESOURCES; 536 BT_HDR *p_cmd = NULL; 537 UINT16 offset = 0, handle; 538 539 if (p_tcb != NULL) 540 { 541 switch (op_code) 542 { 543 case GATT_REQ_MTU: 544 if (p_msg->mtu <= GATT_MAX_MTU_SIZE) 545 { 546 p_tcb->payload_size = p_msg->mtu; 547 p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu); 548 } 549 else 550 status = GATT_ILLEGAL_PARAMETER; 551 break; 552 553 case GATT_REQ_FIND_INFO: 554 case GATT_REQ_READ_BY_TYPE: 555 case GATT_REQ_READ_BY_GRP_TYPE: 556 if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) && 557 GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) && 558 p_msg->browse.s_handle <= p_msg->browse.e_handle) 559 { 560 p_cmd = attp_build_browse_cmd(op_code, 561 p_msg->browse.s_handle, 562 p_msg->browse.e_handle, 563 p_msg->browse.uuid); 564 } 565 else 566 status = GATT_ILLEGAL_PARAMETER; 567 break; 568 569 case GATT_REQ_READ_BLOB: 570 offset = p_msg->read_blob.offset; 571 /* fall through */ 572 case GATT_REQ_READ: 573 handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle; 574 /* handle checking */ 575 if (GATT_HANDLE_IS_VALID (handle)) 576 { 577 p_cmd = attp_build_handle_cmd(op_code, handle, offset); 578 } 579 else 580 status = GATT_ILLEGAL_PARAMETER; 581 break; 582 583 case GATT_HANDLE_VALUE_CONF: 584 p_cmd = attp_build_opcode_cmd(op_code); 585 break; 586 587 case GATT_REQ_PREPARE_WRITE: 588 offset = p_msg->attr_value.offset; 589 /* fall through */ 590 case GATT_REQ_WRITE: 591 case GATT_CMD_WRITE: 592 case GATT_SIGN_CMD_WRITE: 593 if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle)) 594 { 595 p_cmd = attp_build_value_cmd (p_tcb->payload_size, 596 op_code, p_msg->attr_value.handle, 597 offset, 598 p_msg->attr_value.len, 599 p_msg->attr_value.value); 600 } 601 else 602 status = GATT_ILLEGAL_PARAMETER; 603 break; 604 605 case GATT_REQ_EXEC_WRITE: 606 p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write); 607 break; 608 609 case GATT_REQ_FIND_TYPE_VALUE: 610 p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value); 611 break; 612 613 case GATT_REQ_READ_MULTI: 614 p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size, 615 p_msg->read_multi.num_handles, 616 p_msg->read_multi.handles); 617 break; 618 619 default: 620 break; 621 } 622 623 if (p_cmd != NULL) 624 status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd); 625 626 } 627 else 628 { 629 GATT_TRACE_ERROR("Peer device not connected"); 630 } 631 632 return status; 633 } 634 #endif 635