Home | History | Annotate | Download | only in gatt
      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