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