mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
Bluetooth: Fix disconnecting connections in non-connected states
When powering off and disconnecting devices we should also consider connections which have not yet reached the BT_CONNECTED state. They may not have a valid handle yet and simply sending a HCI_Disconnect will not work. This patch updates the code to either disconnect, cancel connection creation or reject incoming connection creation based on the current conn->state value as well as the link type in question. When the power off procedure results in canceling connection attempts instead of disconnecting connections we get a connection failed event instead of a disconnection event. Therefore, we also need to have extra code in the mgmt_connect_failed function to check if we should proceed with the power off or not. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
0f36b589e4
commit
c9910d0fb4
@ -1057,10 +1057,34 @@ static int clean_up_hci_state(struct hci_dev *hdev)
|
||||
|
||||
list_for_each_entry(conn, &hdev->conn_hash.list, list) {
|
||||
struct hci_cp_disconnect dc;
|
||||
struct hci_cp_reject_conn_req rej;
|
||||
|
||||
dc.handle = cpu_to_le16(conn->handle);
|
||||
dc.reason = 0x15; /* Terminated due to Power Off */
|
||||
hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
|
||||
switch (conn->state) {
|
||||
case BT_CONNECTED:
|
||||
case BT_CONFIG:
|
||||
dc.handle = cpu_to_le16(conn->handle);
|
||||
dc.reason = 0x15; /* Terminated due to Power Off */
|
||||
hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
|
||||
break;
|
||||
case BT_CONNECT:
|
||||
if (conn->type == LE_LINK)
|
||||
hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
|
||||
0, NULL);
|
||||
else if (conn->type == ACL_LINK)
|
||||
hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
|
||||
6, &conn->dst);
|
||||
break;
|
||||
case BT_CONNECT2:
|
||||
bacpy(&rej.bdaddr, &conn->dst);
|
||||
rej.reason = 0x15; /* Terminated due to Power Off */
|
||||
if (conn->type == ACL_LINK)
|
||||
hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
|
||||
sizeof(rej), &rej);
|
||||
else if (conn->type == SCO_LINK)
|
||||
hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
|
||||
sizeof(rej), &rej);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hci_req_run(&req, clean_up_hci_complete);
|
||||
@ -5184,6 +5208,18 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 status)
|
||||
{
|
||||
struct mgmt_ev_connect_failed ev;
|
||||
struct pending_cmd *power_off;
|
||||
|
||||
power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
|
||||
if (power_off) {
|
||||
struct mgmt_mode *cp = power_off->param;
|
||||
|
||||
/* The connection is still in hci_conn_hash so test for 1
|
||||
* instead of 0 to know if this is the last one.
|
||||
*/
|
||||
if (!cp->val && hci_conn_count(hdev) == 1)
|
||||
queue_work(hdev->req_workqueue, &hdev->power_off.work);
|
||||
}
|
||||
|
||||
bacpy(&ev.addr.bdaddr, bdaddr);
|
||||
ev.addr.type = link_to_bdaddr(link_type, addr_type);
|
||||
|
Loading…
Reference in New Issue
Block a user