Bluetooth: Mesh: Add proxy send callback

Zephyr Bluetooth Mesh did not check whether the proxy message
was actually sent out, so that the response message could
not be received during reset. It did not solve the status
callback of the proxy sending message, so a new problem was
introduced after PR(#28457) merged.

bt_mesh_prov_send(&buf, public_key_sent))

This PR will try to solve the above problem, and will fix
the problem due to thread competition, and PR(#26668) will
not be necessary.

Compared with PR(#30138), it no longer consumes extra RAM
space and supports synchronization of group addresses

Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
This commit is contained in:
Lingao Meng 2021-05-26 20:39:13 -07:00 committed by Johan Hedberg
commit 7531d2e3c8
5 changed files with 105 additions and 92 deletions

View file

@ -1970,11 +1970,27 @@ send_list:
} }
} }
static void reset_send_start(uint16_t duration, int err, void *cb_data)
{
if (err) {
BT_ERR("Sending Node Reset Status failed (err %d)", err);
bt_mesh_reset();
}
}
static void reset_send_end(int err, void *cb_data)
{
bt_mesh_reset();
}
static void node_reset(struct bt_mesh_model *model, static void node_reset(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf) struct net_buf_simple *buf)
{ {
static struct bt_mesh_proxy_idle_cb proxy_idle = {.cb = bt_mesh_reset}; static const struct bt_mesh_send_cb reset_cb = {
.start = reset_send_start,
.end = reset_send_end,
};
BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_RESET_STATUS, 0); BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_RESET_STATUS, 0);
@ -1982,25 +1998,11 @@ static void node_reset(struct bt_mesh_model *model,
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
bt_hex(buf->data, buf->len)); bt_hex(buf->data, buf->len));
bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS); bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS);
/* Send the response first since we wont have any keys left to if (bt_mesh_model_send(model, ctx, &msg, &reset_cb, NULL)) {
* send it later.
*/
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
BT_ERR("Unable to send Node Reset Status"); BT_ERR("Unable to send Node Reset Status");
} }
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
bt_mesh_reset();
return;
}
/* If the response goes to a proxy node, we'll wait for the sending to
* complete before moving on.
*/
bt_mesh_proxy_on_idle(&proxy_idle);
} }
static void send_friend_status(struct bt_mesh_model *model, static void send_friend_status(struct bt_mesh_model *model,

View file

@ -530,12 +530,13 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
goto done; goto done;
} }
BT_MESH_ADV(buf)->cb = cb;
BT_MESH_ADV(buf)->cb_data = cb_data;
/* Deliver to GATT Proxy Clients if necessary. */ /* Deliver to GATT Proxy Clients if necessary. */
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
bt_mesh_proxy_relay(&buf->b, tx->ctx->addr) && bt_mesh_proxy_relay(buf, tx->ctx->addr) &&
BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) {
/* Notify completion if this only went through the Mesh Proxy */
send_cb_finalize(cb, cb_data);
err = 0; err = 0;
goto done; goto done;
@ -702,7 +703,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf,
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
(rx->friend_cred || (rx->friend_cred ||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) { bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
bt_mesh_proxy_relay(&buf->b, rx->ctx.recv_dst); bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
} }
if (relay_to_adv(rx->net_if) || rx->friend_cred) { if (relay_to_adv(rx->net_if) || rx->friend_cred) {

View file

@ -17,10 +17,16 @@
#define LOG_MODULE_NAME bt_mesh_pb_gatt #define LOG_MODULE_NAME bt_mesh_pb_gatt
#include "common/log.h" #include "common/log.h"
struct prov_bearer_send_cb {
prov_bearer_send_complete_t cb;
void *cb_data;
};
struct prov_link { struct prov_link {
struct bt_conn *conn; struct bt_conn *conn;
const struct prov_bearer_cb *cb; const struct prov_bearer_cb *cb;
void *cb_data; void *cb_data;
struct prov_bearer_send_cb comp;
struct net_buf_simple *rx_buf; struct net_buf_simple *rx_buf;
struct k_work_delayable prot_timer; struct k_work_delayable prot_timer;
}; };
@ -123,6 +129,13 @@ static int link_accept(const struct prov_bearer_cb *cb, void *cb_data)
return 0; return 0;
} }
static void buf_send_end(struct bt_conn *conn, void *user_data)
{
if (link.comp.cb) {
link.comp.cb(0, link.comp.cb_data);
}
}
static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb, static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb,
void *cb_data) void *cb_data)
{ {
@ -130,9 +143,12 @@ static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb,
return -ENOTCONN; return -ENOTCONN;
} }
link.comp.cb = cb;
link.comp.cb_data = cb_data;
k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
return bt_mesh_proxy_send(link.conn, BT_MESH_PROXY_PROV, buf); return bt_mesh_pb_gatt_send(link.conn, buf, buf_send_end, NULL);
} }
static void clear_tx(void) static void clear_tx(void)

