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: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Родитель
aef2aa4fa9
Коммит
9b3628d79b
|
@ -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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче