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 *******************************************************************************/ 48 BT_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 *******************************************************************************/ 72 BT_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 *******************************************************************************/ 102 BT_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 *******************************************************************************/ 128 BT_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 *******************************************************************************/ 155 BT_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 *******************************************************************************/ 190 BT_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 *******************************************************************************/ 218 BT_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 *******************************************************************************/ 250 BT_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 *******************************************************************************/ 274 BT_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 *******************************************************************************/ 327 tGATT_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 *******************************************************************************/ 358 BT_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 *******************************************************************************/ 426 tGATT_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 *******************************************************************************/ 453 tGATT_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 *******************************************************************************/ 505 tGATT_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