diff options
author | MichaĆ Lowas-Rzechonek <michal.lowas-rzechonek@silvair.com> | 2019-06-24 09:32:28 +0200 |
---|---|---|
committer | Brian Gix <brian.gix@intel.com> | 2019-06-24 09:04:44 -0700 |
commit | 12b984d1d4d47a8fd5bc8455d586bb208b804ebf (patch) | |
tree | 9ea739eea2eeffafcdfd5186e3f9d8f76ed2aae6 /mesh/mesh-mgmt.c | |
parent | ee70e5e070505e7caef66e9446ac586c378bde0f (diff) | |
download | bluez-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.c | 204 |
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; +} |