lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 448/772] Bluetooth: hci_sync: Cleanup hci_conn if it cannot be aborted
    Date
    From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

    [ Upstream commit 9b3628d79b46f06157affc56fdb218fdd4988321 ]

    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>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    include/net/bluetooth/hci_core.h | 2 +-
    net/bluetooth/hci_conn.c | 32 ++++++++++++++++++++++++--------
    net/bluetooth/hci_event.c | 13 ++++---------
    net/bluetooth/hci_sync.c | 11 ++++++++++-
    4 files changed, 39 insertions(+), 19 deletions(-)

    diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
    index 49a88b2f4678..4524920e4895 100644
    --- a/include/net/bluetooth/hci_core.h
    +++ b/include/net/bluetooth/hci_core.h
    @@ -1147,7 +1147,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
    diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
    index cd51bf2a709b..882a7df13005 100644
    --- a/net/bluetooth/hci_conn.c
    +++ b/net/bluetooth/hci_conn.c
    @@ -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;
    diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
    index 4002a47832bc..1be745b228c1 100644
    --- a/net/bluetooth/hci_event.c
    +++ b/net/bluetooth/hci_event.c
    @@ -2846,7 +2846,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)
    @@ -2871,7 +2871,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)
    @@ -3185,12 +3185,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:
    @@ -5626,7 +5621,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;
    }

    diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
    index 8f4c5698913d..13600bf120b0 100644
    --- a/net/bluetooth/hci_sync.c
    +++ b/net/bluetooth/hci_sync.c
    @@ -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:
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-06-07 23:19    [W:4.209 / U:1.168 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site