Example #1
0
/*******************************************************************************
**
** Function         gatt_process_find_type_value_rsp
**
** Description      This function is called to handle find by type value response.
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES      result;
    UINT8               *p = p_data;

    UNUSED(p_tcb);

    GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
    /* unexpected response */
    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID) {
        return;
    }

    memset (&result, 0, sizeof(tGATT_DISC_RES));
    result.type.len = 2;
    result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;

    /* returns a series of handle ranges */
    while (len >= 4) {
        STREAM_TO_UINT16 (result.handle, p);
        STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
        memcpy (&result.value.group_value.service_type,  &p_clcb->uuid, sizeof(tBT_UUID));

        len -= 4;

        if (p_clcb->p_reg->app_cb.p_disc_res_cb) {
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
        }
    }

    /* last handle  + 1 */
    p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1);
    /* initiate another request */
    gatt_act_discovery(p_clcb) ;
}
Example #2
0
/*******************************************************************************
**
** Function         gatt_process_read_info_rsp
**
** Description      This function is called to handle the read information
**                  response.
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
                                UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES  result;
    UINT8   *p = p_data, uuid_len = 0, type;

    UNUSED(p_tcb);
    UNUSED(op_code);

    if (len < GATT_INFO_RSP_MIN_LEN) {
        GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
        return;
    }
    /* unexpected response */
    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT) {
        return;
    }

    STREAM_TO_UINT8(type, p);
    len -= 1;

    if (type == GATT_INFO_TYPE_PAIR_16) {
        uuid_len = LEN_UUID_16;
    } else if (type == GATT_INFO_TYPE_PAIR_128) {
        uuid_len = LEN_UUID_128;
    }

    while (len >= uuid_len + 2) {
        STREAM_TO_UINT16 (result.handle, p);

        if (uuid_len > 0) {
            if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p)) {
                break;
            }
        } else {
            memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
        }

        len -= (uuid_len + 2);

        if (p_clcb->p_reg->app_cb.p_disc_res_cb) {
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
        }
    }

    p_clcb->s_handle = (result.handle == 0) ? 0 : (result.handle + 1);
    /* initiate another request */
    gatt_act_discovery(p_clcb) ;
}
/*******************************************************************************
**
** Function         gatt_process_read_info_rsp
**
** Description      This function is called to handle the read information
**                  response.
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
                                UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES  result;
    UINT8   *p = p_data, uuid_len = 0, type;

    /* unexpected response */
    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
        return;

    STREAM_TO_UINT8(type, p);
    len -= 1;

    if (type == GATT_INFO_TYPE_PAIR_16)
        uuid_len = LEN_UUID_16;
    else if (type == GATT_INFO_TYPE_PAIR_128)
        uuid_len = LEN_UUID_128;

    while (len >= uuid_len + 2)
    {
        STREAM_TO_UINT16 (result.handle, p);

        if (uuid_len > 0)
        {
            if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
                break;
        }
        else
            memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));

        len -= (uuid_len + 2);

        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
    }

    p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
    /* initiate another request */
    gatt_act_discovery(p_clcb) ;
}
Example #4
0
/*******************************************************************************
**
** Function         gatt_process_read_rsp
**
** Description      This function is called to handle the read BLOB response
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb,  UINT8 op_code,
                           UINT16 len, UINT8 *p_data)
{
    UINT16      offset = p_clcb->counter;
    UINT8        *p = p_data;

    UNUSED(op_code);

    if (p_clcb->operation == GATTC_OPTYPE_READ) {
        if (p_clcb->op_subtype != GATT_READ_BY_HANDLE) {
            p_clcb->counter = len;
            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
        } else {

            /* allocate GKI buffer holding up long attribute value  */
            if (!p_clcb->p_attr_buf) {
                p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN);
            }

            /* copy attrobute value into cb buffer  */
            if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN) {
                if ((len + offset) > GATT_MAX_ATTR_LEN) {
                    len = GATT_MAX_ATTR_LEN - offset;
                }

                p_clcb->counter += len;

                memcpy(p_clcb->p_attr_buf + offset, p, len);

                /* send next request if needed  */

                if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
                        len + offset < GATT_MAX_ATTR_LEN) {
                    GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
                                     offset, len, p_clcb->counter);
                    gatt_act_read(p_clcb, p_clcb->counter);
                } else { /* end of request, send callback */
                    gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
                }
            } else { /* exception, should not happen */
                GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %p ", offset, p_clcb->p_attr_buf);
                gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
            }
        }
    } else {
        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
                p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
                p_clcb->read_uuid128.wait_for_read_rsp ) {
            p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
            p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
            if (len == LEN_UUID_128) {

                memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
                p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
                if ( p_clcb->p_reg->app_cb.p_disc_res_cb) {
                    (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
                }
                gatt_act_discovery(p_clcb) ;
            } else {
                gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
            }
        }
    }

}
Example #5
0
/*******************************************************************************
**
** Function         gatt_process_read_by_type_rsp
**
** Description      This function is called to handle the read by type response.
**                  read by type can be used for discovery, or read by type or
**                  read characteristic value.
**
** Returns          void
**
*******************************************************************************/
void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
                                    UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES      result;
    tGATT_DISC_VALUE    record_value;
    UINT8               *p = p_data, value_len, handle_len = 2;
    UINT16              handle = 0;

    /* discovery procedure and no callback function registered */
    if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)) {
        return;
    }

    if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN) {
        GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard");
        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
        return;
    }

    STREAM_TO_UINT8(value_len, p);

    if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len - 1))  ) {
        /* this is an error case that server's response containing a value length which is larger than MTU-2
           or value_len > message total length -1 */
        GATT_TRACE_ERROR("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
                         op_code, value_len, (p_tcb->payload_size - 2), (len - 1));
        gatt_end_operation(p_clcb, GATT_ERROR, NULL);
        return;
    }

    if (op_code == GATT_RSP_READ_BY_GRP_TYPE) {
        handle_len = 4;
    }

    value_len -= handle_len; /* substract the handle pairs bytes */
    len -= 1;

    while (len >= (handle_len + value_len)) {
        STREAM_TO_UINT16(handle, p);

        if (!GATT_HANDLE_IS_VALID(handle)) {
            gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
            return;
        }

        memset(&result, 0, sizeof(tGATT_DISC_RES));
        memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));

        result.handle = handle;
        result.type.len = 2;
        result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];

        /* discover all services */
        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
                p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
                op_code == GATT_RSP_READ_BY_GRP_TYPE) {
            STREAM_TO_UINT16(handle, p);

            if (!GATT_HANDLE_IS_VALID(handle)) {
                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
                return;
            } else {
                record_value.group_value.e_handle = handle;
                if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p)) {
                    GATT_TRACE_ERROR("discover all service response parsing failure");
                    break;
                }
            }
        }
        /* discover included service */
        else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC) {
            STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
            STREAM_TO_UINT16(record_value.incl_service.e_handle, p);

            if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
                    !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle)) {
                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
                return;
            }

            if (value_len == 6) {
                STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
                record_value.incl_service.service_type.len = LEN_UUID_16;
            } else if (value_len == 4) {
                p_clcb->s_handle = record_value.incl_service.s_handle;
                p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
                p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
                memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
                memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
                p_clcb->op_subtype |= 0x90;
                gatt_act_read(p_clcb, 0);
                return;
            } else {
                GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
                gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
                return;
            }
        }
        /* read by type */
        else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE) {
            p_clcb->counter = len - 2;
            p_clcb->s_handle = handle;
            if ( p_clcb->counter == (p_clcb->p_tcb->payload_size - 4)) {
                p_clcb->op_subtype = GATT_READ_BY_HANDLE;
                if (!p_clcb->p_attr_buf) {
                    p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN);
                }
                if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN) {
                    memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
                    gatt_act_read(p_clcb, p_clcb->counter);
                } else {
                    gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
                }
            } else {
                gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
            }
            return;
        } else { /* discover characterisitic */
            STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
            STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
            if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) {
                gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
                return;
            }
            if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p)) {
                gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
                /* invalid format, and skip the result */
                return;
            }

            /* UUID not matching */
            if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) {
                len -= (value_len + 2);
                continue; /* skip the result, and look for next one */
            } else if (p_clcb->operation == GATTC_OPTYPE_READ)
                /* UUID match for read characteristic value */
            {
                /* only read the first matching UUID characteristic value, and
                  discard the rest results */
                p_clcb->s_handle = record_value.dclr_value.val_handle;
                p_clcb->op_subtype |= 0x80;
                gatt_act_read(p_clcb, 0);
                return;
            }
        }
        len -= (value_len + handle_len);

        /* result is (handle, 16bits UUID) pairs */
        memcpy (&result.value, &record_value, sizeof (result.value));

        /* send callback if is discover procedure */
        if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb) {
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
        }
    }

    p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);

    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
        /* initiate another request */
        gatt_act_discovery(p_clcb) ;
    } else { /* read characteristic value */
        gatt_act_read(p_clcb, 0);
    }
}