Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56e5cb86 authored by Johan Hedberg's avatar Johan Hedberg Committed by Gustavo Padovan
Browse files

Bluetooth: Add missing hci_dev locking when calling mgmt functions



Now that the pending commands are within struct hci_dev we can properly
control access to them throught the hci_dev locking mechanism.

Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Acked-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 2e58ef3e
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -549,8 +549,11 @@ int hci_dev_open(__u16 dev)
		hci_dev_hold(hdev);
		set_bit(HCI_UP, &hdev->flags);
		hci_notify(hdev, HCI_DEV_UP);
		if (!test_bit(HCI_SETUP, &hdev->flags))
		if (!test_bit(HCI_SETUP, &hdev->flags)) {
			hci_dev_lock_bh(hdev);
			mgmt_powered(hdev, 1);
			hci_dev_unlock_bh(hdev);
		}
	} else {
		/* Init failed, cleanup */
		tasklet_kill(&hdev->rx_task);
@@ -642,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
	 * and no tasks are scheduled. */
	hdev->close(hdev);

	hci_dev_lock_bh(hdev);
	mgmt_powered(hdev, 0);
	hci_dev_unlock_bh(hdev);

	/* Clear flags */
	hdev->flags = 0;
@@ -1561,8 +1566,11 @@ void hci_unregister_dev(struct hci_dev *hdev)
		kfree_skb(hdev->reassembly[i]);

	if (!test_bit(HCI_INIT, &hdev->flags) &&
					!test_bit(HCI_SETUP, &hdev->flags))
					!test_bit(HCI_SETUP, &hdev->flags)) {
		hci_dev_lock_bh(hdev);
		mgmt_index_removed(hdev);
		hci_dev_unlock_bh(hdev);
	}

	/* mgmt_index_removed should take care of emptying the
	 * pending list */
+40 −5
Original line number Diff line number Diff line
@@ -60,7 +60,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)

	clear_bit(HCI_INQUIRY, &hdev->flags);

	hci_dev_lock(hdev);
	mgmt_discovering(hdev, 0);
	hci_dev_unlock(hdev);

	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);

@@ -201,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
	if (!sent)
		return;

	hci_dev_lock(hdev);

	if (test_bit(HCI_MGMT, &hdev->flags))
		mgmt_set_local_name_complete(hdev, sent, status);

	if (status)
		return;

	if (status == 0)
		memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);

	hci_dev_unlock(hdev);
}

static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -282,6 +286,8 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)

	param = *((__u8 *) sent);

	hci_dev_lock(hdev);

	if (status != 0) {
		mgmt_write_scan_failed(hdev, param, status);
		hdev->discov_timeout = 0;
@@ -311,6 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
		mgmt_connectable(hdev, 0);

done:
	hci_dev_unlock(hdev);
	hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
}

@@ -834,19 +841,24 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	hci_dev_lock(hdev);

	if (test_bit(HCI_MGMT, &hdev->flags))
		mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);

	if (rp->status != 0)
		return;
		goto unlock;

	cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
	if (!cp)
		return;
		goto unlock;

	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
	if (conn)
		conn->pin_length = cp->pin_len;

unlock:
	hci_dev_unlock(hdev);
}

static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -855,10 +867,15 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	hci_dev_lock(hdev);

	if (test_bit(HCI_MGMT, &hdev->flags))
		mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
								rp->status);

	hci_dev_unlock(hdev);
}

static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
				       struct sk_buff *skb)
{
@@ -885,9 +902,13 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	hci_dev_lock(hdev);

	if (test_bit(HCI_MGMT, &hdev->flags))
		mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
								rp->status);

	hci_dev_unlock(hdev);
}

static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
@@ -897,9 +918,13 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	hci_dev_lock(hdev);

	if (test_bit(HCI_MGMT, &hdev->flags))
		mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
								rp->status);

	hci_dev_unlock(hdev);
}

static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
@@ -909,8 +934,10 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	hci_dev_lock(hdev);
	mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
						rp->randomizer, rp->status);
	hci_dev_unlock(hdev);
}

static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -985,14 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
	if (status) {
		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
		hci_conn_check_pending(hdev);
		hci_dev_lock(hdev);
		if (test_bit(HCI_MGMT, &hdev->flags))
			mgmt_inquiry_failed(hdev, status);
		hci_dev_unlock(hdev);
		return;
	}

	set_bit(HCI_INQUIRY, &hdev->flags);

	hci_dev_lock(hdev);
	mgmt_discovering(hdev, 1);
	hci_dev_unlock(hdev);
}

static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1378,7 +1409,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
	if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
		return;

	hci_dev_lock(hdev);
	mgmt_discovering(hdev, 0);
	hci_dev_unlock(hdev);
}

static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1572,7 +1605,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
	BT_DBG("%s status %d", hdev->name, ev->status);

	if (ev->status) {
		hci_dev_lock(hdev);
		mgmt_disconnect_failed(hdev);
		hci_dev_unlock(hdev);
		return;
	}

+7 −6
Original line number Diff line number Diff line
@@ -1335,16 +1335,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
static void pairing_complete_cb(struct hci_conn *conn, u8 status)
{
	struct pending_cmd *cmd;
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("status %u", status);

	hci_dev_lock_bh(hdev);

	cmd = find_pairing(conn);
	if (!cmd) {
	if (!cmd)
		BT_DBG("Unable to find a pending command");
		return;
	}

	else
		pairing_complete(cmd, status);

	hci_dev_unlock_bh(hdev);
}

static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -2302,9 +2305,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
		goto failed;
	}

	hci_dev_lock_bh(hdev);
	update_eir(hdev);
	hci_dev_unlock_bh(hdev);

	err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
								sizeof(ev));