Commit 9f150019 authored by Iulia Tanasescu's avatar Iulia Tanasescu Committed by Luiz Augusto von Dentz

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: default avatarIulia Tanasescu <iulia.tanasescu@nxp.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent d03376c1
...@@ -54,6 +54,7 @@ static void iso_sock_kill(struct sock *sk); ...@@ -54,6 +54,7 @@ static void iso_sock_kill(struct sock *sk);
enum { enum {
BT_SK_BIG_SYNC, BT_SK_BIG_SYNC,
BT_SK_PA_SYNC, BT_SK_PA_SYNC,
BT_SK_PA_SYNC_TERM,
}; };
struct iso_pinfo { struct iso_pinfo {
...@@ -82,6 +83,11 @@ static bool iso_match_sid(struct sock *sk, void *data); ...@@ -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 bool iso_match_sync_handle(struct sock *sk, void *data);
static void iso_sock_disconn(struct sock *sk); 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 ---- */ /* ---- ISO timers ---- */
#define ISO_CONN_TIMEOUT (HZ * 40) #define ISO_CONN_TIMEOUT (HZ * 40)
#define ISO_DISCONN_TIMEOUT (HZ * 2) #define ISO_DISCONN_TIMEOUT (HZ * 2)
...@@ -190,10 +196,21 @@ static void iso_chan_del(struct sock *sk, int err) ...@@ -190,10 +196,21 @@ static void iso_chan_del(struct sock *sk, int err)
sock_set_flag(sk, SOCK_ZAPPED); 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) static void iso_conn_del(struct hci_conn *hcon, int err)
{ {
struct iso_conn *conn = hcon->iso_data; struct iso_conn *conn = hcon->iso_data;
struct sock *sk; struct sock *sk;
struct sock *parent;
if (!conn) if (!conn)
return; return;
...@@ -209,6 +226,25 @@ static void iso_conn_del(struct hci_conn *hcon, int err) ...@@ -209,6 +226,25 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
if (sk) { if (sk) {
lock_sock(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_sock_clear_timer(sk);
iso_chan_del(sk, err); iso_chan_del(sk, err);
release_sock(sk); release_sock(sk);
...@@ -545,8 +581,6 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc, ...@@ -545,8 +581,6 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc,
return NULL; return NULL;
} }
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
/* Find socket listening: /* Find socket listening:
* source bdaddr (Unicast) * source bdaddr (Unicast)
* destination bdaddr (Broadcast only) * destination bdaddr (Broadcast only)
...@@ -1888,9 +1922,20 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) ...@@ -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 */ /* Try to get PA sync listening socket, if it exists */
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_pa_sync_flag, NULL); iso_match_pa_sync_flag, NULL);
if (!sk)
if (!sk) {
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_sync_handle, ev2); 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) { if (sk) {
int err; int err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment