@@ -1836,6 +1836,38 @@ static uint8_t attribute_authorize(struct gatt_db_attribute *attrib,
return db->authorize(attrib, opcode, att, db->authorize_data);
}
+bool gatt_db_attribute_set_fixed_length(struct gatt_db_attribute *attrib,
+ uint16_t len)
+{
+ struct gatt_db_service *service;
+
+ if (!attrib)
+ return false;
+
+ service = attrib->service;
+
+ /* Don't allow overwriting length of service attribute */
+ if (attrib->service->attributes[0] == attrib)
+ return false;
+
+ /* If attribute is a characteristic declaration ajust to its value */
+ if (!bt_uuid_cmp(&characteristic_uuid, &attrib->uuid)) {
+ int i;
+
+ /* Start from the attribute following the value handle */
+ for (i = 0; i < service->num_handles; i++) {
+ if (service->attributes[i] == attrib) {
+ attrib = service->attributes[i + 1];
+ break;
+ }
+ }
+ }
+
+ attrib->value_len = len;
+
+ return true;
+}
+
bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
uint8_t opcode, struct bt_att *att,
gatt_db_attribute_read_t func, void *user_data)
@@ -1845,6 +1877,12 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
if (!attrib || !func)
return false;
+ /* Check boundaries if value_len is set */
+ if (attrib->value_len && offset > attrib->value_len) {
+ func(attrib, BT_ATT_ERROR_INVALID_OFFSET, NULL, 0, user_data);
+ return true;
+ }
+
if (attrib->read_func) {
struct pending_read *p;
uint8_t err;
@@ -1870,12 +1908,6 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
return true;
}
- /* Check boundary if value is stored in the db */
- if (offset > attrib->value_len) {
- func(attrib, BT_ATT_ERROR_INVALID_OFFSET, NULL, 0, user_data);
- return true;
- }
-
/* Guard against invalid access if offset equals to value length */
value = offset == attrib->value_len ? NULL : &attrib->value[offset];
@@ -1930,19 +1962,31 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
gatt_db_attribute_write_t func,
void *user_data)
{
+ uint8_t err = 0;
+
if (!attrib || !func)
return false;
if (attrib->write_func) {
struct pending_write *p;
- uint8_t err;
- err = attribute_authorize(attrib, opcode, att);
- if (err) {
- func(attrib, err, user_data);
- return true;
+ /* Check boundaries if value_len is set */
+ if (attrib->value_len) {
+ if (offset > attrib->value_len) {
+ err = BT_ATT_ERROR_INVALID_OFFSET;
+ goto done;
+ }
+
+ if (offset + len > attrib->value_len) {
+ err = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+ goto done;
+ }
}
+ err = attribute_authorize(attrib, opcode, att);
+ if (err)
+ goto done;
+
p = new0(struct pending_write, 1);
p->attrib = attrib;
p->id = ++attrib->write_id;
@@ -1983,7 +2027,7 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
memcpy(&attrib->value[offset], value, len);
done:
- func(attrib, 0, user_data);
+ func(attrib, err, user_data);
return true;
}
@@ -241,6 +241,9 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
uint32_t
gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib);
+bool gatt_db_attribute_set_fixed_length(struct gatt_db_attribute *attrib,
+ uint16_t len);
+
typedef void (*gatt_db_attribute_read_t) (struct gatt_db_attribute *attrib,
int err, const uint8_t *value,
size_t length, void *user_data);
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This enables user to inform if an attribute has a fixed length so it can automatically perform bounds checking. --- src/shared/gatt-db.c | 68 ++++++++++++++++++++++++++++++++++++-------- src/shared/gatt-db.h | 3 ++ 2 files changed, 59 insertions(+), 12 deletions(-)