View file

@ -114,8 +114,6 @@ static struct bt_mesh_proxy_client {
}, },
}; };
static sys_slist_t idle_waiters;
static atomic_t pending_notifications;
static uint8_t __noinit client_buf_data[CLIENT_BUF_SIZE * CONFIG_BT_MAX_CONN]; static uint8_t __noinit client_buf_data[CLIENT_BUF_SIZE * CONFIG_BT_MAX_CONN];
/* Track which service is enabled */ /* Track which service is enabled */
@ -163,7 +161,8 @@ static void proxy_sar_timeout(struct k_work *work)
static struct bt_mesh_subnet *beacon_sub; static struct bt_mesh_subnet *beacon_sub;
static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type, static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type,
struct net_buf_simple *msg); struct net_buf_simple *msg,
bt_gatt_complete_func_t end, void *user_data);
static int filter_set(struct bt_mesh_proxy_client *client, static int filter_set(struct bt_mesh_proxy_client *client,
struct net_buf_simple *buf) struct net_buf_simple *buf)
@ -279,7 +278,8 @@ static void send_filter_status(struct bt_mesh_proxy_client *client,
return; return;
} }
err = proxy_segment_and_send(client->conn, BT_MESH_PROXY_CONFIG, buf); err = proxy_segment_and_send(client->conn, BT_MESH_PROXY_CONFIG, buf,
NULL, NULL);
if (err) { if (err) {
BT_ERR("Failed to send proxy cfg message (err %d)", err); BT_ERR("Failed to send proxy cfg message (err %d)", err);
} }
@ -354,7 +354,7 @@ static int beacon_send(struct bt_conn *conn, struct bt_mesh_subnet *sub)
net_buf_simple_reserve(&buf, 1); net_buf_simple_reserve(&buf, 1);
bt_mesh_beacon_create(sub, &buf); bt_mesh_beacon_create(sub, &buf);
return proxy_segment_and_send(conn, BT_MESH_PROXY_BEACON, &buf); return proxy_segment_and_send(conn, BT_MESH_PROXY_BEACON, &buf, NULL, NULL);
} }
static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data) static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
@ -913,10 +913,17 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client,
return false; return false;
} }
bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst) static void buf_send_end(struct bt_conn *conn, void *user_data)
{
struct net_buf *buf = user_data;
net_buf_unref(buf);
}
bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst)
{ {
bool relayed = false; bool relayed = false;
int i; int i, err;
BT_DBG("%u bytes to dst 0x%04x", buf->len, dst); BT_DBG("%u bytes to dst 0x%04x", buf->len, dst);
@ -932,13 +939,26 @@ bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst)
continue; continue;
} }
if (client->filter_type == PROV) {
BT_ERR("Invalid PDU type for Proxy Client");
return -EINVAL;
}
/* Proxy PDU sending modifies the original buffer, /* Proxy PDU sending modifies the original buffer,
* so we need to make a copy. * so we need to make a copy.
*/ */
net_buf_simple_reserve(&msg, 1); net_buf_simple_reserve(&msg, 1);
net_buf_simple_add_mem(&msg, buf->data, buf->len); net_buf_simple_add_mem(&msg, buf->data, buf->len);
bt_mesh_proxy_send(client->conn, BT_MESH_PROXY_NET_PDU, &msg); err = proxy_segment_and_send(client->conn, BT_MESH_PROXY_NET_PDU,
&msg, buf_send_end, net_buf_ref(buf));
bt_mesh_adv_send_start(0, err, BT_MESH_ADV(buf));
if (err) {
BT_ERR("Failed to send proxy message (err %d)", err);
continue;
}
relayed = true; relayed = true;
} }
@ -947,58 +967,42 @@ bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst)
#endif /* CONFIG_BT_MESH_GATT_PROXY */ #endif /* CONFIG_BT_MESH_GATT_PROXY */
static void notify_complete(struct bt_conn *conn, void *user_data) static int proxy_send(struct bt_conn *conn,
const void *data, uint16_t len,
bt_gatt_complete_func_t end, void *user_data)
{ {
sys_snode_t *n; const struct bt_gatt_attr *attr;
if (atomic_dec(&pending_notifications) > 1) {
return;
}
BT_DBG("");
while ((n = sys_slist_get(&idle_waiters))) {
CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
}
}
static int proxy_send(struct bt_conn *conn, const void *data,
uint16_t len)
{
struct bt_gatt_notify_params params = {
.data = data,
.len = len,
.func = notify_complete,
};
int err;
BT_DBG("%u bytes: %s", len, bt_hex(data, len)); BT_DBG("%u bytes: %s", len, bt_hex(data, len));
#if defined(CONFIG_BT_MESH_GATT_PROXY) #if defined(CONFIG_BT_MESH_GATT_PROXY)
if (gatt_svc == MESH_GATT_PROXY) { if (gatt_svc == MESH_GATT_PROXY) {
params.attr = &proxy_attrs[3]; attr = &proxy_attrs[3];
} }
#endif #endif
#if defined(CONFIG_BT_MESH_PB_GATT) #if defined(CONFIG_BT_MESH_PB_GATT)
if (gatt_svc == MESH_GATT_PROV) { if (gatt_svc == MESH_GATT_PROV) {
params.attr = &prov_attrs[3]; attr = &prov_attrs[3];
} }
#endif #endif
if (!params.attr) { if (!attr) {
return 0; return -ENOENT;
} }
err = bt_gatt_notify_cb(conn, &params); struct bt_gatt_notify_params params = {
if (!err) { .data = data,
atomic_inc(&pending_notifications); .len = len,
} .attr = attr,
.user_data = user_data,
.func = end,
};
return err; return bt_gatt_notify_cb(conn, &params);
} }
static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type, static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type,
struct net_buf_simple *msg) struct net_buf_simple *msg,
bt_gatt_complete_func_t end, void *user_data)
{ {
uint16_t mtu; uint16_t mtu;
@ -1009,30 +1013,30 @@ static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type,
mtu = bt_gatt_get_mtu(conn) - 3; mtu = bt_gatt_get_mtu(conn) - 3;
if (mtu > msg->len) { if (mtu > msg->len) {
net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type));
return proxy_send(conn, msg->data, msg->len); return proxy_send(conn, msg->data, msg->len, end, user_data);
} }
net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type));
proxy_send(conn, msg->data, mtu); proxy_send(conn, msg->data, mtu, NULL, NULL);
net_buf_simple_pull(msg, mtu); net_buf_simple_pull(msg, mtu);
while (msg->len) { while (msg->len) {
if (msg->len + 1 < mtu) { if (msg->len + 1 < mtu) {
net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type));
proxy_send(conn, msg->data, msg->len); proxy_send(conn, msg->data, msg->len, end, user_data);
break; break;
} }
net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type));
proxy_send(conn, msg->data, mtu); proxy_send(conn, msg->data, mtu, NULL, NULL);
net_buf_simple_pull(msg, mtu); net_buf_simple_pull(msg, mtu);
} }
return 0; return 0;
} }
int bt_mesh_proxy_send(struct bt_conn *conn, uint8_t type, int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf,
struct net_buf_simple *msg) bt_gatt_complete_func_t end, void *user_data)
{ {
struct bt_mesh_proxy_client *client = find_client(conn); struct bt_mesh_proxy_client *client = find_client(conn);
@ -1041,12 +1045,12 @@ int bt_mesh_proxy_send(struct bt_conn *conn, uint8_t type,
return -ENOTCONN; return -ENOTCONN;
} }
if ((client->filter_type == PROV) != (type == BT_MESH_PROXY_PROV)) { if (client->filter_type != PROV) {
BT_ERR("Invalid PDU type for Proxy Client"); BT_ERR("Invalid PDU type for Proxy Client");
return -EINVAL; return -EINVAL;
} }
return proxy_segment_and_send(conn, type, msg); return proxy_segment_and_send(conn, BT_MESH_PROXY_PROV, buf, end, user_data);
} }
#if defined(CONFIG_BT_MESH_PB_GATT) #if defined(CONFIG_BT_MESH_PB_GATT)
@ -1395,13 +1399,3 @@ int bt_mesh_proxy_init(void)
return 0; return 0;
} }
void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb)
{
if (!atomic_get(&pending_notifications)) {
cb->cb();
return;
}
sys_slist_append(&idle_waiters, &cb->n);
}

