aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2014-02-27 07:35:12 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-28 02:35:08 -0500
commitc9910d0fb4fc2ede468b26d45a1d50c309897770 (patch)
treed25368485680682de3561753c394fdb2cffb92d3 /net/bluetooth
parent0f36b589e4eea0a0a27349992def2ea7beb45182 (diff)
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/mgmt.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 78ac7c864044..73b6ff817796 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1057,10 +1057,34 @@ static int clean_up_hci_state(struct hci_dev *hdev)
1057 1057
1058 list_for_each_entry(conn, &hdev->conn_hash.list, list) { 1058 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1059 struct hci_cp_disconnect dc; 1059 struct hci_cp_disconnect dc;
1060 1060 struct hci_cp_reject_conn_req rej;
1061 dc.handle = cpu_to_le16(conn->handle); 1061
1062 dc.reason = 0x15; /* Terminated due to Power Off */ 1062 switch (conn->state) {
1063 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc); 1063 case BT_CONNECTED:
1064 case BT_CONFIG:
1065 dc.handle = cpu_to_le16(conn->handle);
1066 dc.reason = 0x15; /* Terminated due to Power Off */
1067 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1068 break;
1069 case BT_CONNECT:
1070 if (conn->type == LE_LINK)
1071 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1072 0, NULL);
1073 else if (conn->type == ACL_LINK)
1074 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1075 6, &conn->dst);
1076 break;
1077 case BT_CONNECT2:
1078 bacpy(&rej.bdaddr, &conn->dst);
1079 rej.reason = 0x15; /* Terminated due to Power Off */
1080 if (conn->type == ACL_LINK)
1081 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1082 sizeof(rej), &rej);
1083 else if (conn->type == SCO_LINK)
1084 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1085 sizeof(rej), &rej);
1086 break;
1087 }
1064 } 1088 }
1065 1089
1066 return hci_req_run(&req, clean_up_hci_complete); 1090 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,
5184 u8 addr_type, u8 status) 5208 u8 addr_type, u8 status)
5185{ 5209{
5186 struct mgmt_ev_connect_failed ev; 5210 struct mgmt_ev_connect_failed ev;
5211 struct pending_cmd *power_off;
5212
5213 power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
5214 if (power_off) {
5215 struct mgmt_mode *cp = power_off->param;
5216
5217 /* The connection is still in hci_conn_hash so test for 1
5218 * instead of 0 to know if this is the last one.
5219 */
5220 if (!cp->val && hci_conn_count(hdev) == 1)
5221 queue_work(hdev->req_workqueue, &hdev->power_off.work);
5222 }
5187 5223
5188 bacpy(&ev.addr.bdaddr, bdaddr); 5224 bacpy(&ev.addr.bdaddr, bdaddr);
5189 ev.addr.type = link_to_bdaddr(link_type, addr_type); 5225 ev.addr.type = link_to_bdaddr(link_type, addr_type);