Bluetooth: Add support for extended index management command

The Read Extended Contoller Index List command can be used for
retrieving the complete list of local available controllers. This
included configured, unconfigured and also AMP controllers.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Marcel Holtmann
2015-03-14 19:27:57 -07:00
committed by Johan Hedberg
parent ced85549c3
commit 96f1474af0
2 changed files with 91 additions and 0 deletions

View File

@@ -96,6 +96,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_SET_EXTERNAL_CONFIG,
MGMT_OP_SET_PUBLIC_ADDRESS,
MGMT_OP_START_SERVICE_DISCOVERY,
MGMT_OP_READ_EXT_INDEX_LIST,
};
static const u16 mgmt_events[] = {
@@ -518,6 +519,82 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
return err;
}
static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
struct mgmt_rp_read_ext_index_list *rp;
struct hci_dev *d;
size_t rp_len;
u16 count;
int err;
BT_DBG("sock %p", sk);
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
count++;
}
rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
read_unlock(&hci_dev_list_lock);
return -ENOMEM;
}
count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (hci_dev_test_flag(d, HCI_SETUP) ||
hci_dev_test_flag(d, HCI_CONFIG) ||
hci_dev_test_flag(d, HCI_USER_CHANNEL))
continue;
/* Devices marked as raw-only are neither configured
* nor unconfigured controllers.
*/
if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
continue;
if (d->dev_type == HCI_BREDR) {
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
rp->entry[count].type = 0x01;
else
rp->entry[count].type = 0x00;
} else if (d->dev_type == HCI_AMP) {
rp->entry[count].type = 0x02;
} else {
continue;
}
rp->entry[count].bus = d->bus;
rp->entry[count++].index = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
rp->num_controllers = cpu_to_le16(count);
rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
read_unlock(&hci_dev_list_lock);
/* If this command is called at least once, then all the
* default index and unconfigured index events are disabled
* and from now on only extended index events are used.
*/
hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
kfree(rp);
return err;
}
static bool is_configured(struct hci_dev *hdev)
{
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
@@ -6264,6 +6341,9 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
HCI_MGMT_UNCONFIGURED },
{ start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
HCI_MGMT_VAR_LEN },
{ NULL },
{ read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
HCI_MGMT_NO_HDEV },
};
int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,