View file

@ -6,20 +6,19 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_
#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_
#include <bluetooth/gatt.h>
int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf,
bt_gatt_complete_func_t end, void *user_data);
#define BT_MESH_PROXY_NET_PDU 0x00 #define BT_MESH_PROXY_NET_PDU 0x00
#define BT_MESH_PROXY_BEACON 0x01 #define BT_MESH_PROXY_BEACON 0x01
#define BT_MESH_PROXY_CONFIG 0x02 #define BT_MESH_PROXY_CONFIG 0x02
#define BT_MESH_PROXY_PROV 0x03 #define BT_MESH_PROXY_PROV 0x03
struct bt_mesh_proxy_idle_cb {
sys_snode_t n;
void (*cb)(void);
};
int bt_mesh_proxy_send(struct bt_conn *conn, uint8_t type,
struct net_buf_simple *msg);
int bt_mesh_proxy_prov_enable(void); int bt_mesh_proxy_prov_enable(void);
int bt_mesh_proxy_prov_disable(bool disconnect); int bt_mesh_proxy_prov_disable(bool disconnect);
@ -36,8 +35,9 @@ int bt_mesh_proxy_adv_start(void);
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub);
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub);
bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst); bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst);
void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr); void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr);
int bt_mesh_proxy_init(void); int bt_mesh_proxy_init(void);
void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb);
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_ */