summaryrefslogtreecommitdiff
path: root/mesh/mesh-mgmt.c
diff options
context:
space:
mode:
authorMichaƂ Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com>2019-06-24 09:32:28 +0200
committerBrian Gix <brian.gix@intel.com>2019-06-24 09:04:44 -0700
commit12b984d1d4d47a8fd5bc8455d586bb208b804ebf (patch)
tree9ea739eea2eeffafcdfd5186e3f9d8f76ed2aae6 /mesh/mesh-mgmt.c
parentee70e5e070505e7caef66e9446ac586c378bde0f (diff)
downloadbluez-12b984d1d4d47a8fd5bc8455d586bb208b804ebf.tar.gz
mesh: Move HCI handling to mesh-io-generic
This patch separates 'mesh' module from 'mesh_io', particularly regarding configuration and initialization. Main code is no longer aware of MGMT and HCI usage - querying available HCI interfaces now happens in mesh-io-generic. MGMT code is now extracted into mesh-mgmt module, which mesh-io-generic uses to query interfaces.
Diffstat (limited to 'mesh/mesh-mgmt.c')
-rw-r--r--mesh/mesh-mgmt.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/mesh/mesh-mgmt.c b/mesh/mesh-mgmt.c
new file mode 100644
index 000000000..27272d4d2
--- /dev/null
+++ b/mesh/mesh-mgmt.c
@@ -0,0 +1,204 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2019 SILVAIR sp. z o.o. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+#include "src/shared/mgmt.h"
+
+#include "ell/queue.h"
+#include "ell/log.h"
+#include "ell/util.h"
+
+#include "mesh/mesh-mgmt.h"
+
+struct read_info_reg {
+ mesh_mgmt_read_info_func_t cb;
+ void *user_data;
+};
+
+struct read_info_req {
+ int index;
+ struct mesh_io *io;
+};
+
+static struct mgmt *mgmt_mesh;
+static struct l_queue *controllers;
+static struct l_queue *read_info_regs;
+
+static bool simple_match(const void *a, const void *b)
+{
+ return a == b;
+}
+
+static void process_read_info_req(void *data, void *user_data)
+{
+ struct read_info_reg *reg = data;
+ int index = L_PTR_TO_UINT(user_data);
+
+ reg->cb(index, reg->user_data);
+}
+
+static void read_info_cb(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ int index = L_PTR_TO_UINT(user_data);
+ const struct mgmt_rp_read_info *rp = param;
+ uint32_t current_settings, supported_settings;
+
+ l_debug("hci %u status 0x%02x", index, status);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ l_error("Failed to read info for hci index %u: %s (0x%02x)",
+ index, mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ l_error("Read info response too short");
+ return;
+ }
+
+ current_settings = btohl(rp->current_settings);
+ supported_settings = btohl(rp->supported_settings);
+
+ l_debug("settings: supp %8.8x curr %8.8x",
+ supported_settings, current_settings);
+
+ if (current_settings & MGMT_SETTING_POWERED) {
+ l_info("Controller hci %u is in use", index);
+ return;
+ }
+
+ if (!(supported_settings & MGMT_SETTING_LE)) {
+ l_info("Controller hci %u does not support LE", index);
+ return;
+ }
+
+ l_queue_foreach(read_info_regs, process_read_info_req,
+ L_UINT_TO_PTR(index));
+}
+
+static void index_added(uint16_t index, uint16_t length, const void *param,
+ void *user_data)
+{
+ if (l_queue_find(controllers, simple_match, L_UINT_TO_PTR(index)))
+ return;
+
+ l_queue_push_tail(controllers, L_UINT_TO_PTR(index));
+
+ if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_cb, L_UINT_TO_PTR(index), NULL) != 0)
+ return;
+
+ l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void index_removed(uint16_t index, uint16_t length, const void *param,
+ void *user_data)
+{
+ l_warn("Hci dev %4.4x removed", index);
+ l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void read_index_list_cb(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_index_list *rp = param;
+ uint16_t num;
+ int i;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ l_error("Failed to read index list: %s (0x%02x)",
+ mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ l_error("Read index list response sixe too short");
+ return;
+ }
+
+ num = btohs(rp->num_controllers);
+
+ l_debug("Number of controllers: %u", num);
+
+ if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+ l_error("Incorrect packet size for index list response");
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ uint16_t index;
+
+ index = btohs(rp->index[i]);
+ index_added(index, 0, NULL, user_data);
+ }
+}
+
+static bool mesh_mgmt_init(void)
+{
+ if (!controllers)
+ controllers = l_queue_new();
+
+ if (!read_info_regs)
+ read_info_regs = l_queue_new();
+
+ if (!mgmt_mesh) {
+ mgmt_mesh = mgmt_new_default();
+
+ if (!mgmt_mesh) {
+ l_error("Failed to initialize mesh management");
+ return false;
+ }
+
+ mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED,
+ MGMT_INDEX_NONE, index_added, NULL, NULL);
+ mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED,
+ MGMT_INDEX_NONE, index_removed, NULL, NULL);
+ }
+
+ return true;
+}
+
+bool mesh_mgmt_list(mesh_mgmt_read_info_func_t cb, void *user_data)
+{
+ struct read_info_reg *reg;
+
+ if (!mesh_mgmt_init())
+ return false;
+
+ reg = l_new(struct read_info_reg, 1);
+ reg->cb = cb;
+ reg->user_data = user_data;
+
+ l_queue_push_tail(read_info_regs, reg);
+
+ /* Use MGMT to find a candidate controller */
+ l_debug("send read index_list");
+ if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INDEX_LIST,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_cb, NULL, NULL) <= 0)
+ return false;
+
+ return true;
+}