From dcc46d4cee21a711e781e493ca50cf70b74bd020 Mon Sep 17 00:00:00 2001 From: Inga Stotland Date: Thu, 14 Nov 2019 15:52:10 -0800 Subject: [PATCH] mesh: Fix io inititalization sequence This introduces a chain of callbacks to indicate whether mesh io is initialized and mesh network is ready to use. This fixes the reported situation when the receive callbacks were setup before the HCI was fully initialized. In other words, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS was called before BT_HCI_CMD_RESET and, as the result, the callback issueing BT_HCI_CMD_LE_SET_SCAN_ENABLE command was not called. --- mesh/main.c | 42 ++++++++++++++++++++++++------------ mesh/mesh-io-api.h | 3 ++- mesh/mesh-io-generic.c | 48 +++++++++++++++++++++++++++++++----------- mesh/mesh-io.c | 5 +++-- mesh/mesh-io.h | 6 +++++- mesh/mesh.c | 33 ++++++++++++++++++++++++----- mesh/mesh.h | 5 ++++- 7 files changed, 107 insertions(+), 35 deletions(-) diff --git a/mesh/main.c b/mesh/main.c index 6ea210c48..3c41acb75 100644 --- a/mesh/main.c +++ b/mesh/main.c @@ -38,6 +38,9 @@ #include "mesh/dbus.h" #include "mesh/mesh-io.h" +static const char *config_dir; +static int ctlr_index = MGMT_INDEX_NONE; + static const struct option main_options[] = { { "index", required_argument, NULL, 'i' }, { "config", optional_argument, NULL, 'c' }, @@ -69,16 +72,38 @@ static void do_debug(const char *str, void *user_data) l_info("%s%s", prefix, str); } +static void mesh_ready_callback(void *user_data, bool success) +{ + struct l_dbus *dbus = user_data; + + if (!success) { + l_error("Failed to start mesh"); + l_main_quit(); + return; + } + + if (!dbus_init(dbus)) { + l_error("Failed to initialize mesh D-Bus resources"); + l_main_quit(); + } +} + static void request_name_callback(struct l_dbus *dbus, bool success, bool queued, void *user_data) { l_info("Request name %s", success ? "success": "failed"); - if (success) - dbus_init(dbus); - else + if (!success) { l_main_quit(); + return; + } + + if (!mesh_init(config_dir, MESH_IO_TYPE_GENERIC, &ctlr_index, + mesh_ready_callback, dbus)) { + l_error("Failed to initialize mesh"); + l_main_quit(); + } } static void ready_callback(void *user_data) @@ -88,7 +113,6 @@ static void ready_callback(void *user_data) l_info("D-Bus ready"); l_dbus_name_acquire(dbus, BLUEZ_MESH_NAME, false, false, false, request_name_callback, NULL); - } static void disconnect_callback(void *user_data) @@ -114,8 +138,6 @@ int main(int argc, char *argv[]) bool detached = true; bool dbus_debug = false; struct l_dbus *dbus = NULL; - const char *config_dir = NULL; - int index = MGMT_INDEX_NONE; if (!l_main_init()) return -1; @@ -148,7 +170,7 @@ int main(int argc, char *argv[]) goto done; } - index = atoi(str); + ctlr_index = atoi(str); break; case 'n': @@ -175,12 +197,6 @@ int main(int argc, char *argv[]) } - if (!mesh_init(config_dir, MESH_IO_TYPE_GENERIC, &index)) { - l_error("Failed to initialize mesh"); - status = EXIT_FAILURE; - goto done; - } - if (!detached) umask(0077); diff --git a/mesh/mesh-io-api.h b/mesh/mesh-io-api.h index 4cdf1f80a..75b881800 100644 --- a/mesh/mesh-io-api.h +++ b/mesh/mesh-io-api.h @@ -19,7 +19,8 @@ struct mesh_io_private; -typedef bool (*mesh_io_init_t)(struct mesh_io *io, void *opts); +typedef bool (*mesh_io_init_t)(struct mesh_io *io, void *opts, + mesh_io_ready_func_t cb, void *user_data); typedef bool (*mesh_io_destroy_t)(struct mesh_io *io); typedef bool (*mesh_io_caps_t)(struct mesh_io *io, struct mesh_io_caps *caps); typedef bool (*mesh_io_send_t)(struct mesh_io *io, diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c index 42bf64a0b..b42fb4f1d 100644 --- a/mesh/mesh-io-generic.c +++ b/mesh/mesh-io-generic.c @@ -37,14 +37,16 @@ #include "mesh/mesh-io-generic.h" struct mesh_io_private { - uint16_t index; struct bt_hci *hci; + void *user_data; + mesh_io_ready_func_t ready_callback; struct l_timeout *tx_timeout; struct l_queue *rx_regs; struct l_queue *tx_pkts; + struct tx_pkt *tx; uint8_t filters[4]; bool sending; - struct tx_pkt *tx; + uint16_t index; uint16_t interval; }; @@ -283,22 +285,29 @@ static void configure_hci(struct mesh_io_private *io) sizeof(cmd), hci_generic_callback, NULL, NULL); } -static bool hci_init(struct mesh_io *io) +static void hci_init(void *user_data) { + struct mesh_io *io = user_data; + bool result = true; + io->pvt->hci = bt_hci_new_user_channel(io->pvt->index); if (!io->pvt->hci) { l_error("Failed to start mesh io (hci %u): %s", io->pvt->index, strerror(errno)); - return false; + result = false; } - configure_hci(io->pvt); + if (result) { + configure_hci(io->pvt); - bt_hci_register(io->pvt->hci, BT_HCI_EVT_LE_META_EVENT, + bt_hci_register(io->pvt->hci, BT_HCI_EVT_LE_META_EVENT, event_callback, io, NULL); - l_debug("Started mesh on hci %u", io->pvt->index); - return true; + l_debug("Started mesh on hci %u", io->pvt->index); + } + + if (io->pvt->ready_callback) + io->pvt->ready_callback(io->pvt->user_data, result); } static void read_info(int index, void *user_data) @@ -315,7 +324,8 @@ static void read_info(int index, void *user_data) hci_init(io); } -static bool dev_init(struct mesh_io *io, void *opts) +static bool dev_init(struct mesh_io *io, void *opts, + mesh_io_ready_func_t cb, void *user_data) { if (!io || io->pvt) return false; @@ -326,10 +336,15 @@ static bool dev_init(struct mesh_io *io, void *opts) io->pvt->rx_regs = l_queue_new(); io->pvt->tx_pkts = l_queue_new(); + io->pvt->ready_callback = cb; + io->pvt->user_data = user_data; + if (io->pvt->index == MGMT_INDEX_NONE) return mesh_mgmt_list(read_info, io); - else - return hci_init(io); + + l_idle_oneshot(hci_init, io, NULL); + + return true; } static bool dev_destroy(struct mesh_io *io) @@ -696,6 +711,15 @@ static bool find_by_filter_id(const void *a, const void *b) return rx_reg->filter_id == filter_id; } +static void scan_enable_rsp(const void *buf, uint8_t size, + void *user_data) +{ + uint8_t status = *((uint8_t *) buf); + + if (status) + l_error("LE Scan enable failed (0x%02x)", status); +} + static void set_recv_scan_enable(const void *buf, uint8_t size, void *user_data) { @@ -705,7 +729,7 @@ static void set_recv_scan_enable(const void *buf, uint8_t size, cmd.enable = 0x01; /* Enable scanning */ cmd.filter_dup = 0x00; /* Report duplicates */ bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE, - &cmd, sizeof(cmd), NULL, NULL, NULL); + &cmd, sizeof(cmd), scan_enable_rsp, pvt, NULL); } static bool recv_register(struct mesh_io *io, uint8_t filter_id, diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c index 94a92e885..95a99b6a5 100644 --- a/mesh/mesh-io.c +++ b/mesh/mesh-io.c @@ -52,7 +52,8 @@ static bool match_by_type(const void *a, const void *b) return io->type == type; } -struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts) +struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts, + mesh_io_ready_func_t cb, void *user_data) { const struct mesh_io_api *api = NULL; struct mesh_io *io; @@ -78,7 +79,7 @@ struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts) io->type = type; io->api = api; - if (!api->init(io, opts)) + if (!api->init(io, opts, cb, user_data)) goto fail; if (!io_list) diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h index 1c10779aa..45ff00a3c 100644 --- a/mesh/mesh-io.h +++ b/mesh/mesh-io.h @@ -81,7 +81,11 @@ typedef void (*mesh_io_recv_func_t)(void *user_data, typedef void (*mesh_io_status_func_t)(void *user_data, int status, uint8_t filter_id); -struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts); +typedef void (*mesh_io_ready_func_t)(void *user_data, bool result); + + +struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts, + mesh_io_ready_func_t cb, void *user_data); void mesh_io_destroy(struct mesh_io *io); bool mesh_io_get_caps(struct mesh_io *io, struct mesh_io_caps *caps); diff --git a/mesh/mesh.c b/mesh/mesh.c index 9b2b2073b..55204da56 100644 --- a/mesh/mesh.c +++ b/mesh/mesh.c @@ -70,6 +70,11 @@ struct join_data{ uint8_t *uuid; }; +struct mesh_init_request { + mesh_ready_func_t cb; + void *user_data; +}; + static struct bt_mesh mesh; /* We allow only one outstanding Join request */ @@ -138,9 +143,23 @@ void mesh_unreg_prov_rx(prov_rx_cb_t cb) mesh_io_deregister_recv_cb(mesh.io, MESH_IO_FILTER_PROV); } -bool mesh_init(const char *config_dir, enum mesh_io_type type, void *opts) +static void io_ready_callback(void *user_data, bool result) +{ + struct mesh_init_request *req = user_data; + + if (result) + node_attach_io_all(mesh.io); + + req->cb(req->user_data, result); + + l_free(req); +} + +bool mesh_init(const char *config_dir, enum mesh_io_type type, void *opts, + mesh_ready_func_t cb, void *user_data) { struct mesh_io_caps caps; + struct mesh_init_request *req; if (mesh.io) return true; @@ -159,16 +178,20 @@ bool mesh_init(const char *config_dir, enum mesh_io_type type, void *opts) if (!node_load_from_storage(storage_dir)) return false; - mesh.io = mesh_io_new(type, opts); - if (!mesh.io) + req = l_new(struct mesh_init_request, 1); + req->cb = cb; + req->user_data = user_data; + + mesh.io = mesh_io_new(type, opts, io_ready_callback, req); + if (!mesh.io) { + l_free(req); return false; + } l_debug("io %p", mesh.io); mesh_io_get_caps(mesh.io, &caps); mesh.max_filters = caps.max_num_filters; - node_attach_io_all(mesh.io); - return true; } diff --git a/mesh/mesh.h b/mesh/mesh.h index e0a3e1b96..c72632b15 100644 --- a/mesh/mesh.h +++ b/mesh/mesh.h @@ -30,9 +30,12 @@ enum mesh_io_type; +typedef void (*mesh_ready_func_t)(void *user_data, bool success); typedef void (*prov_rx_cb_t)(void *user_data, const uint8_t *data, uint16_t len); -bool mesh_init(const char *in_config_name, enum mesh_io_type type, void *opts); + +bool mesh_init(const char *in_config_name, enum mesh_io_type type, void *opts, + mesh_ready_func_t cb, void *user_data); void mesh_cleanup(void); bool mesh_dbus_init(struct l_dbus *dbus); -- 2.47.3