Commit 73d1df2a authored by Marcel Holtmann's avatar Marcel Holtmann
Browse files

Bluetooth: Add support for Read Unconfigured Index List command



This command allows to get the list of currently known controller that
are in unconfigured state.

Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent edd3896b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -464,6 +464,13 @@ struct mgmt_cp_load_conn_param {
} __packed;
#define MGMT_LOAD_CONN_PARAM_SIZE	2

#define MGMT_OP_READ_UNCONF_INDEX_LIST	0x0036
#define MGMT_READ_UNCONF_INDEX_LIST_SIZE 0
struct mgmt_rp_read_unconf_index_list {
	__le16	num_controllers;
	__le16	index[0];
} __packed;

#define MGMT_EV_CMD_COMPLETE		0x0001
struct mgmt_ev_cmd_complete {
	__le16	opcode;
+81 −10
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ static const u16 mgmt_commands[] = {
	MGMT_OP_ADD_DEVICE,
	MGMT_OP_REMOVE_DEVICE,
	MGMT_OP_LOAD_CONN_PARAM,
	MGMT_OP_READ_UNCONF_INDEX_LIST,
};

static const u16 mgmt_events[] = {
@@ -336,7 +337,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,

	count = 0;
	list_for_each_entry(d, &hci_dev_list, list) {
		if (d->dev_type == HCI_BREDR)
		if (d->dev_type == HCI_BREDR &&
		    !test_bit(HCI_UNCONFIGURED, &d->dev_flags))
			count++;
	}

@@ -349,16 +351,18 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,

	count = 0;
	list_for_each_entry(d, &hci_dev_list, list) {
		if (test_bit(HCI_SETUP, &d->dev_flags))
		if (test_bit(HCI_SETUP, &d->dev_flags) ||
		    test_bit(HCI_USER_CHANNEL, &d->dev_flags))
			continue;

		if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
			continue;

		if (test_bit(HCI_UNCONFIGURED, &d->dev_flags))
		/* 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 (d->dev_type == HCI_BREDR &&
		    !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) {
			rp->index[count++] = cpu_to_le16(d->id);
			BT_DBG("Added hci%u", d->id);
		}
@@ -377,6 +381,65 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
	return err;
}

static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
				  void *data, u16 data_len)
{
	struct mgmt_rp_read_unconf_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 &&
		    test_bit(HCI_UNCONFIGURED, &d->dev_flags))
			count++;
	}

	rp_len = sizeof(*rp) + (2 * 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 (test_bit(HCI_SETUP, &d->dev_flags) ||
		    test_bit(HCI_USER_CHANNEL, &d->dev_flags))
			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 &&
		    test_bit(HCI_UNCONFIGURED, &d->dev_flags)) {
			rp->index[count++] = cpu_to_le16(d->id);
			BT_DBG("Added hci%u", d->id);
		}
	}

	rp->num_controllers = cpu_to_le16(count);
	rp_len = sizeof(*rp) + (2 * count);

	read_unlock(&hci_dev_list_lock);

	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_UNCONF_INDEX_LIST,
			   0, rp, rp_len);

	kfree(rp);

	return err;
}

static u32 get_supported_settings(struct hci_dev *hdev)
{
	u32 settings = 0;
@@ -5274,6 +5337,7 @@ static const struct mgmt_handler {
	{ add_device,             false, MGMT_ADD_DEVICE_SIZE },
	{ remove_device,          false, MGMT_REMOVE_DEVICE_SIZE },
	{ load_conn_param,        true,  MGMT_LOAD_CONN_PARAM_SIZE },
	{ read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE },
};

int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
@@ -5335,8 +5399,15 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
		goto done;
	}

	if ((hdev && opcode < MGMT_OP_READ_INFO) ||
	    (!hdev && opcode >= MGMT_OP_READ_INFO)) {
	if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST ||
		     opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) {
		err = cmd_status(sk, index, opcode,
				 MGMT_STATUS_INVALID_INDEX);
		goto done;
	}

	if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST &&
		      opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) {
		err = cmd_status(sk, index, opcode,
				 MGMT_STATUS_INVALID_INDEX);
		goto done;