1 /******************************************************************************
3 * Copyright (C) 2008-2014 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * this file contains ATT protocol functions
23 ******************************************************************************/
25 #include "bt_target.h"
27 #if BLE_INCLUDED == TRUE
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 /*******************************************************************************
39 ** Function attp_build_mtu_exec_cmd
41 ** Description Build a exchange MTU request
45 *******************************************************************************/
46 BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
50 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET);
52 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
53 UINT8_TO_STREAM(p, op_code);
54 UINT16_TO_STREAM(p, rx_mtu);
56 p_buf->offset = L2CAP_MIN_OFFSET;
57 p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
61 /*******************************************************************************
63 ** Function attp_build_exec_write_cmd
65 ** Description Build a execute write request or response.
69 *******************************************************************************/
70 BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
72 BT_HDR *p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE);
75 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
77 p_buf->offset = L2CAP_MIN_OFFSET;
78 p_buf->len = GATT_OP_CODE_SIZE;
80 UINT8_TO_STREAM(p, op_code);
82 if (op_code == GATT_REQ_EXEC_WRITE) {
83 flag &= GATT_PREP_WRITE_EXEC;
84 UINT8_TO_STREAM (p, flag);
91 /*******************************************************************************
93 ** Function attp_build_err_cmd
95 ** Description Build a exchange MTU request
99 *******************************************************************************/
100 BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
103 BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5);
105 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
106 UINT8_TO_STREAM(p, GATT_RSP_ERROR);
107 UINT8_TO_STREAM(p, cmd_code);
108 UINT16_TO_STREAM(p, err_handle);
109 UINT8_TO_STREAM(p, reason);
111 p_buf->offset = L2CAP_MIN_OFFSET;
112 /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */
113 p_buf->len = GATT_HDR_SIZE + 1 + 1;
117 /*******************************************************************************
119 ** Function attp_build_browse_cmd
121 ** Description Build a read information request or read by type request
125 *******************************************************************************/
126 BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
129 BT_HDR *p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 8 + L2CAP_MIN_OFFSET);
131 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
132 /* Describe the built message location and size */
133 p_buf->offset = L2CAP_MIN_OFFSET;
134 p_buf->len = GATT_OP_CODE_SIZE + 4;
136 UINT8_TO_STREAM(p, op_code);
137 UINT16_TO_STREAM(p, s_hdl);
138 UINT16_TO_STREAM(p, e_hdl);
139 p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
144 /*******************************************************************************
146 ** Function attp_build_read_handles_cmd
148 ** Description Build a read by type and value request.
150 ** Returns pointer to the command buffer.
152 *******************************************************************************/
153 BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
156 UINT16 len = p_value_type->value_len;
158 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
160 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
161 p_buf->offset = L2CAP_MIN_OFFSET;
162 p_buf->len = 5; /* opcode + s_handle + e_handle */
164 UINT8_TO_STREAM(p, GATT_REQ_FIND_TYPE_VALUE);
165 UINT16_TO_STREAM(p, p_value_type->s_handle);
166 UINT16_TO_STREAM(p, p_value_type->e_handle);
168 p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
170 if (p_value_type->value_len + p_buf->len > payload_size)
171 len = payload_size - p_buf->len;
173 memcpy(p, p_value_type->value, len);
179 /*******************************************************************************
181 ** Function attp_build_read_multi_cmd
183 ** Description Build a read multiple request
187 *******************************************************************************/
188 BT_HDR *attp_build_read_multi_cmd(UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
192 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET);
194 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
195 p_buf->offset = L2CAP_MIN_OFFSET;
198 UINT8_TO_STREAM(p, GATT_REQ_READ_MULTI);
200 for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
201 UINT16_TO_STREAM (p, *(p_handle + i));
207 /*******************************************************************************
209 ** Function attp_build_handle_cmd
211 ** Description Build a read /read blob request
215 *******************************************************************************/
216 BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
220 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET);
222 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
223 p_buf->offset = L2CAP_MIN_OFFSET;
225 UINT8_TO_STREAM(p, op_code);
228 UINT16_TO_STREAM(p, handle);
231 if (op_code == GATT_REQ_READ_BLOB) {
232 UINT16_TO_STREAM (p, offset);
239 /*******************************************************************************
241 ** Function attp_build_opcode_cmd
243 ** Description Build a request/response with opcode only.
247 *******************************************************************************/
248 BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
252 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET);
254 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
255 p_buf->offset = L2CAP_MIN_OFFSET;
257 UINT8_TO_STREAM(p, op_code);
263 /*******************************************************************************
265 ** Function attp_build_value_cmd
267 ** Description Build a attribute value request
271 *******************************************************************************/
272 BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
273 UINT16 offset, UINT16 len, UINT8 *p_data)
275 UINT8 *p, *pp, pair_len, *p_pair_len;
277 (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
279 p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
280 UINT8_TO_STREAM(p, op_code);
281 p_buf->offset = L2CAP_MIN_OFFSET;
284 if (op_code == GATT_RSP_READ_BY_TYPE) {
287 UINT8_TO_STREAM (p, pair_len);
290 if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) {
291 UINT16_TO_STREAM (p, handle);
295 if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE) {
296 UINT16_TO_STREAM (p, offset);
300 if (len > 0 && p_data != NULL) {
301 /* ensure data not exceed MTU size */
302 if (payload_size - p_buf->len < len) {
303 len = payload_size - p_buf->len;
304 /* update handle value pair length */
305 if (op_code == GATT_RSP_READ_BY_TYPE)
306 *p_pair_len = (len + 2);
308 GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
311 ARRAY_TO_STREAM(p, p_data, len);
318 /*******************************************************************************
320 ** Function attp_send_msg_to_l2cap
322 ** Description Send message to L2CAP.
324 *******************************************************************************/
325 tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
330 if (p_tcb->att_lcid == L2CAP_ATT_CID)
331 l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
333 l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
335 if (l2cap_ret == L2CAP_DW_FAILED)
337 GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP",
338 *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
339 return GATT_INTERNAL_ERROR;
341 else if (l2cap_ret == L2CAP_DW_CONGESTED)
343 GATT_TRACE_DEBUG("ATT congested, message accepted");
344 return GATT_CONGESTED;
349 /*******************************************************************************
351 ** Function attp_build_sr_msg
353 ** Description Build ATT Server PDUs.
355 *******************************************************************************/
356 BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
358 BT_HDR *p_cmd = NULL;
363 case GATT_RSP_READ_BLOB:
364 case GATT_RSP_PREPARE_WRITE:
365 GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
366 p_msg->attr_value.len, p_msg->attr_value.offset);
367 offset = p_msg->attr_value.offset;
368 /* Coverity: [FALSE-POSITIVE error] intended fall through */
369 /* Missing break statement between cases in switch statement */
371 case GATT_RSP_READ_BY_TYPE:
373 case GATT_HANDLE_VALUE_NOTIF:
374 case GATT_HANDLE_VALUE_IND:
375 p_cmd = attp_build_value_cmd(p_tcb->payload_size,
377 p_msg->attr_value.handle,
379 p_msg->attr_value.len,
380 p_msg->attr_value.value);
384 p_cmd = attp_build_opcode_cmd(op_code);
388 p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
391 case GATT_RSP_EXEC_WRITE:
392 p_cmd = attp_build_exec_write_cmd(op_code, 0);
396 p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
400 GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
405 GATT_TRACE_ERROR("No resources");
410 /*******************************************************************************
412 ** Function attp_send_sr_msg
414 ** Description This function sends the server response or indication message
417 ** Parameter p_tcb: pointer to the connecton control block.
418 ** p_msg: pointer to message parameters structure.
420 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
423 *******************************************************************************/
424 tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
426 tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
432 p_msg->offset = L2CAP_MIN_OFFSET;
433 cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
439 /*******************************************************************************
441 ** Function attp_cl_send_cmd
443 ** Description Send a ATT command or enqueue it.
445 ** Returns GATT_SUCCESS if command sent
446 ** GATT_CONGESTED if command sent but channel congested
447 ** GATT_CMD_STARTED if command queue up in GATT
448 ** GATT_ERROR if command sending failure
450 *******************************************************************************/
451 tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
453 tGATT_STATUS att_ret = GATT_SUCCESS;
457 cmd_code &= ~GATT_AUTH_SIGN_MASK;
459 /* no pending request or value confirmation */
460 if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
461 cmd_code == GATT_HANDLE_VALUE_CONF)
463 att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
464 if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
466 /* do not enq cmd if handle value confirmation or set request */
467 if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
469 gatt_start_rsp_timer (clcb_idx);
470 gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
474 att_ret = GATT_INTERNAL_ERROR;
478 att_ret = GATT_CMD_STARTED;
479 gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
483 att_ret = GATT_ERROR;
487 /*******************************************************************************
489 ** Function attp_send_cl_msg
491 ** Description This function sends the client request or confirmation message
494 ** Parameter p_tcb: pointer to the connectino control block.
495 ** clcb_idx: clcb index
496 ** op_code: message op code.
497 ** p_msg: pointer to message parameters structure.
499 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
502 *******************************************************************************/
503 tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
505 tGATT_STATUS status = GATT_NO_RESOURCES;
506 BT_HDR *p_cmd = NULL;
507 UINT16 offset = 0, handle;
514 if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
516 p_tcb->payload_size = p_msg->mtu;
517 p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
520 status = GATT_ILLEGAL_PARAMETER;
523 case GATT_REQ_FIND_INFO:
524 case GATT_REQ_READ_BY_TYPE:
525 case GATT_REQ_READ_BY_GRP_TYPE:
526 if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
527 GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
528 p_msg->browse.s_handle <= p_msg->browse.e_handle)
530 p_cmd = attp_build_browse_cmd(op_code,
531 p_msg->browse.s_handle,
532 p_msg->browse.e_handle,
536 status = GATT_ILLEGAL_PARAMETER;
539 case GATT_REQ_READ_BLOB:
540 offset = p_msg->read_blob.offset;
543 handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
544 /* handle checking */
545 if (GATT_HANDLE_IS_VALID (handle))
547 p_cmd = attp_build_handle_cmd(op_code, handle, offset);
550 status = GATT_ILLEGAL_PARAMETER;
553 case GATT_HANDLE_VALUE_CONF:
554 p_cmd = attp_build_opcode_cmd(op_code);
557 case GATT_REQ_PREPARE_WRITE:
558 offset = p_msg->attr_value.offset;
562 case GATT_SIGN_CMD_WRITE:
563 if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
565 p_cmd = attp_build_value_cmd (p_tcb->payload_size,
566 op_code, p_msg->attr_value.handle,
568 p_msg->attr_value.len,
569 p_msg->attr_value.value);
572 status = GATT_ILLEGAL_PARAMETER;
575 case GATT_REQ_EXEC_WRITE:
576 p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
579 case GATT_REQ_FIND_TYPE_VALUE:
580 p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
583 case GATT_REQ_READ_MULTI:
584 p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
585 p_msg->read_multi.num_handles,
586 p_msg->read_multi.handles);
594 status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
599 GATT_TRACE_ERROR("Peer device not connected");