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

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
Loading
Loading
Loading
Loading
+48 −3
Original line number Diff line number Diff line
@@ -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;