Bluetooth: host: Release ATT request buffers once sent
The ATT request buffers are held until the ATT response has been received. This means that the ATT request buffers are released by the RX thread, instead of the from the RX priority context of num_complete. This can cause a deadlock in the RX thread when we allocate buffers and all the available buffers are ATT requests, since the RX thread is the only thread that can release buffers. Release the ATT request buffers once they have been sent and instead handle ATT request resending by reconstructing the buffer from the GATT parameters. Also re-order the order of resource allocation by allocating the request context before the buffer. This ensures that we cannot allocate more buffers for ATT requests than there are ATT requests. Fixed a buf reference leak that could occur when the ATT request buffer has been allocated, but GATT returns an error before handing the responsebility of the buffer to ATT, for example when bt_att_req_alloc fails. This is fixed by moving the functionality of att_req_destroy to bt_att_req_free. Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
parent
5cbfdf6311
commit
10841b9a14
|
@ -112,18 +112,6 @@ K_MEM_SLAB_DEFINE(chan_slab, sizeof(struct bt_att_chan),
|
|||
__alignof__(struct bt_att_chan));
|
||||
static struct bt_att_req cancel;
|
||||
|
||||
static void att_req_destroy(struct bt_att_req *req)
|
||||
{
|
||||
BT_DBG("req %p", req);
|
||||
|
||||
if (req->buf) {
|
||||
net_buf_unref(req->buf);
|
||||
req->buf = NULL;
|
||||
}
|
||||
|
||||
bt_att_req_free(req);
|
||||
}
|
||||
|
||||
typedef void (*bt_att_chan_sent_t)(struct bt_att_chan *chan);
|
||||
|
||||
static bt_att_chan_sent_t chan_cb(struct net_buf *buf);
|
||||
|
@ -201,19 +189,14 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
|
|||
|
||||
chan->sent = cb ? cb : chan_cb(buf);
|
||||
|
||||
/* Take a ref since bt_l2cap_send_cb takes ownership of the buffer */
|
||||
err = bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT,
|
||||
net_buf_ref(buf), att_cb(chan->sent),
|
||||
buf, att_cb(chan->sent),
|
||||
&chan->chan.chan);
|
||||
if (!err) {
|
||||
net_buf_unref(buf);
|
||||
return 0;
|
||||
if (err) {
|
||||
net_buf_simple_restore(&buf->b, &state);
|
||||
}
|
||||
|
||||
net_buf_simple_restore(&buf->b, &state);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static int process_queue(struct bt_att_chan *chan, struct k_fifo *queue)
|
||||
|
@ -239,6 +222,7 @@ static int process_queue(struct bt_att_chan *chan, struct k_fifo *queue)
|
|||
/* Send requests without taking tx_sem */
|
||||
static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
int err;
|
||||
|
||||
if (chan->chan.tx.mtu < net_buf_frags_len(req->buf)) {
|
||||
|
@ -250,19 +234,14 @@ static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req)
|
|||
|
||||
chan->req = req;
|
||||
|
||||
/* Save request state so it can be resent */
|
||||
net_buf_simple_save(&req->buf->b, &req->state);
|
||||
/* Release since bt_l2cap_send_cb takes ownership of the buffer */
|
||||
buf = req->buf;
|
||||
req->buf = NULL;
|
||||
|
||||
/* Keep a reference for resending the req in case the security
|
||||
* needs to be changed.
|
||||
*/
|
||||
err = chan_send(chan, net_buf_ref(req->buf), NULL);
|
||||
err = chan_send(chan, buf, NULL);
|
||||
if (err) {
|
||||
/* Drop the extra reference if buffer could not be sent but
|
||||
* don't reset the buffer as it will likelly be pushed back to
|
||||
* request queue to be send later.
|
||||
*/
|
||||
net_buf_unref(req->buf);
|
||||
/* We still have the ownership of the buffer */
|
||||
req->buf = buf;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -607,19 +586,13 @@ static uint8_t att_handle_rsp(struct bt_att_chan *chan, void *pdu, uint16_t len,
|
|||
goto process;
|
||||
}
|
||||
|
||||
/* Release original buffer */
|
||||
if (chan->req->buf) {
|
||||
net_buf_unref(chan->req->buf);
|
||||
chan->req->buf = NULL;
|
||||
}
|
||||
|
||||
/* Reset func so it can be reused by the callback */
|
||||
func = chan->req->func;
|
||||
chan->req->func = NULL;
|
||||
params = chan->req->user_data;
|
||||
|
||||
/* free allocated request so its memory can be reused */
|
||||
att_req_destroy(chan->req);
|
||||
bt_att_req_free(chan->req);
|
||||
chan->req = NULL;
|
||||
|
||||
process:
|
||||
|
@ -2040,11 +2013,6 @@ static uint8_t att_error_rsp(struct bt_att_chan *chan, struct net_buf *buf)
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (chan->req->buf) {
|
||||
/* Restore state to be resent */
|
||||
net_buf_simple_restore(&chan->req->buf->b, &chan->req->state);
|
||||
}
|
||||
|
||||
err = rsp->error;
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
/* Check if error can be handled by elevating security. */
|
||||
|
@ -2530,7 +2498,7 @@ static void att_reset(struct bt_att *att)
|
|||
req->user_data);
|
||||
}
|
||||
|
||||
att_req_destroy(req);
|
||||
bt_att_req_free(req);
|
||||
}
|
||||
|
||||
k_mem_slab_free(&att_slab, (void **)&att);
|
||||
|
@ -2646,12 +2614,43 @@ static void bt_att_disconnected(struct bt_l2cap_chan *chan)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
static uint8_t att_req_retry(struct bt_att_chan *att_chan)
|
||||
{
|
||||
struct bt_att_req *req = att_chan->req;
|
||||
struct net_buf *buf;
|
||||
|
||||
/* Resend buffer */
|
||||
if (!req->encode) {
|
||||
/* This request does not support resending */
|
||||
return BT_ATT_ERR_AUTHENTICATION;
|
||||
}
|
||||
|
||||
|
||||
buf = bt_att_chan_create_pdu(att_chan, req->att_op, req->len);
|
||||
if (!buf) {
|
||||
return BT_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
if (req->encode(buf, req->len, req->user_data)) {
|
||||
net_buf_unref(buf);
|
||||
return BT_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
if (chan_send(att_chan, buf, NULL)) {
|
||||
net_buf_unref(buf);
|
||||
return BT_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return BT_ATT_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void bt_att_encrypt_change(struct bt_l2cap_chan *chan,
|
||||
uint8_t hci_status)
|
||||
{
|
||||
struct bt_att_chan *att_chan = ATT_CHAN(chan);
|
||||
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
|
||||
struct bt_conn *conn = ch->chan.conn;
|
||||
uint8_t err;
|
||||
|
||||
BT_DBG("chan %p conn %p handle %u sec_level 0x%02x status 0x%02x", ch,
|
||||
conn, conn->handle, conn->sec_level, hci_status);
|
||||
|
@ -2686,14 +2685,10 @@ static void bt_att_encrypt_change(struct bt_l2cap_chan *chan,
|
|||
|
||||
BT_DBG("Retrying");
|
||||
|
||||
/* Resend buffer */
|
||||
|
||||
/* Since packets are created in ATT and released in L2CAP we need to
|
||||
* take a new reference to "create" the packet in ATT again.
|
||||
*/
|
||||
if (chan_send(att_chan, net_buf_ref(att_chan->req->buf), NULL)) {
|
||||
net_buf_unref(att_chan->req->buf);
|
||||
att_handle_rsp(att_chan, NULL, 0, BT_ATT_ERR_AUTHENTICATION);
|
||||
err = att_req_retry(att_chan);
|
||||
if (err) {
|
||||
BT_DBG("Retry failed (%d)", err);
|
||||
att_handle_rsp(att_chan, NULL, 0, err);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
|
@ -2932,6 +2927,7 @@ struct bt_att_req *bt_att_req_alloc(k_timeout_t timeout)
|
|||
|
||||
/* Reserve space for request */
|
||||
if (k_mem_slab_alloc(&req_slab, (void **)&req, timeout)) {
|
||||
BT_DBG("No space for req");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2946,6 +2942,11 @@ void bt_att_req_free(struct bt_att_req *req)
|
|||
{
|
||||
BT_DBG("req %p", req);
|
||||
|
||||
if (req->buf) {
|
||||
net_buf_unref(req->buf);
|
||||
req->buf = NULL;
|
||||
}
|
||||
|
||||
k_mem_slab_free(&req_slab, (void **)&req);
|
||||
}
|
||||
|
||||
|
@ -3003,8 +3004,6 @@ int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req)
|
|||
|
||||
att = att_get(conn);
|
||||
if (!att) {
|
||||
net_buf_unref(req->buf);
|
||||
req->buf = NULL;
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
|
@ -3037,7 +3036,7 @@ static bool bt_att_chan_req_cancel(struct bt_att_chan *chan,
|
|||
|
||||
chan->req = &cancel;
|
||||
|
||||
att_req_destroy(req);
|
||||
bt_att_req_free(req);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3068,5 +3067,5 @@ void bt_att_req_cancel(struct bt_conn *conn, struct bt_att_req *req)
|
|||
/* Remove request from the list */
|
||||
sys_slist_find_and_remove(&att->reqs, &req->node);
|
||||
|
||||
att_req_destroy(req);
|
||||
bt_att_req_free(req);
|
||||
}
|
||||
|
|
|
@ -263,14 +263,19 @@ typedef void (*bt_att_func_t)(struct bt_conn *conn, uint8_t err,
|
|||
const void *pdu, uint16_t length,
|
||||
void *user_data);
|
||||
|
||||
typedef int (*bt_att_encode_t)(struct net_buf *buf, size_t len,
|
||||
void *user_data);
|
||||
|
||||
/* ATT request context */
|
||||
struct bt_att_req {
|
||||
sys_snode_t node;
|
||||
bt_att_func_t func;
|
||||
struct net_buf_simple_state state;
|
||||
struct net_buf *buf;
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
bool retrying;
|
||||
bt_att_encode_t encode;
|
||||
uint8_t retrying : 1;
|
||||
uint8_t att_op;
|
||||
size_t len;
|
||||
#endif /* CONFIG_BT_SMP */
|
||||
void *user_data;
|
||||
};
|
||||
|
|
|
@ -1910,44 +1910,75 @@ static void gatt_indicate_rsp(struct bt_conn *conn, uint8_t err,
|
|||
}
|
||||
}
|
||||
|
||||
static int gatt_send(struct bt_conn *conn, struct net_buf *buf,
|
||||
bt_att_func_t func, void *params)
|
||||
static struct bt_att_req *gatt_req_alloc(bt_att_func_t func, void *params,
|
||||
bt_att_encode_t encode,
|
||||
uint8_t op,
|
||||
size_t len)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (params) {
|
||||
struct bt_att_req *req;
|
||||
|
||||
/* Allocate new request */
|
||||
req = bt_att_req_alloc(BT_ATT_TIMEOUT);
|
||||
if (!req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_SMP)
|
||||
req->att_op = op;
|
||||
req->len = len;
|
||||
req->encode = encode;
|
||||
#endif
|
||||
req->func = func;
|
||||
req->user_data = params;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_GATT_CLIENT
|
||||
static int gatt_req_send(struct bt_conn *conn, bt_att_func_t func, void *params,
|
||||
bt_att_encode_t encode, uint8_t op, size_t len)
|
||||
|
||||
{
|
||||
struct bt_att_req *req;
|
||||
struct net_buf *buf;
|
||||
int err;
|
||||
|
||||
req = gatt_req_alloc(func, params, encode, op, len);
|
||||
if (!req) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
buf = bt_att_create_pdu(conn, op, len);
|
||||
if (!buf) {
|
||||
bt_att_req_free(req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req->buf = buf;
|
||||
req->func = func;
|
||||
req->user_data = params;
|
||||
|
||||
err = encode(buf, len, params);
|
||||
if (err) {
|
||||
bt_att_req_free(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_att_req_send(conn, req);
|
||||
if (err) {
|
||||
bt_att_req_free(req);
|
||||
}
|
||||
} else {
|
||||
err = bt_att_send(conn, buf, NULL, NULL);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Error sending ATT PDU: %d", err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gatt_indicate(struct bt_conn *conn, uint16_t handle,
|
||||
struct bt_gatt_indicate_params *params)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_att_indicate *ind;
|
||||
struct bt_att_req *req;
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
#if defined(CONFIG_BT_GATT_ENFORCE_CHANGE_UNAWARE)
|
||||
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
|
||||
|
@ -1961,15 +1992,20 @@ static int gatt_indicate(struct bt_conn *conn, uint16_t handle,
|
|||
return -EAGAIN;
|
||||
}
|
||||
#endif
|
||||
len = sizeof(*ind) + params->len;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE,
|
||||
sizeof(*ind) + params->len);
|
||||
if (!buf) {
|
||||
BT_WARN("No buffer available to send indication");
|
||||
req = gatt_req_alloc(gatt_indicate_rsp, params, NULL,
|
||||
BT_ATT_OP_INDICATE, len);
|
||||
if (!req) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
BT_DBG("conn %p handle 0x%04x", conn, handle);
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE, len);
|
||||
if (!buf) {
|
||||
BT_WARN("No buffer available to send indication");
|
||||
bt_att_req_free(req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ind = net_buf_add(buf, sizeof(*ind));
|
||||
ind->handle = sys_cpu_to_le16(handle);
|
||||
|
@ -1977,7 +2013,16 @@ static int gatt_indicate(struct bt_conn *conn, uint16_t handle,
|
|||
net_buf_add(buf, params->len);
|
||||
memcpy(ind->value, params->data, params->len);
|
||||
|
||||
return gatt_send(conn, buf, gatt_indicate_rsp, params);
|
||||
BT_DBG("conn %p handle 0x%04x", conn, handle);
|
||||
|
||||
req->buf = buf;
|
||||
|
||||
err = bt_att_req_send(conn, req);
|
||||
if (err) {
|
||||
bt_att_req_free(req);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint8_t notify_cb(const struct bt_gatt_attr *attr, uint16_t handle,
|
||||
|
@ -2724,25 +2769,12 @@ static void gatt_mtu_rsp(struct bt_conn *conn, uint8_t err, const void *pdu,
|
|||
params->func(conn, err, params);
|
||||
}
|
||||
|
||||
int bt_gatt_exchange_mtu(struct bt_conn *conn,
|
||||
struct bt_gatt_exchange_params *params)
|
||||
static int gatt_exchange_mtu_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct bt_att_exchange_mtu_req *req;
|
||||
struct net_buf *buf;
|
||||
uint16_t mtu;
|
||||
|
||||
__ASSERT(conn, "invalid parameter\n");
|
||||
__ASSERT(params && params->func, "invalid parameters\n");
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_MTU_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mtu = BT_ATT_MTU;
|
||||
|
||||
BT_DBG("Client MTU %u", mtu);
|
||||
|
@ -2750,7 +2782,22 @@ int bt_gatt_exchange_mtu(struct bt_conn *conn,
|
|||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->mtu = sys_cpu_to_le16(mtu);
|
||||
|
||||
return gatt_send(conn, buf, gatt_mtu_rsp, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_gatt_exchange_mtu(struct bt_conn *conn,
|
||||
struct bt_gatt_exchange_params *params)
|
||||
{
|
||||
__ASSERT(conn, "invalid parameter\n");
|
||||
__ASSERT(params && params->func, "invalid parameters\n");
|
||||
|
||||
if (conn->state != BT_CONN_CONNECTED) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
return gatt_req_send(conn, gatt_mtu_rsp, params,
|
||||
gatt_exchange_mtu_encode, BT_ATT_OP_MTU_REQ,
|
||||
sizeof(struct bt_att_exchange_mtu_req));
|
||||
}
|
||||
|
||||
static void gatt_discover_next(struct bt_conn *conn, uint16_t last_handle,
|
||||
|
@ -2839,17 +2886,12 @@ done:
|
|||
params->func(conn, NULL, params);
|
||||
}
|
||||
|
||||
static int gatt_find_type(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
static int gatt_find_type_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
uint16_t uuid_val;
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_discover_params *params = user_data;
|
||||
struct bt_att_find_type_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_FIND_TYPE_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
uint16_t uuid_val;
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->start_handle = sys_cpu_to_le16(params->start_handle);
|
||||
|
@ -2874,13 +2916,33 @@ static int gatt_find_type(struct bt_conn *conn,
|
|||
case BT_UUID_TYPE_128:
|
||||
net_buf_add_mem(buf, BT_UUID_128(params->uuid)->val, 16);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_find_type(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = sizeof(struct bt_att_find_type_req);
|
||||
|
||||
switch (params->uuid->type) {
|
||||
case BT_UUID_TYPE_16:
|
||||
len += BT_UUID_SIZE_16;
|
||||
break;
|
||||
case BT_UUID_TYPE_128:
|
||||
len += BT_UUID_SIZE_128;
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown UUID type %u", params->uuid->type);
|
||||
net_buf_unref(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return gatt_send(conn, buf, gatt_find_type_rsp, params);
|
||||
return gatt_req_send(conn, gatt_find_type_rsp, params,
|
||||
gatt_find_type_encode, BT_ATT_OP_FIND_TYPE_REQ,
|
||||
len);
|
||||
}
|
||||
|
||||
static void read_included_uuid_cb(struct bt_conn *conn, uint8_t err,
|
||||
|
@ -2929,23 +2991,26 @@ next:
|
|||
return;
|
||||
}
|
||||
|
||||
static int read_included_uuid(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
static int read_included_uuid_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_discover_params *params = user_data;
|
||||
struct bt_att_read_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->_included.start_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_included_uuid(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
BT_DBG("handle 0x%04x", params->_included.start_handle);
|
||||
|
||||
return gatt_send(conn, buf, read_included_uuid_cb, params);
|
||||
return gatt_req_send(conn, read_included_uuid_cb, params,
|
||||
read_included_uuid_encode, BT_ATT_OP_READ_REQ,
|
||||
sizeof(struct bt_att_read_req));
|
||||
}
|
||||
|
||||
static uint16_t parse_include(struct bt_conn *conn, const void *pdu,
|
||||
|
@ -3143,17 +3208,12 @@ static void gatt_read_type_rsp(struct bt_conn *conn, uint8_t err,
|
|||
gatt_discover_next(conn, handle, params);
|
||||
}
|
||||
|
||||
static int gatt_read_type(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
static int gatt_read_type_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_discover_params *params = user_data;
|
||||
struct bt_att_read_type_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_TYPE_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->start_handle = sys_cpu_to_le16(params->start_handle);
|
||||
req->end_handle = sys_cpu_to_le16(params->end_handle);
|
||||
|
@ -3164,10 +3224,18 @@ static int gatt_read_type(struct bt_conn *conn,
|
|||
net_buf_add_le16(buf, BT_UUID_GATT_CHRC_VAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_type(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
BT_DBG("start_handle 0x%04x end_handle 0x%04x", params->start_handle,
|
||||
params->end_handle);
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_type_rsp, params);
|
||||
return gatt_req_send(conn, gatt_read_type_rsp, params,
|
||||
gatt_read_type_encode, BT_ATT_OP_READ_TYPE_REQ,
|
||||
sizeof(struct bt_att_read_type_req));
|
||||
}
|
||||
|
||||
static uint16_t parse_service(struct bt_conn *conn, const void *pdu,
|
||||
|
@ -3277,17 +3345,12 @@ static void gatt_read_group_rsp(struct bt_conn *conn, uint8_t err,
|
|||
gatt_discover_next(conn, handle, params);
|
||||
}
|
||||
|
||||
static int gatt_read_group(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
static int gatt_read_group_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_discover_params *params = user_data;
|
||||
struct bt_att_read_group_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_GROUP_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->start_handle = sys_cpu_to_le16(params->start_handle);
|
||||
req->end_handle = sys_cpu_to_le16(params->end_handle);
|
||||
|
@ -3298,10 +3361,19 @@ static int gatt_read_group(struct bt_conn *conn,
|
|||
net_buf_add_le16(buf, BT_UUID_GATT_SECONDARY_VAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_group(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
BT_DBG("start_handle 0x%04x end_handle 0x%04x", params->start_handle,
|
||||
params->end_handle);
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_group_rsp, params);
|
||||
return gatt_req_send(conn, gatt_read_group_rsp, params,
|
||||
gatt_read_group_encode,
|
||||
BT_ATT_OP_READ_GROUP_REQ,
|
||||
sizeof(struct bt_att_read_group_req));
|
||||
}
|
||||
|
||||
static void gatt_find_info_rsp(struct bt_conn *conn, uint8_t err,
|
||||
|
@ -3417,25 +3489,28 @@ done:
|
|||
params->func(conn, NULL, params);
|
||||
}
|
||||
|
||||
static int gatt_find_info(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
static int gatt_find_info_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_discover_params *params = user_data;
|
||||
struct bt_att_find_info_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_FIND_INFO_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->start_handle = sys_cpu_to_le16(params->start_handle);
|
||||
req->end_handle = sys_cpu_to_le16(params->end_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_find_info(struct bt_conn *conn,
|
||||
struct bt_gatt_discover_params *params)
|
||||
{
|
||||
BT_DBG("start_handle 0x%04x end_handle 0x%04x", params->start_handle,
|
||||
params->end_handle);
|
||||
|
||||
return gatt_send(conn, buf, gatt_find_info_rsp, params);
|
||||
return gatt_req_send(conn, gatt_find_info_rsp, params,
|
||||
gatt_find_info_encode, BT_ATT_OP_FIND_INFO_REQ,
|
||||
sizeof(struct bt_att_find_info_req));
|
||||
}
|
||||
|
||||
int bt_gatt_discover(struct bt_conn *conn,
|
||||
|
@ -3574,38 +3649,36 @@ static void gatt_read_rsp(struct bt_conn *conn, uint8_t err, const void *pdu,
|
|||
}
|
||||
}
|
||||
|
||||
static int gatt_read_blob(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
static int gatt_read_blob_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_read_params *params = user_data;
|
||||
struct bt_att_read_blob_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_BLOB_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->single.handle);
|
||||
req->offset = sys_cpu_to_le16(params->single.offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_blob(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
{
|
||||
BT_DBG("handle 0x%04x offset 0x%04x", params->single.handle,
|
||||
params->single.offset);
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_rsp, params);
|
||||
return gatt_req_send(conn, gatt_read_rsp, params,
|
||||
gatt_read_blob_encode, BT_ATT_OP_READ_BLOB_REQ,
|
||||
sizeof(struct bt_att_read_blob_req));
|
||||
}
|
||||
|
||||
static int gatt_read_uuid(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
static int gatt_read_uuid_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_read_params *params = user_data;
|
||||
struct bt_att_read_type_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_TYPE_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->start_handle = sys_cpu_to_le16(params->by_uuid.start_handle);
|
||||
req->end_handle = sys_cpu_to_le16(params->by_uuid.end_handle);
|
||||
|
@ -3616,11 +3689,19 @@ static int gatt_read_uuid(struct bt_conn *conn,
|
|||
net_buf_add_mem(buf, BT_UUID_128(params->by_uuid.uuid)->val, 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_uuid(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
{
|
||||
BT_DBG("start_handle 0x%04x end_handle 0x%04x uuid %s",
|
||||
params->by_uuid.start_handle, params->by_uuid.end_handle,
|
||||
bt_uuid_str(params->by_uuid.uuid));
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_rsp, params);
|
||||
return gatt_req_send(conn, gatt_read_rsp, params,
|
||||
gatt_read_uuid_encode, BT_ATT_OP_READ_TYPE_REQ,
|
||||
sizeof(struct bt_att_read_type_req));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_GATT_READ_MULTIPLE)
|
||||
|
@ -3642,23 +3723,27 @@ static void gatt_read_mult_rsp(struct bt_conn *conn, uint8_t err, const void *pd
|
|||
params->func(conn, 0, params, NULL, 0);
|
||||
}
|
||||
|
||||
static int gatt_read_mult(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
static int gatt_read_mult_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_read_params *params = user_data;
|
||||
uint8_t i;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_MULT_REQ,
|
||||
params->handle_count * sizeof(uint16_t));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0U; i < params->handle_count; i++) {
|
||||
net_buf_add_le16(buf, params->handles[i]);
|
||||
}
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_mult_rsp, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_mult(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
{
|
||||
BT_DBG("handle_count %zu", params->handle_count);
|
||||
|
||||
return gatt_req_send(conn, gatt_read_mult_rsp, params,
|
||||
gatt_read_mult_encode, BT_ATT_OP_READ_MULT_REQ,
|
||||
params->handle_count * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_EATT)
|
||||
|
@ -3705,23 +3790,28 @@ static void gatt_read_mult_vl_rsp(struct bt_conn *conn, uint8_t err,
|
|||
params->func(conn, 0, params, NULL, 0);
|
||||
}
|
||||
|
||||
static int gatt_read_mult_vl(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
static int gatt_read_mult_vl_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_read_params *params = user_data;
|
||||
uint8_t i;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_MULT_VL_REQ,
|
||||
params->handle_count * sizeof(uint16_t));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0U; i < params->handle_count; i++) {
|
||||
net_buf_add_le16(buf, params->handles[i]);
|
||||
}
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_mult_vl_rsp, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_read_mult_vl(struct bt_conn *conn,
|
||||
struct bt_gatt_read_params *params)
|
||||
{
|
||||
BT_DBG("handle_count %zu", params->handle_count);
|
||||
|
||||
return gatt_req_send(conn, gatt_read_mult_vl_rsp, params,
|
||||
gatt_read_mult_vl_encode,
|
||||
BT_ATT_OP_READ_MULT_VL_REQ,
|
||||
params->handle_count * sizeof(uint16_t));
|
||||
}
|
||||
#endif /* CONFIG_BT_EATT */
|
||||
|
||||
|
@ -3739,11 +3829,19 @@ static int gatt_read_mult_vl(struct bt_conn *conn,
|
|||
}
|
||||
#endif /* CONFIG_BT_GATT_READ_MULTIPLE */
|
||||
|
||||
int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
|
||||
static int gatt_read_encode(struct net_buf *buf, size_t len, void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_read_params *params = user_data;
|
||||
struct bt_att_read_req *req;
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->single.handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
|
||||
{
|
||||
__ASSERT(conn, "invalid parameters\n");
|
||||
__ASSERT(params && params->func, "invalid parameters\n");
|
||||
|
||||
|
@ -3767,17 +3865,11 @@ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)
|
|||
return gatt_read_blob(conn, params);
|
||||
}
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_READ_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->single.handle);
|
||||
|
||||
BT_DBG("handle 0x%04x", params->single.handle);
|
||||
|
||||
return gatt_send(conn, buf, gatt_read_rsp, params);
|
||||
return gatt_req_send(conn, gatt_read_rsp, params, gatt_read_encode,
|
||||
BT_ATT_OP_READ_REQ,
|
||||
sizeof(struct bt_att_read_req));
|
||||
}
|
||||
|
||||
static void gatt_write_rsp(struct bt_conn *conn, uint8_t err, const void *pdu,
|
||||
|
@ -3840,23 +3932,24 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle,
|
|||
return bt_att_send(conn, buf, func, user_data);
|
||||
}
|
||||
|
||||
static int gatt_exec_write(struct bt_conn *conn,
|
||||
struct bt_gatt_write_params *params)
|
||||
static int gatt_exec_encode(struct net_buf *buf, size_t len, void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_att_exec_write_req *req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_EXEC_WRITE_REQ, sizeof(*req));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->flags = BT_ATT_FLAG_EXEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_exec_write(struct bt_conn *conn,
|
||||
struct bt_gatt_write_params *params)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
return gatt_send(conn, buf, gatt_write_rsp, params);
|
||||
return gatt_req_send(conn, gatt_write_rsp, params, gatt_exec_encode,
|
||||
BT_ATT_OP_EXEC_WRITE_REQ,
|
||||
sizeof(struct bt_att_exec_write_req));
|
||||
}
|
||||
|
||||
static void gatt_prepare_write_rsp(struct bt_conn *conn, uint8_t err,
|
||||
|
@ -3864,16 +3957,28 @@ static void gatt_prepare_write_rsp(struct bt_conn *conn, uint8_t err,
|
|||
void *user_data)
|
||||
{
|
||||
struct bt_gatt_write_params *params = user_data;
|
||||
const struct bt_att_prepare_write_rsp *rsp = pdu;
|
||||
size_t len;
|
||||
|
||||
BT_DBG("err 0x%02x", err);
|
||||
|
||||
|
||||
/* Don't continue in case of error */
|
||||
if (err) {
|
||||
params->func(conn, err, params);
|
||||
return;
|
||||
}
|
||||
|
||||
len = length - sizeof(*rsp);
|
||||
if (len > params->length) {
|
||||
params->func(conn, BT_ATT_ERR_INVALID_PDU, params);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update params */
|
||||
params->offset += len;
|
||||
params->data = (const uint8_t *)params->data + len;
|
||||
params->length -= len;
|
||||
|
||||
/* If there is no more data execute */
|
||||
if (!params->length) {
|
||||
gatt_exec_write(conn, params);
|
||||
|
@ -3884,46 +3989,64 @@ static void gatt_prepare_write_rsp(struct bt_conn *conn, uint8_t err,
|
|||
bt_gatt_write(conn, params);
|
||||
}
|
||||
|
||||
static int gatt_prepare_write(struct bt_conn *conn,
|
||||
struct bt_gatt_write_params *params)
|
||||
static int gatt_prepare_write_encode(struct net_buf *buf, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_gatt_write_params *params = user_data;
|
||||
struct bt_att_prepare_write_req *req;
|
||||
uint16_t len;
|
||||
size_t write;
|
||||
|
||||
len = MIN(params->length, bt_att_get_mtu(conn) - sizeof(*req) - 1);
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_PREPARE_WRITE_REQ,
|
||||
sizeof(*req) + len);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->handle);
|
||||
req->offset = sys_cpu_to_le16(params->offset);
|
||||
|
||||
/* Append as much as possible */
|
||||
write = net_buf_append_bytes(buf, len, params->data, K_NO_WAIT,
|
||||
NULL, NULL);
|
||||
write = net_buf_append_bytes(buf, len - sizeof(*req),
|
||||
(uint8_t *)params->data, K_NO_WAIT, NULL,
|
||||
NULL);
|
||||
if (write != (len - sizeof(*req))) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update params */
|
||||
params->offset += write;
|
||||
params->data = (const uint8_t *)params->data + len;
|
||||
params->length -= write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_DBG("handle 0x%04x offset %u len %u", params->handle, params->offset,
|
||||
params->length);
|
||||
static int gatt_prepare_write(struct bt_conn *conn,
|
||||
struct bt_gatt_write_params *params)
|
||||
{
|
||||
uint16_t len, req_len;
|
||||
|
||||
return gatt_send(conn, buf, gatt_prepare_write_rsp, params);
|
||||
req_len = sizeof(struct bt_att_prepare_write_req);
|
||||
|
||||
len = bt_att_get_mtu(conn) - req_len - 1;
|
||||
len = MIN(params->length, len);
|
||||
len += req_len;
|
||||
|
||||
return gatt_req_send(conn, gatt_prepare_write_rsp, params,
|
||||
gatt_prepare_write_encode,
|
||||
BT_ATT_OP_PREPARE_WRITE_REQ, len);
|
||||
}
|
||||
|
||||
static int gatt_write_encode(struct net_buf *buf, size_t len, void *user_data)
|
||||
{
|
||||
struct bt_gatt_write_params *params = user_data;
|
||||
struct bt_att_write_req *req;
|
||||
size_t write;
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->handle);
|
||||
|
||||
write = net_buf_append_bytes(buf, params->length, params->data,
|
||||
K_NO_WAIT, NULL, NULL);
|
||||
if (write != params->length) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_att_write_req *req;
|
||||
size_t write;
|
||||
size_t len;
|
||||
|
||||
__ASSERT(conn, "invalid parameters\n");
|
||||
__ASSERT(params && params->func, "invalid parameters\n");
|
||||
|
@ -3933,31 +4056,17 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
|
|||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
len = sizeof(struct bt_att_write_req) + params->length;
|
||||
|
||||
/* Use Prepare Write if offset is set or Long Write is required */
|
||||
if (params->offset ||
|
||||
params->length > (bt_att_get_mtu(conn) - sizeof(*req) - 1)) {
|
||||
if (params->offset || len > (bt_att_get_mtu(conn) - 1)) {
|
||||
return gatt_prepare_write(conn, params);
|
||||
}
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_WRITE_REQ,
|
||||
sizeof(*req) + params->length);
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(params->handle);
|
||||
|
||||
write = net_buf_append_bytes(buf, params->length, params->data,
|
||||
K_NO_WAIT, NULL, NULL);
|
||||
if (write != params->length) {
|
||||
net_buf_unref(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
BT_DBG("handle 0x%04x length %u", params->handle, params->length);
|
||||
|
||||
return gatt_send(conn, buf, gatt_write_rsp, params);
|
||||
return gatt_req_send(conn, gatt_write_rsp, params, gatt_write_encode,
|
||||
BT_ATT_OP_WRITE_REQ, len);
|
||||
}
|
||||
|
||||
static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err,
|
||||
|
@ -3998,28 +4107,30 @@ static void gatt_write_ccc_rsp(struct bt_conn *conn, uint8_t err,
|
|||
}
|
||||
}
|
||||
|
||||
static int gatt_write_ccc(struct bt_conn *conn, uint16_t handle, uint16_t value,
|
||||
bt_att_func_t func,
|
||||
struct bt_gatt_subscribe_params *params)
|
||||
|
||||
static int gatt_write_ccc_buf(struct net_buf *buf, size_t len, void *user_data)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
struct bt_att_write_req *req;
|
||||
struct bt_gatt_subscribe_params *params = user_data;
|
||||
struct bt_att_write_req *write_req;
|
||||
|
||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_WRITE_REQ,
|
||||
sizeof(*req) + sizeof(uint16_t));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req = net_buf_add(buf, sizeof(*req));
|
||||
req->handle = sys_cpu_to_le16(handle);
|
||||
net_buf_add_le16(buf, value);
|
||||
|
||||
BT_DBG("handle 0x%04x value 0x%04x", handle, value);
|
||||
write_req = net_buf_add(buf, sizeof(*write_req));
|
||||
write_req->handle = sys_cpu_to_le16(params->ccc_handle);
|
||||
net_buf_add_le16(buf, params->value);
|
||||
|
||||
atomic_set_bit(params->flags, BT_GATT_SUBSCRIBE_FLAG_WRITE_PENDING);
|
||||
|
||||
return gatt_send(conn, buf, func, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gatt_write_ccc(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params)
|
||||
{
|
||||
size_t len = sizeof(struct bt_att_write_req) + sizeof(uint16_t);
|
||||
|
||||
BT_DBG("handle 0x%04x value 0x%04x", params->ccc_handle, params->value);
|
||||
|
||||
return gatt_req_send(conn, gatt_write_ccc_rsp, params,
|
||||
gatt_write_ccc_buf, BT_ATT_OP_WRITE_REQ, len);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC)
|
||||
|
@ -4129,8 +4240,7 @@ int bt_gatt_subscribe(struct bt_conn *conn,
|
|||
return gatt_ccc_discover(conn, params);
|
||||
}
|
||||
#endif
|
||||
err = gatt_write_ccc(conn, params->ccc_handle, params->value,
|
||||
gatt_write_ccc_rsp, params);
|
||||
err = gatt_write_ccc(conn, params);
|
||||
if (err) {
|
||||
gatt_sub_remove(conn, sub, NULL, NULL);
|
||||
return err;
|
||||
|
@ -4228,8 +4338,7 @@ int bt_gatt_unsubscribe(struct bt_conn *conn,
|
|||
|
||||
params->value = 0x0000;
|
||||
|
||||
return gatt_write_ccc(conn, params->ccc_handle, params->value,
|
||||
gatt_write_ccc_rsp, params);
|
||||
return gatt_write_ccc(conn, params);
|
||||
}
|
||||
|
||||
void bt_gatt_cancel(struct bt_conn *conn, void *params)
|
||||
|
@ -4255,8 +4364,7 @@ static void add_subscriptions(struct bt_conn *conn)
|
|||
/* Force write to CCC to workaround devices that don't
|
||||
* track it properly.
|
||||
*/
|
||||
gatt_write_ccc(conn, params->ccc_handle, params->value,
|
||||
gatt_write_ccc_rsp, params);
|
||||
gatt_write_ccc(conn, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue