Bluetooth: ISO: Avoid creating child socket if PA sync is terminating

When a PA sync socket is closed, the associated hcon is also unlinked
and cleaned up. If there are no other hcons marked with the
HCI_CONN_PA_SYNC flag, HCI_OP_LE_PA_TERM_SYNC is sent to controller.

Between the time of the command and the moment PA sync is terminated
in controller, residual BIGInfo reports might continue to come.
This causes a new PA sync hcon to be added, and a new socket to be
notified to user space.

This commit fixs this by adding a flag on a Broadcast listening
socket to mark when the PA sync child has been closed.

This flag is checked when BIGInfo reports are indicated in
iso_connect_ind, to avoid recreating a hcon and socket if
residual reports arrive before PA sync is terminated.

Signed-off-by: Iulia Tanasescu <iulia.tanasescu@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Iulia Tanasescu 2023-12-05 18:11:40 +02:00 committed by Luiz Augusto von Dentz
parent d03376c185
commit 9f150019f1

View file

@ -54,6 +54,7 @@ static void iso_sock_kill(struct sock *sk);
enum {
BT_SK_BIG_SYNC,
BT_SK_PA_SYNC,
BT_SK_PA_SYNC_TERM,
};
struct iso_pinfo {
@ -82,6 +83,11 @@ static bool iso_match_sid(struct sock *sk, void *data);
static bool iso_match_sync_handle(struct sock *sk, void *data);
static void iso_sock_disconn(struct sock *sk);
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst,
iso_sock_match_t match, void *data);
/* ---- ISO timers ---- */
#define ISO_CONN_TIMEOUT (HZ * 40)
#define ISO_DISCONN_TIMEOUT (HZ * 2)
@ -190,10 +196,21 @@ static void iso_chan_del(struct sock *sk, int err)
sock_set_flag(sk, SOCK_ZAPPED);
}
static bool iso_match_conn_sync_handle(struct sock *sk, void *data)
{
struct hci_conn *hcon = data;
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags))
return false;
return hcon->sync_handle == iso_pi(sk)->sync_handle;
}
static void iso_conn_del(struct hci_conn *hcon, int err)
{
struct iso_conn *conn = hcon->iso_data;
struct sock *sk;
struct sock *parent;
if (!conn)
return;
@ -209,6 +226,25 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
if (sk) {
lock_sock(sk);
/* While a PA sync hcon is in the process of closing,
* mark parent socket with a flag, so that any residual
* BIGInfo adv reports that arrive before PA sync is
* terminated are not processed anymore.
*/
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
parent = iso_get_sock_listen(&hcon->src,
&hcon->dst,
iso_match_conn_sync_handle,
hcon);
if (parent) {
set_bit(BT_SK_PA_SYNC_TERM,
&iso_pi(parent)->flags);
sock_put(parent);
}
}
iso_sock_clear_timer(sk);
iso_chan_del(sk, err);
release_sock(sk);
@ -545,8 +581,6 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc,
return NULL;
}
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
/* Find socket listening:
* source bdaddr (Unicast)
* destination bdaddr (Broadcast only)
@ -1888,9 +1922,20 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
/* Try to get PA sync listening socket, if it exists */
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_pa_sync_flag, NULL);
if (!sk)
if (!sk) {
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_sync_handle, ev2);
/* If PA Sync is in process of terminating,
* do not handle any more BIGInfo adv reports.
*/
if (sk && test_bit(BT_SK_PA_SYNC_TERM,
&iso_pi(sk)->flags))
return lm;
}
if (sk) {
int err;