From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 1/5] shared/gatt-db: Use util_iov helpers to build and parse values
Date: Tue, 10 Nov 2026 16:35:21 -0500 [thread overview]
Message-ID: <20261110213525.2942339-2-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20261110213525.2942339-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Build the hash input, characteristic, include and service declarations
with util_iov_push_*, and parse declaration values in the
gatt_db_attribute_get_*_data functions with util_iov_pull_* so they are
checked against the stored value length.
The hash input allocation is now also checked.
Assisted-by: OpenCode:claude-sonnet-5.5
---
src/shared/gatt-db.c | 201 +++++++++++++++++++++++++------------------
1 file changed, 117 insertions(+), 84 deletions(-)
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 23c705bd9d16..3e9c3d6ae55f 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -377,8 +377,8 @@ struct hash_data {
static void gen_hash_m(struct gatt_db_attribute *attr, void *user_data)
{
struct hash_data *hash = user_data;
- uint8_t *data;
- size_t len;
+ struct iovec iov = {};
+ bool with_value;
if (!attr || !attr->value)
return;
@@ -391,30 +391,31 @@ static void gen_hash_m(struct gatt_db_attribute *attr, void *user_data)
case GATT_SND_SVC_UUID:
case GATT_INCLUDE_UUID:
case GATT_CHARAC_UUID:
- /* Allocate space for handle + type + value */
- len = 2 + 2 + attr->value_len;
- data = malloc(2 + 2 + attr->value_len);
- put_le16(attr->handle, data);
- bt_uuid_to_le(&attr->uuid, data + 2);
- memcpy(data + 4, attr->value, attr->value_len);
+ with_value = true;
break;
case GATT_CHARAC_USER_DESC_UUID:
case GATT_CLIENT_CHARAC_CFG_UUID:
case GATT_SERVER_CHARAC_CFG_UUID:
case GATT_CHARAC_FMT_UUID:
case GATT_CHARAC_AGREG_FMT_UUID:
- /* Allocate space for handle + type */
- len = 2 + 2;
- data = malloc(2 + 2 + attr->value_len);
- put_le16(attr->handle, data);
- bt_uuid_to_le(&attr->uuid, data + 2);
+ with_value = false;
break;
default:
return;
}
- hash->iov[hash->i].iov_base = data;
- hash->iov[hash->i].iov_len = len;
+ /* Allocate space for handle + type + value */
+ iov.iov_base = malloc(2 + 2 + attr->value_len);
+ if (!iov.iov_base)
+ return;
+
+ util_iov_push_le16(&iov, attr->handle);
+ util_iov_push_le16(&iov, attr->uuid.value.u16);
+
+ if (with_value)
+ util_iov_push_mem(&iov, attr->value_len, attr->value);
+
+ hash->iov[hash->i] = iov;
hash->i++;
@@ -563,41 +564,57 @@ bool gatt_db_isempty(struct gatt_db *db)
return queue_isempty(db->services);
}
-static int uuid_to_le(const bt_uuid_t *uuid, uint8_t *dst)
+static bool push_uuid_le(struct iovec *iov, const bt_uuid_t *uuid)
{
bt_uuid_t uuid128;
+ void *data;
- if (uuid->type == BT_UUID16) {
- put_le16(uuid->value.u16, dst);
- return bt_uuid_len(uuid);
- }
+ if (uuid->type == BT_UUID16)
+ return util_iov_push_le16(iov, uuid->value.u16) != NULL;
bt_uuid_to_uuid128(uuid, &uuid128);
- bswap_128(&uuid128.value.u128, dst);
- return bt_uuid_len(&uuid128);
+
+ data = util_iov_push(iov, sizeof(uuid128.value.u128));
+ if (!data)
+ return false;
+
+ bswap_128(&uuid128.value.u128, data);
+
+ return true;
}
-static bool le_to_uuid(const uint8_t *src, size_t len, bt_uuid_t *uuid)
+/* Pull a 16, 32 or 128 bits UUID taking all the remaining data in iov */
+static bool pull_uuid_le(struct iovec *iov, bt_uuid_t *uuid)
{
uint128_t u128;
+ uint16_t u16;
+ uint32_t u32;
+ void *data;
- if (len == 2) {
- bt_uuid16_create(uuid, get_le16(src));
+ switch (iov->iov_len) {
+ case 2:
+ if (!util_iov_pull_le16(iov, &u16))
+ return false;
+
+ bt_uuid16_create(uuid, u16);
return true;
- }
+ case 4:
+ if (!util_iov_pull_le32(iov, &u32))
+ return false;
- if (len == 4) {
- bt_uuid32_create(uuid, get_le32(src));
+ bt_uuid32_create(uuid, u32);
return true;
- }
+ case 16:
+ data = util_iov_pull_mem(iov, sizeof(u128));
+ if (!data)
+ return false;
- if (len != 16)
+ bswap_128(data, &u128);
+ bt_uuid128_create(uuid, u128);
+ return true;
+ default:
return false;
-
- bswap_128(src, &u128);
- bt_uuid128_create(uuid, u128);
-
- return true;
+ }
}
static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
@@ -608,7 +625,7 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
struct gatt_db_service *service;
const bt_uuid_t *type;
uint8_t value[16];
- uint16_t len;
+ struct iovec iov = { value, 0 };
if (num_handles < 1)
return NULL;
@@ -621,10 +638,10 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
else
type = &secondary_service_uuid;
- len = uuid_to_le(uuid, value);
+ push_uuid_le(&iov, uuid);
service->attributes[0] = new_attribute(service, handle, type, value,
- len);
+ iov.iov_len);
if (!service->attributes[0]) {
gatt_db_service_destroy(service);
return NULL;
@@ -943,6 +960,14 @@ static uint16_t service_get_attribute_index(struct gatt_db_service *service,
return i;
}
+static void push_chrc_decl(struct iovec *iov, uint8_t properties,
+ uint16_t value_handle, const bt_uuid_t *uuid)
+{
+ util_iov_push_u8(iov, properties);
+ util_iov_push_le16(iov, value_handle);
+ push_uuid_le(iov, uuid);
+}
+
static struct gatt_db_attribute *
service_insert_characteristic(struct gatt_db_service *service,
uint16_t handle,
@@ -956,7 +981,7 @@ service_insert_characteristic(struct gatt_db_service *service,
{
struct gatt_db_attribute **chrc;
uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
- uint16_t len = 0;
+ struct iovec iov = { value, 0 };
int i;
/* Check if handle is in within service range */
@@ -980,17 +1005,12 @@ service_insert_characteristic(struct gatt_db_service *service,
if (!i)
return NULL;
- value[0] = properties;
- len += sizeof(properties);
-
/* We set handle of characteristic value, which will be added next */
- put_le16(value_handle, &value[1]);
- len += sizeof(uint16_t);
- len += uuid_to_le(uuid, &value[3]);
+ push_chrc_decl(&iov, properties, value_handle, uuid);
service->attributes[i] = new_attribute(service, handle,
&characteristic_uuid,
- value, len);
+ value, iov.iov_len);
if (!service->attributes[i])
return NULL;
@@ -1014,7 +1034,8 @@ service_insert_characteristic(struct gatt_db_service *service,
}
/* Update handle of characteristic value_handle if it has changed */
- put_le16(value_handle, &value[1]);
+ iov.iov_len = 0;
+ push_chrc_decl(&iov, properties, value_handle, uuid);
if (!(*chrc)->value) {
free(*chrc);
@@ -1022,8 +1043,8 @@ service_insert_characteristic(struct gatt_db_service *service,
return NULL;
}
- if (memcmp((*chrc)->value, value, len))
- memcpy((*chrc)->value, value, len);
+ if (memcmp((*chrc)->value, iov.iov_base, iov.iov_len))
+ memcpy((*chrc)->value, iov.iov_base, iov.iov_len);
set_attribute_data(service->attributes[i], read_func, write_func,
permissions, user_data);
@@ -1349,7 +1370,8 @@ service_insert_included(struct gatt_db_service *service, uint16_t handle,
{
struct gatt_db_service *included;
uint8_t value[MAX_INCLUDED_VALUE_LEN];
- uint16_t included_handle, len = 0;
+ struct iovec iov = { value, 0 };
+ uint16_t included_handle;
int index;
if (!include || !include->value || !include->service || !service)
@@ -1363,19 +1385,14 @@ service_insert_included(struct gatt_db_service *service, uint16_t handle,
included_handle = include->handle;
- put_le16(included_handle, &value[len]);
- len += sizeof(uint16_t);
-
- put_le16(included_handle + included->num_handles - 1, &value[len]);
- len += sizeof(uint16_t);
+ util_iov_push_le16(&iov, included_handle);
+ util_iov_push_le16(&iov, included_handle + included->num_handles - 1);
/* The Service UUID shall only be present when the UUID is a 16-bit
* Bluetooth UUID. Vol 2. Part G. 3.2
*/
- if (include->value_len == sizeof(uint16_t)) {
- memcpy(&value[len], include->value, include->value_len);
- len += include->value_len;
- }
+ if (include->value_len == sizeof(uint16_t))
+ util_iov_push_mem(&iov, include->value_len, include->value);
index = service_get_attribute_index(service, &handle, 0);
if (!index)
@@ -1383,7 +1400,7 @@ service_insert_included(struct gatt_db_service *service, uint16_t handle,
service->attributes[index] = new_attribute(service, handle,
&included_service_uuid,
- value, len);
+ value, iov.iov_len);
if (!service->attributes[index])
return NULL;
@@ -1953,28 +1970,19 @@ bool gatt_db_attribute_get_service_uuid(const struct gatt_db_attribute *attrib,
bt_uuid_t *uuid)
{
struct gatt_db_service *service;
+ struct gatt_db_attribute *decl;
if (!attrib || !uuid)
return false;
service = attrib->service;
+ decl = service->attributes[0];
- if (service->attributes[0]->value_len == sizeof(uint16_t)) {
- uint16_t value;
-
- value = get_le16(service->attributes[0]->value);
- bt_uuid16_create(uuid, value);
-
- return true;
- }
-
- if (service->attributes[0]->value_len == sizeof(uint128_t)) {
- uint128_t value;
-
- bswap_128(service->attributes[0]->value, &value);
- bt_uuid128_create(uuid, value);
+ if (decl->value_len == sizeof(uint16_t) ||
+ decl->value_len == sizeof(uint128_t)) {
+ struct iovec iov = { decl->value, decl->value_len };
- return true;
+ return pull_uuid_le(&iov, uuid);
}
return false;
@@ -2005,6 +2013,7 @@ bool gatt_db_attribute_get_service_data(const struct gatt_db_attribute *attrib,
{
struct gatt_db_service *service;
struct gatt_db_attribute *decl;
+ struct iovec iov;
if (!attrib)
return false;
@@ -2024,7 +2033,10 @@ bool gatt_db_attribute_get_service_data(const struct gatt_db_attribute *attrib,
* The service declaration attribute value is the 16 or 128 bit service
* UUID.
*/
- return le_to_uuid(decl->value, decl->value_len, uuid);
+ iov.iov_base = decl->value;
+ iov.iov_len = decl->value_len;
+
+ return pull_uuid_le(&iov, uuid);
}
static void read_ext_prop_value(struct gatt_db_attribute *attrib,
@@ -2091,6 +2103,10 @@ bool gatt_db_attribute_get_char_data(const struct gatt_db_attribute *attrib,
uint16_t *ext_prop,
bt_uuid_t *uuid)
{
+ struct iovec iov;
+ uint8_t props;
+ uint16_t vhandle;
+
if (!attrib)
return false;
@@ -2117,22 +2133,29 @@ bool gatt_db_attribute_get_char_data(const struct gatt_db_attribute *attrib,
attrib->value_len != 19))
return false;
+ iov.iov_base = attrib->value;
+ iov.iov_len = attrib->value_len;
+
+ if (!util_iov_pull_u8(&iov, &props) ||
+ !util_iov_pull_le16(&iov, &vhandle))
+ return false;
+
+ if (uuid && !pull_uuid_le(&iov, uuid))
+ return false;
+
if (handle)
*handle = attrib->handle;
if (properties)
- *properties = attrib->value[0];
+ *properties = props;
if (ext_prop)
*ext_prop = get_char_extended_prop(attrib);
if (value_handle)
- *value_handle = get_le16(attrib->value + 1);
-
- if (!uuid)
- return true;
+ *value_handle = vhandle;
- return le_to_uuid(attrib->value + 3, attrib->value_len - 3, uuid);
+ return true;
}
bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
@@ -2140,6 +2163,9 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
uint16_t *start_handle,
uint16_t *end_handle)
{
+ struct iovec iov;
+ uint16_t start, end;
+
if (!attrib)
return false;
@@ -2155,6 +2181,13 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
if (!attrib->value || attrib->value_len < 4 || attrib->value_len > 6)
return false;
+ iov.iov_base = attrib->value;
+ iov.iov_len = attrib->value_len;
+
+ if (!util_iov_pull_le16(&iov, &start) ||
+ !util_iov_pull_le16(&iov, &end))
+ return false;
+
/*
* We only return the handles since the UUID can be easily obtained
* from the corresponding attribute.
@@ -2163,10 +2196,10 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
*handle = attrib->handle;
if (start_handle)
- *start_handle = get_le16(attrib->value);
+ *start_handle = start;
if (end_handle)
- *end_handle = get_le16(attrib->value + 2);
+ *end_handle = end;
return true;
}
--
2.56.0
next prev parent reply other threads:[~2026-11-10 21:35 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 21:35 [PATCH BlueZ v1 0/5] shared: Use util_iov helpers in gatt-db, hog, asha and micp Luiz Augusto von Dentz
2026-11-10 21:35 ` Luiz Augusto von Dentz [this message]
2026-11-10 21:35 ` [PATCH BlueZ v1 2/5] shared/hog: Use util_iov helpers to parse characteristic values Luiz Augusto von Dentz
2026-11-10 21:35 ` [PATCH BlueZ v1 3/5] shared/asha: " Luiz Augusto von Dentz
2026-11-10 21:35 ` [PATCH BlueZ v1 4/5] shared/micp: Fix reading Mute State from an empty notification Luiz Augusto von Dentz
2026-11-10 21:35 ` [PATCH BlueZ v1 5/5] shared/micp: Use util_iov_pull_mem instead of a local helper Luiz Augusto von Dentz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110213525.2942339-2-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox