Commit 9b3628d7 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

Bluetooth: hci_sync: Cleanup hci_conn if it cannot be aborted

This attempts to cleanup the hci_conn if it cannot be aborted as
otherwise it would likely result in having the controller and host
stack out of sync with respect to connection handle.
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent aef2aa4f
...@@ -1156,7 +1156,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role); ...@@ -1156,7 +1156,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active); void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
void hci_le_conn_failed(struct hci_conn *conn, u8 status); void hci_conn_failed(struct hci_conn *conn, u8 status);
/* /*
* hci_conn_get() and hci_conn_put() are used to control the life-time of an * hci_conn_get() and hci_conn_put() are used to control the life-time of an
......
...@@ -670,7 +670,7 @@ static void le_conn_timeout(struct work_struct *work) ...@@ -670,7 +670,7 @@ static void le_conn_timeout(struct work_struct *work)
/* Disable LE Advertising */ /* Disable LE Advertising */
le_disable_advertising(hdev); le_disable_advertising(hdev);
hci_dev_lock(hdev); hci_dev_lock(hdev);
hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); hci_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return; return;
} }
...@@ -873,7 +873,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type) ...@@ -873,7 +873,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
EXPORT_SYMBOL(hci_get_route); EXPORT_SYMBOL(hci_get_route);
/* This function requires the caller holds hdev->lock */ /* This function requires the caller holds hdev->lock */
void hci_le_conn_failed(struct hci_conn *conn, u8 status) static void hci_le_conn_failed(struct hci_conn *conn, u8 status)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
struct hci_conn_params *params; struct hci_conn_params *params;
...@@ -886,8 +886,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) ...@@ -886,8 +886,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
params->conn = NULL; params->conn = NULL;
} }
conn->state = BT_CLOSED;
/* If the status indicates successful cancellation of /* If the status indicates successful cancellation of
* the attempt (i.e. Unknown Connection Id) there's no point of * the attempt (i.e. Unknown Connection Id) there's no point of
* notifying failure since we'll go back to keep trying to * notifying failure since we'll go back to keep trying to
...@@ -899,10 +897,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) ...@@ -899,10 +897,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
mgmt_connect_failed(hdev, &conn->dst, conn->type, mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status); conn->dst_type, status);
hci_connect_cfm(conn, status);
hci_conn_del(conn);
/* Since we may have temporarily stopped the background scanning in /* Since we may have temporarily stopped the background scanning in
* favor of connection establishment, we should restart it. * favor of connection establishment, we should restart it.
*/ */
...@@ -914,6 +908,28 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) ...@@ -914,6 +908,28 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_enable_advertising(hdev); hci_enable_advertising(hdev);
} }
/* This function requires the caller holds hdev->lock */
void hci_conn_failed(struct hci_conn *conn, u8 status)
{
struct hci_dev *hdev = conn->hdev;
bt_dev_dbg(hdev, "status 0x%2.2x", status);
switch (conn->type) {
case LE_LINK:
hci_le_conn_failed(conn, status);
break;
case ACL_LINK:
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
break;
}
conn->state = BT_CLOSED;
hci_connect_cfm(conn, status);
hci_conn_del(conn);
}
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err) static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
{ {
struct hci_conn *conn = data; struct hci_conn *conn = data;
......
...@@ -2834,7 +2834,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) ...@@ -2834,7 +2834,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
bt_dev_dbg(hdev, "status 0x%2.2x", status); bt_dev_dbg(hdev, "status 0x%2.2x", status);
/* All connection failure handling is taken care of by the /* All connection failure handling is taken care of by the
* hci_le_conn_failed function which is triggered by the HCI * hci_conn_failed function which is triggered by the HCI
* request completion callbacks used for connecting. * request completion callbacks used for connecting.
*/ */
if (status) if (status)
...@@ -2859,7 +2859,7 @@ static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status) ...@@ -2859,7 +2859,7 @@ static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status)
bt_dev_dbg(hdev, "status 0x%2.2x", status); bt_dev_dbg(hdev, "status 0x%2.2x", status);
/* All connection failure handling is taken care of by the /* All connection failure handling is taken care of by the
* hci_le_conn_failed function which is triggered by the HCI * hci_conn_failed function which is triggered by the HCI
* request completion callbacks used for connecting. * request completion callbacks used for connecting.
*/ */
if (status) if (status)
...@@ -3179,12 +3179,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, ...@@ -3179,12 +3179,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
done: done:
if (status) { if (status) {
conn->state = BT_CLOSED; hci_conn_failed(conn, status);
if (conn->type == ACL_LINK)
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
hci_connect_cfm(conn, status);
hci_conn_del(conn);
} else if (ev->link_type == SCO_LINK) { } else if (ev->link_type == SCO_LINK) {
switch (conn->setting & SCO_AIRMODE_MASK) { switch (conn->setting & SCO_AIRMODE_MASK) {
case SCO_AIRMODE_CVSD: case SCO_AIRMODE_CVSD:
...@@ -5623,7 +5618,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, ...@@ -5623,7 +5618,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
} }
if (status) { if (status) {
hci_le_conn_failed(conn, status); hci_conn_failed(conn, status);
goto unlock; goto unlock;
} }
......
...@@ -4408,12 +4408,21 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, ...@@ -4408,12 +4408,21 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
static int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, static int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
u8 reason) u8 reason)
{ {
int err;
switch (conn->state) { switch (conn->state) {
case BT_CONNECTED: case BT_CONNECTED:
case BT_CONFIG: case BT_CONFIG:
return hci_disconnect_sync(hdev, conn, reason); return hci_disconnect_sync(hdev, conn, reason);
case BT_CONNECT: case BT_CONNECT:
return hci_connect_cancel_sync(hdev, conn); err = hci_connect_cancel_sync(hdev, conn);
/* Cleanup hci_conn object if it cannot be cancelled as it
* likelly means the controller and host stack are out of sync.
*/
if (err)
hci_conn_failed(conn, err);
return err;
case BT_CONNECT2: case BT_CONNECT2:
return hci_reject_conn_sync(hdev, conn, reason); return hci_reject_conn_sync(hdev, conn, reason);
default: default:
......
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