2022-11-04 21:38:48

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 1/2] monitor/att: Add handler support for Read by Type

From: Luiz Augusto von Dentz <[email protected]>

This adds handler support for Read by Type so it can further decode
the values when the procedure is used.
---
monitor/att.c | 206 ++++++++++++++++++++++++++++++++++--------------
monitor/l2cap.h | 13 ++-
2 files changed, 155 insertions(+), 64 deletions(-)

diff --git a/monitor/att.c b/monitor/att.c
index fbd75db03b83..289f4fc04d9a 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -43,6 +43,21 @@
#include "l2cap.h"
#include "att.h"

+struct att_read {
+ struct gatt_db_attribute *attr;
+ bool in;
+ uint16_t chan;
+ void (*func)(const struct l2cap_frame *frame);
+};
+
+struct att_conn_data {
+ struct gatt_db *ldb;
+ struct timespec ldb_mtim;
+ struct gatt_db *rdb;
+ struct timespec rdb_mtim;
+ struct queue *reads;
+};
+
static void print_uuid(const char *label, const void *data, uint16_t size)
{
const char *str;
@@ -77,27 +92,66 @@ static void print_handle_range(const char *label, const void *data)
get_le16(data), get_le16(data + 2));
}

-static void print_data_list(const char *label, uint8_t length,
- const void *data, uint16_t size)
+static bool match_read_frame(const void *data, const void *match_data)
{
+ const struct att_read *read = data;
+ const struct l2cap_frame *frame = match_data;
+
+ /* Read frame and response frame shall be in the opposite direction to
+ * match.
+ */
+ if (read->in == frame->in)
+ return false;
+
+ return read->chan == frame->chan;
+}
+
+static void print_data_list(const char *label, uint8_t length,
+ const struct l2cap_frame *frame)
+{
+ struct packet_conn_data *conn;
+ struct att_conn_data *data;
+ struct att_read *read;
uint8_t count;

if (length == 0)
return;

- count = size / length;
+ conn = packet_get_conn_data(frame->handle);
+ if (conn) {
+ data = conn->data;
+ if (data)
+ read = queue_remove_if(data->reads, match_read_frame,
+ (void *)frame);
+ else
+ read = NULL;
+ } else
+ read = NULL;
+
+ count = frame->size / length;

print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");

- while (size >= length) {
- print_field("Handle: 0x%4.4x", get_le16(data));
- print_hex_field("Value", data + 2, length - 2);
+ while (frame->size >= length) {
+ if (!l2cap_frame_print_le16((void *)frame, "Handle"))
+ break;

- data += length;
- size -= length;
+ print_hex_field("Value", frame->data, length - 2);
+
+ if (read) {
+ struct l2cap_frame f;
+
+ l2cap_frame_clone_size(&f, frame, length - 2);
+
+ read->func(&f);
+ }
+
+ if (!l2cap_frame_pull((void *)frame, frame, length - 2))
+ break;
}

- packet_hexdump(data, size);
+ packet_hexdump(frame->data, frame->size);
+ free(read);
}

static void print_attribute_info(uint16_t type, const void *data, uint16_t len)
@@ -2292,9 +2346,8 @@ struct gatt_handler {
GATT_HANDLER(0x2bba, content_control_id_read, NULL, NULL),
};

-static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
+static struct gatt_handler *get_handler_uuid(const bt_uuid_t *uuid)
{
- const bt_uuid_t *uuid = gatt_db_attribute_get_type(attr);
size_t i;

for (i = 0; i < ARRAY_SIZE(gatt_handlers); i++) {
@@ -2307,6 +2360,11 @@ static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
return NULL;
}

+static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)
+{
+ return get_handler_uuid(gatt_db_attribute_get_type(attr));
+}
+
static void att_exchange_mtu_req(const struct l2cap_frame *frame)
{
const struct bt_l2cap_att_exchange_mtu_req *pdu = frame->data;
@@ -2403,36 +2461,23 @@ static void att_find_by_type_val_rsp(const struct l2cap_frame *frame)
packet_hexdump(ptr, len);
}

-static void att_read_type_req(const struct l2cap_frame *frame)
+static int bt_uuid_from_data(bt_uuid_t *uuid, const void *data, uint16_t size)
{
- print_handle_range("Handle range", frame->data);
- print_uuid("Attribute type", frame->data + 4, frame->size - 4);
+ uint128_t u128;
+
+ switch (size) {
+ case 2:
+ return bt_uuid16_create(uuid, get_le16(data));
+ case 4:
+ return bt_uuid32_create(uuid, get_le32(data));
+ case 16:
+ memcpy(u128.data, data, sizeof(u128.data));
+ return bt_uuid128_create(uuid, u128);
+ }
+
+ return -EINVAL;
}

-static void att_read_type_rsp(const struct l2cap_frame *frame)
-{
- const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;
-
- print_field("Attribute data length: %d", pdu->length);
- print_data_list("Attribute data list", pdu->length,
- frame->data + 1, frame->size - 1);
-}
-
-struct att_read {
- struct gatt_db_attribute *attr;
- bool in;
- uint16_t chan;
- void (*func)(const struct l2cap_frame *frame);
-};
-
-struct att_conn_data {
- struct gatt_db *ldb;
- struct timespec ldb_mtim;
- struct gatt_db *rdb;
- struct timespec rdb_mtim;
- struct queue *reads;
-};
-
static void att_conn_data_free(void *data)
{
struct att_conn_data *att_data = data;
@@ -2443,6 +2488,67 @@ static void att_conn_data_free(void *data)
free(att_data);
}

+static struct att_conn_data *att_get_conn_data(struct packet_conn_data *conn)
+{
+ struct att_conn_data *data = conn->data;
+
+ if (data)
+ return data;
+
+ data = new0(struct att_conn_data, 1);
+ data->rdb = gatt_db_new();
+ data->ldb = gatt_db_new();
+ conn->data = data;
+ conn->destroy = att_conn_data_free;
+
+ return data;
+}
+
+static void att_read_type_req(const struct l2cap_frame *frame)
+{
+ bt_uuid_t uuid;
+ struct packet_conn_data *conn;
+ struct att_conn_data *data;
+ struct att_read *read;
+ struct gatt_handler *handler;
+
+ print_handle_range("Handle range", frame->data);
+ print_uuid("Attribute type", frame->data + 4, frame->size - 4);
+
+ if (bt_uuid_from_data(&uuid, frame->data + 4, frame->size - 4))
+ return;
+
+ handler = get_handler_uuid(&uuid);
+ if (!handler || !handler->read)
+ return;
+
+ conn = packet_get_conn_data(frame->handle);
+ data = att_get_conn_data(conn);
+
+ if (!data->reads)
+ data->reads = queue_new();
+
+ read = new0(struct att_read, 1);
+ read->in = frame->in;
+ read->chan = frame->chan;
+ read->func = handler->read;
+
+ queue_push_tail(data->reads, read);
+}
+
+static void att_read_type_rsp(const struct l2cap_frame *frame)
+{
+ uint8_t len;
+
+ if (!l2cap_frame_get_u8((void *)frame, &len)) {
+ print_text(COLOR_ERROR, "invalid size");
+ return;
+ }
+
+ print_field("Attribute data length: %d", len);
+ print_data_list("Attribute data list", len, frame);
+}
+
static void gatt_load_db(struct gatt_db *db, const char *filename,
struct timespec *mtim)
{
@@ -2467,19 +2573,11 @@ static void gatt_load_db(struct gatt_db *db, const char *filename,

static void load_gatt_db(struct packet_conn_data *conn)
{
- struct att_conn_data *data = conn->data;
+ struct att_conn_data *data = att_get_conn_data(conn);
char filename[PATH_MAX];
char local[18];
char peer[18];

- if (!data) {
- data = new0(struct att_conn_data, 1);
- data->rdb = gatt_db_new();
- data->ldb = gatt_db_new();
- conn->data = data;
- conn->destroy = att_conn_data_free;
- }
-
ba2str((bdaddr_t *)conn->src, local);
ba2str((bdaddr_t *)conn->dst, peer);

@@ -2605,20 +2703,6 @@ static void att_read_req(const struct l2cap_frame *frame)
queue_push_tail(data->reads, read);
}

-static bool match_read_frame(const void *data, const void *match_data)
-{
- const struct att_read *read = data;
- const struct l2cap_frame *frame = match_data;
-
- /* Read frame and response frame shall be in the opposite direction to
- * match.
- */
- if (read->in == frame->in)
- return false;
-
- return read->chan == frame->chan;
-}
-
static void att_read_rsp(const struct l2cap_frame *frame)
{
struct packet_conn_data *conn;
diff --git a/monitor/l2cap.h b/monitor/l2cap.h
index e63377857cf7..935066e6e7dc 100644
--- a/monitor/l2cap.h
+++ b/monitor/l2cap.h
@@ -31,8 +31,9 @@ void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in,
uint16_t cid, uint16_t psm,
const void *data, uint16_t size);

-static inline void l2cap_frame_clone(struct l2cap_frame *frame,
- const struct l2cap_frame *source)
+static inline void l2cap_frame_clone_size(struct l2cap_frame *frame,
+ const struct l2cap_frame *source,
+ uint16_t size)
{
if (frame != source) {
frame->index = source->index;
@@ -44,10 +45,16 @@ static inline void l2cap_frame_clone(struct l2cap_frame *frame,
frame->chan = source->chan;
frame->mode = source->mode;
frame->data = source->data;
- frame->size = source->size;
+ frame->size = size;
}
}

+static inline void l2cap_frame_clone(struct l2cap_frame *frame,
+ const struct l2cap_frame *source)
+{
+ l2cap_frame_clone_size(frame, source, source->size);
+}
+
static inline void *l2cap_frame_pull(struct l2cap_frame *frame,
const struct l2cap_frame *source, uint16_t len)
{
--
2.37.3



2022-11-04 21:39:38

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 2/2] monitor/att: Add support for decoding Characteristic Declaration

From: Luiz Augusto von Dentz <[email protected]>

This adds supports for decoding the so called Characteristic
Declaration (0x2803):

> ACL Data RX: Handle 3585 flags 0x02 dlen 76
ATT: Read By Type Response (0x09) len 71
Attribute data length: 7
Attribute data list: 10 entries
Handle: 0x0002
Value: 200300052a
Properties: 0x20
Indicate (0x20)
Value Handle: 0x0003
Value UUID: Service Changed (0x2a05)
Handle: 0x0015
Value: 021600002a
Properties: 0x02
Read (0x02)
Value Handle: 0x0016
Value UUID: Device Name (0x2a00)
Handle: 0x0017
Value: 021800012a
Properties: 0x02
Read (0x02)
Value Handle: 0x0018
Value UUID: Appearance (0x2a01)
Handle: 0x0019
Value: 021a00a62a
Properties: 0x02
Read (0x02)
Value Handle: 0x001a
Value UUID: Central Address Resolution (0x2aa6)
Handle: 0x0029
Value: 102a00372a
Properties: 0x10
Notify (0x10)
Value Handle: 0x002a
Value UUID: Heart Rate Measurement (0x2a37)
Handle: 0x002c
Value: 022d00382a
Properties: 0x02
Read (0x02)
Value Handle: 0x002d
Value UUID: Body Sensor Location (0x2a38)
Handle: 0x002e
Value: 082f00392a
Properties: 0x08
Write (0x08)
Value Handle: 0x002f
Value UUID: Heart Rate Control Point (0x2a39)
Handle: 0x0031
Value: 0a32008a2a
Properties: 0x0a
Read (0x02)
Write (0x08)
Value Handle: 0x0032
Value UUID: First Name (0x2a8a)
Handle: 0x0033
Value: 0a3400902a
Properties: 0x0a
Read (0x02)
Write (0x08)
Value Handle: 0x0034
Value UUID: Last Name (0x2a90)
Handle: 0x0035
Value: 0a36008c2a
Properties: 0x0a
Read (0x02)
Write (0x08)
Value Handle: 0x0036
Value UUID: Gender (0x2a8c)
---
monitor/att.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)

diff --git a/monitor/att.c b/monitor/att.c
index 289f4fc04d9a..efd840d51961 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -273,6 +273,46 @@ static void att_error_response(const struct l2cap_frame *frame)
print_field("Error: %s (0x%2.2x)", str, pdu->error);
}

+static const struct bitfield_data chrc_prop_table[] = {
+ { 0, "Broadcast (0x01)" },
+ { 1, "Read (0x02)" },
+ { 2, "Write Without Response (0x04)" },
+ { 3, "Write (0x08)" },
+ { 4, "Notify (0x10)" },
+ { 5, "Indicate (0x20)" },
+ { 6, "Authorize (0x40)" },
+ { 6, "Extended Properties (0x80)" },
+ { }
+};
+
+static void print_chrc(const struct l2cap_frame *frame)
+{
+ uint8_t prop;
+ uint8_t mask;
+
+ if (!l2cap_frame_get_u8((void *)frame, &prop)) {
+ print_text(COLOR_ERROR, "Property: invalid size");
+ return;
+ }
+
+ print_field(" Properties: 0x%2.2x", prop);
+
+ mask = print_bitfield(6, prop, chrc_prop_table);
+ if (mask)
+ print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)",
+ mask);
+
+ if (!l2cap_frame_print_le16((void *)frame, " Value Handle"))
+ return;
+
+ print_uuid(" Value UUID", frame->data, frame->size);
+}
+
+static void chrc_read(const struct l2cap_frame *frame)
+{
+ print_chrc(frame);
+}
+
static const struct bitfield_data ccc_value_table[] = {
{ 0, "Notification (0x01)" },
{ 1, "Indication (0x02)" },
@@ -2314,6 +2354,7 @@ struct gatt_handler {
void (*write)(const struct l2cap_frame *frame);
void (*notify)(const struct l2cap_frame *frame);
} gatt_handlers[] = {
+ GATT_HANDLER(0x2803, chrc_read, NULL, NULL),
GATT_HANDLER(0x2902, ccc_read, ccc_write, NULL),
GATT_HANDLER(0x2bc4, ase_read, NULL, ase_notify),
GATT_HANDLER(0x2bc5, ase_read, NULL, ase_notify),
--
2.37.3


2022-11-04 22:30:44

by bluez.test.bot

[permalink] [raw]
Subject: RE: [BlueZ,1/2] monitor/att: Add handler support for Read by Type

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=692284

---Test result---

Test Summary:
CheckPatch PASS 2.48 seconds
GitLint PASS 1.63 seconds
Prep - Setup ELL PASS 26.72 seconds
Build - Prep PASS 0.74 seconds
Build - Configure PASS 8.59 seconds
Build - Make PASS 822.68 seconds
Make Check PASS 11.56 seconds
Make Check w/Valgrind PASS 292.16 seconds
Make Distcheck PASS 237.97 seconds
Build w/ext ELL - Configure PASS 8.62 seconds
Build w/ext ELL - Make PASS 85.40 seconds
Incremental Build w/ patches PASS 204.50 seconds
Scan Build PASS 603.42 seconds



---
Regards,
Linux Bluetooth

2022-11-07 19:12:14

by patchwork-bot+bluetooth

[permalink] [raw]
Subject: Re: [PATCH BlueZ 1/2] monitor/att: Add handler support for Read by Type

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <[email protected]>:

On Fri, 4 Nov 2022 14:36:48 -0700 you wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This adds handler support for Read by Type so it can further decode
> the values when the procedure is used.
> ---
> monitor/att.c | 206 ++++++++++++++++++++++++++++++++++--------------
> monitor/l2cap.h | 13 ++-
> 2 files changed, 155 insertions(+), 64 deletions(-)

Here is the summary with links:
- [BlueZ,1/2] monitor/att: Add handler support for Read by Type
(no matching commit)
- [BlueZ,2/2] monitor/att: Add support for decoding Characteristic Declaration
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7e0e08ca5396

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html