2022-11-15 00:41:02

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 1/6] monitor/att: Fix not dequeing att_read on error response

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

If a read/read by type fails it needs to be dequeued otherwise it can
cause the next operation of the same type to return the wrong request
and possible decoding as if it was a different attribute type.
---
monitor/att.c | 109 +++++++++++++++++++++++++++-----------------------
1 file changed, 58 insertions(+), 51 deletions(-)

diff --git a/monitor/att.c b/monitor/att.c
index efd840d51961..d14cbd165697 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -106,27 +106,66 @@ static bool match_read_frame(const void *data, const void *match_data)
return read->chan == frame->chan;
}

-static void print_data_list(const char *label, uint8_t length,
- const struct l2cap_frame *frame)
+static struct att_read *att_get_read(const struct l2cap_frame *frame)
{
struct packet_conn_data *conn;
struct att_conn_data *data;
+
+ conn = packet_get_conn_data(frame->handle);
+ if (!conn)
+ return NULL;
+
+ data = conn->data;
+ if (!data)
+ return NULL;
+
+ return queue_remove_if(data->reads, match_read_frame, (void *)frame);
+}
+
+static void print_attribute(struct gatt_db_attribute *attr)
+{
+ uint16_t handle;
+ const bt_uuid_t *uuid;
+ char label[21];
+
+ handle = gatt_db_attribute_get_handle(attr);
+ if (!handle)
+ goto done;
+
+ uuid = gatt_db_attribute_get_type(attr);
+ if (!uuid)
+ goto done;
+
+ switch (uuid->type) {
+ case BT_UUID16:
+ sprintf(label, "Handle: 0x%4.4x Type", handle);
+ print_field("%s: %s (0x%4.4x)", label,
+ bt_uuid16_to_str(uuid->value.u16),
+ uuid->value.u16);
+ return;
+ case BT_UUID128:
+ sprintf(label, "Handle: 0x%4.4x Type", handle);
+ print_uuid(label, &uuid->value.u128, 16);
+ return;
+ case BT_UUID_UNSPEC:
+ case BT_UUID32:
+ break;
+ }
+
+done:
+ print_field("Handle: 0x%4.4x", handle);
+}
+
+static void print_data_list(const char *label, uint8_t length,
+ const struct l2cap_frame *frame)
+{
struct att_read *read;
uint8_t count;

if (length == 0)
return;

- 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;
+ read = att_get_read(frame);

count = frame->size / length;

@@ -271,6 +310,12 @@ static void att_error_response(const struct l2cap_frame *frame)
pdu->request);
print_field("Handle: 0x%4.4x", le16_to_cpu(pdu->handle));
print_field("Error: %s (0x%2.2x)", str, pdu->error);
+
+ /* Read/Read By Type may create a read object which needs to be dequeued
+ * and freed in case the operation fails.
+ */
+ if (pdu->request == 0x08 || pdu->request == 0x0a)
+ free(att_get_read(frame));
}

static const struct bitfield_data chrc_prop_table[] = {
@@ -2662,36 +2707,6 @@ static struct gatt_db_attribute *get_attribute(const struct l2cap_frame *frame,
return gatt_db_get_attribute(db, handle);
}

-static void print_attribute(struct gatt_db_attribute *attr)
-{
- uint16_t handle = gatt_db_attribute_get_handle(attr);
- const bt_uuid_t *uuid;
- char label[21];
-
- uuid = gatt_db_attribute_get_type(attr);
- if (!uuid)
- goto done;
-
- switch (uuid->type) {
- case BT_UUID16:
- sprintf(label, "Handle: 0x%4.4x Type", handle);
- print_field("%s: %s (0x%4.4x)", label,
- bt_uuid16_to_str(uuid->value.u16),
- uuid->value.u16);
- return;
- case BT_UUID128:
- sprintf(label, "Handle: 0x%4.4x Type", handle);
- print_uuid(label, &uuid->value.u128, 16);
- return;
- case BT_UUID_UNSPEC:
- case BT_UUID32:
- break;
- }
-
-done:
- print_field("Handle: 0x%4.4x", handle);
-}
-
static void print_handle(const struct l2cap_frame *frame, uint16_t handle,
bool rsp)
{
@@ -2746,19 +2761,11 @@ static void att_read_req(const struct l2cap_frame *frame)

static void att_read_rsp(const struct l2cap_frame *frame)
{
- struct packet_conn_data *conn;
- struct att_conn_data *data;
struct att_read *read;

print_hex_field("Value", frame->data, frame->size);

- conn = packet_get_conn_data(frame->handle);
- if (!conn)
- return;
-
- data = conn->data;
-
- read = queue_remove_if(data->reads, match_read_frame, (void *)frame);
+ read = att_get_read(frame);
if (!read)
return;

--
2.37.3



2022-11-15 00:41:11

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 5/6] shared/bap: Fix crash when canceling requests

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

If bt_bap_unref/bap_free is called while there is an ongoing pending
request it may endup calling into bap_notify_ready which will try to
notify ready callbacks while holding a reference, but in case the
reference is already 0 that means it would switch to 1 and back 0
causing a double free.

To prevent that bap_notify_ready now checks that the reference is not 0
with use of bt_bap_ref_safe.
---
src/shared/bap.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index 25369e619051..21aa8aa6c5ca 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -2638,6 +2638,14 @@ struct bt_bap *bt_bap_ref(struct bt_bap *bap)
return bap;
}

+static struct bt_bap *bt_bap_ref_safe(struct bt_bap *bap)
+{
+ if (!bap || !bap->ref_count)
+ return NULL;
+
+ return bt_bap_ref(bap);
+}
+
void bt_bap_unref(struct bt_bap *bap)
{
if (!bap)
@@ -2656,7 +2664,8 @@ static void bap_notify_ready(struct bt_bap *bap)
if (!queue_isempty(bap->pending))
return;

- bt_bap_ref(bap);
+ if (!bt_bap_ref_safe(bap))
+ return;

for (entry = queue_get_entries(bap->ready_cbs); entry;
entry = entry->next) {
--
2.37.3


2022-11-15 00:41:15

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 3/6] shared/bap: Make use of util_iov helpers

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

This make use of util_iov helpers instead of reimplementing them.
---
src/shared/bap.c | 183 +++++++++++++----------------------------------
1 file changed, 51 insertions(+), 132 deletions(-)

diff --git a/src/shared/bap.c b/src/shared/bap.c
index c3c0d596fe91..25369e619051 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -262,76 +262,6 @@ static bool bap_db_match(const void *data, const void *match_data)
return (bdb->db == db);
}

-static void *iov_add(struct iovec *iov, size_t len)
-{
- void *data;
-
- data = iov->iov_base + iov->iov_len;
- iov->iov_len += len;
-
- return data;
-}
-
-static void *iov_add_mem(struct iovec *iov, size_t len, const void *d)
-{
- void *data;
-
- data = iov->iov_base + iov->iov_len;
- iov->iov_len += len;
-
- memcpy(data, d, len);
-
- return data;
-}
-
-static void iov_free(void *data)
-{
- struct iovec *iov = data;
-
- if (!iov)
- return;
-
- free(iov->iov_base);
- free(iov);
-}
-
-static void iov_memcpy(struct iovec *iov, void *src, size_t len)
-{
- iov->iov_base = realloc(iov->iov_base, len);
- iov->iov_len = len;
- memcpy(iov->iov_base, src, len);
-}
-
-static int iov_memcmp(struct iovec *iov1, struct iovec *iov2)
-{
- if (!iov1)
- return 1;
-
- if (!iov2)
- return -1;
-
- if (iov1->iov_len != iov2->iov_len)
- return iov1->iov_len - iov2->iov_len;
-
- return memcmp(iov1->iov_base, iov2->iov_base, iov1->iov_len);
-}
-
-static struct iovec *iov_dup(struct iovec *iov, size_t len)
-{
- struct iovec *dup;
- size_t i;
-
- if (!iov)
- return NULL;
-
- dup = new0(struct iovec, len);
-
- for (i = 0; i < len; i++)
- iov_memcpy(&dup[i], iov[i].iov_base, iov[i].iov_len);
-
- return dup;
-}
-
unsigned int bt_bap_pac_register(bt_bap_pac_func_t added,
bt_bap_pac_func_t removed, void *user_data,
bt_bap_destroy_func_t destroy)
@@ -407,27 +337,27 @@ static void pac_foreach(void *data, void *user_data)
struct bt_pac_metadata *meta;

if (!iov->iov_len) {
- rsp = iov_add(iov, sizeof(*rsp));
+ rsp = util_iov_push(iov, sizeof(*rsp));
rsp->num_pac = 0;
} else
rsp = iov->iov_base;

rsp->num_pac++;

- p = iov_add(iov, sizeof(*p));
+ p = util_iov_push(iov, sizeof(*p));
p->codec.id = pac->codec.id;

if (pac->data) {
p->cc_len = pac->data->iov_len;
- iov_add_mem(iov, p->cc_len, pac->data->iov_base);
+ util_iov_push_mem(iov, p->cc_len, pac->data->iov_base);
} else
p->cc_len = 0;

- meta = iov_add(iov, sizeof(*meta));
+ meta = util_iov_push(iov, sizeof(*meta));

if (pac->metadata) {
meta->len = pac->metadata->iov_len;
- iov_add_mem(iov, meta->len, pac->metadata->iov_base);
+ util_iov_push_mem(iov, meta->len, pac->metadata->iov_base);
} else
meta->len = 0;
}
@@ -814,19 +744,6 @@ static void ase_new(struct bt_ascs *ascs, int i)
ascs->ase[i] = ase;
}

-static void *iov_pull_mem(struct iovec *iov, size_t len)
-{
- void *data = iov->iov_base;
-
- if (iov->iov_len < len)
- return NULL;
-
- iov->iov_base += len;
- iov->iov_len -= len;
-
- return data;
-}
-
static bool bap_codec_equal(const struct bt_bap_codec *c1,
const struct bt_bap_codec *c2)
{
@@ -852,7 +769,7 @@ static struct bt_bap_stream *bap_stream_new(struct bt_bap *bap,
ep->stream = stream;
stream->lpac = lpac;
stream->rpac = rpac;
- stream->cc = iov_dup(data, 1);
+ stream->cc = util_iov_dup(data, 1);
stream->client = client;

queue_push_tail(bap->streams, stream);
@@ -1050,8 +967,8 @@ static void bap_stream_free(void *data)
queue_foreach(stream->links, bap_stream_unlink, stream);
queue_destroy(stream->links, NULL);
stream_io_unref(stream->io);
- iov_free(stream->cc);
- iov_free(stream->meta);
+ util_iov_free(stream->cc, 1);
+ util_iov_free(stream->meta, 1);
free(stream);
}

@@ -1454,13 +1371,13 @@ static uint8_t stream_config(struct bt_bap_stream *stream, struct iovec *cc,
/* TODO: Wait for pac->ops response */
ascs_ase_rsp_success(rsp, stream->ep->id);

- if (!iov_memcmp(stream->cc, cc)) {
+ if (!util_iov_memcmp(stream->cc, cc)) {
stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG);
return 0;
}

- iov_free(stream->cc);
- stream->cc = iov_dup(cc, 1);
+ util_iov_free(stream->cc, 1);
+ stream->cc = util_iov_dup(cc, 1);

if (pac->ops && pac->ops->config)
pac->ops->config(stream, cc, NULL, ep_config_cb,
@@ -1497,7 +1414,7 @@ static uint8_t ep_config(struct bt_bap_endpoint *ep, struct bt_bap *bap,
if (iov->iov_len < req->cc_len)
return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;

- cc.iov_base = iov_pull_mem(iov, req->cc_len);
+ cc.iov_base = util_iov_pull_mem(iov, req->cc_len);
cc.iov_len = req->cc_len;

if (!bap_print_cc(cc.iov_base, cc.iov_len, bap->debug_func,
@@ -1548,7 +1465,7 @@ static uint8_t ascs_config(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_config *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

DBG(bap, "codec 0x%02x phy 0x%02x latency %u", req->codec.id, req->phy,
req->latency);
@@ -1616,7 +1533,7 @@ static uint8_t ascs_qos(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_ascs_qos *req;
struct bt_bap_qos qos;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

memset(&qos, 0, sizeof(qos));

@@ -1653,8 +1570,8 @@ static uint8_t stream_enable(struct bt_bap_stream *stream, struct iovec *meta,

ascs_ase_rsp_success(rsp, stream->ep->id);

- iov_free(stream->meta);
- stream->meta = iov_dup(meta, 1);
+ util_iov_free(stream->meta, 1);
+ stream->meta = util_iov_dup(meta, 1);

stream_set_state(stream, BT_BAP_STREAM_STATE_ENABLING);

@@ -1677,7 +1594,7 @@ static bool bap_print_ltv(const char *label, void *data, size_t len,
util_debug(func, user_data, "Length %zu", iov.iov_len);

for (i = 0; iov.iov_len > 1; i++) {
- struct bt_ltv *ltv = iov_pull_mem(&iov, sizeof(*ltv));
+ struct bt_ltv *ltv = util_iov_pull_mem(&iov, sizeof(*ltv));
uint8_t *data;

if (!ltv) {
@@ -1689,7 +1606,7 @@ static bool bap_print_ltv(const char *label, void *data, size_t len,
util_debug(func, user_data, "%s #%u: len %u type %u",
label, i, ltv->len, ltv->type);

- data = iov_pull_mem(&iov, ltv->len - 1);
+ data = util_iov_pull_mem(&iov, ltv->len - 1);
if (!data) {
util_debug(func, user_data, "Unable to parse %s",
label);
@@ -1728,7 +1645,7 @@ static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap,
return 0;
}

- meta.iov_base = iov_pull_mem(iov, req->meta.len);
+ meta.iov_base = util_iov_pull_mem(iov, req->meta.len);
meta.iov_len = req->meta.len;

if (!bap_print_metadata(meta.iov_base, meta.iov_len, bap->debug_func,
@@ -1756,7 +1673,7 @@ static uint8_t ascs_enable(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_enable *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->meta.ase);
if (!ep) {
@@ -1820,7 +1737,7 @@ static uint8_t ascs_start(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_start *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->ase);
if (!ep) {
@@ -1892,7 +1809,7 @@ static uint8_t ascs_disable(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_disable *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->ase);
if (!ep) {
@@ -1967,7 +1884,7 @@ static uint8_t ascs_stop(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_stop *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->ase);
if (!ep) {
@@ -1995,8 +1912,8 @@ static uint8_t stream_metadata(struct bt_bap_stream *stream, struct iovec *meta,

ascs_ase_rsp_success(rsp, stream->ep->id);

- iov_free(stream->meta);
- stream->meta = iov_dup(meta, 1);
+ util_iov_free(stream->meta, 1);
+ stream->meta = util_iov_dup(meta, 1);

return 0;
}
@@ -2032,7 +1949,7 @@ static uint8_t ascs_metadata(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_metadata *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->ase);
if (!ep) {
@@ -2076,7 +1993,7 @@ static uint8_t ascs_release(struct bt_ascs *ascs, struct bt_bap *bap,
struct bt_bap_endpoint *ep;
struct bt_ascs_release *req;

- req = iov_pull_mem(iov, sizeof(*req));
+ req = util_iov_pull_mem(iov, sizeof(*req));

ep = bap_get_endpoint_id(bap, bap->ldb, req->ase);
if (!ep) {
@@ -2177,7 +2094,7 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
return;
}

- hdr = iov_pull_mem(&iov, sizeof(*hdr));
+ hdr = util_iov_pull_mem(&iov, sizeof(*hdr));
rsp = ascs_ase_cp_rsp_new(hdr->op);

for (handler = handlers; handler && handler->str; handler++) {
@@ -2214,7 +2131,7 @@ respond:
gatt_db_attribute_notify(attrib, rsp->iov_base, rsp->iov_len, att);
gatt_db_attribute_write_result(attrib, id, ret);

- iov_free(rsp);
+ util_iov_free(rsp, 1);
}

static struct bt_ascs *ascs_new(struct gatt_db *db)
@@ -2333,8 +2250,8 @@ static struct bt_bap_pac *bap_pac_new(struct bt_bap_db *bdb, const char *name,
pac->name = name ? strdup(name) : NULL;
pac->type = type;
pac->codec = *codec;
- pac->data = iov_dup(data, 1);
- pac->metadata = iov_dup(metadata, 1);
+ pac->data = util_iov_dup(data, 1);
+ pac->metadata = util_iov_dup(metadata, 1);

if (qos)
pac->qos = *qos;
@@ -2347,8 +2264,8 @@ static void bap_pac_free(void *data)
struct bt_bap_pac *pac = data;

free(pac->name);
- iov_free(pac->metadata);
- iov_free(pac->data);
+ util_iov_free(pac->metadata, 1);
+ util_iov_free(pac->data, 1);
free(pac);
}

@@ -2769,7 +2686,7 @@ static void bap_parse_pacs(struct bt_bap *bap, uint8_t type,
};
int i;

- rsp = iov_pull_mem(&iov, sizeof(*rsp));
+ rsp = util_iov_pull_mem(&iov, sizeof(*rsp));
if (!rsp) {
DBG(bap, "Unable to parse PAC");
return;
@@ -2784,7 +2701,7 @@ static void bap_parse_pacs(struct bt_bap *bap, uint8_t type,
struct bt_pac_metadata *meta;
struct iovec data, metadata;

- p = iov_pull_mem(&iov, sizeof(*p));
+ p = util_iov_pull_mem(&iov, sizeof(*p));
if (!p) {
DBG(bap, "Unable to parse PAC");
return;
@@ -2796,13 +2713,13 @@ static void bap_parse_pacs(struct bt_bap *bap, uint8_t type,
bap->debug_data))
return;

- cc = iov_pull_mem(&iov, p->cc_len);
+ cc = util_iov_pull_mem(&iov, p->cc_len);
if (!cc) {
DBG(bap, "Unable to parse PAC codec capabilities");
return;
}

- meta = iov_pull_mem(&iov, sizeof(*meta));
+ meta = util_iov_pull_mem(&iov, sizeof(*meta));
if (!meta) {
DBG(bap, "Unable to parse PAC metadata");
return;
@@ -2814,7 +2731,7 @@ static void bap_parse_pacs(struct bt_bap *bap, uint8_t type,
metadata.iov_len = meta->len;
metadata.iov_base = meta->data;

- iov_pull_mem(&iov, meta->len);
+ util_iov_pull_mem(&iov, meta->len);

pac = bap_pac_new(bap->rdb, NULL, type, &p->codec, NULL, &data,
&metadata);
@@ -3089,7 +3006,7 @@ static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep,
uint32_t pd_min, pd_max, ppd_min, ppd_max;
int i;

- cfg = iov_pull_mem(iov, sizeof(*cfg));
+ cfg = util_iov_pull_mem(iov, sizeof(*cfg));
if (!cfg) {
DBG(bap, "Unable to parse Config Status");
return;
@@ -3113,14 +3030,14 @@ static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep,
}

for (i = 0; iov->iov_len >= sizeof(*cc); i++) {
- cc = iov_pull_mem(iov, sizeof(*cc));
+ cc = util_iov_pull_mem(iov, sizeof(*cc));
if (!cc)
break;

DBG(bap, "Codec Config #%u: type 0x%02x len %u", i,
cc->type, cc->len);

- iov_pull_mem(iov, cc->len - 1);
+ util_iov_pull_mem(iov, cc->len - 1);
}

/* Any previously applied codec configuration may be cached by the
@@ -3160,7 +3077,7 @@ static void ep_status_config(struct bt_bap *bap, struct bt_bap_endpoint *ep,
if (!ep->stream->cc)
ep->stream->cc = new0(struct iovec, 1);

- iov_memcpy(ep->stream->cc, cfg->cc, cfg->cc_len);
+ util_iov_memcpy(ep->stream->cc, cfg->cc, cfg->cc_len);
}

static void bap_stream_config_cfm_cb(struct bt_bap_stream *stream, int err)
@@ -3200,7 +3117,7 @@ static void ep_status_qos(struct bt_bap *bap, struct bt_bap_endpoint *ep,
uint16_t sdu;
uint16_t latency;

- qos = iov_pull_mem(iov, sizeof(*qos));
+ qos = util_iov_pull_mem(iov, sizeof(*qos));
if (!qos) {
DBG(bap, "Unable to parse QoS Status");
return;
@@ -3236,7 +3153,7 @@ static void ep_status_metadata(struct bt_bap *bap, struct bt_bap_endpoint *ep,
{
struct bt_ascs_ase_status_metadata *meta;

- meta = iov_pull_mem(iov, sizeof(*meta));
+ meta = util_iov_pull_mem(iov, sizeof(*meta));
if (!meta) {
DBG(bap, "Unable to parse Metadata Status");
return;
@@ -3255,7 +3172,7 @@ static void bap_ep_set_status(struct bt_bap *bap, struct bt_bap_endpoint *ep,
.iov_len = length,
};

- rsp = iov_pull_mem(&iov, sizeof(*rsp));
+ rsp = util_iov_pull_mem(&iov, sizeof(*rsp));
if (!rsp)
return;

@@ -3391,7 +3308,8 @@ static void append_group(void *data, void *user_data)
size_t i;

for (i = 0; i < req->len; i++)
- iov_add_mem(iov, req->iov[i].iov_len, req->iov[i].iov_base);
+ util_iov_push_mem(iov, req->iov[i].iov_len,
+ req->iov[i].iov_base);
}

static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req)
@@ -3414,10 +3332,11 @@ static bool bap_send(struct bt_bap *bap, struct bt_bap_req *req)
hdr.op = req->op;
hdr.num = 1 + queue_length(req->group);

- iov_add_mem(&iov, sizeof(hdr), &hdr);
+ util_iov_push_mem(&iov, sizeof(hdr), &hdr);

for (i = 0; i < req->len; i++)
- iov_add_mem(&iov, req->iov[i].iov_len, req->iov[i].iov_base);
+ util_iov_push_mem(&iov, req->iov[i].iov_len,
+ req->iov[i].iov_base);

/* Append the request group with the same opcode */
queue_foreach(req->group, append_group, &iov);
@@ -4011,7 +3930,7 @@ static struct bt_bap_req *bap_req_new(struct bt_bap_stream *stream,
req->id = ++id;
req->stream = stream;
req->op = op;
- req->iov = iov_dup(iov, len);
+ req->iov = util_iov_dup(iov, len);
req->len = len;
req->func = func;
req->user_data = user_data;
--
2.37.3


2022-11-15 00:41:17

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 6/6] unit: Introduce test-bap

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

Test Summary
------------
BAP/UCL/DISC/BV-01-C Passed
BAP/UCL/DISC/BV-02-C Passed
BAP/UCL/DISC/BV-06-C Passed
BAP/UCL/DISC/BV-05-C Passed
BAP/UCL/DISC/BV-03-C Passed
BAP/UCL/DISC/BV-04-C Passed
Total: 6, Passed: 6 (100.0%), Failed: 0, Not Run: 0
---
Makefile.am | 6 +
unit/test-bap.c | 568 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 574 insertions(+)
create mode 100644 unit/test-bap.c

diff --git a/Makefile.am b/Makefile.am
index 7041f8eeb52b..aa3a5e053cd8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -569,6 +569,12 @@ unit_test_gattrib_LDADD = lib/libbluetooth-internal.la \
src/libshared-glib.la \
$(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt

+unit_tests += unit/test-bap
+
+unit_test_bap_SOURCES = unit/test-bap.c
+unit_test_bap_LDADD = src/libshared-glib.la \
+ lib/libbluetooth-internal.la $(GLIB_LIBS)
+
if MIDI
unit_tests += unit/test-midi
unit_test_midi_CPPFLAGS = $(AM_CPPFLAGS) $(ALSA_CFLAGS) -DMIDI_TEST
diff --git a/unit/test-bap.c b/unit/test-bap.c
new file mode 100644
index 000000000000..afeefac84091
--- /dev/null
+++ b/unit/test-bap.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2022 Intel Corporation.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "src/shared/util.h"
+#include "src/shared/io.h"
+#include "src/shared/tester.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/bap.h"
+
+struct test_data {
+ struct bt_gatt_client *client;
+ struct bt_bap *bap;
+ size_t iovcnt;
+ struct iovec *iov;
+};
+
+#define iov_data(args...) ((const struct iovec[]) { args })
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct iovec iov[] = { args }; \
+ static struct test_data data; \
+ data.iovcnt = ARRAY_SIZE(iov_data(args)); \
+ data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
+ tester_add(name, &data, test_setup, function, \
+ test_teardown); \
+ } while (0)
+
+static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
+{
+ if (!success)
+ tester_setup_failed();
+ else
+ tester_setup_complete();
+}
+
+/* GATT Discover All procedure */
+static const struct iovec setup_data[] = {
+ /* ATT: Exchange MTU Response (0x03) len 2
+ * Server RX MTU: 64
+ */
+ IOV_DATA(0x02, 0x40, 0x00),
+ /* ATT: Exchange MTU Request (0x02) len 2
+ * Client RX MTU: 64
+ */
+ IOV_DATA(0x03, 0x40, 0x00),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute type: Server Supported Features (0x2b3a)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+ /*
+ * ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Primary Service (0x2800)
+ */
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ /*
+ * ATT: Read By Group Type Response (0x11) len 37
+ * Attribute data length: 6
+ * Attribute group list: 2 entries
+ * Handle range: 0x0001-0x0013
+ * UUID: Published Audio Capabilities (0x1850)
+ * Handle range: 0x0014-0x0023
+ * UUID: Audio Stream Control (0x184e)
+ */
+ IOV_DATA(0x11, 0x06,
+ 0x01, 0x00, 0x13, 0x00, 0x50, 0x18,
+ 0x14, 0x00, 0x23, 0x00, 0x4e, 0x18),
+ /* ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0024-0xffff
+ * Attribute group type: Primary Service (0x2800)
+ */
+ IOV_DATA(0x10, 0x24, 0x00, 0xff, 0xff, 0x00, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0024
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x10, 0x24, 0x00, 0x0a),
+ /* ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Secondary Service (0x2801)
+ */
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0023
+ * Attribute group type: Include (0x2802)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x02, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0023
+ * Attribute type: Characteristic (0x2803)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x03, 0x28),
+ /* ATT: Read By Type Response (0x09) len 57
+ * Attribute data length: 7
+ * Attribute data list: 8 entries
+ * Handle: 0x0002
+ * Value: 120300c92b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0003
+ * Value UUID: Sink PAC (0x2bc9)
+ * Handle: 0x0005
+ * Value: 120600ca2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0006
+ * Value UUID: Sink Audio Locations (0x2bca)
+ * Handle: 0x0008
+ * Value: 120900cb2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0009
+ * Value UUID: Source PAC (0x2bcb)
+ * Handle: 0x000b
+ * Value: 120c00cc2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x000c
+ * Value UUID: Source Audio Locations (0x2bcc)
+ * Handle: 0x000e
+ * Value: 120f00cd2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x000f
+ * Value UUID: Available Audio Contexts (0x2bcd)
+ * Handle: 0x0011
+ * Value: 121200ce2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0012
+ * Value UUID: Supported Audio Contexts (0x2bce)
+ * Handle: 0x0015
+ * Value: 121600c42b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0016
+ * Value UUID: Sink ASE (0x2bc4)
+ * Handle: 0x0018
+ * Value: 121900c42b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0019
+ * Value UUID: Sink ASE (0x2bc4)
+ */
+ IOV_DATA(0x09, 0x07,
+ 0x02, 0x00, 0x12, 0x03, 0x00, 0xc9, 0x2b,
+ 0x05, 0x00, 0x12, 0x06, 0x00, 0xca, 0x2b,
+ 0x08, 0x00, 0x12, 0x09, 0x00, 0xcb, 0x2b,
+ 0x0b, 0x00, 0x12, 0x0c, 0x00, 0xcc, 0x2b,
+ 0x0e, 0x00, 0x12, 0x0f, 0x00, 0xcd, 0x2b,
+ 0x11, 0x00, 0x12, 0x12, 0x00, 0xce, 0x2b,
+ 0x15, 0x00, 0x12, 0x16, 0x00, 0xc4, 0x2b,
+ 0x18, 0x00, 0x12, 0x19, 0x00, 0xc4, 0x2b),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0023
+ * Attribute type: Characteristic (0x2803)
+ */
+ IOV_DATA(0x08, 0x19, 0x00, 0x23, 0x00, 0x03, 0x28),
+ /* ATT: Read By Type Response (0x09) len 22
+ * Attribute data length: 7
+ * Attribute data list: 3 entries
+ * Handle: 0x001b
+ * Value: 121c00c52b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x001c
+ * Value UUID: Source ASE (0x2bc5)
+ * Handle: 0x001e
+ * Value: 121f00c52b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x001f
+ * Value UUID: Source ASE (0x2bc5)
+ * Handle: 0x0021
+ * Value: 182200c62b
+ * Properties: 0x18
+ * Write (0x08)
+ * Notify (0x10)
+ * Value Handle: 0x0022
+ * Value UUID: ASE Control Point (0x2bc6)
+ */
+ IOV_DATA(0x09, 0x07,
+ 0x1b, 0x00, 0x12, 0x1c, 0x00, 0xc5, 0x2b,
+ 0x1e, 0x00, 0x12, 0x1f, 0x00, 0xc5, 0x2b,
+ 0x21, 0x00, 0x18, 0x22, 0x00, 0xc6, 0x2b),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0022-0x0023
+ * Attribute type: Characteristic (0x2803)
+ */
+ IOV_DATA(0x08, 0x22, 0x00, 0x23, 0x00, 0x03, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0022
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x23, 0x00, 0x0a),
+ /* ACL Data TX: Handle 42 flags 0x00 dlen 11
+ * ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute type: Database Hash (0x2b2a)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+};
+
+static void print_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ if (tester_use_debug())
+ tester_debug("%s%s", prefix, str);
+}
+
+static void test_setup(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct bt_att *att;
+ struct gatt_db *db;
+ struct io *io;
+
+ io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data));
+ g_assert(io);
+
+ att = bt_att_new(io_get_fd(io), false);
+ g_assert(att);
+
+ bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
+
+ db = gatt_db_new();
+ g_assert(db);
+
+ data->client = bt_gatt_client_new(db, att, 64, 0);
+ g_assert(data->client);
+
+ bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
+ NULL);
+
+ bt_gatt_client_ready_register(data->client, client_ready_cb, data,
+ NULL);
+
+ bt_att_unref(att);
+ gatt_db_unref(db);
+}
+
+static void test_complete_cb(const void *user_data)
+{
+ tester_test_passed();
+}
+
+static void test_client(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct io *io;
+ struct gatt_db *db;
+
+ io = tester_setup_io(data->iov, data->iovcnt);
+ g_assert(io);
+
+ tester_io_set_complete_func(test_complete_cb);
+
+ db = gatt_db_new();
+ g_assert(db);
+
+ data->bap = bt_bap_new(db, bt_gatt_client_get_db(data->client));
+ g_assert(data->bap);
+
+ bt_bap_set_debug(data->bap, print_debug, "bt_bap:", NULL);
+
+ bt_bap_attach(data->bap, data->client);
+}
+
+static void test_teardown(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+
+ bt_bap_unref(data->bap);
+ bt_gatt_client_unref(data->client);
+ util_iov_free(data->iov, data->iovcnt);
+
+ tester_teardown_complete();
+}
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x0003 Type: Sink PAC (0x2bc9)
+ * ATT: Read Response (0x0b) len 24
+ * Value: 010600000000100301ff0002020302030305041e00f00000
+ * Handle: 0x0003 Type: Sink PAC (0x2bc9)
+ * Number of PAC(s): 1
+ * PAC #0:
+ * Codec: LC3 (0x06)
+ * Codec Specific Capabilities #0: len 0x03 type 0x01
+ * Sampling Frequencies: 0x00ff
+ * 8 Khz (0x0001)
+ * 11.25 Khz (0x0002)
+ * 16 Khz (0x0004)
+ * 22.05 Khz (0x0008)
+ * 24 Khz (0x0010)
+ * 32 Khz (0x0020)
+ * 44.1 Khz (0x0040)
+ * 48 Khz (0x0080)
+ * Codec Specific Capabilities #1: len 0x02 type 0x02
+ * Frame Duration: 0x0003
+ * 7.5 ms (0x01)
+ * 10 ms (0x02)
+ * Codec Specific Capabilities #2: len 0x02 type 0x03
+ * Audio Channel Count: 0x03
+ * 1 channel (0x01)
+ * 2 channels (0x02)
+ * Codec Specific Capabilities #3: len 0x05 type 0x04
+ * Frame Length: 30 (0x001e) - 240 (0x00f0)
+ * ATT: Read Request (0x0a) len 2
+ * Handle: 0x0006 Type: Sink Audio Location (0x2bca)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 03000000
+ * Handle: 0x0006 Type: Sink Audio Locations (0x2bca)
+ * Location: 0x00000003
+ * Front Left (0x00000001)
+ * Front Right (0x00000002)
+ */
+#define DISC_SINK_PAC \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
+ 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
+ 0x1e, 0x00, 0xf0, 0x00, 0x00), \
+ IOV_DATA(0x0a, 0x06, 0x00), \
+ IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00)
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x0009 Type: Source PAC (0x2bcb)
+ * ATT: Read Response (0x0b) len 24
+ * Value: 010600000000100301ff0002020302030305041e00f00000
+ * Handle: 0x0009 Type: Source PAC (0x2bcb)
+ * Number of PAC(s): 1
+ * PAC #0:
+ * Codec: LC3 (0x06)
+ * Codec Specific Capabilities #0: len 0x03 type 0x01
+ * Sampling Frequencies: 0x00ff
+ * 8 Khz (0x0001)
+ * 11.25 Khz (0x0002)
+ * 16 Khz (0x0004)
+ * 22.05 Khz (0x0008)
+ * 24 Khz (0x0010)
+ * 32 Khz (0x0020)
+ * 44.1 Khz (0x0040)
+ * 48 Khz (0x0080)
+ * Codec Specific Capabilities #1: len 0x02 type 0x02
+ * Frame Duration: 0x0003
+ * 7.5 ms (0x01)
+ * 10 ms (0x02)
+ * Codec Specific Capabilities #2: len 0x02 type 0x03
+ * Audio Channel Count: 0x03
+ * 1 channel (0x01)
+ * 2 channels (0x02)
+ * Codec Specific Capabilities #3: len 0x05 type 0x04
+ * Frame Length: 30 (0x001e) - 240 (0x00f0)
+ * ATT: Read Request (0x0a) len 2
+ * Handle: 0x000c Type: Source Audio Location (0x2bcc)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 03000000
+ * Handle: 0x000c Type: Source Audio Locations (0x2bcc)
+ * Location: 0x00000003
+ * Front Left (0x00000001)
+ * Front Right (0x00000002)
+ */
+#define DISC_SOURCE_PAC \
+ DISC_SINK_PAC, \
+ IOV_DATA(0x0a, 0x09, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
+ 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
+ 0x1e, 0x00, 0xf0, 0x00, 0x00), \
+ IOV_DATA(0x0a, 0x0c, 0x00), \
+ IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00)
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
+ * ATT: Read Response (0x0b) len 4
+ * Value: ff0f0e00
+ * Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
+ */
+#define DISC_CTX \
+ DISC_SOURCE_PAC, \
+ IOV_DATA(0x0a, 0x0f, 0x00), \
+ IOV_DATA(0x0b, 0xff, 0x0f, 0x0e, 0x00)
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
+ * ATT: Read Response (0x0b) len 4
+ * Value: ff0f0e00
+ * Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
+ */
+#define DISC_SUP_CTX \
+ DISC_CTX, \
+ IOV_DATA(0x0a, 0x12, 0x00), \
+ IOV_DATA(0x0b, 0xff, 0x0f, 0x0e, 0x00)
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x0016 Type: Sink ASE (0x2bc4)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 0100
+ * Handle: 0x0016 Type: Sink ASE (0x2bc4)
+ * ATT: Write Request (0x12) len 4
+ * Handle: 0x0017 Type: Client Characteristic Configuration (0x2902)
+ * Data: 0100
+ * Notification (0x01)
+ * ATT: Write Response (0x13) len 0
+ * ATT: Read Request (0x0a) len 2
+ * Handle: 0x0019 Type: Sink ASE (0x2bc4)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 0200
+ * Handle: 0x0019 Type: Sink ASE (0x2bc4)
+ * ATT: Write Request (0x12) len 4
+ * Handle: 0x001a Type: Client Characteristic Configuration (0x2902)
+ * Data: 0100
+ * Notification (0x01)
+ * ATT: Write Response (0x13) len 0
+ */
+#define DISC_SINK_ASE \
+ DISC_SUP_CTX, \
+ IOV_DATA(0x0a, 0x16, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x00), \
+ IOV_DATA(0x12, 0x17, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ IOV_DATA(0x0a, 0x19, 0x00), \
+ IOV_DATA(0x0b, 0x02, 0x00), \
+ IOV_DATA(0x12, 0x1a, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+/* ATT: Read Request (0x0a) len 2
+ * Handle: 0x001c Type: Source ASE (0x2bc5)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 0300
+ * Handle: 0x001c Type: Source ASE (0x2bc5)
+ * ATT: Write Request (0x12) len 4
+ * Handle: 0x001d Type: Client Characteristic Configuration (0x2902)
+ * Data: 0100
+ * Notification (0x01)
+ * ATT: Write Response (0x13) len 0
+ * ATT: Read Request (0x0a) len 2
+ * Handle: 0x001f Type: Source ASE (0x2bc5)
+ * ATT: Read Response (0x0b) len 4
+ * Value: 0400
+ * Handle: 0x001f Type: Source ASE (0x2bc5)
+ * ATT: Write Request (0x12) len 4
+ * Handle: 0x0020 Type: Client Characteristic Configuration (0x2902)
+ * Data: 0100
+ * Notification (0x01)
+ * ATT: Write Response (0x13) len 0
+ * ATT: Write Request (0x12) len 4
+ * Handle: 0x0023 Type: Client Characteristic Configuration (0x2902)
+ * Data: 0100
+ * Notification (0x01)
+ * ATT: Write Response (0x13) len 0
+ */
+#define DISC_SOURCE_ASE \
+ DISC_SINK_ASE, \
+ IOV_DATA(0x0a, 0x1c, 0x00), \
+ IOV_DATA(0x0b, 0x03, 0x00), \
+ IOV_DATA(0x12, 0x1d, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ IOV_DATA(0x0a, 0x1f, 0x00), \
+ IOV_DATA(0x0b, 0x04, 0x00), \
+ IOV_DATA(0x12, 0x20, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ IOV_DATA(0x12, 0x23, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+static void test_disc(void)
+{
+ /* The IUT discovers the characteristics specified in the PAC
+ * Characteristic and Location Characteristic columns in Table 4.4.
+ * The IUT reads the values of the characteristics specified in the PAC
+ * Characteristic and Location Characteristic columns.
+ */
+ define_test("BAP/UCL/DISC/BV-01-C", test_client, DISC_SINK_PAC);
+ define_test("BAP/UCL/DISC/BV-02-C", test_client, DISC_SOURCE_PAC);
+
+ /* BAP/UCL/DISC/BV-06-C [Discover Available Audio Contexts]
+ *
+ * The IUT successfully reads the value of the Available Audio Contexts
+ * characteristic on the LowerTester.
+ */
+ define_test("BAP/UCL/DISC/BV-06-C", test_client, DISC_CTX);
+
+ /* BAP/UCL/DISC/BV-05-C [Discover Supported Audio Contexts]
+ *
+ * The IUT successfully reads the value of the Supported Audio Contexts
+ * characteristic on the Lower Tester.
+ */
+ define_test("BAP/UCL/DISC/BV-05-C", test_client, DISC_SUP_CTX);
+
+ /* BAP/UCL/DISC/BV-03-C [Discover Sink ASE_ID]
+ * BAP/UCL/DISC/BV-04-C [Discover Source ASE_ID]
+ *
+ * The IUT successfully reads the ASE_ID values of each discovered ASE
+ * characteristic on the LowerTester.
+ */
+ define_test("BAP/UCL/DISC/BV-03-C", test_client, DISC_SINK_ASE);
+ define_test("BAP/UCL/DISC/BV-04-C", test_client, DISC_SOURCE_ASE);
+}
+
+int main(int argc, char *argv[])
+{
+ tester_init(&argc, &argv);
+
+ test_disc();
+
+ return tester_run();
+}
--
2.37.3


2022-11-15 00:42:02

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 4/6] shared/tester: Add tester_io_set_complete_func

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

This adds tester_io_set_complete_func which can be used to set a
callback when all iovec has been sent/received.
---
src/shared/tester.c | 16 ++++++++++++++++
src/shared/tester.h | 1 +
2 files changed, 17 insertions(+)

diff --git a/src/shared/tester.c b/src/shared/tester.c
index e88dfabdc37c..1feaba48335c 100644
--- a/src/shared/tester.c
+++ b/src/shared/tester.c
@@ -89,6 +89,7 @@ struct test_case {
tester_data_func_t test_func;
tester_data_func_t teardown_func;
tester_data_func_t post_teardown_func;
+ tester_data_func_t io_complete_func;
gdouble start_time;
gdouble end_time;
unsigned int timeout;
@@ -913,6 +914,9 @@ static bool test_io_send(struct io *io, void *user_data)

g_assert_cmpint(len, ==, iov->iov_len);

+ if (!test->iovcnt && test->io_complete_func)
+ test->io_complete_func(test->test_data);
+
return false;
}

@@ -937,10 +941,15 @@ static bool test_io_recv(struct io *io, void *user_data)

g_assert_cmpint(len, ==, iov->iov_len);

+ if (memcmp(buf, iov->iov_base, len))
+ tester_monitor('!', 0x0004, 0x0000, iov->iov_base, len);
+
g_assert(memcmp(buf, iov->iov_base, len) == 0);

if (test->iovcnt)
io_set_write_handler(io, test_io_send, NULL, NULL);
+ else if (test->io_complete_func)
+ test->io_complete_func(test->test_data);

return true;
}
@@ -1004,6 +1013,13 @@ void tester_io_send(void)
io_set_write_handler(ios[1], test_io_send, NULL, NULL);
}

+void tester_io_set_complete_func(tester_data_func_t func)
+{
+ struct test_case *test = tester_get_test();
+
+ test->io_complete_func = func;
+}
+
int tester_run(void)
{
int ret;
diff --git a/src/shared/tester.h b/src/shared/tester.h
index c28f61e7fd6b..49610185a444 100644
--- a/src/shared/tester.h
+++ b/src/shared/tester.h
@@ -78,3 +78,4 @@ void tester_wait(unsigned int seconds, tester_wait_func_t func,

struct io *tester_setup_io(const struct iovec *iov, int iovcnt);
void tester_io_send(void);
+void tester_io_set_complete_func(tester_data_func_t func);
--
2.37.3


2022-11-15 19:45:08

by patchwork-bot+bluetooth

[permalink] [raw]
Subject: Re: [PATCH BlueZ 1/6] monitor/att: Fix not dequeing att_read on error response

Hello:

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

On Mon, 14 Nov 2022 16:30:33 -0800 you wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> If a read/read by type fails it needs to be dequeued otherwise it can
> cause the next operation of the same type to return the wrong request
> and possible decoding as if it was a different attribute type.
> ---
> monitor/att.c | 109 +++++++++++++++++++++++++++-----------------------
> 1 file changed, 58 insertions(+), 51 deletions(-)

Here is the summary with links:
- [BlueZ,1/6] monitor/att: Fix not dequeing att_read on error response
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=b3a8f8fea99b
- [BlueZ,2/6] shared/util: Add iovec helpers
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7c2e276d9e7c
- [BlueZ,3/6] shared/bap: Make use of util_iov helpers
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f96bccd80979
- [BlueZ,4/6] shared/tester: Add tester_io_set_complete_func
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=918c73acb778
- [BlueZ,5/6] shared/bap: Fix crash when canceling requests
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7fcd6889fb13
- [BlueZ,6/6] unit: Introduce test-bap
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=1ebbfee34517

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