Commit 96f1474a authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Johan Hedberg

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: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent ced85549
...@@ -505,6 +505,17 @@ struct mgmt_cp_start_service_discovery { ...@@ -505,6 +505,17 @@ struct mgmt_cp_start_service_discovery {
} __packed; } __packed;
#define MGMT_START_SERVICE_DISCOVERY_SIZE 4 #define MGMT_START_SERVICE_DISCOVERY_SIZE 4
#define MGMT_OP_READ_EXT_INDEX_LIST 0x003C
#define MGMT_READ_EXT_INDEX_LIST_SIZE 0
struct mgmt_rp_read_ext_index_list {
__le16 num_controllers;
struct {
__le16 index;
__u8 type;
__u8 bus;
} entry[0];
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
__le16 opcode; __le16 opcode;
......
...@@ -96,6 +96,7 @@ static const u16 mgmt_commands[] = { ...@@ -96,6 +96,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_SET_EXTERNAL_CONFIG, MGMT_OP_SET_EXTERNAL_CONFIG,
MGMT_OP_SET_PUBLIC_ADDRESS, MGMT_OP_SET_PUBLIC_ADDRESS,
MGMT_OP_START_SERVICE_DISCOVERY, MGMT_OP_START_SERVICE_DISCOVERY,
MGMT_OP_READ_EXT_INDEX_LIST,
}; };
static const u16 mgmt_events[] = { static const u16 mgmt_events[] = {
...@@ -518,6 +519,82 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, ...@@ -518,6 +519,82 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
return err; 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) static bool is_configured(struct hci_dev *hdev)
{ {
if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) && if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
...@@ -6264,6 +6341,9 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { ...@@ -6264,6 +6341,9 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
HCI_MGMT_UNCONFIGURED }, HCI_MGMT_UNCONFIGURED },
{ start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE, { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
HCI_MGMT_VAR_LEN }, 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, int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment