• Ruihan Li's avatar
    Bluetooth: Unlink CISes when LE disconnects in hci_conn_del · a2904d28
    Ruihan Li authored
    Currently, hci_conn_del calls hci_conn_unlink for BR/EDR, (e)SCO, and
    CIS connections, i.e., everything except LE connections. However, if
    (e)SCO connections are unlinked when BR/EDR disconnects, CIS connections
    should also be unlinked when LE disconnects.
    
    In terms of disconnection behavior, CIS and (e)SCO connections are not
    too different. One peculiarity of CIS is that when CIS connections are
    disconnected, the CIS handle isn't deleted, as per [BLUETOOTH CORE
    SPECIFICATION Version 5.4 | Vol 4, Part E] 7.1.6 Disconnect command:
    
            All SCO, eSCO, and CIS connections on a physical link should be
            disconnected before the ACL connection on the same physical
            connection is disconnected. If it does not, they will be
            implicitly disconnected as part of the ACL disconnection.
            ...
            Note: As specified in Section 7.7.5, on the Central, the handle
            for a CIS remains valid even after disconnection and, therefore,
            the Host can recreate a disconnected CIS at a later point in
            time using the same connection handle.
    
    Since hci_conn_link invokes both hci_conn_get and hci_conn_hold,
    hci_conn_unlink should perform both hci_conn_put and hci_conn_drop as
    well. However, currently it performs only hci_conn_put.
    
    This patch makes hci_conn_unlink call hci_conn_drop as well, which
    simplifies the logic in hci_conn_del a bit and may benefit future users
    of hci_conn_unlink. But it is noted that this change additionally
    implies that hci_conn_unlink can queue disc_work on conn itself, with
    the following call stack:
    
            hci_conn_unlink(conn)  [conn->parent == NULL]
                    -> hci_conn_unlink(child)  [child->parent == conn]
                            -> hci_conn_drop(child->parent)
                                    -> queue_delayed_work(&conn->disc_work)
    
    Queued disc_work after hci_conn_del can be spurious, so during the
    process of hci_conn_del, it is necessary to make the call to
    cancel_delayed_work(&conn->disc_work) after invoking hci_conn_unlink.
    Signed-off-by: default avatarRuihan Li <lrh2000@pku.edu.cn>
    Co-developed-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
    Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
    a2904d28
hci_conn.c 71 KB