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
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
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
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