Skip to content
Permalink
Browse files

Bluetooth: GATT: Fix not parsing result of Read by Type

When using the procedure Read By Type the response may contain multiple
instances so it needs to be parsed properly. When dealing with long
values only the beggining will be read, for the remaining bytes the
application should issue another bt_gatt_read with offset so Read Blob
procedure is used as recommended by the spec:

BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part F page 2312:

The Read Blob Request would be used to read the remaining octets of a
long attribute value.

Fixes #16107

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information...
Vudentz authored and jhedberg committed May 13, 2019
1 parent fc3270d commit 852b1dca55c9d2a994dc4884aa66e3bd7b984e37
Showing with 58 additions and 0 deletions.
  1. +8 −0 include/bluetooth/gatt.h
  2. +50 −0 subsys/bluetooth/host/gatt.c
@@ -1029,6 +1029,14 @@ struct bt_gatt_read_params {
*
* This procedure read the attribute value and return it to the callback.
*
* When reading attributes by UUID the callback can be called multiple times
* depending on how many instances of given the UUID exists with the
* start_handle being updated for each instance.
*
* If an instance does contain a long value which cannot be read entirely the
* caller will need to read the remaining data separately using the handle and
* offset.
*
* Note: This procedure is asynchronous therefore the parameters need to
* remains valid while it is active.
*
@@ -2490,6 +2490,51 @@ int bt_gatt_discover(struct bt_conn *conn,
return -EINVAL;
}

static void parse_read_by_uuid(struct bt_conn *conn,
struct bt_gatt_read_params *params,
const void *pdu, u16_t length)
{
const struct bt_att_read_type_rsp *rsp = pdu;

/* Parse values found */
for (length--, pdu = rsp->data; length;
length -= rsp->len, pdu = (const u8_t *)pdu + rsp->len) {
const struct bt_att_data *data = pdu;
u16_t handle;
u8_t len;

handle = sys_le16_to_cpu(data->handle);

/* Handle 0 is invalid */
if (!handle) {
BT_ERR("Invalid handle");
return;
}

len = rsp->len > length ? length - 2 : rsp->len - 2;

BT_DBG("handle 0x%04x len %u value %u", handle, rsp->len, len);

/* Update start_handle */
params->by_uuid.start_handle = handle;

if (params->func(conn, 0, params, data->value, len) ==
BT_GATT_ITER_STOP) {
return;
}

/* Check if long attribute */
if (rsp->len > length) {
break;
}
}

/* Continue reading the attributes */
if (bt_gatt_read(conn, params) < 0) {
params->func(conn, BT_ATT_ERR_UNLIKELY, params, NULL, 0);
}
}

static void gatt_read_rsp(struct bt_conn *conn, u8_t err, const void *pdu,
u16_t length, void *user_data)
{
@@ -2502,6 +2547,11 @@ static void gatt_read_rsp(struct bt_conn *conn, u8_t err, const void *pdu,
return;
}

if (!params->handle_count) {
parse_read_by_uuid(conn, params, pdu, length);
return;
}

if (params->func(conn, 0, params, pdu, length) == BT_GATT_ITER_STOP) {
return;
}

0 comments on commit 852b1dc

Please sign in to comment.
You can’t perform that action at this time.