mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-15 16:24:28 +08:00
12b984d1d4
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.
205 lines
4.7 KiB
C
205 lines
4.7 KiB
C
/*
|
|
*
|
|
* 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;
|
|
}
|