From 87c3db9e0be68b9344ee980de7c3340468530773 Mon Sep 17 00:00:00 2001 From: Kim Sekkelund Date: Wed, 24 Jul 2019 14:23:48 +0200 Subject: [PATCH] Bluetooth: Host: Find by type should accept 128bit UUIDs Find by type does only accept a UUID with the same length as the UUID which is stored in the internal list. If a UUID is stored in the short 16 bit format then a request with 128 bit UUID will fail. Add support for the missing formats. Signed-off-by: Kim Sekkelund --- include/bluetooth/uuid.h | 32 +++++++++++++++++++ subsys/bluetooth/host/att.c | 59 +++++++++++++++++++----------------- subsys/bluetooth/host/uuid.c | 47 ++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 28 deletions(-) diff --git a/include/bluetooth/uuid.h b/include/bluetooth/uuid.h index 4d0f60a48932da..1f2f5cdc9c4f23 100644 --- a/include/bluetooth/uuid.h +++ b/include/bluetooth/uuid.h @@ -465,6 +465,38 @@ struct bt_uuid_128 { */ int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2); +/** @brief Copy UUID from packet data (LE) to internal bt_uuid. + * + * Copy UUID from packet data in little endian format to internal bt_uuid + * format. The data_len parameter is used to determine whether the received + * UUID is of 16 or 128 bit format (length 2 or 16). 32 bit format is not + * allowed over the air. + * + * @param uuid Pointer to where to write the Bluetooth UUID + * @param data pointer to location of the UUID in the packet + * @param data_len length of the UUID in the packet + * + * @return true if the data was valid and the UUID was successfully created. + */ +bool bt_uuid_create_le(struct bt_uuid *uuid, const u8_t *data, u8_t data_len); + +/** @brief Copy UUID from internal variable to internal bt_uuid. + * + * Copy UUID from internal variable pointer to internal bt_uuid format. + * The data parameter points to a variable (originally stored in bt_uuid_128, + * bt_uuid_32 or bt_uuid_16 format) and therefore take into account of + * alignment of the val member. + * The data_len parameter is used to determine whether to copy the UUID from + * 16, 32 or 128 bit format (length 2, 4 or 16). + * + * @param uuid Pointer to where to write the Bluetooth UUID + * @param data pointer to location of the UUID variable + * @param data_len length of the UUID in the packet + * + * @return true if the data was valid and the UUID was successfully created. + */ +bool bt_uuid_create(struct bt_uuid *uuid, u8_t *data, u8_t data_len); + #if defined(CONFIG_BT_DEBUG) /** @brief Convert Bluetooth UUID to string. * diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index e28bf5fb786921..63618dad6f9b4a 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -580,8 +580,7 @@ static u8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data) /* Skip secondary services */ if (!bt_uuid_cmp(attr->uuid, BT_UUID_GATT_SECONDARY)) { - data->group = NULL; - return BT_GATT_ITER_CONTINUE; + goto skip; } /* Update group end_handle if not a primary service */ @@ -607,14 +606,29 @@ static u8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data) * Since we don't know if it is the service with requested UUID, * we cannot respond with an error to this request. */ - data->group = NULL; - return BT_GATT_ITER_CONTINUE; + goto skip; } /* Check if data matches */ - if (read != data->value_len || memcmp(data->value, uuid, read)) { - data->group = NULL; - return BT_GATT_ITER_CONTINUE; + if (read != data->value_len) { + /* Use bt_uuid_cmp() to compare UUIDs of different form. */ + struct bt_uuid_128 ref_uuid; + struct bt_uuid_128 recvd_uuid; + + if (!bt_uuid_create_le(&recvd_uuid.uuid, data->value, + data->value_len)) { + BT_WARN("Unable to create UUID: size %u", data->value_len); + goto skip; + } + if (!bt_uuid_create(&ref_uuid.uuid, uuid, read)) { + BT_WARN("Unable to create UUID: size %d", read); + goto skip; + } + if (bt_uuid_cmp(&recvd_uuid.uuid, &ref_uuid.uuid)) { + goto skip; + } + } else if (memcmp(data->value, uuid, read)) { + goto skip; } /* If service has been found, error should be cleared */ @@ -627,6 +641,10 @@ static u8_t find_type_cb(const struct bt_gatt_attr *attr, void *user_data) /* continue to find the end_handle */ return BT_GATT_ITER_CONTINUE; + +skip: + data->group = NULL; + return BT_GATT_ITER_CONTINUE; } static u8_t att_find_type_rsp(struct bt_att *att, u16_t start_handle, @@ -705,22 +723,6 @@ static u8_t att_find_type_req(struct bt_att *att, struct net_buf *buf) buf->len); } -static bool uuid_create(struct bt_uuid *uuid, struct net_buf *buf) -{ - switch (buf->len) { - case 2: - uuid->type = BT_UUID_TYPE_16; - BT_UUID_16(uuid)->val = net_buf_pull_le16(buf); - return true; - case 16: - uuid->type = BT_UUID_TYPE_128; - memcpy(BT_UUID_128(uuid)->val, buf->data, buf->len); - return true; - } - - return false; -} - static u8_t check_perm(struct bt_conn *conn, const struct bt_gatt_attr *attr, u8_t mask) { @@ -891,9 +893,10 @@ static u8_t att_read_type_req(struct bt_att *att, struct net_buf *buf) struct bt_uuid_16 u16; struct bt_uuid_128 u128; } u; + u8_t uuid_len = buf->len - sizeof(*req); /* Type can only be UUID16 or UUID128 */ - if (buf->len != sizeof(*req) + 2 && buf->len != sizeof(*req) + 16) { + if (uuid_len != 2 && uuid_len != 16) { return BT_ATT_ERR_INVALID_PDU; } @@ -901,8 +904,7 @@ static u8_t att_read_type_req(struct bt_att *att, struct net_buf *buf) start_handle = sys_le16_to_cpu(req->start_handle); end_handle = sys_le16_to_cpu(req->end_handle); - - if (!uuid_create(&u.uuid, buf)) { + if (!bt_uuid_create_le(&u.uuid, req->uuid, uuid_len)) { return BT_ATT_ERR_UNLIKELY; } @@ -1197,9 +1199,10 @@ static u8_t att_read_group_req(struct bt_att *att, struct net_buf *buf) struct bt_uuid_16 u16; struct bt_uuid_128 u128; } u; + u8_t uuid_len = buf->len - sizeof(*req); /* Type can only be UUID16 or UUID128 */ - if (buf->len != sizeof(*req) + 2 && buf->len != sizeof(*req) + 16) { + if (uuid_len != 2 && uuid_len != 16) { return BT_ATT_ERR_INVALID_PDU; } @@ -1208,7 +1211,7 @@ static u8_t att_read_group_req(struct bt_att *att, struct net_buf *buf) start_handle = sys_le16_to_cpu(req->start_handle); end_handle = sys_le16_to_cpu(req->end_handle); - if (!uuid_create(&u.uuid, buf)) { + if (!bt_uuid_create_le(&u.uuid, req->uuid, uuid_len)) { return BT_ATT_ERR_UNLIKELY; } diff --git a/subsys/bluetooth/host/uuid.c b/subsys/bluetooth/host/uuid.c index c971553a37a2e9..a2027d344a532e 100644 --- a/subsys/bluetooth/host/uuid.c +++ b/subsys/bluetooth/host/uuid.c @@ -80,6 +80,53 @@ int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2) return -EINVAL; } +bool bt_uuid_create_le(struct bt_uuid *uuid, const u8_t *data, u8_t data_len) +{ + /* Copy UUID from packet data to internal bt_uuid */ + switch (data_len) { + case 2: + uuid->type = BT_UUID_TYPE_16; + BT_UUID_16(uuid)->val = sys_get_le16(data); + break; + case 16: + uuid->type = BT_UUID_TYPE_128; + memcpy(&BT_UUID_128(uuid)->val, data, 16); + break; + default: + return false; + } + return true; +} + +bool bt_uuid_create(struct bt_uuid *uuid, u8_t *data, u8_t data_len) +{ + /* Copy UUID from internal variable to internal bt_uuid */ + union { + u16_t *u16; + u32_t *u32; + u8_t *u128; + } v; + + v.u128 = data; + switch (data_len) { + case 2: + uuid->type = BT_UUID_TYPE_16; + BT_UUID_16(uuid)->val = *v.u16; + break; + case 4: + uuid->type = BT_UUID_TYPE_32; + BT_UUID_32(uuid)->val = *v.u32; + break; + case 16: + uuid->type = BT_UUID_TYPE_128; + memcpy(&BT_UUID_128(uuid)->val, v.u128, 16); + break; + default: + return false; + } + return true; +} + #if defined(CONFIG_BT_DEBUG) void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len) {