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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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_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
+24 −8
Original line number Diff line number Diff line
@@ -670,7 +670,7 @@ static void le_conn_timeout(struct work_struct *work)
		/* Disable LE Advertising */
		le_disable_advertising(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);
		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);

/* 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_conn_params *params;
@@ -886,8 +886,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
		params->conn = NULL;
	}

	conn->state = BT_CLOSED;

	/* If the status indicates successful cancellation of
	 * the attempt (i.e. Unknown Connection Id) there's no point of
	 * 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,
				    conn->dst_type, status);

	hci_connect_cfm(conn, status);

	hci_conn_del(conn);

	/* Since we may have temporarily stopped the background scanning in
	 * 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);
}

/* 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)
{
	struct hci_conn *conn = data;
+4 −9
Original line number Diff line number Diff line
@@ -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);

	/* 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.
	 */
	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);

	/* 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.
	 */
	if (status)
@@ -3179,12 +3179,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,

done:
	if (status) {
		conn->state = BT_CLOSED;
		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);
		hci_conn_failed(conn, status);
	} else if (ev->link_type == SCO_LINK) {
		switch (conn->setting & SCO_AIRMODE_MASK) {
		case SCO_AIRMODE_CVSD:
@@ -5623,7 +5618,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
	}

	if (status) {
		hci_le_conn_failed(conn, status);
		hci_conn_failed(conn, status);
		goto unlock;
	}

+10 −1
Original line number Diff line number Diff line
@@ -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,
			       u8 reason)
{
	int err;

	switch (conn->state) {
	case BT_CONNECTED:
	case BT_CONFIG:
		return hci_disconnect_sync(hdev, conn, reason);
	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:
		return hci_reject_conn_sync(hdev, conn, reason);
	default: