From cb7835d18f066366ed3021e314e6d28ddc6d6437 Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Mon, 6 Jul 2020 14:09:16 +0200 Subject: [PATCH] Bluetooth: Mesh: Wait for proxy on node reset Adds idle wait callback to proxy by counting the number of pending notifications. Ensures that all connected nodes have received messages before resetting the mesh stack. Signed-off-by: Trond Einar Snekvik --- subsys/bluetooth/mesh/cfg_srv.c | 12 +++++++- subsys/bluetooth/mesh/proxy.c | 53 +++++++++++++++++++++++++++++---- subsys/bluetooth/mesh/proxy.h | 7 +++++ 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 95b8bf494ee..652b8d0bc57 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -2622,6 +2622,8 @@ static void node_reset(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + static struct bt_mesh_proxy_idle_cb proxy_idle = {.cb = bt_mesh_reset}; + BT_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_RESET_STATUS, 0); BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", @@ -2638,7 +2640,15 @@ static void node_reset(struct bt_mesh_model *model, BT_ERR("Unable to send Node Reset Status"); } - bt_mesh_reset(); + 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, diff --git a/subsys/bluetooth/mesh/proxy.c b/subsys/bluetooth/mesh/proxy.c index 5ba610f06c9..c1385b75ee9 100644 --- a/subsys/bluetooth/mesh/proxy.c +++ b/subsys/bluetooth/mesh/proxy.c @@ -103,6 +103,8 @@ 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]; /* Track which service is enabled */ @@ -921,23 +923,54 @@ bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst) #endif /* CONFIG_BT_MESH_GATT_PROXY */ -static int proxy_send(struct bt_conn *conn, const void *data, uint16_t len) +static void notify_complete(struct bt_conn *conn, void *user_data) { + sys_snode_t *n; + + 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)); #if defined(CONFIG_BT_MESH_GATT_PROXY) if (gatt_svc == MESH_GATT_PROXY) { - return bt_gatt_notify(conn, &proxy_attrs[3], data, len); + params.attr = &proxy_attrs[3]; } #endif - #if defined(CONFIG_BT_MESH_PB_GATT) if (gatt_svc == MESH_GATT_PROV) { - return bt_gatt_notify(conn, &prov_attrs[3], data, len); + params.attr = &prov_attrs[3]; } #endif - return 0; + if (!params.attr) { + return 0; + } + + err = bt_gatt_notify_cb(conn, ¶ms); + if (!err) { + atomic_inc(&pending_notifications); + } + + return err; } static int proxy_segment_and_send(struct bt_conn *conn, uint8_t type, @@ -1320,3 +1353,13 @@ int bt_mesh_proxy_init(void) 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); +} diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index 6bc01241231..d0f20f29ede 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -11,6 +11,12 @@ #define BT_MESH_PROXY_CONFIG 0x02 #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); @@ -35,3 +41,4 @@ bool bt_mesh_proxy_relay(struct net_buf_simple *buf, uint16_t dst); void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr); int bt_mesh_proxy_init(void); +void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb);