Commit 56e5cb86 authored by Johan Hedberg's avatar Johan Hedberg Committed by Gustavo F. Padovan

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
...@@ -549,8 +549,11 @@ int hci_dev_open(__u16 dev) ...@@ -549,8 +549,11 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev); hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags); set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP); 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); mgmt_powered(hdev, 1);
hci_dev_unlock_bh(hdev);
}
} else { } else {
/* Init failed, cleanup */ /* Init failed, cleanup */
tasklet_kill(&hdev->rx_task); tasklet_kill(&hdev->rx_task);
...@@ -642,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -642,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */ * and no tasks are scheduled. */
hdev->close(hdev); hdev->close(hdev);
hci_dev_lock_bh(hdev);
mgmt_powered(hdev, 0); mgmt_powered(hdev, 0);
hci_dev_unlock_bh(hdev);
/* Clear flags */ /* Clear flags */
hdev->flags = 0; hdev->flags = 0;
...@@ -1561,8 +1566,11 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -1561,8 +1566,11 @@ void hci_unregister_dev(struct hci_dev *hdev)
kfree_skb(hdev->reassembly[i]); kfree_skb(hdev->reassembly[i]);
if (!test_bit(HCI_INIT, &hdev->flags) && 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); mgmt_index_removed(hdev);
hci_dev_unlock_bh(hdev);
}
/* mgmt_index_removed should take care of emptying the /* mgmt_index_removed should take care of emptying the
* pending list */ * pending list */
......
...@@ -60,7 +60,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -60,7 +60,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_INQUIRY, &hdev->flags); clear_bit(HCI_INQUIRY, &hdev->flags);
hci_dev_lock(hdev);
mgmt_discovering(hdev, 0); mgmt_discovering(hdev, 0);
hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); 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) ...@@ -201,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (!sent) if (!sent)
return; return;
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_set_local_name_complete(hdev, sent, status); mgmt_set_local_name_complete(hdev, sent, status);
if (status) if (status == 0)
return; memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
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) 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) ...@@ -282,6 +286,8 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
param = *((__u8 *) sent); param = *((__u8 *) sent);
hci_dev_lock(hdev);
if (status != 0) { if (status != 0) {
mgmt_write_scan_failed(hdev, param, status); mgmt_write_scan_failed(hdev, param, status);
hdev->discov_timeout = 0; hdev->discov_timeout = 0;
...@@ -311,6 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -311,6 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
mgmt_connectable(hdev, 0); mgmt_connectable(hdev, 0);
done: done:
hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status); 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) ...@@ -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); BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status); mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
if (rp->status != 0) if (rp->status != 0)
return; goto unlock;
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY); cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
if (!cp) if (!cp)
return; goto unlock;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn) if (conn)
conn->pin_length = cp->pin_len; 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) 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) ...@@ -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); BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr, mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
rp->status); rp->status);
hci_dev_unlock(hdev);
} }
static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -885,9 +902,13 @@ static void hci_cc_user_confirm_reply(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); BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr, mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
rp->status); rp->status);
hci_dev_unlock(hdev);
} }
static void hci_cc_user_confirm_neg_reply(struct hci_dev *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, ...@@ -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); BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr, mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
rp->status); rp->status);
hci_dev_unlock(hdev);
} }
static void hci_cc_read_local_oob_data_reply(struct hci_dev *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, ...@@ -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); BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
mgmt_read_local_oob_data_reply_complete(hdev, rp->hash, mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
rp->randomizer, rp->status); rp->randomizer, rp->status);
hci_dev_unlock(hdev);
} }
static void hci_cc_le_set_scan_enable(struct hci_dev *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) ...@@ -985,14 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
if (status) { if (status) {
hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags)) if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_inquiry_failed(hdev, status); mgmt_inquiry_failed(hdev, status);
hci_dev_unlock(hdev);
return; return;
} }
set_bit(HCI_INQUIRY, &hdev->flags); set_bit(HCI_INQUIRY, &hdev->flags);
hci_dev_lock(hdev);
mgmt_discovering(hdev, 1); mgmt_discovering(hdev, 1);
hci_dev_unlock(hdev);
} }
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) 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 ...@@ -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)) if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
return; return;
hci_dev_lock(hdev);
mgmt_discovering(hdev, 0); mgmt_discovering(hdev, 0);
hci_dev_unlock(hdev);
} }
static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) 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 ...@@ -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); BT_DBG("%s status %d", hdev->name, ev->status);
if (ev->status) { if (ev->status) {
hci_dev_lock(hdev);
mgmt_disconnect_failed(hdev); mgmt_disconnect_failed(hdev);
hci_dev_unlock(hdev);
return; return;
} }
......
...@@ -1335,16 +1335,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) ...@@ -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) static void pairing_complete_cb(struct hci_conn *conn, u8 status)
{ {
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct hci_dev *hdev = conn->hdev;
BT_DBG("status %u", status); BT_DBG("status %u", status);
hci_dev_lock_bh(hdev);
cmd = find_pairing(conn); cmd = find_pairing(conn);
if (!cmd) { if (!cmd)
BT_DBG("Unable to find a pending command"); BT_DBG("Unable to find a pending command");
return; else
} pairing_complete(cmd, status);
pairing_complete(cmd, status); hci_dev_unlock_bh(hdev);
} }
static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) 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) ...@@ -2302,9 +2305,7 @@ int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
goto failed; goto failed;
} }
hci_dev_lock_bh(hdev);
update_eir(hdev); update_eir(hdev);
hci_dev_unlock_bh(hdev);
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev, err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
sizeof(ev)); sizeof(ev));
......
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