Skip to content

Commit 53531e3

Browse files
committed
Bluetooth: Host: Fix multiple notify issue
Use a single PDU with the list of tuples of notification handle values, rather than multiple PDUs. Signed-off-by: Lang Xie <[email protected]>
1 parent 6388778 commit 53531e3

File tree

1 file changed

+89
-80
lines changed

1 file changed

+89
-80
lines changed

subsys/bluetooth/host/gatt.c

Lines changed: 89 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,42 +2061,10 @@ struct notify_data {
20612061
};
20622062
};
20632063

2064-
#if defined(CONFIG_BT_GATT_NOTIFY_MULTIPLE)
2065-
2066-
static struct net_buf *nfy_mult[CONFIG_BT_MAX_CONN];
2067-
2068-
static int gatt_notify_mult_send(struct bt_conn *conn, struct net_buf **buf)
2069-
{
2070-
int ret;
2071-
2072-
ret = bt_att_send(conn, *buf);
2073-
if (ret < 0) {
2074-
net_buf_unref(*buf);
2075-
}
2076-
2077-
*buf = NULL;
2078-
2079-
return ret;
2080-
}
2081-
2082-
static void notify_mult_process(struct k_work *work)
2083-
{
2084-
int i;
2085-
2086-
/* Send to any connection with an allocated buffer */
2087-
for (i = 0; i < ARRAY_SIZE(nfy_mult); i++) {
2088-
struct net_buf **buf = &nfy_mult[i];
2089-
2090-
if (*buf) {
2091-
struct bt_conn *conn = bt_conn_lookup_index(i);
2092-
2093-
gatt_notify_mult_send(conn, buf);
2094-
bt_conn_unref(conn);
2095-
}
2096-
}
2097-
}
2064+
static bool gatt_find_by_uuid(struct notify_data *found,
2065+
const struct bt_uuid *uuid);
20982066

2099-
K_WORK_DEFINE(nfy_mult_work, notify_mult_process);
2067+
#if defined(CONFIG_BT_GATT_NOTIFY_MULTIPLE)
21002068

21012069
static bool gatt_cf_notify_multi(struct bt_conn *conn)
21022070
{
@@ -2110,47 +2078,73 @@ static bool gatt_cf_notify_multi(struct bt_conn *conn)
21102078
return CF_NOTIFY_MULTI(cfg);
21112079
}
21122080

2113-
static int gatt_notify_mult(struct bt_conn *conn, uint16_t handle,
2114-
struct bt_gatt_notify_params *params)
2081+
static int gatt_notify_mult(struct bt_conn *conn, uint16_t num_params,
2082+
struct bt_gatt_notify_params *params)
21152083
{
2116-
struct net_buf **buf = &nfy_mult[bt_conn_index(conn)];
2084+
struct net_buf *buf;
21172085
struct bt_att_notify_mult *nfy;
2118-
2119-
/* Check if we can fit more data into it, in case it doesn't fit send
2120-
* the existing buffer and proceed to create a new one
2121-
*/
2122-
if (*buf && ((net_buf_tailroom(*buf) < sizeof(*nfy) + params->len) ||
2123-
!bt_att_tx_meta_data_match(*buf, params->func, params->user_data))) {
2124-
int ret;
2125-
2126-
ret = gatt_notify_mult_send(conn, buf);
2127-
if (ret < 0) {
2128-
return ret;
2086+
struct notify_data data;
2087+
uint16_t pdu_len = 0;
2088+
2089+
for (uint16_t i = 0; i < num_params; i++) {
2090+
data.attr = params[i].attr;
2091+
data.handle = bt_gatt_attr_get_handle(params[i].attr);
2092+
/* Lookup UUID if it was given */
2093+
if (params[i].uuid) {
2094+
if (!gatt_find_by_uuid(&data, params[i].uuid)) {
2095+
return -ENOENT;
2096+
}
2097+
params[i].attr = data.attr;
2098+
} else {
2099+
if (!data.handle) {
2100+
return -ENOENT;
2101+
}
21292102
}
2130-
}
21312103

2132-
if (!*buf) {
2133-
*buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY_MULT,
2134-
sizeof(*nfy) + params->len);
2135-
if (!*buf) {
2136-
return -ENOMEM;
2104+
/* Confirm that the connection has the correct level of security */
2105+
if (bt_gatt_check_perm(conn, params[i].attr,
2106+
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_READ_AUTHEN)) {
2107+
BT_WARN("Link is not encrypted");
2108+
return -EPERM;
21372109
}
2110+
/* Calculate the ATT_MULTIPLE_HANDLE_VALUE_NTF pdu length */
2111+
pdu_len += sizeof(*nfy) + params[i].len;
2112+
if (pdu_len > UINT16_MAX) {
2113+
return -EINVAL;
2114+
}
2115+
}
21382116

2139-
bt_att_set_tx_meta_data(*buf, params->func, params->user_data);
2117+
buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY_MULT, pdu_len);
2118+
if (!buf) {
2119+
return -ENOMEM;
21402120
}
21412121

2142-
BT_DBG("handle 0x%04x len %u", handle, params->len);
2122+
bt_att_set_tx_meta_data(buf, params[0].func, params[0].user_data);
21432123

2144-
nfy = net_buf_add(*buf, sizeof(*nfy));
2145-
nfy->handle = sys_cpu_to_le16(handle);
2146-
nfy->len = sys_cpu_to_le16(params->len);
2124+
for (uint16_t i = 0; i < num_params; i++) {
2125+
data.handle = bt_gatt_attr_get_handle(params[i].attr);
2126+
/* Check if attribute is a characteristic then adjust the handle */
2127+
if (!bt_uuid_cmp(params[i].attr->uuid, BT_UUID_GATT_CHRC)) {
2128+
struct bt_gatt_chrc *chrc = params[i].attr->user_data;
21472129

2148-
net_buf_add(*buf, params->len);
2149-
memcpy(nfy->value, params->data, params->len);
2130+
if (!(chrc->properties & BT_GATT_CHRC_NOTIFY)) {
2131+
return -EINVAL;
2132+
}
2133+
2134+
data.handle = bt_gatt_attr_value_handle(params[i].attr);
2135+
}
21502136

2151-
k_work_submit(&nfy_mult_work);
2137+
BT_DBG("handle 0x%04x len %u", data.handle, params[i].len);
21522138

2153-
return 0;
2139+
nfy = net_buf_add(buf, sizeof(*nfy));
2140+
nfy->handle = sys_cpu_to_le16(data.handle);
2141+
nfy->len = sys_cpu_to_le16(params[i].len);
2142+
2143+
net_buf_add(buf, params[i].len);
2144+
(void)memcpy(nfy->value, params[i].data, params[i].len);
2145+
}
2146+
2147+
return bt_att_send(conn, buf, params[0].func, params[0].user_data);
21542148
}
21552149
#endif /* CONFIG_BT_GATT_NOTIFY_MULTIPLE */
21562150

@@ -2178,12 +2172,6 @@ static int gatt_notify(struct bt_conn *conn, uint16_t handle,
21782172
return -EPERM;
21792173
}
21802174

2181-
#if defined(CONFIG_BT_GATT_NOTIFY_MULTIPLE)
2182-
if (gatt_cf_notify_multi(conn)) {
2183-
return gatt_notify_mult(conn, handle, params);
2184-
}
2185-
#endif /* CONFIG_BT_GATT_NOTIFY_MULTIPLE */
2186-
21872175
buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY,
21882176
sizeof(*nfy) + params->len);
21892177
if (!buf) {
@@ -2539,23 +2527,44 @@ int bt_gatt_notify_cb(struct bt_conn *conn,
25392527
}
25402528

25412529
#if defined(CONFIG_BT_GATT_NOTIFY_MULTIPLE)
2530+
25422531
int bt_gatt_notify_multiple(struct bt_conn *conn, uint16_t num_params,
25432532
struct bt_gatt_notify_params *params)
25442533
{
2545-
int i, ret;
2546-
25472534
__ASSERT(params, "invalid parameters\n");
2548-
__ASSERT(num_params, "invalid parameters\n");
2549-
__ASSERT(params->attr, "invalid parameters\n");
2535+
__ASSERT(num_params >= 2, "invalid parameters\n");
2536+
__ASSERT(params->attr || params->uuid, "invalid parameters\n");
2537+
for (uint16_t i = 1; i < num_params; i++) {
2538+
__ASSERT(params[0].func == params[i].func, "invalid parameters\n");
2539+
__ASSERT(memcmp(params[0].user_data, params[i].user_data, 1) == 0,
2540+
"invalid parameters\n");
2541+
}
25502542

2551-
for (i = 0; i < num_params; i++) {
2552-
ret = bt_gatt_notify_cb(conn, &params[i]);
2553-
if (ret < 0) {
2554-
return ret;
2555-
}
2543+
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
2544+
return -EAGAIN;
25562545
}
25572546

2558-
return 0;
2547+
if (conn && conn->state != BT_CONN_CONNECTED) {
2548+
return -ENOTCONN;
2549+
}
2550+
2551+
#if defined(CONFIG_BT_GATT_ENFORCE_CHANGE_UNAWARE)
2552+
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
2553+
* Except for the Handle Value indication, the server shall not send
2554+
* notifications and indications to such a client until it becomes
2555+
* change-aware.
2556+
*/
2557+
if (!bt_gatt_change_aware(conn, false)) {
2558+
return -EAGAIN;
2559+
}
2560+
#endif
2561+
2562+
if (gatt_cf_notify_multi(conn)) {
2563+
return gatt_notify_mult(conn, num_params, params);
2564+
}
2565+
2566+
BT_ERR("Multiple variable length notifications is not supported");
2567+
return -EOPNOTSUPP;
25592568
}
25602569
#endif /* CONFIG_BT_GATT_NOTIFY_MULTIPLE */
25612570

0 commit comments

Comments
 (0)