Re: [PATCH v2 1/1] Bluetooth: ISO: Notify user space about failed bis connections

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Iulia,

On Wed, Jun 28, 2023 at 8:06 AM Iulia Tanasescu <iulia.tanasescu@xxxxxxx> wrote:
>
> Some use cases require the user to be informed if BIG synchronization
> fails. This commit makes it so that even if the BIG sync established
> event arrives with error status, a new hconn is added for each BIS,
> and the iso layer is notified about the failed connections.
>
> Unsuccesful bis connections will be marked using the
> HCI_CONN_BIG_SYNC_FAILED flag. From the iso layer, the POLLERR event
> is triggered on the newly allocated bis sockets, before adding them
> to the accept list of the parent socket.
>
> From user space, a new fd for each failed bis connection will be
> obtained by calling accept. The user should check for the POLLERR
> event on the new socket, to determine if the connection was successful
> or not.
>
> The HCI_CONN_BIG_SYNC flag has been added to mark whether the BIG sync
> has been successfully established. This flag is checked at bis cleanup,
> so the HCI LE BIG Terminate Sync command is only issued if needed.
>
> The BT_SK_BIG_SYNC flag indicates if BIG create sync has been called
> for a listening socket, to avoid issuing the command everytime a BIGInfo
> advertising report is received.
>
> Signed-off-by: Iulia Tanasescu <iulia.tanasescu@xxxxxxx>
> ---
>  include/net/bluetooth/hci_core.h | 25 ++++++++++++++++
>  net/bluetooth/hci_conn.c         | 50 +++++++++++++++++---------------
>  net/bluetooth/hci_event.c        | 21 +++++++++++---
>  net/bluetooth/iso.c              | 37 ++++++++++++++++-------
>  4 files changed, 95 insertions(+), 38 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 05a9b3ab3f56..f068a578ff59 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -978,6 +978,8 @@ enum {
>         HCI_CONN_PER_ADV,
>         HCI_CONN_BIG_CREATED,
>         HCI_CONN_CREATE_CIS,
> +       HCI_CONN_BIG_SYNC,
> +       HCI_CONN_BIG_SYNC_FAILED,
>  };
>
>  static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
> @@ -1288,6 +1290,29 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
>         return NULL;
>  }
>
> +static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *hdev,
> +                                                       __u8 handle)
> +{
> +       struct hci_conn_hash *h = &hdev->conn_hash;
> +       struct hci_conn  *c;
> +
> +       rcu_read_lock();
> +
> +       list_for_each_entry_rcu(c, &h->list, list) {
> +               if (c->type != ISO_LINK)
> +                       continue;
> +
> +               if (handle == c->iso_qos.bcast.big) {
> +                       rcu_read_unlock();
> +                       return c;
> +               }
> +       }
> +
> +       rcu_read_unlock();
> +
> +       return NULL;
> +}
> +
>  static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
>                                                         __u8 type, __u16 state)
>  {
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 47e7aa4d63a9..491ca8e876f0 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -686,6 +686,19 @@ static void hci_conn_timeout(struct work_struct *work)
>                 return;
>         }
>
> +       /* Cleanup bises that failed to be established */
> +       if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags)) {
> +               conn->state = BT_CLOSED;
> +               hci_disconn_cfm(conn, hci_proto_disconn_ind(conn));
> +               hci_conn_hash_del(conn->hdev, conn);
> +
> +               if (conn->cleanup)
> +                       conn->cleanup(conn);
> +
> +               hci_conn_put(conn);
> +               return;
> +       }

I will be pushing some changes to how hci_abort_conn works, the code
above shall probably be done inside the likes of hci_conn_failed
though but first we need to add support for BIS into
hci_abort_conn_sync.

