diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2014-02-27 07:35:12 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-02-28 02:35:08 -0500 |
commit | c9910d0fb4fc2ede468b26d45a1d50c309897770 (patch) | |
tree | d25368485680682de3561753c394fdb2cffb92d3 /net/bluetooth | |
parent | 0f36b589e4eea0a0a27349992def2ea7beb45182 (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.c | 44 |
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); |