>         hci_abort_conn(conn, hci_proto_disconn_ind(conn));
>  }
>
> @@ -793,6 +806,7 @@ struct iso_list_data {
>         int count;
>         struct iso_cig_params pdu;
>         bool big_term;
> +       bool big_sync_term;
>  };
>
>  static void bis_list(struct hci_conn *conn, void *data)
> @@ -810,17 +824,6 @@ static void bis_list(struct hci_conn *conn, void *data)
>         d->count++;
>  }
>
> -static void find_bis(struct hci_conn *conn, void *data)
> -{
> -       struct iso_list_data *d = data;
> -
> -       /* Ignore unicast */
> -       if (bacmp(&conn->dst, BDADDR_ANY))
> -               return;
> -
> -       d->count++;
> -}
> -
>  static int terminate_big_sync(struct hci_dev *hdev, void *data)
>  {
>         struct iso_list_data *d = data;
> @@ -873,31 +876,26 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
>         bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", d->big,
>                    d->sync_handle);
>
> -       /* Check if ISO connection is a BIS and terminate BIG if there are
> -        * no other connections using it.
> -        */
> -       hci_conn_hash_list_state(hdev, find_bis, ISO_LINK, BT_CONNECTED, d);
> -       if (d->count)
> -               return 0;
> -
> -       hci_le_big_terminate_sync(hdev, d->big);
> +       if (d->big_sync_term)
> +               hci_le_big_terminate_sync(hdev, d->big);
>
>         return hci_le_pa_terminate_sync(hdev, d->sync_handle);
>  }
>
> -static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
> +static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
>  {
>         struct iso_list_data *d;
>         int ret;
>
> -       bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle);
> +       bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle);
>
>         d = kzalloc(sizeof(*d), GFP_KERNEL);
>         if (!d)
>                 return -ENOMEM;
>
>         d->big = big;
> -       d->sync_handle = sync_handle;
> +       d->sync_handle = conn->sync_handle;
> +       d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
>
>         ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
>                                  terminate_big_destroy);
> @@ -933,8 +931,14 @@ static void bis_cleanup(struct hci_conn *conn)
>
>                 hci_le_terminate_big(hdev, conn);
>         } else {
> +               bis = hci_conn_hash_lookup_big_any_dst(hdev,
> +                                                      conn->iso_qos.bcast.big);
> +
> +               if (bis)
> +                       return;
> +
>                 hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
> -                                    conn->sync_handle);
> +                                    conn);
>         }
>  }
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 77cbf13037b3..30d0a6631e17 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -7039,9 +7039,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
>                                 flex_array_size(ev, bis, ev->num_bis)))
>                 return;
>
> -       if (ev->status)
> -               return;
> -
>         hci_dev_lock(hdev);
>
>         for (i = 0; i < ev->num_bis; i++) {
> @@ -7065,9 +7062,25 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
>                 bis->iso_qos.bcast.in.latency = le16_to_cpu(ev->interval) * 125 / 100;
>                 bis->iso_qos.bcast.in.sdu = le16_to_cpu(ev->max_pdu);
>
> -               hci_iso_setup_path(bis);
> +               if (!ev->status) {
> +                       set_bit(HCI_CONN_BIG_SYNC, &bis->flags);
> +                       hci_iso_setup_path(bis);
> +               }
>         }
>
> +       /* In case BIG sync failed, notify each failed connection to
> +        * the user after all hci connections have been added
> +        */
> +       if (ev->status)
> +               for (i = 0; i < ev->num_bis; i++) {
> +                       u16 handle = le16_to_cpu(ev->bis[i]);
> +
> +                       bis = hci_conn_hash_lookup_handle(hdev, handle);
> +
> +                       set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags);
> +                       hci_connect_cfm(bis, ev->status);
> +               }
> +
>         hci_dev_unlock(hdev);
>  }
>
> diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
> index 84d238d0639a..e0386b12ea4e 100644
> --- a/net/bluetooth/iso.c
> +++ b/net/bluetooth/iso.c
> @@ -48,6 +48,11 @@ static void iso_sock_kill(struct sock *sk);
>  #define EIR_SERVICE_DATA_LENGTH 4
>  #define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)
>
> +/* iso_pinfo flags values */
> +enum {
> +       BT_SK_BIG_SYNC,
> +};
> +
>  struct iso_pinfo {
>         struct bt_sock          bt;
>         bdaddr_t                src;
> @@ -58,7 +63,7 @@ struct iso_pinfo {
>         __u8                    bc_num_bis;
>         __u8                    bc_bis[ISO_MAX_NUM_BIS];
>         __u16                   sync_handle;
> -       __u32                   flags;
> +       unsigned long           flags;
>         struct bt_iso_qos       qos;
>         bool                    qos_user_set;
>         __u8                    base_len;
> @@ -1569,6 +1574,12 @@ static void iso_conn_ready(struct iso_conn *conn)
>                 hci_conn_hold(hcon);
>                 iso_chan_add(conn, sk, parent);
>
> +               if (ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) {
> +                       /* Trigger error signal on child socket */
> +                       sk->sk_err = ECONNREFUSED;
> +                       sk->sk_error_report(sk);
> +               }
> +
>                 if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
>                         sk->sk_state = BT_CONNECT2;
>                 else
> @@ -1637,15 +1648,19 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
>                         if (ev2->num_bis < iso_pi(sk)->bc_num_bis)
>                                 iso_pi(sk)->bc_num_bis = ev2->num_bis;
>
> -                       err = hci_le_big_create_sync(hdev,
> -                                                    &iso_pi(sk)->qos,
> -                                                    iso_pi(sk)->sync_handle,
> -                                                    iso_pi(sk)->bc_num_bis,
> -                                                    iso_pi(sk)->bc_bis);
> -                       if (err) {
> -                               bt_dev_err(hdev, "hci_le_big_create_sync: %d",
> -                                          err);
> -                               sk = NULL;
> +                       if (!test_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
> +                               set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags);

You can probably use test_and_set_bit instead above.

> +
> +                               err = hci_le_big_create_sync(hdev,
> +                                                            &iso_pi(sk)->qos,
> +                                                            iso_pi(sk)->sync_handle,
> +                                                            iso_pi(sk)->bc_num_bis,
> +                                                            iso_pi(sk)->bc_bis);
> +                               if (err) {
> +                                       bt_dev_err(hdev, "hci_le_big_create_sync: %d",
> +                                                  err);
> +                                       sk = NULL;
> +                               }
>                         }
>                 }
>         } else {
> @@ -1688,7 +1703,7 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
>
>         BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
>
> -       if (!status) {
> +       if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {

Shouldn't it be !test_bit above?

>                 struct iso_conn *conn;
>
>                 conn = iso_conn_add(hcon);
> --
> 2.34.1
>


-- 
Luiz Augusto von Dentz




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux